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 Attribute *attribute = NULL; 278 while (GetNextAttribute(&attribute) == B_OK) { 279 if (!strcmp(attribute->GetName(), name)) { 280 *_attribute = attribute; 281 return B_OK; 282 } 283 } 284 error = B_ENTRY_NOT_FOUND; 285 } 286 return error; 287 } 288 289 // GetPreviousAttribute 290 status_t 291 Node::GetPreviousAttribute(Attribute **attribute) const 292 { 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; 303 } 304 return error; 305 } 306 307 // GetNextAttribute 308 status_t 309 Node::GetNextAttribute(Attribute **attribute) const 310 { 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; 321 } 322 return error; 323 } 324 325 // GetFirstReferrer 326 Entry * 327 Node::GetFirstReferrer() const 328 { 329 return fReferrers.First(); 330 } 331 332 // GetLastReferrer 333 Entry * 334 Node::GetLastReferrer() const 335 { 336 return fReferrers.Last(); 337 } 338 339 // GetPreviousReferrer 340 Entry * 341 Node::GetPreviousReferrer(Entry *entry) const 342 { 343 return (entry ? fReferrers.GetPrevious(entry) : NULL ); 344 } 345 346 // GetNextReferrer 347 Entry * 348 Node::GetNextReferrer(Entry *entry) const 349 { 350 return (entry ? fReferrers.GetNext(entry) : NULL ); 351 } 352 353 // GetAllocationInfo 354 void 355 Node::GetAllocationInfo(AllocationInfo &info) 356 { 357 Attribute *attribute = NULL; 358 while (GetNextAttribute(&attribute) == B_OK) 359 attribute->GetAllocationInfo(info); 360 } 361 362