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