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 // delete all attributes 70 while (Attribute *attribute = fAttributes.First()) { 71 status_t error = DeleteAttribute(attribute); 72 if (error != B_OK) { 73 FATAL("Node::~Node(): Failed to delete attribute!\n"); 74 break; 75 } 76 } 77 } 78 79 // InitCheck 80 status_t 81 Node::InitCheck() const 82 { 83 return (fVolume && fID >= 0 ? B_OK : B_NO_INIT); 84 } 85 86 // AddReference 87 status_t 88 Node::AddReference() 89 { 90 if (++fRefCount == 1) { 91 status_t error = GetVolume()->PublishVNode(this); 92 if (error != B_OK) { 93 fRefCount--; 94 return error; 95 } 96 97 fIsKnownToVFS = true; 98 } 99 100 return B_OK; 101 } 102 103 // RemoveReference 104 void 105 Node::RemoveReference() 106 { 107 if (--fRefCount == 0) { 108 GetVolume()->RemoveVNode(this); 109 fRefCount++; 110 } 111 } 112 113 // Link 114 status_t 115 Node::Link(Entry *entry) 116 { 117 PRINT("Node[%Ld]::Link(): %" B_PRId32 " ->...\n", fID, fRefCount); 118 fReferrers.Insert(entry); 119 120 status_t error = AddReference(); 121 if (error != B_OK) 122 fReferrers.Remove(entry); 123 124 return error; 125 } 126 127 // Unlink 128 status_t 129 Node::Unlink(Entry *entry) 130 { 131 PRINT("Node[%Ld]::Unlink(): %" B_PRId32 " ->...\n", fID, fRefCount); 132 RemoveReference(); 133 fReferrers.Remove(entry); 134 135 return B_OK; 136 } 137 138 // SetMTime 139 void 140 Node::SetMTime(time_t mTime) 141 { 142 time_t oldMTime = fMTime; 143 fATime = fMTime = mTime; 144 if (oldMTime != fMTime) { 145 if (LastModifiedIndex *index = fVolume->GetLastModifiedIndex()) 146 index->Changed(this, oldMTime); 147 } 148 } 149 150 // CheckPermissions 151 status_t 152 Node::CheckPermissions(int mode) const 153 { 154 int userPermissions = (fMode & S_IRWXU) >> 6; 155 int groupPermissions = (fMode & S_IRWXG) >> 3; 156 int otherPermissions = fMode & S_IRWXO; 157 // get the permissions for this uid/gid 158 int permissions = 0; 159 uid_t uid = geteuid(); 160 // user is root 161 if (uid == 0) { 162 // root has always read/write permission, but at least one of the 163 // X bits must be set for execute permission 164 permissions = userPermissions | groupPermissions | otherPermissions 165 | ACCESS_R | ACCESS_W; 166 // user is node owner 167 } else if (uid == fUID) 168 permissions = userPermissions; 169 // user is in owning group 170 else if (is_user_in_group(fGID)) 171 permissions = groupPermissions; 172 // user is one of the others 173 else 174 permissions = otherPermissions; 175 // do the check 176 return ((mode & ~permissions) ? B_NOT_ALLOWED : B_OK); 177 } 178 179 // CreateAttribute 180 status_t 181 Node::CreateAttribute(const char *name, Attribute **_attribute) 182 { 183 status_t error = (name && _attribute ? B_OK : B_BAD_VALUE); 184 if (error == B_OK) { 185 // create attribute 186 Attribute *attribute = new(nothrow) Attribute(fVolume, NULL, name); 187 if (attribute) { 188 error = attribute->InitCheck(); 189 if (error == B_OK) { 190 // add attribute to node 191 error = AddAttribute(attribute); 192 if (error == B_OK) 193 *_attribute = attribute; 194 } 195 if (error != B_OK) 196 delete attribute; 197 } else 198 SET_ERROR(error, B_NO_MEMORY); 199 } 200 return error; 201 } 202 203 // DeleteAttribute 204 status_t 205 Node::DeleteAttribute(Attribute *attribute) 206 { 207 status_t error = RemoveAttribute(attribute); 208 if (error == B_OK) 209 delete attribute; 210 return error; 211 } 212 213 // AddAttribute 214 status_t 215 Node::AddAttribute(Attribute *attribute) 216 { 217 status_t error = (attribute && !attribute->GetNode() ? B_OK : B_BAD_VALUE); 218 if (error == B_OK) { 219 error = GetVolume()->NodeAttributeAdded(GetID(), attribute); 220 if (error == B_OK) { 221 fAttributes.Insert(attribute); 222 attribute->SetNode(this); 223 MarkModified(B_STAT_MODIFICATION_TIME); 224 } 225 } 226 return error; 227 } 228 229 // RemoveAttribute 230 status_t 231 Node::RemoveAttribute(Attribute *attribute) 232 { 233 status_t error = (attribute && attribute->GetNode() == this 234 ? B_OK : B_BAD_VALUE); 235 if (error == B_OK) { 236 // move all iterators pointing to the attribute to the next attribute 237 if (GetVolume()->IteratorLock()) { 238 // set the iterators' current entry 239 Attribute *nextAttr = fAttributes.GetNext(attribute); 240 DoublyLinkedList<AttributeIterator> *iterators 241 = attribute->GetAttributeIteratorList(); 242 for (AttributeIterator *iterator = iterators->First(); 243 iterator; 244 iterator = iterators->GetNext(iterator)) { 245 iterator->SetCurrent(nextAttr, true); 246 } 247 // Move the iterators from one list to the other, or just remove 248 // them, if there is no next attribute. 249 if (nextAttr) { 250 DoublyLinkedList<AttributeIterator> *nextIterators 251 = nextAttr->GetAttributeIteratorList(); 252 nextIterators->MoveFrom(iterators); 253 } else 254 iterators->RemoveAll(); 255 GetVolume()->IteratorUnlock(); 256 } else 257 error = B_ERROR; 258 // remove the attribute 259 if (error == B_OK) { 260 error = GetVolume()->NodeAttributeRemoved(GetID(), attribute); 261 if (error == B_OK) { 262 fAttributes.Remove(attribute); 263 attribute->SetNode(NULL); 264 MarkModified(B_STAT_MODIFICATION_TIME); 265 } 266 } 267 } 268 return error; 269 } 270 271 // FindAttribute 272 status_t 273 Node::FindAttribute(const char *name, Attribute **_attribute) const 274 { 275 status_t error = (name && _attribute ? B_OK : B_BAD_VALUE); 276 if (error == B_OK) { 277 /* 278 Attribute *attribute = NULL; 279 while (GetNextAttribute(&attribute) == B_OK) { 280 if (!strcmp(attribute->GetName(), name)) { 281 *_attribute = attribute; 282 return B_OK; 283 } 284 } 285 error = B_ENTRY_NOT_FOUND; 286 */ 287 error = GetVolume()->FindNodeAttribute(GetID(), name, _attribute); 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 365