xref: /haiku/src/add-ons/kernel/file_systems/ramfs/Node.cpp (revision bab3f64413902761dc4b26c74a46c62a29bc6f86)
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 "Node.h"
7 
8 #include <util/AutoLock.h>
9 
10 #include "AllocationInfo.h"
11 #include "DebugSupport.h"
12 #include "EntryIterator.h"
13 #include "LastModifiedIndex.h"
14 #include "Volume.h"
15 
16 
Node(Volume * volume,uint8 type)17 Node::Node(Volume *volume, uint8 type)
18 	: fVolume(volume),
19 	  fID(fVolume->NextNodeID()),
20 	  fRefCount(0),
21 	  fMode(0),
22 	  fUID(0),
23 	  fGID(0),
24 	  fATime(0),
25 	  fMTime(0),
26 	  fCTime(0),
27 	  fCrTime(0),
28 	  fModified(0),
29 	  fIsKnownToVFS(false),
30 	  fAttributes(),
31 	  fReferrers()
32 {
33 	// set file type
34 	switch (type) {
35 		case NODE_TYPE_DIRECTORY:
36 			fMode = S_IFDIR;
37 			break;
38 		case NODE_TYPE_FILE:
39 			fMode = S_IFREG;
40 			break;
41 		case NODE_TYPE_SYMLINK:
42 			fMode = S_IFLNK;
43 			break;
44 	}
45 	// set defaults for time
46 	fATime = fMTime = fCTime = fCrTime = time(NULL);
47 }
48 
49 
~Node()50 Node::~Node()
51 {
52 	ASSERT(fRefCount == 0);
53 
54 	// delete all attributes
55 	while (Attribute *attribute = fAttributes.First()) {
56 		status_t error = DeleteAttribute(attribute);
57 		if (error != B_OK) {
58 			FATAL("Node::~Node(): Failed to delete attribute!\n");
59 			break;
60 		}
61 	}
62 }
63 
64 
65 status_t
InitCheck() const66 Node::InitCheck() const
67 {
68 	return (fVolume && fID >= 0 ? B_OK : B_NO_INIT);
69 }
70 
71 
72 status_t
AddReference()73 Node::AddReference()
74 {
75 	if (++fRefCount == 1) {
76 		status_t error = GetVolume()->PublishVNode(this);
77 		if (error != B_OK) {
78 			fRefCount--;
79 			return error;
80 		}
81 
82 		fIsKnownToVFS = true;
83 	}
84 
85 	return B_OK;
86 }
87 
88 
89 void
RemoveReference()90 Node::RemoveReference()
91 {
92 	ASSERT(fRefCount > 0);
93 	if (--fRefCount == 0) {
94 		GetVolume()->RemoveVNode(this);
95 			// RemoveVNode can potentially delete us immediately!
96 	}
97 }
98 
99 
100 status_t
Link(Entry * entry)101 Node::Link(Entry *entry)
102 {
103 PRINT("Node[%" B_PRIdINO "]::Link(): %" B_PRId32 " ->...\n", fID, fRefCount);
104 	fReferrers.Insert(entry);
105 
106 	status_t error = AddReference();
107 	if (error != B_OK)
108 		fReferrers.Remove(entry);
109 
110 	return error;
111 }
112 
113 
114 status_t
Unlink(Entry * entry)115 Node::Unlink(Entry *entry)
116 {
117 PRINT("Node[%" B_PRIdINO "]::Unlink(): %" B_PRId32 " ->...\n", fID, fRefCount);
118 	fReferrers.Remove(entry);
119 
120 	RemoveReference();
121 	return B_OK;
122 }
123 
124 
125 void
SetMTime(time_t mTime)126 Node::SetMTime(time_t mTime)
127 {
128 	time_t oldMTime = fMTime;
129 	fATime = fMTime = mTime;
130 	if (oldMTime != fMTime) {
131 		if (LastModifiedIndex *index = fVolume->GetLastModifiedIndex())
132 			index->Changed(this, oldMTime);
133 	}
134 }
135 
136 
137 status_t
CheckPermissions(int mode) const138 Node::CheckPermissions(int mode) const
139 {
140 	return check_access_permissions(mode, fMode, fGID, fUID);
141 }
142 
143 
144 status_t
CreateAttribute(const char * name,Attribute ** _attribute)145 Node::CreateAttribute(const char *name, Attribute **_attribute)
146 {
147 	status_t error = (name && _attribute ? B_OK : B_BAD_VALUE);
148 	if (error == B_OK) {
149 		// create attribute
150 		Attribute *attribute = new(nothrow) Attribute(fVolume, NULL, name);
151 		if (attribute) {
152 			error = attribute->InitCheck();
153 			if (error == B_OK) {
154 				// add attribute to node
155 				error = AddAttribute(attribute);
156 				if (error == B_OK)
157 					*_attribute = attribute;
158 			}
159 			if (error != B_OK)
160 				delete attribute;
161 		} else
162 			SET_ERROR(error, B_NO_MEMORY);
163 	}
164 	return error;
165 }
166 
167 
168 status_t
DeleteAttribute(Attribute * attribute)169 Node::DeleteAttribute(Attribute *attribute)
170 {
171 	status_t error = RemoveAttribute(attribute);
172 	if (error == B_OK)
173 		delete attribute;
174 	return error;
175 }
176 
177 
178 status_t
AddAttribute(Attribute * attribute)179 Node::AddAttribute(Attribute *attribute)
180 {
181 	status_t error = (attribute && !attribute->GetNode() ? B_OK : B_BAD_VALUE);
182 	if (error == B_OK) {
183 		error = GetVolume()->NodeAttributeAdded(GetID(), attribute);
184 		if (error == B_OK) {
185 			fAttributes.Insert(attribute);
186 			attribute->SetNode(this);
187 			MarkModified(B_STAT_MODIFICATION_TIME);
188 		}
189 	}
190 	return error;
191 }
192 
193 
194 status_t
RemoveAttribute(Attribute * attribute)195 Node::RemoveAttribute(Attribute *attribute)
196 {
197 	if (attribute == NULL || attribute->GetNode() != this)
198 		return B_BAD_VALUE;
199 
200 	RecursiveLocker locker(GetVolume()->AttributeIteratorLocker());
201 	if (!locker.IsLocked())
202 		return B_ERROR;
203 
204 	// move all iterators pointing to the attribute to the next attribute
205 	Attribute *nextAttr = fAttributes.GetNext(attribute);
206 	DoublyLinkedList<AttributeIterator> *iterators
207 		= attribute->GetAttributeIteratorList();
208 	for (AttributeIterator *iterator = iterators->First();
209 			iterator != NULL; iterator = iterators->GetNext(iterator)) {
210 		iterator->SetCurrent(nextAttr, true);
211 	}
212 
213 	// Move the iterators from one list to the other, or just remove
214 	// them, if there is no next attribute.
215 	if (nextAttr != NULL) {
216 		DoublyLinkedList<AttributeIterator> *nextIterators
217 			= nextAttr->GetAttributeIteratorList();
218 		nextIterators->MoveFrom(iterators);
219 	} else
220 		iterators->RemoveAll();
221 
222 	locker.Unlock();
223 
224 	// remove the attribute
225 	status_t error = GetVolume()->NodeAttributeRemoved(GetID(), attribute);
226 	if (error == B_OK) {
227 		fAttributes.Remove(attribute);
228 		attribute->SetNode(NULL);
229 		MarkModified(B_STAT_MODIFICATION_TIME);
230 	}
231 	return error;
232 }
233 
234 
235 status_t
FindAttribute(const char * name,Attribute ** _attribute) const236 Node::FindAttribute(const char *name, Attribute **_attribute) const
237 {
238 	status_t error = (name && _attribute ? B_OK : B_BAD_VALUE);
239 	if (error == B_OK) {
240 		Attribute *attribute = NULL;
241 		while (GetNextAttribute(&attribute) == B_OK) {
242 			if (!strcmp(attribute->GetName(), name)) {
243 				*_attribute = attribute;
244 				return B_OK;
245 			}
246 		}
247 		error = B_ENTRY_NOT_FOUND;
248 	}
249 	return error;
250 }
251 
252 
253 status_t
GetPreviousAttribute(Attribute ** attribute) const254 Node::GetPreviousAttribute(Attribute **attribute) const
255 {
256 	status_t error = (attribute ? B_OK : B_BAD_VALUE);
257 	if (error == B_OK) {
258 		if (!*attribute)
259 			*attribute = fAttributes.Last();
260 		else if ((*attribute)->GetNode() == this)
261 			*attribute = fAttributes.GetPrevious(*attribute);
262 		else
263 			error = B_BAD_VALUE;
264 		if (error == B_OK && !*attribute)
265 			error = B_ENTRY_NOT_FOUND;
266 	}
267 	return error;
268 }
269 
270 
271 status_t
GetNextAttribute(Attribute ** attribute) const272 Node::GetNextAttribute(Attribute **attribute) const
273 {
274 	status_t error = (attribute ? B_OK : B_BAD_VALUE);
275 	if (error == B_OK) {
276 		if (!*attribute)
277 			*attribute = fAttributes.First();
278 		else if ((*attribute)->GetNode() == this)
279 			*attribute = fAttributes.GetNext(*attribute);
280 		else
281 			error = B_BAD_VALUE;
282 		if (error == B_OK && !*attribute)
283 			error = B_ENTRY_NOT_FOUND;
284 	}
285 	return error;
286 }
287 
288 
289 Entry *
GetFirstReferrer() const290 Node::GetFirstReferrer() const
291 {
292 	return fReferrers.First();
293 }
294 
295 
296 Entry *
GetLastReferrer() const297 Node::GetLastReferrer() const
298 {
299 	return fReferrers.Last();
300 }
301 
302 
303 Entry *
GetPreviousReferrer(Entry * entry) const304 Node::GetPreviousReferrer(Entry *entry) const
305 {
306 	return (entry ? fReferrers.GetPrevious(entry) : NULL );
307 }
308 
309 
310 Entry *
GetNextReferrer(Entry * entry) const311 Node::GetNextReferrer(Entry *entry) const
312 {
313 	return (entry ? fReferrers.GetNext(entry) : NULL );
314 }
315 
316 
317 void
GetAllocationInfo(AllocationInfo & info)318 Node::GetAllocationInfo(AllocationInfo &info)
319 {
320 	Attribute *attribute = NULL;
321 	while (GetNextAttribute(&attribute) == B_OK)
322 		attribute->GetAllocationInfo(info);
323 }
324