xref: /haiku/src/add-ons/kernel/file_systems/netfs/server/Directory.cpp (revision 4052469d007d17112b0fdf8814c92c77414a1398)
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