xref: /haiku/src/add-ons/kernel/file_systems/ramfs/Node.cpp (revision ed6250c95736c0b55da79d6e9dd01369532260c0)
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
11 inline static
12 bool
13 is_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
29 Node::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(0),
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
64 Node::~Node()
65 {
66 	// delete all attributes
67 	while (Attribute *attribute = fAttributes.GetFirst()) {
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
77 status_t
78 Node::InitCheck() const
79 {
80 	return (fVolume && fID >= 0 ? B_OK : B_NO_INIT);
81 }
82 
83 // AddReference
84 status_t
85 Node::AddReference()
86 {
87 	if (++fRefCount == 1) {
88 		status_t error = GetVolume()->PublishVNode(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
101 void
102 Node::RemoveReference()
103 {
104 	if (--fRefCount == 0) {
105 		GetVolume()->RemoveVNode(this);
106 		fRefCount++;
107 	}
108 }
109 
110 // Link
111 status_t
112 Node::Link(Entry *entry)
113 {
114 PRINT(("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
125 status_t
126 Node::Unlink(Entry *entry)
127 {
128 PRINT(("Node[%Ld]::Unlink(): %ld ->...\n", fID, fRefCount));
129 	RemoveReference();
130 	fReferrers.Remove(entry);
131 
132 	return B_OK;
133 }
134 
135 // SetMTime
136 void
137 Node::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
148 status_t
149 Node::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
177 status_t
178 Node::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
201 status_t
202 Node::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
211 status_t
212 Node::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(B_STAT_MODIFICATION_TIME);
221 		}
222 	}
223 	return error;
224 }
225 
226 // RemoveAttribute
227 status_t
228 Node::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 			DLList<AttributeIterator> *iterators
238 				= attribute->GetAttributeIteratorList();
239 			for (AttributeIterator *iterator = iterators->GetFirst();
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 				DLList<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(B_STAT_MODIFICATION_TIME);
262 			}
263 		}
264 	}
265 	return error;
266 }
267 
268 // FindAttribute
269 status_t
270 Node::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
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.GetLast();
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.GetFirst();
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.GetHead();
330 }
331 
332 // GetLastReferrer
333 Entry *
334 Node::GetLastReferrer() const
335 {
336 	return fReferrers.GetTail();
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