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 13Directory::Directory(Volume *volume) 14 : Node(volume, NODE_TYPE_DIRECTORY), 15 fEntries() 16{ 17} 18 19// destructor 20Directory::~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 32status_t 33Directory::Link(Entry *entry) 34{ 35 if (fReferrers.IsEmpty()) 36 return Node::Link(entry); 37 return B_IS_A_DIRECTORY; 38} 39 40// Unlink 41status_t 42Directory::Unlink(Entry *entry) 43{ 44 if (entry == fReferrers.First()) 45 return Node::Unlink(entry); 46 return B_BAD_VALUE; 47} 48 49// SetSize 50status_t 51Directory::SetSize(off_t /*newSize*/) 52{ 53 return B_IS_A_DIRECTORY; 54} 55 56// GetSize 57off_t 58Directory::GetSize() const 59{ 60 return 0; 61} 62 63// GetParent 64Directory * 65Directory::GetParent() const 66{ 67 Entry *entry = fReferrers.First(); 68 return (entry ? entry->GetParent() : NULL); 69} 70 71// CreateDirectory 72status_t 73Directory::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 90status_t 91Directory::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 108status_t 109Directory::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 130status_t 131Directory::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 149status_t 150Directory::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 183status_t 184Directory::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 225status_t 226Directory::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 243status_t 244Directory::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 264status_t 265Directory::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 275status_t 276Directory::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 290status_t 291Directory::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 308status_t 309Directory::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 326void 327Directory::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 337status_t 338Directory::_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