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