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