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