1// Directory.cpp 2 3#include <new> 4 5#include <dirent.h> 6#include <errno.h> 7 8#include <AutoDeleter.h> 9 10#include "Directory.h" 11#include "FDManager.h" 12#include "Path.h" 13#include "VolumeManager.h" 14 15// CachedDirIterator 16class CachedDirIterator : public DirIterator { 17public: 18 CachedDirIterator(); 19 ~CachedDirIterator(); 20 21 virtual status_t SetDirectory(Directory* directory); 22 23 virtual Entry* NextEntry(); 24 virtual void Rewind(); 25 26 virtual Entry* GetCurrentEntry() const; 27 28 virtual status_t GetStat(struct stat* st); 29 30private: 31 Entry* fCurrentEntry; 32}; 33 34// UncachedDirIterator 35class UncachedDirIterator : public DirIterator { 36public: 37 UncachedDirIterator(); 38 ~UncachedDirIterator(); 39 40 virtual status_t SetDirectory(Directory* directory); 41 42 virtual Entry* NextEntry(); 43 virtual void Rewind(); 44 45 virtual Entry* GetCurrentEntry() const; 46 47protected: 48 virtual int GetFD() const; 49 50private: 51 DIR* fDirHandle; 52}; 53 54 55// #pragma mark - 56 57// constructor 58CachedDirIterator::CachedDirIterator() 59 : DirIterator(), 60 fCurrentEntry(NULL) 61{ 62} 63 64// destructor 65CachedDirIterator::~CachedDirIterator() 66{ 67} 68 69// SetDirectory 70status_t 71CachedDirIterator::SetDirectory(Directory* directory) 72{ 73 // set the new directory 74 fDirectory = directory; 75 fCurrentEntry = (fDirectory ? fDirectory->GetFirstEntry() : NULL); 76 77 if (directory) 78 fNodeRef = directory->GetNodeRef(); 79 80 return B_OK; 81} 82 83// NextEntry 84Entry* 85CachedDirIterator::NextEntry() 86{ 87 if (!IsValid() || !fCurrentEntry) 88 return NULL; 89 90 Entry* entry = fCurrentEntry; 91 fCurrentEntry = fDirectory->GetNextEntry(fCurrentEntry); 92 return entry; 93} 94 95// Rewind 96void 97CachedDirIterator::Rewind() 98{ 99 fCurrentEntry = (IsValid() ? fDirectory->GetFirstEntry() : NULL); 100} 101 102// GetCurrentEntry 103Entry* 104CachedDirIterator::GetCurrentEntry() const 105{ 106 return (IsValid() ? fCurrentEntry : NULL); 107} 108 109// GetStat 110status_t 111CachedDirIterator::GetStat(struct stat* st) 112{ 113 if (!fDirectory || !st) 114 return B_BAD_VALUE; 115 116 *st = fDirectory->GetStat(); 117 return B_OK; 118} 119 120 121// #pragma mark - 122 123// constructor 124UncachedDirIterator::UncachedDirIterator() 125 : DirIterator(), 126 fDirHandle(NULL) 127{ 128} 129 130// destructor 131UncachedDirIterator::~UncachedDirIterator() 132{ 133 // close 134 if (fDirHandle) { 135 closedir(fDirHandle); 136 fDirHandle = NULL; 137 } 138} 139 140// SetDirectory 141status_t 142UncachedDirIterator::SetDirectory(Directory* directory) 143{ 144 // unset old 145 if (fDirHandle) { 146 closedir(fDirHandle); 147 fDirHandle = NULL; 148 } 149 fDirectory = NULL; 150 151 // set new 152 if (directory) { 153 // get the directory path 154 Path path; 155 status_t error = directory->GetPath(&path); 156 if (error != B_OK) 157 return error; 158 159 // open the directory 160 error = FDManager::OpenDir(path.GetPath(), fDirHandle); 161 if (error != B_OK) 162 return error; 163 164 fDirectory = directory; 165 fNodeRef = directory->GetNodeRef(); 166 } 167 168 return B_OK; 169} 170 171// NextEntry 172Entry* 173UncachedDirIterator::NextEntry() 174{ 175 if (!IsValid() && fDirHandle) 176 return NULL; 177 178 while (struct dirent* dirEntry = readdir(fDirHandle)) { 179 Entry* entry; 180 if (VolumeManager::GetDefault()->LoadEntry(dirEntry->d_pdev, 181 dirEntry->d_pino, dirEntry->d_name, false, &entry) == B_OK) { 182 return entry; 183 } 184 } 185 186 // we're through: set the directory to "complete" 187 fDirectory->SetComplete(true); 188 189 return NULL; 190} 191 192// Rewind 193void 194UncachedDirIterator::Rewind() 195{ 196 if (IsValid() && fDirHandle) 197 rewinddir(fDirHandle); 198} 199 200// GetCurrentEntry 201Entry* 202UncachedDirIterator::GetCurrentEntry() const 203{ 204 return NULL; 205} 206 207// GetFD 208int 209UncachedDirIterator::GetFD() const 210{ 211 return dirfd(fDirHandle); 212} 213 214 215// #pragma mark - 216 217// constructor 218Directory::Directory(Volume* volume, const struct stat& st) 219 : Node(volume, st), 220 fEntries(), 221 fIterators(), 222 fIsComplete(false) 223{ 224} 225 226// destructor 227Directory::~Directory() 228{ 229 // remove all directory iterators 230 while (DirIterator* iterator = fIterators.First()) 231 iterator->SetDirectory(NULL); 232} 233 234// GetActualReferringEntry 235Entry* 236Directory::GetActualReferringEntry() const 237{ 238 // any entry other than "." and ".." is fine 239 for (Entry* entry = GetFirstReferringEntry(); 240 entry; 241 entry = GetNextReferringEntry(entry)) { 242 if (entry->IsActualEntry()) 243 return entry; 244 } 245 return NULL; 246} 247 248// AddEntry 249void 250Directory::AddEntry(Entry* entry) 251{ 252 if (entry) 253 fEntries.Insert(entry); 254} 255 256// RemoveEntry 257void 258Directory::RemoveEntry(Entry* entry) 259{ 260 if (entry) { 261 // update the directory iterators pointing to the removed entry 262 for (DirIterator* iterator = fIterators.First(); 263 iterator; 264 iterator = fIterators.GetNext(iterator)) { 265 if (iterator->GetCurrentEntry() == entry) 266 iterator->NextEntry(); 267 } 268 269 fEntries.Remove(entry); 270 } 271} 272 273// GetFirstEntry 274Entry* 275Directory::GetFirstEntry() const 276{ 277 return fEntries.First(); 278} 279 280// GetNextEntry 281Entry* 282Directory::GetNextEntry(Entry* entry) const 283{ 284 return (entry ? fEntries.GetNext(entry) : NULL); 285} 286 287// CountEntries 288int32 289Directory::CountEntries() const 290{ 291 int32 count = 0; 292 Entry* entry = GetFirstEntry(); 293 while (entry) { 294 count++; 295 entry = GetNextEntry(entry); 296 } 297 return count; 298} 299 300// OpenDir 301status_t 302Directory::OpenDir(DirIterator** _iterator) 303{ 304 if (!_iterator) 305 return B_BAD_VALUE; 306 307 // create the iterator 308 DirIterator* iterator; 309 if (fIsComplete) 310 iterator = new(std::nothrow) CachedDirIterator; 311 else 312 iterator = new(std::nothrow) UncachedDirIterator; 313 if (!iterator) 314 return B_NO_MEMORY; 315 ObjectDeleter<DirIterator> iteratorDeleter(iterator); 316 317 // initialize it 318 status_t error = iterator->SetDirectory(this); 319 if (error != B_OK) 320 return error; 321 322 // check, if it really belongs to this node 323 error = _CheckNodeHandle(iterator); 324 if (error != B_OK) 325 return error; 326 327 // add it 328 fIterators.Insert(iterator); 329 330 iteratorDeleter.Detach(); 331 *_iterator = iterator; 332 return B_OK; 333} 334 335// HasDirIterators 336bool 337Directory::HasDirIterators() const 338{ 339 return fIterators.First(); 340} 341 342// RemoveDirIterator 343void 344Directory::RemoveDirIterator(DirIterator* iterator) 345{ 346 if (iterator) 347 fIterators.Remove(iterator); 348} 349 350// SetComplete 351void 352Directory::SetComplete(bool complete) 353{ 354 fIsComplete = complete; 355} 356 357// IsComplete 358bool 359Directory::IsComplete() const 360{ 361 return fIsComplete; 362} 363