1// Node.cpp
2
3#include "AllocationInfo.h"
4#include "Debug.h"
5#include "EntryIterator.h"
6#include "LastModifiedIndex.h"
7#include "Node.h"
8#include "Volume.h"
9
10// is_user_in_group
11inline static
12bool
13is_user_in_group(gid_t gid)
14{
15// Either I miss something, or we don't have getgroups() in the kernel. :-(
16/*
17	gid_t groups[NGROUPS_MAX];
18	int groupCount = getgroups(NGROUPS_MAX, groups);
19	for (int i = 0; i < groupCount; i++) {
20		if (gid == groups[i])
21			return true;
22	}
23*/
24	return (gid == getegid());
25}
26
27
28// constructor
29Node::Node(Volume *volume, uint8 type)
30	: fVolume(volume),
31	  fID(fVolume->NextNodeID()),
32	  fRefCount(0),
33	  fMode(0),
34	  fUID(0),
35	  fGID(0),
36	  fATime(0),
37	  fMTime(0),
38	  fCTime(0),
39	  fCrTime(0),
40	  fModified(false),
41	  fIsKnownToVFS(false),
42	  // attribute management
43	  fAttributes(),
44	  // referrers
45	  fReferrers()
46{
47	// set file type
48	switch (type) {
49		case NODE_TYPE_DIRECTORY:
50			fMode = S_IFDIR;
51			break;
52		case NODE_TYPE_FILE:
53			fMode = S_IFREG;
54			break;
55		case NODE_TYPE_SYMLINK:
56			fMode = S_IFLNK;
57			break;
58	}
59	// set defaults for time
60	fATime = fMTime = fCTime = fCrTime = time(NULL);
61}
62
63// destructor
64Node::~Node()
65{
66	// delete all attributes
67	while (Attribute *attribute = fAttributes.First()) {
68		status_t error = DeleteAttribute(attribute);
69		if (error != B_OK) {
70			FATAL(("Node::~Node(): Failed to delete attribute!\n"));
71			break;
72		}
73	}
74}
75
76// InitCheck
77status_t
78Node::InitCheck() const
79{
80	return (fVolume && fID >= 0 ? B_OK : B_NO_INIT);
81}
82
83// AddReference
84status_t
85Node::AddReference()
86{
87	if (++fRefCount == 1) {
88		status_t error = GetVolume()->NewVNode(this);
89		if (error != B_OK) {
90			fRefCount--;
91			return error;
92		}
93
94		fIsKnownToVFS = true;
95	}
96
97	return B_OK;
98}
99
100// RemoveReference
101void
102Node::RemoveReference()
103{
104	if (--fRefCount == 0) {
105		GetVolume()->RemoveVNode(this);
106		fRefCount++;
107	}
108}
109
110// Link
111status_t
112Node::Link(Entry *entry)
113{
114PRINT(("Node[%Ld]::Link(): %ld ->...\n", fID, fRefCount));
115	fReferrers.Insert(entry);
116
117	status_t error = AddReference();
118	if (error != B_OK)
119		fReferrers.Remove(entry);
120
121	return error;
122}
123
124// Unlink
125status_t
126Node::Unlink(Entry *entry)
127{
128PRINT(("Node[%Ld]::Unlink(): %ld ->...\n", fID, fRefCount));
129	RemoveReference();
130	fReferrers.Remove(entry);
131
132	return B_OK;
133}
134
135// SetMTime
136void
137Node::SetMTime(time_t mTime)
138{
139	time_t oldMTime = fMTime;
140	fATime = fMTime = mTime;
141	if (oldMTime != fMTime) {
142		if (LastModifiedIndex *index = fVolume->GetLastModifiedIndex())
143			index->Changed(this, oldMTime);
144	}
145}
146
147// CheckPermissions
148status_t
149Node::CheckPermissions(int mode) const
150{
151	int userPermissions = (fMode & S_IRWXU) >> 6;
152	int groupPermissions = (fMode & S_IRWXG) >> 3;
153	int otherPermissions = fMode & S_IRWXO;
154	// get the permissions for this uid/gid
155	int permissions = 0;
156	uid_t uid = geteuid();
157	// user is root
158	if (uid == 0) {
159		// root has always read/write permission, but at least one of the
160		// X bits must be set for execute permission
161		permissions = userPermissions | groupPermissions | otherPermissions
162			| ACCESS_R | ACCESS_W;
163	// user is node owner
164	} else if (uid == fUID)
165		permissions = userPermissions;
166	// user is in owning group
167	else if (is_user_in_group(fGID))
168		permissions = groupPermissions;
169	// user is one of the others
170	else
171		permissions = otherPermissions;
172	// do the check
173	return ((mode & ~permissions) ? B_NOT_ALLOWED : B_OK);
174}
175
176// CreateAttribute
177status_t
178Node::CreateAttribute(const char *name, Attribute **_attribute)
179{
180	status_t error = (name && _attribute ? B_OK : B_BAD_VALUE);
181	if (error == B_OK) {
182		// create attribute
183		Attribute *attribute = new(nothrow) Attribute(fVolume, NULL, name);
184		if (attribute) {
185			error = attribute->InitCheck();
186			if (error == B_OK) {
187				// add attribute to node
188				error = AddAttribute(attribute);
189				if (error == B_OK)
190					*_attribute = attribute;
191			}
192			if (error != B_OK)
193				delete attribute;
194		} else
195			SET_ERROR(error, B_NO_MEMORY);
196	}
197	return error;
198}
199
200// DeleteAttribute
201status_t
202Node::DeleteAttribute(Attribute *attribute)
203{
204	status_t error = RemoveAttribute(attribute);
205	if (error == B_OK)
206		delete attribute;
207	return error;
208}
209
210// AddAttribute
211status_t
212Node::AddAttribute(Attribute *attribute)
213{
214	status_t error = (attribute && !attribute->GetNode() ? B_OK : B_BAD_VALUE);
215	if (error == B_OK) {
216		error = GetVolume()->NodeAttributeAdded(GetID(), attribute);
217		if (error == B_OK) {
218			fAttributes.Insert(attribute);
219			attribute->SetNode(this);
220			MarkModified();
221		}
222	}
223	return error;
224}
225
226// RemoveAttribute
227status_t
228Node::RemoveAttribute(Attribute *attribute)
229{
230	status_t error = (attribute && attribute->GetNode() == this
231					  ? B_OK : B_BAD_VALUE);
232	if (error == B_OK) {
233		// move all iterators pointing to the attribute to the next attribute
234		if (GetVolume()->IteratorLock()) {
235			// set the iterators' current entry
236			Attribute *nextAttr = fAttributes.GetNext(attribute);
237			DoublyLinkedList<AttributeIterator> *iterators
238				= attribute->GetAttributeIteratorList();
239			for (AttributeIterator *iterator = iterators->First();
240				 iterator;
241				 iterator = iterators->GetNext(iterator)) {
242				iterator->SetCurrent(nextAttr, true);
243			}
244			// Move the iterators from one list to the other, or just remove
245			// them, if there is no next attribute.
246			if (nextAttr) {
247				DoublyLinkedList<AttributeIterator> *nextIterators
248					= nextAttr->GetAttributeIteratorList();
249				nextIterators->MoveFrom(iterators);
250			} else
251				iterators->RemoveAll();
252			GetVolume()->IteratorUnlock();
253		} else
254			error = B_ERROR;
255		// remove the attribute
256		if (error == B_OK) {
257			error = GetVolume()->NodeAttributeRemoved(GetID(), attribute);
258			if (error == B_OK) {
259				fAttributes.Remove(attribute);
260				attribute->SetNode(NULL);
261				MarkModified();
262			}
263		}
264	}
265	return error;
266}
267
268// FindAttribute
269status_t
270Node::FindAttribute(const char *name, Attribute **_attribute) const
271{
272	status_t error = (name && _attribute ? B_OK : B_BAD_VALUE);
273	if (error == B_OK) {
274/*
275		Attribute *attribute = NULL;
276		while (GetNextAttribute(&attribute) == B_OK) {
277			if (!strcmp(attribute->GetName(), name)) {
278				*_attribute = attribute;
279				return B_OK;
280			}
281		}
282		error = B_ENTRY_NOT_FOUND;
283*/
284		error = GetVolume()->FindNodeAttribute(GetID(), name, _attribute);
285	}
286	return error;
287}
288
289// GetPreviousAttribute
290status_t
291Node::GetPreviousAttribute(Attribute **attribute) const
292{
293	status_t error = (attribute ? B_OK : B_BAD_VALUE);
294	if (error == B_OK) {
295		if (!*attribute)
296			*attribute = fAttributes.Last();
297		else if ((*attribute)->GetNode() == this)
298			*attribute = fAttributes.GetPrevious(*attribute);
299		else
300			error = B_BAD_VALUE;
301		if (error == B_OK && !*attribute)
302			error = B_ENTRY_NOT_FOUND;
303	}
304	return error;
305}
306
307// GetNextAttribute
308status_t
309Node::GetNextAttribute(Attribute **attribute) const
310{
311	status_t error = (attribute ? B_OK : B_BAD_VALUE);
312	if (error == B_OK) {
313		if (!*attribute)
314			*attribute = fAttributes.First();
315		else if ((*attribute)->GetNode() == this)
316			*attribute = fAttributes.GetNext(*attribute);
317		else
318			error = B_BAD_VALUE;
319		if (error == B_OK && !*attribute)
320			error = B_ENTRY_NOT_FOUND;
321	}
322	return error;
323}
324
325// GetFirstReferrer
326Entry *
327Node::GetFirstReferrer() const
328{
329	return fReferrers.First();
330}
331
332// GetLastReferrer
333Entry *
334Node::GetLastReferrer() const
335{
336	return fReferrers.Last();
337}
338
339// GetPreviousReferrer
340Entry *
341Node::GetPreviousReferrer(Entry *entry) const
342{
343	return (entry ? fReferrers.GetPrevious(entry) : NULL );
344}
345
346// GetNextReferrer
347Entry *
348Node::GetNextReferrer(Entry *entry) const
349{
350	return (entry ? fReferrers.GetNext(entry) : NULL );
351}
352
353// GetAllocationInfo
354void
355Node::GetAllocationInfo(AllocationInfo &info)
356{
357	Attribute *attribute = NULL;
358	while (GetNextAttribute(&attribute) == B_OK)
359		attribute->GetAllocationInfo(info);
360}
361
362