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
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 = NodeInitVFS(deviceID, fID, _ActivePackageNode());
38	if (error == B_OK)
39		Node::VFSInit(deviceID);
40
41	return error;
42}
43
44
45void
46UnpackingLeafNode::VFSUninit()
47{
48	NodeUninitVFS(_ActivePackageNode(), fFlags);
49	Node::VFSUninit();
50}
51
52
53mode_t
54UnpackingLeafNode::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
62uid_t
63UnpackingLeafNode::UserID() const
64{
65	if (PackageLeafNode* packageNode = _ActivePackageNode())
66		return packageNode->UserID();
67	return 0;
68}
69
70
71gid_t
72UnpackingLeafNode::GroupID() const
73{
74	if (PackageLeafNode* packageNode = _ActivePackageNode())
75		return packageNode->GroupID();
76	return 0;
77}
78
79
80timespec
81UnpackingLeafNode::ModifiedTime() const
82{
83	if (PackageLeafNode* packageNode = _ActivePackageNode())
84		return packageNode->ModifiedTime();
85
86	timespec time = { 0, 0 };
87	return time;
88}
89
90
91off_t
92UnpackingLeafNode::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
103Node*
104UnpackingLeafNode::GetNode()
105{
106	return this;
107}
108
109
110status_t
111UnpackingLeafNode::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
139void
140UnpackingLeafNode::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
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->HasPrecedenceOver(headNode);
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());
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 (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
250status_t
251UnpackingLeafNode::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
262status_t
263UnpackingLeafNode::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
289status_t
290UnpackingLeafNode::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
291{
292	if (HasVFSInitError())
293		return B_ERROR;
294
295	return UnpackingAttributeDirectoryCookie::Open(_ActivePackageNode(),
296		_cookie);
297}
298
299
300status_t
301UnpackingLeafNode::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
312status_t
313UnpackingLeafNode::IndexAttribute(AttributeIndexer* indexer)
314{
315	return UnpackingAttributeCookie::IndexAttribute(_ActivePackageNode(),
316		indexer);
317}
318
319
320void*
321UnpackingLeafNode::IndexCookieForAttribute(const StringKey& name) const
322{
323	if (PackageLeafNode* packageNode = _ActivePackageNode())
324		return packageNode->IndexCookieForAttribute(name);
325	return NULL;
326}
327
328
329PackageLeafNode*
330UnpackingLeafNode::_ActivePackageNode() const
331{
332	if (PackageLeafNode* packageNode = fPackageNodes.Head())
333		return packageNode;
334	return fFinalPackageNode;
335}
336