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