1 // Directory.cpp 2 3 #include "AllocationInfo.h" 4 #include "Debug.h" 5 #include "Directory.h" 6 #include "Entry.h" 7 #include "EntryIterator.h" 8 #include "File.h" 9 #include "SymLink.h" 10 #include "Volume.h" 11 12 // constructor 13 Directory::Directory(Volume *volume) 14 : Node(volume, NODE_TYPE_DIRECTORY), 15 fEntries() 16 { 17 } 18 19 // destructor 20 Directory::~Directory() 21 { 22 // delete all entries 23 while (Entry *entry = fEntries.First()) { 24 if (DeleteEntry(entry) != B_OK) { 25 FATAL(("Could not delete all entries in directory.\n")); 26 break; 27 } 28 } 29 } 30 31 // Link 32 status_t 33 Directory::Link(Entry *entry) 34 { 35 if (fReferrers.IsEmpty()) 36 return Node::Link(entry); 37 return B_IS_A_DIRECTORY; 38 } 39 40 // Unlink 41 status_t 42 Directory::Unlink(Entry *entry) 43 { 44 if (entry == fReferrers.First()) 45 return Node::Unlink(entry); 46 return B_BAD_VALUE; 47 } 48 49 // SetSize 50 status_t 51 Directory::SetSize(off_t /*newSize*/) 52 { 53 return B_IS_A_DIRECTORY; 54 } 55 56 // GetSize 57 off_t 58 Directory::GetSize() const 59 { 60 return 0; 61 } 62 63 // GetParent 64 Directory * 65 Directory::GetParent() const 66 { 67 Entry *entry = fReferrers.First(); 68 return (entry ? entry->GetParent() : NULL); 69 } 70 71 // CreateDirectory 72 status_t 73 Directory::CreateDirectory(const char *name, Directory **directory) 74 { 75 status_t error = (name && directory ? B_OK : B_BAD_VALUE); 76 if (error == B_OK) { 77 // create directory 78 if (Directory *node = new(nothrow) Directory(GetVolume())) { 79 error = _CreateCommon(node, name); 80 // deletes the node on failure 81 if (error == B_OK) 82 *directory = node; 83 } else 84 SET_ERROR(error, B_NO_MEMORY); 85 } 86 return error; 87 } 88 89 // CreateFile 90 status_t 91 Directory::CreateFile(const char *name, File **file) 92 { 93 status_t error = (name && file ? B_OK : B_BAD_VALUE); 94 if (error == B_OK) { 95 // create file 96 if (File *node = new(nothrow) File(GetVolume())) { 97 error = _CreateCommon(node, name); 98 // deletes the node on failure 99 if (error == B_OK) 100 *file = node; 101 } else 102 SET_ERROR(error, B_NO_MEMORY); 103 } 104 return error; 105 } 106 107 // CreateSymLink 108 status_t 109 Directory::CreateSymLink(const char *name, const char *path, SymLink **symLink) 110 { 111 status_t error = (name && symLink ? B_OK : B_BAD_VALUE); 112 if (error == B_OK) { 113 // create symlink 114 if (SymLink *node = new(nothrow) SymLink(GetVolume())) { 115 error = node->SetLinkedPath(path); 116 if (error == B_OK) { 117 error = _CreateCommon(node, name); 118 // deletes the node on failure 119 if (error == B_OK) 120 *symLink = node; 121 } else 122 delete node; 123 } else 124 SET_ERROR(error, B_NO_MEMORY); 125 } 126 return error; 127 } 128 129 // AddEntry 130 status_t 131 Directory::AddEntry(Entry *entry) 132 { 133 status_t error = (entry && !entry->GetParent() ? B_OK : B_BAD_VALUE); 134 if (error == B_OK) { 135 fEntries.Insert(entry); 136 entry->SetParent(this); 137 error = GetVolume()->EntryAdded(GetID(), entry); 138 if (error == B_OK) { 139 MarkModified(B_STAT_MODIFICATION_TIME); 140 } else { 141 fEntries.Remove(entry); 142 entry->SetParent(NULL); 143 } 144 } 145 return error; 146 } 147 148 // CreateEntry 149 status_t 150 Directory::CreateEntry(Node *node, const char *name, Entry **_entry) 151 { 152 status_t error = (node ? B_OK : B_BAD_VALUE); 153 if (error == B_OK) { 154 // create an entry 155 Entry *entry = new(nothrow) Entry(name); 156 if (entry) { 157 error = entry->InitCheck(); 158 if (error == B_OK) { 159 // link to the node 160 error = entry->Link(node); 161 if (error == B_OK) { 162 // add the entry 163 error = AddEntry(entry); 164 if (error == B_OK) { 165 if (_entry) 166 *_entry = entry; 167 } else { 168 // failure: unlink the node 169 entry->Unlink(); 170 } 171 } 172 } 173 // delete the entry on failure 174 if (error != B_OK) 175 delete entry; 176 } else 177 SET_ERROR(error, B_NO_MEMORY); 178 } 179 return error; 180 } 181 182 // RemoveEntry 183 status_t 184 Directory::RemoveEntry(Entry *entry) 185 { 186 status_t error = (entry && entry->GetParent() == this ? B_OK 187 : B_BAD_VALUE); 188 if (error == B_OK) { 189 // move all iterators pointing to the entry to the next entry 190 if (GetVolume()->IteratorLock()) { 191 // set the iterators' current entry 192 Entry *nextEntry = fEntries.GetNext(entry); 193 DoublyLinkedList<EntryIterator> *iterators 194 = entry->GetEntryIteratorList(); 195 for (EntryIterator *iterator = iterators->First(); 196 iterator; 197 iterator = iterators->GetNext(iterator)) { 198 iterator->SetCurrent(nextEntry, true); 199 } 200 // Move the iterators from one list to the other, or just remove 201 // them, if there is no next entry. 202 if (nextEntry) { 203 DoublyLinkedList<EntryIterator> *nextIterators 204 = nextEntry->GetEntryIteratorList(); 205 nextIterators->MoveFrom(iterators); 206 } else 207 iterators->RemoveAll(); 208 GetVolume()->IteratorUnlock(); 209 } else 210 error = B_ERROR; 211 // remove the entry 212 if (error == B_OK) { 213 error = GetVolume()->EntryRemoved(GetID(), entry); 214 if (error == B_OK) { 215 fEntries.Remove(entry); 216 entry->SetParent(NULL); 217 MarkModified(B_STAT_MODIFICATION_TIME); 218 } 219 } 220 } 221 return error; 222 } 223 224 // DeleteEntry 225 status_t 226 Directory::DeleteEntry(Entry *entry) 227 { 228 status_t error = RemoveEntry(entry); 229 if (error == B_OK) { 230 error = entry->Unlink(); 231 if (error == B_OK) 232 delete entry; 233 else { 234 FATAL(("Failed to Unlink() entry %p from node %Ld!\n", entry, 235 entry->GetNode()->GetID())); 236 AddEntry(entry); 237 } 238 } 239 return error; 240 } 241 242 // FindEntry 243 status_t 244 Directory::FindEntry(const char *name, Entry **_entry) const 245 { 246 status_t error = (name && _entry ? B_OK : B_BAD_VALUE); 247 if (error == B_OK) { 248 /* 249 Entry *entry = NULL; 250 while (GetNextEntry(&entry) == B_OK) { 251 if (!strcmp(entry->GetName(), name)) { 252 *_entry = entry; 253 return B_OK; 254 } 255 } 256 error = B_ENTRY_NOT_FOUND; 257 */ 258 error = GetVolume()->FindEntry(GetID(), name, _entry); 259 } 260 return error; 261 } 262 263 // FindNode 264 status_t 265 Directory::FindNode(const char *name, Node **node) const 266 { 267 status_t error = (name && node ? B_OK : B_BAD_VALUE); 268 Entry *entry = NULL; 269 if (error == B_OK && (error = FindEntry(name, &entry)) == B_OK) 270 *node = entry->GetNode(); 271 return error; 272 } 273 274 // FindAndGetNode 275 status_t 276 Directory::FindAndGetNode(const char *name, Node **node, Entry **_entry) const 277 { 278 status_t error = (name && node ? B_OK : B_BAD_VALUE); 279 Entry *entry = NULL; 280 if (error == B_OK && (error = FindEntry(name, &entry)) == B_OK) { 281 *node = entry->GetNode(); 282 if (_entry) 283 *_entry = entry; 284 error = GetVolume()->GetVNode(*node); 285 } 286 return error; 287 } 288 289 // GetPreviousEntry 290 status_t 291 Directory::GetPreviousEntry(Entry **entry) const 292 { 293 status_t error = (entry ? B_OK : B_BAD_VALUE); 294 if (error == B_OK) { 295 if (!*entry) 296 *entry = fEntries.Last(); 297 else if ((*entry)->GetParent() == this) 298 *entry = fEntries.GetPrevious(*entry); 299 else 300 error = B_BAD_VALUE; 301 if (error == B_OK && !*entry) 302 error = B_ENTRY_NOT_FOUND; 303 } 304 return error; 305 } 306 307 // GetNextEntry 308 status_t 309 Directory::GetNextEntry(Entry **entry) const 310 { 311 status_t error = (entry ? B_OK : B_BAD_VALUE); 312 if (error == B_OK) { 313 if (!*entry) 314 *entry = fEntries.First(); 315 else if ((*entry)->GetParent() == this) 316 *entry = fEntries.GetNext(*entry); 317 else 318 error = B_BAD_VALUE; 319 if (error == B_OK && !*entry) 320 error = B_ENTRY_NOT_FOUND; 321 } 322 return error; 323 } 324 325 // GetAllocationInfo 326 void 327 Directory::GetAllocationInfo(AllocationInfo &info) 328 { 329 Node::GetAllocationInfo(info); 330 info.AddDirectoryAllocation(); 331 Entry *entry = NULL; 332 while (GetNextEntry(&entry) == B_OK) 333 entry->GetAllocationInfo(info); 334 } 335 336 // _CreateCommon 337 status_t 338 Directory::_CreateCommon(Node *node, const char *name) 339 { 340 status_t error = node->InitCheck(); 341 if (error == B_OK) { 342 // add node to directory 343 error = CreateEntry(node, name); 344 } 345 if (error != B_OK) 346 delete node; 347 return error; 348 } 349 350