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