xref: /haiku/src/add-ons/kernel/file_systems/packagefs/nodes/UnpackingLeafNode.cpp (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
1 /*
2  * Copyright 2009-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "UnpackingLeafNode.h"
8 
9 #include <string.h>
10 
11 #include <algorithm>
12 #include <new>
13 
14 #include "ClassCache.h"
15 #include "UnpackingAttributeCookie.h"
16 #include "UnpackingAttributeDirectoryCookie.h"
17 #include "Utils.h"
18 
19 
20 CLASS_CACHE(UnpackingLeafNode);
21 
22 
23 UnpackingLeafNode::UnpackingLeafNode(ino_t id)
24 	:
25 	Node(id),
26 	fFinalPackageNode(NULL)
27 {
28 }
29 
30 
31 UnpackingLeafNode::~UnpackingLeafNode()
32 {
33 	if (fFinalPackageNode != NULL)
34 		fFinalPackageNode->ReleaseReference();
35 }
36 
37 
38 status_t
39 UnpackingLeafNode::VFSInit(dev_t deviceID)
40 {
41 	status_t error = NodeInitVFS(deviceID, fID, _ActivePackageNode());
42 	if (error == B_OK)
43 		Node::VFSInit(deviceID);
44 
45 	return error;
46 }
47 
48 
49 void
50 UnpackingLeafNode::VFSUninit()
51 {
52 	NodeUninitVFS(_ActivePackageNode(), fFlags);
53 	Node::VFSUninit();
54 }
55 
56 
57 mode_t
58 UnpackingLeafNode::Mode() const
59 {
60 	if (PackageLeafNode* packageNode = _ActivePackageNode())
61 		return packageNode->Mode();
62 	return S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
63 }
64 
65 
66 uid_t
67 UnpackingLeafNode::UserID() const
68 {
69 	if (PackageLeafNode* packageNode = _ActivePackageNode())
70 		return packageNode->UserID();
71 	return 0;
72 }
73 
74 
75 gid_t
76 UnpackingLeafNode::GroupID() const
77 {
78 	if (PackageLeafNode* packageNode = _ActivePackageNode())
79 		return packageNode->GroupID();
80 	return 0;
81 }
82 
83 
84 timespec
85 UnpackingLeafNode::ModifiedTime() const
86 {
87 	if (PackageLeafNode* packageNode = _ActivePackageNode())
88 		return packageNode->ModifiedTime();
89 
90 	timespec time = { 0, 0 };
91 	return time;
92 }
93 
94 
95 off_t
96 UnpackingLeafNode::FileSize() const
97 {
98 	if (PackageLeafNode* packageNode = _ActivePackageNode()) {
99 		if (S_ISLNK(packageNode->Mode()))
100 			return strlen(packageNode->SymlinkPath());
101 		return packageNode->FileSize();
102 	}
103 	return 0;
104 }
105 
106 
107 Node*
108 UnpackingLeafNode::GetNode()
109 {
110 	return this;
111 }
112 
113 
114 status_t
115 UnpackingLeafNode::AddPackageNode(PackageNode* packageNode, dev_t deviceID)
116 {
117 	ASSERT(fFinalPackageNode == NULL);
118 
119 	if (S_ISDIR(packageNode->Mode()))
120 		return B_IS_A_DIRECTORY;
121 
122 	PackageLeafNode* packageLeafNode
123 		= dynamic_cast<PackageLeafNode*>(packageNode);
124 
125 	PackageLeafNode* headNode = fPackageNodes.Head();
126 	bool overridesHead = headNode == NULL
127 		|| packageLeafNode->HasPrecedenceOver(headNode);
128 
129 	if (overridesHead) {
130 		fPackageNodes.Add(packageLeafNode);
131 		NodeReinitVFS(deviceID, fID, packageLeafNode, headNode, fFlags);
132 	} else {
133 		// add after the head
134 		fPackageNodes.RemoveHead();
135 		fPackageNodes.Add(packageLeafNode);
136 		fPackageNodes.Add(headNode);
137 	}
138 
139 	return B_OK;
140 }
141 
142 
143 void
144 UnpackingLeafNode::RemovePackageNode(PackageNode* packageNode, dev_t deviceID)
145 {
146 	ASSERT(fFinalPackageNode == NULL);
147 
148 	bool isNewest = packageNode == fPackageNodes.Head();
149 	fPackageNodes.Remove(dynamic_cast<PackageLeafNode*>(packageNode));
150 
151 	// when removing the newest node, we need to find the next node (the list
152 	// is not sorted)
153 	PackageLeafNode* newestNode = fPackageNodes.Head();
154 	if (isNewest && newestNode != NULL) {
155 		PackageLeafNodeList::ConstIterator it = fPackageNodes.GetIterator();
156 		it.Next();
157 			// skip the first one
158 		while (PackageLeafNode* otherNode = it.Next()) {
159 			if (otherNode->HasPrecedenceOver(newestNode))
160 				newestNode = otherNode;
161 		}
162 
163 		// re-add the newest node to the head
164 		fPackageNodes.Remove(newestNode);
165 		fPackageNodes.Add(newestNode);
166 		NodeReinitVFS(deviceID, fID, newestNode, packageNode, fFlags);
167 	}
168 }
169 
170 
171 PackageNode*
172 UnpackingLeafNode::GetPackageNode()
173 {
174 	return _ActivePackageNode();
175 }
176 
177 
178 bool
179 UnpackingLeafNode::IsOnlyPackageNode(PackageNode* node) const
180 {
181 	ASSERT(fFinalPackageNode == NULL);
182 
183 	PackageLeafNode* head = fPackageNodes.Head();
184 	return node == head && fPackageNodes.GetNext(head) == NULL;
185 }
186 
187 
188 bool
189 UnpackingLeafNode::WillBeFirstPackageNode(PackageNode* packageNode) const
190 {
191 	PackageLeafNode* packageLeafNode
192 		= dynamic_cast<PackageLeafNode*>(packageNode);
193 	if (packageLeafNode == NULL)
194 		return false;
195 
196 	PackageLeafNode* headNode = fPackageNodes.Head();
197 	return headNode == NULL
198 		|| packageLeafNode->HasPrecedenceOver(headNode);
199 }
200 
201 void
202 UnpackingLeafNode::PrepareForRemoval()
203 {
204 	ASSERT(fFinalPackageNode == NULL);
205 
206 	fFinalPackageNode = fPackageNodes.Head();
207 	if (fFinalPackageNode != NULL) {
208 		fFinalPackageNode->AcquireReference();
209 		fPackageNodes.MakeEmpty();
210 	}
211 }
212 
213 
214 status_t
215 UnpackingLeafNode::CloneTransferPackageNodes(ino_t id, UnpackingNode*& _newNode)
216 {
217 	ASSERT(fFinalPackageNode == NULL);
218 
219 	UnpackingLeafNode* clone = new UnpackingLeafNode(id);
220 	if (clone == NULL)
221 		return B_NO_MEMORY;
222 
223 	status_t error = clone->Init(Name());
224 	if (error != B_OK) {
225 		delete clone;
226 		return error;
227 	}
228 
229 	// We keep the old head as fFinalPackageNode, which will make us to behave
230 	// exactly as before with respect to FS operations.
231 	fFinalPackageNode = fPackageNodes.Head();
232 	if (fFinalPackageNode != NULL) {
233 		fFinalPackageNode->AcquireReference();
234 		clone->fPackageNodes.MoveFrom(&fPackageNodes);
235 	}
236 
237 	_newNode = clone;
238 	return B_OK;
239 }
240 
241 
242 status_t
243 UnpackingLeafNode::Read(off_t offset, void* buffer, size_t* bufferSize)
244 {
245 	if (HasVFSInitError())
246 		return B_ERROR;
247 
248 	if (PackageLeafNode* packageNode = _ActivePackageNode())
249 		return packageNode->Read(offset, buffer, bufferSize);
250 	return B_ERROR;
251 }
252 
253 
254 status_t
255 UnpackingLeafNode::Read(io_request* request)
256 {
257 	if (HasVFSInitError())
258 		return B_ERROR;
259 
260 	if (PackageLeafNode* packageNode = _ActivePackageNode())
261 		return packageNode->Read(request);
262 	return EBADF;
263 }
264 
265 
266 status_t
267 UnpackingLeafNode::ReadSymlink(void* buffer, size_t* bufferSize)
268 {
269 	if (HasVFSInitError())
270 		return B_ERROR;
271 
272 	PackageLeafNode* packageNode = _ActivePackageNode();
273 	if (packageNode == NULL)
274 		return B_BAD_VALUE;
275 
276 	const String& linkPath = packageNode->SymlinkPath();
277 	if (linkPath[0] == '\0') {
278 		*bufferSize = 0;
279 		return B_OK;
280 	}
281 
282 	size_t linkLength = strnlen(linkPath, B_PATH_NAME_LENGTH);
283 
284 	size_t bytesToCopy = std::min(linkLength, *bufferSize);
285 
286 	*bufferSize = linkLength;
287 
288 	memcpy(buffer, linkPath, bytesToCopy);
289 	return B_OK;
290 }
291 
292 
293 status_t
294 UnpackingLeafNode::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
295 {
296 	if (HasVFSInitError())
297 		return B_ERROR;
298 
299 	return UnpackingAttributeDirectoryCookie::Open(_ActivePackageNode(),
300 		_cookie);
301 }
302 
303 
304 status_t
305 UnpackingLeafNode::OpenAttribute(const StringKey& name, int openMode,
306 	AttributeCookie*& _cookie)
307 {
308 	if (HasVFSInitError())
309 		return B_ERROR;
310 
311 	return UnpackingAttributeCookie::Open(_ActivePackageNode(), name, openMode,
312 		_cookie);
313 }
314 
315 
316 status_t
317 UnpackingLeafNode::IndexAttribute(AttributeIndexer* indexer)
318 {
319 	return UnpackingAttributeCookie::IndexAttribute(_ActivePackageNode(),
320 		indexer);
321 }
322 
323 
324 void*
325 UnpackingLeafNode::IndexCookieForAttribute(const StringKey& name) const
326 {
327 	if (PackageLeafNode* packageNode = _ActivePackageNode())
328 		return packageNode->IndexCookieForAttribute(name);
329 	return NULL;
330 }
331 
332 
333 PackageLeafNode*
334 UnpackingLeafNode::_ActivePackageNode() const
335 {
336 	if (PackageLeafNode* packageNode = fPackageNodes.Head())
337 		return packageNode;
338 	return fFinalPackageNode;
339 }
340