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.GetFirst()) { 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.GetFirst()) 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.GetFirst(); 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 DLList<EntryIterator> *iterators = entry->GetEntryIteratorList(); 194 for (EntryIterator *iterator = iterators->GetFirst(); 195 iterator; 196 iterator = iterators->GetNext(iterator)) { 197 iterator->SetCurrent(nextEntry, true); 198 } 199 // Move the iterators from one list to the other, or just remove 200 // them, if there is no next entry. 201 if (nextEntry) { 202 DLList<EntryIterator> *nextIterators 203 = nextEntry->GetEntryIteratorList(); 204 nextIterators->MoveFrom(iterators); 205 } else 206 iterators->RemoveAll(); 207 GetVolume()->IteratorUnlock(); 208 } else 209 error = B_ERROR; 210 // remove the entry 211 if (error == B_OK) { 212 error = GetVolume()->EntryRemoved(GetID(), entry); 213 if (error == B_OK) { 214 fEntries.Remove(entry); 215 entry->SetParent(NULL); 216 MarkModified(B_STAT_MODIFICATION_TIME); 217 } 218 } 219 } 220 return error; 221 } 222 223 // DeleteEntry 224 status_t 225 Directory::DeleteEntry(Entry *entry) 226 { 227 status_t error = RemoveEntry(entry); 228 if (error == B_OK) { 229 error = entry->Unlink(); 230 if (error == B_OK) 231 delete entry; 232 else { 233 FATAL(("Failed to Unlink() entry %p from node %Ld!\n", entry, 234 entry->GetNode()->GetID())); 235 AddEntry(entry); 236 } 237 } 238 return error; 239 } 240 241 // FindEntry 242 status_t 243 Directory::FindEntry(const char *name, Entry **_entry) const 244 { 245 status_t error = (name && _entry ? B_OK : B_BAD_VALUE); 246 if (error == B_OK) { 247 /* 248 Entry *entry = NULL; 249 while (GetNextEntry(&entry) == B_OK) { 250 if (!strcmp(entry->GetName(), name)) { 251 *_entry = entry; 252 return B_OK; 253 } 254 } 255 error = B_ENTRY_NOT_FOUND; 256 */ 257 error = GetVolume()->FindEntry(GetID(), name, _entry); 258 } 259 return error; 260 } 261 262 // FindNode 263 status_t 264 Directory::FindNode(const char *name, Node **node) const 265 { 266 status_t error = (name && node ? B_OK : B_BAD_VALUE); 267 Entry *entry = NULL; 268 if (error == B_OK && (error = FindEntry(name, &entry)) == B_OK) 269 *node = entry->GetNode(); 270 return error; 271 } 272 273 // FindAndGetNode 274 status_t 275 Directory::FindAndGetNode(const char *name, Node **node, Entry **_entry) const 276 { 277 status_t error = (name && node ? B_OK : B_BAD_VALUE); 278 Entry *entry = NULL; 279 if (error == B_OK && (error = FindEntry(name, &entry)) == B_OK) { 280 *node = entry->GetNode(); 281 if (_entry) 282 *_entry = entry; 283 error = GetVolume()->GetVNode(*node); 284 } 285 return error; 286 } 287 288 // GetPreviousEntry 289 status_t 290 Directory::GetPreviousEntry(Entry **entry) const 291 { 292 status_t error = (entry ? B_OK : B_BAD_VALUE); 293 if (error == B_OK) { 294 if (!*entry) 295 *entry = fEntries.GetLast(); 296 else if ((*entry)->GetParent() == this) 297 *entry = fEntries.GetPrevious(*entry); 298 else 299 error = B_BAD_VALUE; 300 if (error == B_OK && !*entry) 301 error = B_ENTRY_NOT_FOUND; 302 } 303 return error; 304 } 305 306 // GetNextEntry 307 status_t 308 Directory::GetNextEntry(Entry **entry) const 309 { 310 status_t error = (entry ? B_OK : B_BAD_VALUE); 311 if (error == B_OK) { 312 if (!*entry) 313 *entry = fEntries.GetFirst(); 314 else if ((*entry)->GetParent() == this) 315 *entry = fEntries.GetNext(*entry); 316 else 317 error = B_BAD_VALUE; 318 if (error == B_OK && !*entry) 319 error = B_ENTRY_NOT_FOUND; 320 } 321 return error; 322 } 323 324 // GetAllocationInfo 325 void 326 Directory::GetAllocationInfo(AllocationInfo &info) 327 { 328 Node::GetAllocationInfo(info); 329 info.AddDirectoryAllocation(); 330 Entry *entry = NULL; 331 while (GetNextEntry(&entry) == B_OK) 332 entry->GetAllocationInfo(info); 333 } 334 335 // _CreateCommon 336 status_t 337 Directory::_CreateCommon(Node *node, const char *name) 338 { 339 status_t error = node->InitCheck(); 340 if (error == B_OK) { 341 // add node to directory 342 error = CreateEntry(node, name); 343 } 344 if (error != B_OK) 345 delete node; 346 return error; 347 } 348 349