1 // Node.cpp 2 3 #include "AllocationInfo.h" 4 #include "DebugSupport.h" 5 #include "EntryIterator.h" 6 #include "LastModifiedIndex.h" 7 #include "Node.h" 8 #include "Volume.h" 9 10 // is_user_in_group 11 inline static 12 bool 13 is_user_in_group(gid_t gid) 14 { 15 // Either I miss something, or we don't have getgroups() in the kernel. :-( 16 /* 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; 22 } 23 */ 24 return (gid == getegid()); 25 } 26 27 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() 46 { 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; 58 } 59 // set defaults for time 60 fATime = fMTime = fCTime = fCrTime = time(NULL); 61 } 62 63 // destructor 64 Node::~Node() 65 { 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; 72 } 73 } 74 } 75 76 // InitCheck 77 status_t 78 Node::InitCheck() const 79 { 80 return (fVolume && fID >= 0 ? B_OK : B_NO_INIT); 81 } 82 83 // AddReference 84 status_t 85 Node::AddReference() 86 { 87 if (++fRefCount == 1) { 88 status_t error = GetVolume()->PublishVNode(this); 89 if (error != B_OK) { 90 fRefCount--; 91 return error; 92 } 93 94 fIsKnownToVFS = true; 95 } 96 97 return B_OK; 98 } 99 100 // RemoveReference 101 void 102 Node::RemoveReference() 103 { 104 if (--fRefCount == 0) { 105 GetVolume()->RemoveVNode(this); 106 fRefCount++; 107 } 108 } 109 110 // Link 111 status_t 112 Node::Link(Entry *entry) 113 { 114 PRINT(("Node[%Ld]::Link(): %ld ->...\n", fID, fRefCount)); 115 fReferrers.Insert(entry); 116 117 status_t error = AddReference(); 118 if (error != B_OK) 119 fReferrers.Remove(entry); 120 121 return error; 122 } 123 124 // Unlink 125 status_t 126 Node::Unlink(Entry *entry) 127 { 128 PRINT(("Node[%Ld]::Unlink(): %ld ->...\n", fID, fRefCount)); 129 RemoveReference(); 130 fReferrers.Remove(entry); 131 132 return B_OK; 133 } 134 135 // SetMTime 136 void 137 Node::SetMTime(time_t mTime) 138 { 139 time_t oldMTime = fMTime; 140 fATime = fMTime = mTime; 141 if (oldMTime != fMTime) { 142 if (LastModifiedIndex *index = fVolume->GetLastModifiedIndex()) 143 index->Changed(this, oldMTime); 144 } 145 } 146 147 // CheckPermissions 148 status_t 149 Node::CheckPermissions(int mode) const 150 { 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); 174 } 175 176 // CreateAttribute 177 status_t 178 Node::CreateAttribute(const char *name, Attribute **_attribute) 179 { 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; 191 } 192 if (error != B_OK) 193 delete attribute; 194 } else 195 SET_ERROR(error, B_NO_MEMORY); 196 } 197 return error; 198 } 199 200 // DeleteAttribute 201 status_t 202 Node::DeleteAttribute(Attribute *attribute) 203 { 204 status_t error = RemoveAttribute(attribute); 205 if (error == B_OK) 206 delete attribute; 207 return error; 208 } 209 210 // AddAttribute 211 status_t 212 Node::AddAttribute(Attribute *attribute) 213 { 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); 221 } 222 } 223 return error; 224 } 225 226 // RemoveAttribute 227 status_t 228 Node::RemoveAttribute(Attribute *attribute) 229 { 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); 243 } 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); 262 } 263 } 264 } 265 return error; 266 } 267 268 // FindAttribute 269 status_t 270 Node::FindAttribute(const char *name, Attribute **_attribute) const 271 { 272 status_t error = (name && _attribute ? B_OK : B_BAD_VALUE); 273 if (error == B_OK) { 274 /* 275 Attribute *attribute = NULL; 276 while (GetNextAttribute(&attribute) == B_OK) { 277 if (!strcmp(attribute->GetName(), name)) { 278 *_attribute = attribute; 279 return B_OK; 280 } 281 } 282 error = B_ENTRY_NOT_FOUND; 283 */ 284 error = GetVolume()->FindNodeAttribute(GetID(), name, _attribute); 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