BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / file_systems / ramfs / Node.cpp
blob72aba18202b0f20481114063494e3c52f3472cf0
1 // Node.cpp
3 #include "AllocationInfo.h"
4 #include "Debug.h"
5 #include "EntryIterator.h"
6 #include "LastModifiedIndex.h"
7 #include "Node.h"
8 #include "Volume.h"
10 // is_user_in_group
11 inline static
12 bool
13 is_user_in_group(gid_t gid)
15 // Either I miss something, or we don't have getgroups() in the kernel. :-(
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;
24 return (gid == getegid());
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()
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;
59 // set defaults for time
60 fATime = fMTime = fCTime = fCrTime = time(NULL);
63 // destructor
64 Node::~Node()
66 // delete all attributes
67 while (Attribute *attribute = fAttributes.First()) {
68 status_t error = DeleteAttribute(attribute);
69 if (error != B_OK) {
70 FATAL(("Node::~Node(): Failed to delete attribute!\n"));
71 break;
76 // InitCheck
77 status_t
78 Node::InitCheck() const
80 return (fVolume && fID >= 0 ? B_OK : B_NO_INIT);
83 // AddReference
84 status_t
85 Node::AddReference()
87 if (++fRefCount == 1) {
88 status_t error = GetVolume()->PublishVNode(this);
89 if (error != B_OK) {
90 fRefCount--;
91 return error;
94 fIsKnownToVFS = true;
97 return B_OK;
100 // RemoveReference
101 void
102 Node::RemoveReference()
104 if (--fRefCount == 0) {
105 GetVolume()->RemoveVNode(this);
106 fRefCount++;
110 // Link
111 status_t
112 Node::Link(Entry *entry)
114 PRINT(("Node[%Ld]::Link(): %ld ->...\n", fID, fRefCount));
115 fReferrers.Insert(entry);
117 status_t error = AddReference();
118 if (error != B_OK)
119 fReferrers.Remove(entry);
121 return error;
124 // Unlink
125 status_t
126 Node::Unlink(Entry *entry)
128 PRINT(("Node[%Ld]::Unlink(): %ld ->...\n", fID, fRefCount));
129 RemoveReference();
130 fReferrers.Remove(entry);
132 return B_OK;
135 // SetMTime
136 void
137 Node::SetMTime(time_t mTime)
139 time_t oldMTime = fMTime;
140 fATime = fMTime = mTime;
141 if (oldMTime != fMTime) {
142 if (LastModifiedIndex *index = fVolume->GetLastModifiedIndex())
143 index->Changed(this, oldMTime);
147 // CheckPermissions
148 status_t
149 Node::CheckPermissions(int mode) const
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);
176 // CreateAttribute
177 status_t
178 Node::CreateAttribute(const char *name, Attribute **_attribute)
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;
192 if (error != B_OK)
193 delete attribute;
194 } else
195 SET_ERROR(error, B_NO_MEMORY);
197 return error;
200 // DeleteAttribute
201 status_t
202 Node::DeleteAttribute(Attribute *attribute)
204 status_t error = RemoveAttribute(attribute);
205 if (error == B_OK)
206 delete attribute;
207 return error;
210 // AddAttribute
211 status_t
212 Node::AddAttribute(Attribute *attribute)
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);
223 return error;
226 // RemoveAttribute
227 status_t
228 Node::RemoveAttribute(Attribute *attribute)
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 DoublyLinkedList<AttributeIterator> *iterators
238 = attribute->GetAttributeIteratorList();
239 for (AttributeIterator *iterator = iterators->First();
240 iterator;
241 iterator = iterators->GetNext(iterator)) {
242 iterator->SetCurrent(nextAttr, true);
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 DoublyLinkedList<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);
265 return error;
268 // FindAttribute
269 status_t
270 Node::FindAttribute(const char *name, Attribute **_attribute) const
272 status_t error = (name && _attribute ? B_OK : B_BAD_VALUE);
273 if (error == B_OK) {
275 Attribute *attribute = NULL;
276 while (GetNextAttribute(&attribute) == B_OK) {
277 if (!strcmp(attribute->GetName(), name)) {
278 *_attribute = attribute;
279 return B_OK;
282 error = B_ENTRY_NOT_FOUND;
284 error = GetVolume()->FindNodeAttribute(GetID(), name, _attribute);
286 return error;
289 // GetPreviousAttribute
290 status_t
291 Node::GetPreviousAttribute(Attribute **attribute) const
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;
304 return error;
307 // GetNextAttribute
308 status_t
309 Node::GetNextAttribute(Attribute **attribute) const
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;
322 return error;
325 // GetFirstReferrer
326 Entry *
327 Node::GetFirstReferrer() const
329 return fReferrers.First();
332 // GetLastReferrer
333 Entry *
334 Node::GetLastReferrer() const
336 return fReferrers.Last();
339 // GetPreviousReferrer
340 Entry *
341 Node::GetPreviousReferrer(Entry *entry) const
343 return (entry ? fReferrers.GetPrevious(entry) : NULL );
346 // GetNextReferrer
347 Entry *
348 Node::GetNextReferrer(Entry *entry) const
350 return (entry ? fReferrers.GetNext(entry) : NULL );
353 // GetAllocationInfo
354 void
355 Node::GetAllocationInfo(AllocationInfo &info)
357 Attribute *attribute = NULL;
358 while (GetNextAttribute(&attribute) == B_OK)
359 attribute->GetAllocationInfo(info);