1/*
2 * Copyright 2009-2011, 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
19UnpackingLeafNode::UnpackingLeafNode(ino_t id)
20	:
21	Node(id),
22	fFinalPackageNode(NULL)
23{
24}
25
26
27UnpackingLeafNode::~UnpackingLeafNode()
28{
29	if (fFinalPackageNode != NULL)
30		fFinalPackageNode->ReleaseReference();
31}
32
33
34status_t
35UnpackingLeafNode::VFSInit(dev_t deviceID)
36{
37	status_t error = B_OK;
38	if (PackageLeafNode* packageNode = _ActivePackageNode())
39		error = packageNode->VFSInit(deviceID, fID);
40
41	if (error == B_OK)
42		Node::VFSInit(deviceID);
43
44	return error;
45}
46
47
48void
49UnpackingLeafNode::VFSUninit()
50{
51	if (PackageLeafNode* packageNode = _ActivePackageNode())
52		packageNode->VFSUninit();
53
54	Node::VFSUninit();
55}
56
57
58mode_t
59UnpackingLeafNode::Mode() const
60{
61	if (PackageLeafNode* packageNode = _ActivePackageNode())
62		return packageNode->Mode();
63	return S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
64}
65
66
67uid_t
68UnpackingLeafNode::UserID() const
69{
70	if (PackageLeafNode* packageNode = _ActivePackageNode())
71		return packageNode->UserID();
72	return 0;
73}
74
75
76gid_t
77UnpackingLeafNode::GroupID() const
78{
79	if (PackageLeafNode* packageNode = _ActivePackageNode())
80		return packageNode->GroupID();
81	return 0;
82}
83
84
85timespec
86UnpackingLeafNode::ModifiedTime() const
87{
88	if (PackageLeafNode* packageNode = _ActivePackageNode())
89		return packageNode->ModifiedTime();
90
91	timespec time = { 0, 0 };
92	return time;
93}
94
95
96off_t
97UnpackingLeafNode::FileSize() const
98{
99	if (PackageLeafNode* packageNode = _ActivePackageNode())
100		return packageNode->FileSize();
101	return 0;
102}
103
104
105Node*
106UnpackingLeafNode::GetNode()
107{
108	return this;
109}
110
111
112status_t
113UnpackingLeafNode::AddPackageNode(PackageNode* packageNode)
114{
115	ASSERT(fFinalPackageNode == NULL);
116
117	if (S_ISDIR(packageNode->Mode()))
118		return B_BAD_VALUE;
119
120	PackageLeafNode* packageLeafNode
121		= dynamic_cast<PackageLeafNode*>(packageNode);
122
123	PackageLeafNode* headNode = fPackageNodes.Head();
124	bool isNewest = headNode == NULL
125		|| packageLeafNode->ModifiedTime() > headNode->ModifiedTime();
126
127	if (isNewest) {
128		fPackageNodes.Add(packageLeafNode);
129	} else {
130		// add after the head
131		fPackageNodes.RemoveHead();
132		fPackageNodes.Add(packageLeafNode);
133		fPackageNodes.Add(headNode);
134	}
135
136	return B_OK;
137}
138
139
140void
141UnpackingLeafNode::RemovePackageNode(PackageNode* packageNode)
142{
143	ASSERT(fFinalPackageNode == NULL);
144
145	bool isNewest = packageNode == fPackageNodes.Head();
146	fPackageNodes.Remove(dynamic_cast<PackageLeafNode*>(packageNode));
147
148	// when removing the newest node, we need to find the next node (the list
149	// is not sorted)
150	PackageLeafNode* newestNode = fPackageNodes.Head();
151	if (isNewest && newestNode != NULL) {
152		PackageLeafNodeList::Iterator it = fPackageNodes.GetIterator();
153		it.Next();
154			// skip the first one
155		while (PackageLeafNode* otherNode = it.Next()) {
156			if (otherNode->ModifiedTime() > newestNode->ModifiedTime())
157				newestNode = otherNode;
158		}
159
160		// re-add the newest node to the head
161		fPackageNodes.Remove(newestNode);
162		fPackageNodes.Add(newestNode);
163	}
164}
165
166
167PackageNode*
168UnpackingLeafNode::GetPackageNode()
169{
170	return _ActivePackageNode();
171}
172
173
174bool
175UnpackingLeafNode::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
184bool
185UnpackingLeafNode::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->ModifiedTime() > headNode->ModifiedTime();
195}
196
197void
198UnpackingLeafNode::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
210status_t
211UnpackingLeafNode::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(), 0);
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
238status_t
239UnpackingLeafNode::Read(off_t offset, void* buffer, size_t* bufferSize)
240{
241	if (PackageLeafNode* packageNode = _ActivePackageNode())
242		return packageNode->Read(offset, buffer, bufferSize);
243	return B_ERROR;
244}
245
246
247status_t
248UnpackingLeafNode::Read(io_request* request)
249{
250	if (PackageLeafNode* packageNode = _ActivePackageNode())
251		return packageNode->Read(request);
252	return EBADF;
253}
254
255
256status_t
257UnpackingLeafNode::ReadSymlink(void* buffer, size_t* bufferSize)
258{
259	PackageLeafNode* packageNode = _ActivePackageNode();
260	if (packageNode == NULL)
261		return B_BAD_VALUE;
262
263	const char* linkPath = packageNode->SymlinkPath();
264	if (linkPath == NULL) {
265		*bufferSize = 0;
266		return B_OK;
267	}
268
269	size_t toCopy = std::min(strlen(linkPath), *bufferSize);
270	memcpy(buffer, linkPath, toCopy);
271	*bufferSize = toCopy;
272
273	return B_OK;
274}
275
276
277status_t
278UnpackingLeafNode::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
279{
280	return UnpackingAttributeDirectoryCookie::Open(_ActivePackageNode(),
281		_cookie);
282}
283
284
285status_t
286UnpackingLeafNode::OpenAttribute(const char* name, int openMode,
287	AttributeCookie*& _cookie)
288{
289	return UnpackingAttributeCookie::Open(_ActivePackageNode(), name, openMode,
290		_cookie);
291}
292
293
294status_t
295UnpackingLeafNode::IndexAttribute(AttributeIndexer* indexer)
296{
297	return UnpackingAttributeCookie::IndexAttribute(_ActivePackageNode(),
298		indexer);
299}
300
301
302void*
303UnpackingLeafNode::IndexCookieForAttribute(const char* name) const
304{
305	if (PackageLeafNode* packageNode = _ActivePackageNode())
306		return packageNode->IndexCookieForAttribute(name);
307	return NULL;
308}
309
310
311PackageLeafNode*
312UnpackingLeafNode::_ActivePackageNode() const
313{
314	if (PackageLeafNode* packageNode = fPackageNodes.Head())
315		return packageNode;
316	return fFinalPackageNode;
317}
318