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 14 inline static 15 bool 16 is_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 32 Node::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 67 Node::~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 82 status_t 83 Node::InitCheck() const 84 { 85 return (fVolume && fID >= 0 ? B_OK : B_NO_INIT); 86 } 87 88 // AddReference 89 status_t 90 Node::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 106 void 107 Node::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 117 status_t 118 Node::Link(Entry *entry) 119 { 120 PRINT("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 131 status_t 132 Node::Unlink(Entry *entry) 133 { 134 PRINT("Node[%" B_PRIdINO "]::Unlink(): %" B_PRId32 " ->...\n", fID, fRefCount); 135 fReferrers.Remove(entry); 136 137 RemoveReference(); 138 return B_OK; 139 } 140 141 // SetMTime 142 void 143 Node::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 154 status_t 155 Node::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 183 status_t 184 Node::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 207 status_t 208 Node::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 217 status_t 218 Node::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 233 status_t 234 Node::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 275 status_t 276 Node::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 293 status_t 294 Node::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 311 status_t 312 Node::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 329 Entry * 330 Node::GetFirstReferrer() const 331 { 332 return fReferrers.First(); 333 } 334 335 // GetLastReferrer 336 Entry * 337 Node::GetLastReferrer() const 338 { 339 return fReferrers.Last(); 340 } 341 342 // GetPreviousReferrer 343 Entry * 344 Node::GetPreviousReferrer(Entry *entry) const 345 { 346 return (entry ? fReferrers.GetPrevious(entry) : NULL ); 347 } 348 349 // GetNextReferrer 350 Entry * 351 Node::GetNextReferrer(Entry *entry) const 352 { 353 return (entry ? fReferrers.GetNext(entry) : NULL ); 354 } 355 356 // GetAllocationInfo 357 void 358 Node::GetAllocationInfo(AllocationInfo &info) 359 { 360 Attribute *attribute = NULL; 361 while (GetNextAttribute(&attribute) == B_OK) 362 attribute->GetAllocationInfo(info); 363 } 364