xref: /haiku/src/add-ons/kernel/file_systems/packagefs/nodes/UnpackingLeafNode.cpp (revision 040a81419dda83d1014e9dc94936a4cb3f027303)
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 		return packageNode->FileSize();
96 	return 0;
97 }
98 
99 
100 Node*
101 UnpackingLeafNode::GetNode()
102 {
103 	return this;
104 }
105 
106 
107 status_t
108 UnpackingLeafNode::AddPackageNode(PackageNode* packageNode, dev_t deviceID)
109 {
110 	ASSERT(fFinalPackageNode == NULL);
111 
112 	if (S_ISDIR(packageNode->Mode()))
113 		return B_BAD_VALUE;
114 
115 	PackageLeafNode* packageLeafNode
116 		= dynamic_cast<PackageLeafNode*>(packageNode);
117 
118 	PackageLeafNode* headNode = fPackageNodes.Head();
119 	bool isNewest = headNode == NULL
120 		|| packageLeafNode->ModifiedTime() > headNode->ModifiedTime();
121 
122 	if (isNewest) {
123 		fPackageNodes.Add(packageLeafNode);
124 		NodeReinitVFS(deviceID, fID, packageLeafNode, headNode, fFlags);
125 	} else {
126 		// add after the head
127 		fPackageNodes.RemoveHead();
128 		fPackageNodes.Add(packageLeafNode);
129 		fPackageNodes.Add(headNode);
130 	}
131 
132 	return B_OK;
133 }
134 
135 
136 void
137 UnpackingLeafNode::RemovePackageNode(PackageNode* packageNode, dev_t deviceID)
138 {
139 	ASSERT(fFinalPackageNode == NULL);
140 
141 	bool isNewest = packageNode == fPackageNodes.Head();
142 	fPackageNodes.Remove(dynamic_cast<PackageLeafNode*>(packageNode));
143 
144 	// when removing the newest node, we need to find the next node (the list
145 	// is not sorted)
146 	PackageLeafNode* newestNode = fPackageNodes.Head();
147 	if (isNewest && newestNode != NULL) {
148 		PackageLeafNodeList::Iterator it = fPackageNodes.GetIterator();
149 		it.Next();
150 			// skip the first one
151 		while (PackageLeafNode* otherNode = it.Next()) {
152 			if (otherNode->ModifiedTime() > newestNode->ModifiedTime())
153 				newestNode = otherNode;
154 		}
155 
156 		// re-add the newest node to the head
157 		fPackageNodes.Remove(newestNode);
158 		fPackageNodes.Add(newestNode);
159 		NodeReinitVFS(deviceID, fID, newestNode, packageNode, fFlags);
160 	}
161 }
162 
163 
164 PackageNode*
165 UnpackingLeafNode::GetPackageNode()
166 {
167 	return _ActivePackageNode();
168 }
169 
170 
171 bool
172 UnpackingLeafNode::IsOnlyPackageNode(PackageNode* node) const
173 {
174 	ASSERT(fFinalPackageNode == NULL);
175 
176 	PackageLeafNode* head = fPackageNodes.Head();
177 	return node == head && fPackageNodes.GetNext(head) == NULL;
178 }
179 
180 
181 bool
182 UnpackingLeafNode::WillBeFirstPackageNode(PackageNode* packageNode) const
183 {
184 	PackageLeafNode* packageLeafNode
185 		= dynamic_cast<PackageLeafNode*>(packageNode);
186 	if (packageLeafNode == NULL)
187 		return false;
188 
189 	PackageLeafNode* headNode = fPackageNodes.Head();
190 	return headNode == NULL
191 		|| packageLeafNode->ModifiedTime() > headNode->ModifiedTime();
192 }
193 
194 void
195 UnpackingLeafNode::PrepareForRemoval()
196 {
197 	ASSERT(fFinalPackageNode == NULL);
198 
199 	fFinalPackageNode = fPackageNodes.Head();
200 	if (fFinalPackageNode != NULL) {
201 		fFinalPackageNode->AcquireReference();
202 		fPackageNodes.MakeEmpty();
203 	}
204 }
205 
206 
207 status_t
208 UnpackingLeafNode::CloneTransferPackageNodes(ino_t id, UnpackingNode*& _newNode)
209 {
210 	ASSERT(fFinalPackageNode == NULL);
211 
212 	UnpackingLeafNode* clone = new(std::nothrow) UnpackingLeafNode(id);
213 	if (clone == NULL)
214 		return B_NO_MEMORY;
215 
216 	status_t error = clone->Init(Parent(), Name());
217 	if (error != B_OK) {
218 		delete clone;
219 		return error;
220 	}
221 
222 	// We keep the old head as fFinalPackageNode, which will make us to behave
223 	// exactly as before with respect to FS operations.
224 	fFinalPackageNode = fPackageNodes.Head();
225 	if (fFinalPackageNode != NULL) {
226 		fFinalPackageNode->AcquireReference();
227 		clone->fPackageNodes.MoveFrom(&fPackageNodes);
228 	}
229 
230 	_newNode = clone;
231 	return B_OK;
232 }
233 
234 
235 status_t
236 UnpackingLeafNode::Read(off_t offset, void* buffer, size_t* bufferSize)
237 {
238 	if (HasVFSInitError())
239 		return B_ERROR;
240 
241 	if (PackageLeafNode* packageNode = _ActivePackageNode())
242 		return packageNode->Read(offset, buffer, bufferSize);
243 	return B_ERROR;
244 }
245 
246 
247 status_t
248 UnpackingLeafNode::Read(io_request* request)
249 {
250 	if (HasVFSInitError())
251 		return B_ERROR;
252 
253 	if (PackageLeafNode* packageNode = _ActivePackageNode())
254 		return packageNode->Read(request);
255 	return EBADF;
256 }
257 
258 
259 status_t
260 UnpackingLeafNode::ReadSymlink(void* buffer, size_t* bufferSize)
261 {
262 	if (HasVFSInitError())
263 		return B_ERROR;
264 
265 	PackageLeafNode* packageNode = _ActivePackageNode();
266 	if (packageNode == NULL)
267 		return B_BAD_VALUE;
268 
269 	const String& linkPath = packageNode->SymlinkPath();
270 	if (linkPath[0] == '\0') {
271 		*bufferSize = 0;
272 		return B_OK;
273 	}
274 
275 	size_t toCopy = std::min(strlen(linkPath), *bufferSize);
276 	memcpy(buffer, linkPath, toCopy);
277 	*bufferSize = toCopy;
278 
279 	return B_OK;
280 }
281 
282 
283 status_t
284 UnpackingLeafNode::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
285 {
286 	if (HasVFSInitError())
287 		return B_ERROR;
288 
289 	return UnpackingAttributeDirectoryCookie::Open(_ActivePackageNode(),
290 		_cookie);
291 }
292 
293 
294 status_t
295 UnpackingLeafNode::OpenAttribute(const StringKey& name, int openMode,
296 	AttributeCookie*& _cookie)
297 {
298 	if (HasVFSInitError())
299 		return B_ERROR;
300 
301 	return UnpackingAttributeCookie::Open(_ActivePackageNode(), name, openMode,
302 		_cookie);
303 }
304 
305 
306 status_t
307 UnpackingLeafNode::IndexAttribute(AttributeIndexer* indexer)
308 {
309 	return UnpackingAttributeCookie::IndexAttribute(_ActivePackageNode(),
310 		indexer);
311 }
312 
313 
314 void*
315 UnpackingLeafNode::IndexCookieForAttribute(const StringKey& name) const
316 {
317 	if (PackageLeafNode* packageNode = _ActivePackageNode())
318 		return packageNode->IndexCookieForAttribute(name);
319 	return NULL;
320 }
321 
322 
323 PackageLeafNode*
324 UnpackingLeafNode::_ActivePackageNode() const
325 {
326 	if (PackageLeafNode* packageNode = fPackageNodes.Head())
327 		return packageNode;
328 	return fFinalPackageNode;
329 }
330