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 16 class CachedDirIterator : public DirIterator { 17 public: 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 30 private: 31 Entry* fCurrentEntry; 32 }; 33 34 // UncachedDirIterator 35 class UncachedDirIterator : public DirIterator { 36 public: 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 47 protected: 48 virtual int GetFD() const; 49 50 private: 51 DIR* fDirHandle; 52 }; 53 54 55 // #pragma mark - 56 57 // constructor 58 CachedDirIterator::CachedDirIterator() 59 : DirIterator(), 60 fCurrentEntry(NULL) 61 { 62 } 63 64 // destructor 65 CachedDirIterator::~CachedDirIterator() 66 { 67 } 68 69 // SetDirectory 70 status_t 71 CachedDirIterator::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 84 Entry* 85 CachedDirIterator::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 96 void 97 CachedDirIterator::Rewind() 98 { 99 fCurrentEntry = (IsValid() ? fDirectory->GetFirstEntry() : NULL); 100 } 101 102 // GetCurrentEntry 103 Entry* 104 CachedDirIterator::GetCurrentEntry() const 105 { 106 return (IsValid() ? fCurrentEntry : NULL); 107 } 108 109 // GetStat 110 status_t 111 CachedDirIterator::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 124 UncachedDirIterator::UncachedDirIterator() 125 : DirIterator(), 126 fDirHandle(NULL) 127 { 128 } 129 130 // destructor 131 UncachedDirIterator::~UncachedDirIterator() 132 { 133 // close 134 if (fDirHandle) { 135 closedir(fDirHandle); 136 fDirHandle = NULL; 137 } 138 } 139 140 // SetDirectory 141 status_t 142 UncachedDirIterator::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 172 Entry* 173 UncachedDirIterator::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 193 void 194 UncachedDirIterator::Rewind() 195 { 196 if (IsValid() && fDirHandle) 197 rewinddir(fDirHandle); 198 } 199 200 // GetCurrentEntry 201 Entry* 202 UncachedDirIterator::GetCurrentEntry() const 203 { 204 return NULL; 205 } 206 207 // GetFD 208 int 209 UncachedDirIterator::GetFD() const 210 { 211 return dirfd(fDirHandle); 212 } 213 214 215 // #pragma mark - 216 217 // constructor 218 Directory::Directory(Volume* volume, const struct stat& st) 219 : Node(volume, st), 220 fEntries(), 221 fIterators(), 222 fIsComplete(false) 223 { 224 } 225 226 // destructor 227 Directory::~Directory() 228 { 229 // remove all directory iterators 230 while (DirIterator* iterator = fIterators.First()) 231 iterator->SetDirectory(NULL); 232 } 233 234 // GetActualReferringEntry 235 Entry* 236 Directory::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 249 void 250 Directory::AddEntry(Entry* entry) 251 { 252 if (entry) 253 fEntries.Insert(entry); 254 } 255 256 // RemoveEntry 257 void 258 Directory::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 274 Entry* 275 Directory::GetFirstEntry() const 276 { 277 return fEntries.First(); 278 } 279 280 // GetNextEntry 281 Entry* 282 Directory::GetNextEntry(Entry* entry) const 283 { 284 return (entry ? fEntries.GetNext(entry) : NULL); 285 } 286 287 // CountEntries 288 int32 289 Directory::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 301 status_t 302 Directory::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 336 bool 337 Directory::HasDirIterators() const 338 { 339 return fIterators.First(); 340 } 341 342 // RemoveDirIterator 343 void 344 Directory::RemoveDirIterator(DirIterator* iterator) 345 { 346 if (iterator) 347 fIterators.Remove(iterator); 348 } 349 350 // SetComplete 351 void 352 Directory::SetComplete(bool complete) 353 { 354 fIsComplete = complete; 355 } 356 357 // IsComplete 358 bool 359 Directory::IsComplete() const 360 { 361 return fIsComplete; 362 } 363