xref: /haiku/src/add-ons/kernel/file_systems/ramfs/Node.cpp (revision b84574958d92055d2e33c26e1f2d43d48c9ed50c)
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 	// delete all attributes
70 	while (Attribute *attribute = fAttributes.First()) {
71 		status_t error = DeleteAttribute(attribute);
72 		if (error != B_OK) {
73 			FATAL("Node::~Node(): Failed to delete attribute!\n");
74 			break;
75 		}
76 	}
77 }
78 
79 // InitCheck
80 status_t
81 Node::InitCheck() const
82 {
83 	return (fVolume && fID >= 0 ? B_OK : B_NO_INIT);
84 }
85 
86 // AddReference
87 status_t
88 Node::AddReference()
89 {
90 	if (++fRefCount == 1) {
91 		status_t error = GetVolume()->PublishVNode(this);
92 		if (error != B_OK) {
93 			fRefCount--;
94 			return error;
95 		}
96 
97 		fIsKnownToVFS = true;
98 	}
99 
100 	return B_OK;
101 }
102 
103 // RemoveReference
104 void
105 Node::RemoveReference()
106 {
107 	if (--fRefCount == 0) {
108 		GetVolume()->RemoveVNode(this);
109 		fRefCount++;
110 	}
111 }
112 
113 // Link
114 status_t
115 Node::Link(Entry *entry)
116 {
117 PRINT("Node[%Ld]::Link(): %" B_PRId32 " ->...\n", fID, fRefCount);
118 	fReferrers.Insert(entry);
119 
120 	status_t error = AddReference();
121 	if (error != B_OK)
122 		fReferrers.Remove(entry);
123 
124 	return error;
125 }
126 
127 // Unlink
128 status_t
129 Node::Unlink(Entry *entry)
130 {
131 PRINT("Node[%Ld]::Unlink(): %" B_PRId32 " ->...\n", fID, fRefCount);
132 	RemoveReference();
133 	fReferrers.Remove(entry);
134 
135 	return B_OK;
136 }
137 
138 // SetMTime
139 void
140 Node::SetMTime(time_t mTime)
141 {
142 	time_t oldMTime = fMTime;
143 	fATime = fMTime = mTime;
144 	if (oldMTime != fMTime) {
145 		if (LastModifiedIndex *index = fVolume->GetLastModifiedIndex())
146 			index->Changed(this, oldMTime);
147 	}
148 }
149 
150 // CheckPermissions
151 status_t
152 Node::CheckPermissions(int mode) const
153 {
154 	int userPermissions = (fMode & S_IRWXU) >> 6;
155 	int groupPermissions = (fMode & S_IRWXG) >> 3;
156 	int otherPermissions = fMode & S_IRWXO;
157 	// get the permissions for this uid/gid
158 	int permissions = 0;
159 	uid_t uid = geteuid();
160 	// user is root
161 	if (uid == 0) {
162 		// root has always read/write permission, but at least one of the
163 		// X bits must be set for execute permission
164 		permissions = userPermissions | groupPermissions | otherPermissions
165 			| ACCESS_R | ACCESS_W;
166 	// user is node owner
167 	} else if (uid == fUID)
168 		permissions = userPermissions;
169 	// user is in owning group
170 	else if (is_user_in_group(fGID))
171 		permissions = groupPermissions;
172 	// user is one of the others
173 	else
174 		permissions = otherPermissions;
175 	// do the check
176 	return ((mode & ~permissions) ? B_NOT_ALLOWED : B_OK);
177 }
178 
179 // CreateAttribute
180 status_t
181 Node::CreateAttribute(const char *name, Attribute **_attribute)
182 {
183 	status_t error = (name && _attribute ? B_OK : B_BAD_VALUE);
184 	if (error == B_OK) {
185 		// create attribute
186 		Attribute *attribute = new(nothrow) Attribute(fVolume, NULL, name);
187 		if (attribute) {
188 			error = attribute->InitCheck();
189 			if (error == B_OK) {
190 				// add attribute to node
191 				error = AddAttribute(attribute);
192 				if (error == B_OK)
193 					*_attribute = attribute;
194 			}
195 			if (error != B_OK)
196 				delete attribute;
197 		} else
198 			SET_ERROR(error, B_NO_MEMORY);
199 	}
200 	return error;
201 }
202 
203 // DeleteAttribute
204 status_t
205 Node::DeleteAttribute(Attribute *attribute)
206 {
207 	status_t error = RemoveAttribute(attribute);
208 	if (error == B_OK)
209 		delete attribute;
210 	return error;
211 }
212 
213 // AddAttribute
214 status_t
215 Node::AddAttribute(Attribute *attribute)
216 {
217 	status_t error = (attribute && !attribute->GetNode() ? B_OK : B_BAD_VALUE);
218 	if (error == B_OK) {
219 		error = GetVolume()->NodeAttributeAdded(GetID(), attribute);
220 		if (error == B_OK) {
221 			fAttributes.Insert(attribute);
222 			attribute->SetNode(this);
223 			MarkModified(B_STAT_MODIFICATION_TIME);
224 		}
225 	}
226 	return error;
227 }
228 
229 // RemoveAttribute
230 status_t
231 Node::RemoveAttribute(Attribute *attribute)
232 {
233 	status_t error = (attribute && attribute->GetNode() == this
234 					  ? B_OK : B_BAD_VALUE);
235 	if (error == B_OK) {
236 		// move all iterators pointing to the attribute to the next attribute
237 		if (GetVolume()->IteratorLock()) {
238 			// set the iterators' current entry
239 			Attribute *nextAttr = fAttributes.GetNext(attribute);
240 			DoublyLinkedList<AttributeIterator> *iterators
241 				= attribute->GetAttributeIteratorList();
242 			for (AttributeIterator *iterator = iterators->First();
243 				 iterator;
244 				 iterator = iterators->GetNext(iterator)) {
245 				iterator->SetCurrent(nextAttr, true);
246 			}
247 			// Move the iterators from one list to the other, or just remove
248 			// them, if there is no next attribute.
249 			if (nextAttr) {
250 				DoublyLinkedList<AttributeIterator> *nextIterators
251 					= nextAttr->GetAttributeIteratorList();
252 				nextIterators->MoveFrom(iterators);
253 			} else
254 				iterators->RemoveAll();
255 			GetVolume()->IteratorUnlock();
256 		} else
257 			error = B_ERROR;
258 		// remove the attribute
259 		if (error == B_OK) {
260 			error = GetVolume()->NodeAttributeRemoved(GetID(), attribute);
261 			if (error == B_OK) {
262 				fAttributes.Remove(attribute);
263 				attribute->SetNode(NULL);
264 				MarkModified(B_STAT_MODIFICATION_TIME);
265 			}
266 		}
267 	}
268 	return error;
269 }
270 
271 // FindAttribute
272 status_t
273 Node::FindAttribute(const char *name, Attribute **_attribute) const
274 {
275 	status_t error = (name && _attribute ? B_OK : B_BAD_VALUE);
276 	if (error == B_OK) {
277 		Attribute *attribute = NULL;
278 		while (GetNextAttribute(&attribute) == B_OK) {
279 			if (!strcmp(attribute->GetName(), name)) {
280 				*_attribute = attribute;
281 				return B_OK;
282 			}
283 		}
284 		error = B_ENTRY_NOT_FOUND;
285 	}
286 	return error;
287 }
288 
289 // GetPreviousAttribute
290 status_t
291 Node::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
308 status_t
309 Node::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
326 Entry *
327 Node::GetFirstReferrer() const
328 {
329 	return fReferrers.First();
330 }
331 
332 // GetLastReferrer
333 Entry *
334 Node::GetLastReferrer() const
335 {
336 	return fReferrers.Last();
337 }
338 
339 // GetPreviousReferrer
340 Entry *
341 Node::GetPreviousReferrer(Entry *entry) const
342 {
343 	return (entry ? fReferrers.GetPrevious(entry) : NULL );
344 }
345 
346 // GetNextReferrer
347 Entry *
348 Node::GetNextReferrer(Entry *entry) const
349 {
350 	return (entry ? fReferrers.GetNext(entry) : NULL );
351 }
352 
353 // GetAllocationInfo
354 void
355 Node::GetAllocationInfo(AllocationInfo &info)
356 {
357 	Attribute *attribute = NULL;
358 	while (GetNextAttribute(&attribute) == B_OK)
359 		attribute->GetAllocationInfo(info);
360 }
361 
362