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 14 Node::Node(Volume *volume, uint8 type) 15 : fVolume(volume), 16 fID(fVolume->NextNodeID()), 17 fRefCount(0), 18 fMode(0), 19 fUID(0), 20 fGID(0), 21 fATime(0), 22 fMTime(0), 23 fCTime(0), 24 fCrTime(0), 25 fModified(0), 26 fIsKnownToVFS(false), 27 fAttributes(), 28 fReferrers() 29 { 30 // set file type 31 switch (type) { 32 case NODE_TYPE_DIRECTORY: 33 fMode = S_IFDIR; 34 break; 35 case NODE_TYPE_FILE: 36 fMode = S_IFREG; 37 break; 38 case NODE_TYPE_SYMLINK: 39 fMode = S_IFLNK; 40 break; 41 } 42 // set defaults for time 43 fATime = fMTime = fCTime = fCrTime = time(NULL); 44 } 45 46 47 Node::~Node() 48 { 49 ASSERT(fRefCount == 0); 50 51 // delete all attributes 52 while (Attribute *attribute = fAttributes.First()) { 53 status_t error = DeleteAttribute(attribute); 54 if (error != B_OK) { 55 FATAL("Node::~Node(): Failed to delete attribute!\n"); 56 break; 57 } 58 } 59 } 60 61 62 status_t 63 Node::InitCheck() const 64 { 65 return (fVolume && fID >= 0 ? B_OK : B_NO_INIT); 66 } 67 68 69 status_t 70 Node::AddReference() 71 { 72 if (++fRefCount == 1) { 73 status_t error = GetVolume()->PublishVNode(this); 74 if (error != B_OK) { 75 fRefCount--; 76 return error; 77 } 78 79 fIsKnownToVFS = true; 80 } 81 82 return B_OK; 83 } 84 85 86 void 87 Node::RemoveReference() 88 { 89 ASSERT(fRefCount > 0); 90 if (--fRefCount == 0) { 91 GetVolume()->RemoveVNode(this); 92 // RemoveVNode can potentially delete us immediately! 93 } 94 } 95 96 97 status_t 98 Node::Link(Entry *entry) 99 { 100 PRINT("Node[%" B_PRIdINO "]::Link(): %" B_PRId32 " ->...\n", fID, fRefCount); 101 fReferrers.Insert(entry); 102 103 status_t error = AddReference(); 104 if (error != B_OK) 105 fReferrers.Remove(entry); 106 107 return error; 108 } 109 110 111 status_t 112 Node::Unlink(Entry *entry) 113 { 114 PRINT("Node[%" B_PRIdINO "]::Unlink(): %" B_PRId32 " ->...\n", fID, fRefCount); 115 fReferrers.Remove(entry); 116 117 RemoveReference(); 118 return B_OK; 119 } 120 121 122 void 123 Node::SetMTime(time_t mTime) 124 { 125 time_t oldMTime = fMTime; 126 fATime = fMTime = mTime; 127 if (oldMTime != fMTime) { 128 if (LastModifiedIndex *index = fVolume->GetLastModifiedIndex()) 129 index->Changed(this, oldMTime); 130 } 131 } 132 133 134 status_t 135 Node::CheckPermissions(int mode) const 136 { 137 return check_access_permissions(mode, fMode, fGID, fUID); 138 } 139 140 141 status_t 142 Node::CreateAttribute(const char *name, Attribute **_attribute) 143 { 144 status_t error = (name && _attribute ? B_OK : B_BAD_VALUE); 145 if (error == B_OK) { 146 // create attribute 147 Attribute *attribute = new(nothrow) Attribute(fVolume, NULL, name); 148 if (attribute) { 149 error = attribute->InitCheck(); 150 if (error == B_OK) { 151 // add attribute to node 152 error = AddAttribute(attribute); 153 if (error == B_OK) 154 *_attribute = attribute; 155 } 156 if (error != B_OK) 157 delete attribute; 158 } else 159 SET_ERROR(error, B_NO_MEMORY); 160 } 161 return error; 162 } 163 164 165 status_t 166 Node::DeleteAttribute(Attribute *attribute) 167 { 168 status_t error = RemoveAttribute(attribute); 169 if (error == B_OK) 170 delete attribute; 171 return error; 172 } 173 174 175 status_t 176 Node::AddAttribute(Attribute *attribute) 177 { 178 status_t error = (attribute && !attribute->GetNode() ? B_OK : B_BAD_VALUE); 179 if (error == B_OK) { 180 error = GetVolume()->NodeAttributeAdded(GetID(), attribute); 181 if (error == B_OK) { 182 fAttributes.Insert(attribute); 183 attribute->SetNode(this); 184 MarkModified(B_STAT_MODIFICATION_TIME); 185 } 186 } 187 return error; 188 } 189 190 191 status_t 192 Node::RemoveAttribute(Attribute *attribute) 193 { 194 status_t error = (attribute && attribute->GetNode() == this 195 ? B_OK : B_BAD_VALUE); 196 if (error == B_OK) { 197 // move all iterators pointing to the attribute to the next attribute 198 if (GetVolume()->IteratorLock()) { 199 // set the iterators' current entry 200 Attribute *nextAttr = fAttributes.GetNext(attribute); 201 DoublyLinkedList<AttributeIterator> *iterators 202 = attribute->GetAttributeIteratorList(); 203 for (AttributeIterator *iterator = iterators->First(); 204 iterator; 205 iterator = iterators->GetNext(iterator)) { 206 iterator->SetCurrent(nextAttr, true); 207 } 208 // Move the iterators from one list to the other, or just remove 209 // them, if there is no next attribute. 210 if (nextAttr) { 211 DoublyLinkedList<AttributeIterator> *nextIterators 212 = nextAttr->GetAttributeIteratorList(); 213 nextIterators->MoveFrom(iterators); 214 } else 215 iterators->RemoveAll(); 216 GetVolume()->IteratorUnlock(); 217 } else 218 error = B_ERROR; 219 // remove the attribute 220 if (error == B_OK) { 221 error = GetVolume()->NodeAttributeRemoved(GetID(), attribute); 222 if (error == B_OK) { 223 fAttributes.Remove(attribute); 224 attribute->SetNode(NULL); 225 MarkModified(B_STAT_MODIFICATION_TIME); 226 } 227 } 228 } 229 return error; 230 } 231 232 233 status_t 234 Node::FindAttribute(const char *name, Attribute **_attribute) const 235 { 236 status_t error = (name && _attribute ? B_OK : B_BAD_VALUE); 237 if (error == B_OK) { 238 Attribute *attribute = NULL; 239 while (GetNextAttribute(&attribute) == B_OK) { 240 if (!strcmp(attribute->GetName(), name)) { 241 *_attribute = attribute; 242 return B_OK; 243 } 244 } 245 error = B_ENTRY_NOT_FOUND; 246 } 247 return error; 248 } 249 250 251 status_t 252 Node::GetPreviousAttribute(Attribute **attribute) const 253 { 254 status_t error = (attribute ? B_OK : B_BAD_VALUE); 255 if (error == B_OK) { 256 if (!*attribute) 257 *attribute = fAttributes.Last(); 258 else if ((*attribute)->GetNode() == this) 259 *attribute = fAttributes.GetPrevious(*attribute); 260 else 261 error = B_BAD_VALUE; 262 if (error == B_OK && !*attribute) 263 error = B_ENTRY_NOT_FOUND; 264 } 265 return error; 266 } 267 268 269 status_t 270 Node::GetNextAttribute(Attribute **attribute) const 271 { 272 status_t error = (attribute ? B_OK : B_BAD_VALUE); 273 if (error == B_OK) { 274 if (!*attribute) 275 *attribute = fAttributes.First(); 276 else if ((*attribute)->GetNode() == this) 277 *attribute = fAttributes.GetNext(*attribute); 278 else 279 error = B_BAD_VALUE; 280 if (error == B_OK && !*attribute) 281 error = B_ENTRY_NOT_FOUND; 282 } 283 return error; 284 } 285 286 287 Entry * 288 Node::GetFirstReferrer() const 289 { 290 return fReferrers.First(); 291 } 292 293 294 Entry * 295 Node::GetLastReferrer() const 296 { 297 return fReferrers.Last(); 298 } 299 300 301 Entry * 302 Node::GetPreviousReferrer(Entry *entry) const 303 { 304 return (entry ? fReferrers.GetPrevious(entry) : NULL ); 305 } 306 307 308 Entry * 309 Node::GetNextReferrer(Entry *entry) const 310 { 311 return (entry ? fReferrers.GetNext(entry) : NULL ); 312 } 313 314 315 void 316 Node::GetAllocationInfo(AllocationInfo &info) 317 { 318 Attribute *attribute = NULL; 319 while (GetNextAttribute(&attribute) == B_OK) 320 attribute->GetAllocationInfo(info); 321 } 322