xref: /haiku/src/kits/storage/Directory.cpp (revision b06a48ab8f30b45916a9c157b992827779182163)
1 /*
2  * Copyright 2002-2008, Haiku Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Tyler Dauwalder
7  *		Ingo Weinhold, bonefish@users.sf.net
8  *		Axel Dörfler, axeld@pinc-software.de
9  */
10 
11 
12 #include "storage_support.h"
13 
14 #include <syscalls.h>
15 
16 #include <Directory.h>
17 #include <Entry.h>
18 #include <File.h>
19 #include <fs_info.h>
20 #include <Path.h>
21 #include <SymLink.h>
22 
23 #include <fcntl.h>
24 #include <string.h>
25 
26 
27 // constructor
28 //! Creates an uninitialized BDirectory object.
29 BDirectory::BDirectory()
30 	:
31 	fDirFd(-1)
32 {
33 }
34 
35 // copy constructor
36 //! Creates a copy of the supplied BDirectory.
37 /*!	\param dir the BDirectory object to be copied
38 */
39 BDirectory::BDirectory(const BDirectory &dir)
40 	:
41 	fDirFd(-1)
42 {
43 	*this = dir;
44 }
45 
46 // constructor
47 /*! \brief Creates a BDirectory and initializes it to the directory referred
48 	to by the supplied entry_ref.
49 	\param ref the entry_ref referring to the directory
50 */
51 BDirectory::BDirectory(const entry_ref *ref)
52 	:
53 	fDirFd(-1)
54 {
55 	SetTo(ref);
56 }
57 
58 // constructor
59 /*! \brief Creates a BDirectory and initializes it to the directory referred
60 	to by the supplied node_ref.
61 	\param nref the node_ref referring to the directory
62 */
63 BDirectory::BDirectory(const node_ref *nref)
64 	:
65 	fDirFd(-1)
66 {
67 	SetTo(nref);
68 }
69 
70 // constructor
71 /*! \brief Creates a BDirectory and initializes it to the directory referred
72 	to by the supplied BEntry.
73 	\param entry the BEntry referring to the directory
74 */
75 BDirectory::BDirectory(const BEntry *entry)
76 	:
77 	fDirFd(-1)
78 {
79 	SetTo(entry);
80 }
81 
82 // constructor
83 /*! \brief Creates a BDirectory and initializes it to the directory referred
84 	to by the supplied path name.
85 	\param path the directory's path name
86 */
87 BDirectory::BDirectory(const char *path)
88 	:
89 	fDirFd(-1)
90 {
91 	SetTo(path);
92 }
93 
94 // constructor
95 /*! \brief Creates a BDirectory and initializes it to the directory referred
96 	to by the supplied path name relative to the specified BDirectory.
97 	\param dir the BDirectory, relative to which the directory's path name is
98 		   given
99 	\param path the directory's path name relative to \a dir
100 */
101 BDirectory::BDirectory(const BDirectory *dir, const char *path)
102 	:
103 	fDirFd(-1)
104 {
105 	SetTo(dir, path);
106 }
107 
108 // destructor
109 //! Frees all allocated resources.
110 /*! If the BDirectory is properly initialized, the directory's file descriptor
111 	is closed.
112 */
113 BDirectory::~BDirectory()
114 {
115 	// Also called by the BNode destructor, but we rather try to avoid
116 	// problems with calling virtual functions in the base class destructor.
117 	// Depending on the compiler implementation an object may be degraded to
118 	// an object of the base class after the destructor of the derived class
119 	// has been executed.
120 	close_fd();
121 }
122 
123 // SetTo
124 /*! \brief Re-initializes the BDirectory to the directory referred to by the
125 	supplied entry_ref.
126 	\param ref the entry_ref referring to the directory
127 	\return
128 	- \c B_OK: Everything went fine.
129 	- \c B_BAD_VALUE: \c NULL \a ref.
130 	- \c B_ENTRY_NOT_FOUND: Directory not found.
131 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
132 	- \c B_NO_MEMORY: Insufficient memory for operation.
133 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
134 	- \c B_BUSY: A node was busy.
135 	- \c B_FILE_ERROR: A general file error.
136 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
137 */
138 status_t
139 BDirectory::SetTo(const entry_ref *ref)
140 {
141 	// open node
142 	status_t error = _SetTo(ref, true);
143 	if (error != B_OK)
144 		return error;
145 
146 	// open dir
147 	fDirFd = _kern_open_dir_entry_ref(ref->device, ref->directory, ref->name);
148 	if (fDirFd < 0) {
149 		status_t error = fDirFd;
150 		Unset();
151 		return (fCStatus = error);
152 	}
153 
154 	// set close on exec flag on dir FD
155 	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
156 
157 	return B_OK;
158 }
159 
160 // SetTo
161 /*! \brief Re-initializes the BDirectory to the directory referred to by the
162 	supplied node_ref.
163 	\param nref the node_ref referring to the directory
164 	\return
165 	- \c B_OK: Everything went fine.
166 	- \c B_BAD_VALUE: \c NULL \a nref.
167 	- \c B_ENTRY_NOT_FOUND: Directory not found.
168 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
169 	- \c B_NO_MEMORY: Insufficient memory for operation.
170 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
171 	- \c B_BUSY: A node was busy.
172 	- \c B_FILE_ERROR: A general file error.
173 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
174 */
175 status_t
176 BDirectory::SetTo(const node_ref *nref)
177 {
178 	Unset();
179 	status_t error = (nref ? B_OK : B_BAD_VALUE);
180 	if (error == B_OK) {
181 		entry_ref ref(nref->device, nref->node, ".");
182 		error = SetTo(&ref);
183 	}
184 	set_status(error);
185 	return error;
186 }
187 
188 // SetTo
189 /*! \brief Re-initializes the BDirectory to the directory referred to by the
190 	supplied BEntry.
191 	\param entry the BEntry referring to the directory
192 	\return
193 	- \c B_OK: Everything went fine.
194 	- \c B_BAD_VALUE: \c NULL \a entry.
195 	- \c B_ENTRY_NOT_FOUND: Directory not found.
196 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
197 	- \c B_NO_MEMORY: Insufficient memory for operation.
198 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
199 	- \c B_BUSY: A node was busy.
200 	- \c B_FILE_ERROR: A general file error.
201 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
202 */
203 status_t
204 BDirectory::SetTo(const BEntry *entry)
205 {
206 	if (!entry) {
207 		Unset();
208 		return (fCStatus = B_BAD_VALUE);
209 	}
210 
211 	// open node
212 	status_t error = _SetTo(entry->fDirFd, entry->fName, true);
213 	if (error != B_OK)
214 		return error;
215 
216 	// open dir
217 	fDirFd = _kern_open_dir(entry->fDirFd, entry->fName);
218 	if (fDirFd < 0) {
219 		status_t error = fDirFd;
220 		Unset();
221 		return (fCStatus = error);
222 	}
223 
224 	// set close on exec flag on dir FD
225 	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
226 
227 	return B_OK;
228 }
229 
230 // SetTo
231 /*! \brief Re-initializes the BDirectory to the directory referred to by the
232 	supplied path name.
233 	\param path the directory's path name
234 	\return
235 	- \c B_OK: Everything went fine.
236 	- \c B_BAD_VALUE: \c NULL \a path.
237 	- \c B_ENTRY_NOT_FOUND: Directory not found.
238 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
239 	- \c B_NO_MEMORY: Insufficient memory for operation.
240 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
241 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
242 	- \c B_BUSY: A node was busy.
243 	- \c B_FILE_ERROR: A general file error.
244 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
245 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
246 */
247 status_t
248 BDirectory::SetTo(const char *path)
249 {
250 	// open node
251 	status_t error = _SetTo(-1, path, true);
252 	if (error != B_OK)
253 		return error;
254 
255 	// open dir
256 	fDirFd = _kern_open_dir(-1, path);
257 	if (fDirFd < 0) {
258 		status_t error = fDirFd;
259 		Unset();
260 		return (fCStatus = error);
261 	}
262 
263 	// set close on exec flag on dir FD
264 	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
265 
266 	return B_OK;
267 }
268 
269 // SetTo
270 /*! \brief Re-initializes the BDirectory to the directory referred to by the
271 	supplied path name relative to the specified BDirectory.
272 	\param dir the BDirectory, relative to which the directory's path name is
273 		   given
274 	\param path the directory's path name relative to \a dir
275 	\return
276 	- \c B_OK: Everything went fine.
277 	- \c B_BAD_VALUE: \c NULL \a dir or \a path, or \a path is absolute.
278 	- \c B_ENTRY_NOT_FOUND: Directory not found.
279 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
280 	- \c B_NO_MEMORY: Insufficient memory for operation.
281 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
282 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
283 	- \c B_BUSY: A node was busy.
284 	- \c B_FILE_ERROR: A general file error.
285 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
286 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
287 */
288 status_t
289 BDirectory::SetTo(const BDirectory *dir, const char *path)
290 {
291 	if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) {
292 		Unset();
293 		return (fCStatus = B_BAD_VALUE);
294 	}
295 
296 	int dirFD = dir->fDirFd;
297 	if (dir == this) {
298 		// prevent that our file descriptor goes away in _SetTo()
299 		fDirFd = -1;
300 	}
301 
302 	// open node
303 	status_t error = _SetTo(dirFD, path, true);
304 	if (error != B_OK)
305 		return error;
306 
307 	// open dir
308 	fDirFd = _kern_open_dir(dirFD, path);
309 	if (fDirFd < 0) {
310 		status_t error = fDirFd;
311 		Unset();
312 		return (fCStatus = error);
313 	}
314 
315 	if (dir == this) {
316 		// cleanup after _SetTo()
317 		_kern_close(dirFD);
318 	}
319 
320 	// set close on exec flag on dir FD
321 	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
322 
323 	return B_OK;
324 }
325 
326 // GetEntry
327 //! Returns a BEntry referring to the directory represented by this object.
328 /*!	If the initialization of \a entry fails, it is Unset().
329 	\param entry a pointer to the entry that shall be set to refer to the
330 		   directory
331 	\return
332 	- \c B_OK: Everything went fine.
333 	- \c B_BAD_VALUE: \c NULL \a entry.
334 	- \c B_ENTRY_NOT_FOUND: Directory not found.
335 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
336 	- \c B_NO_MEMORY: Insufficient memory for operation.
337 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
338 	- \c B_BUSY: A node was busy.
339 	- \c B_FILE_ERROR: A general file error.
340 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
341 */
342 status_t
343 BDirectory::GetEntry(BEntry *entry) const
344 {
345 	if (!entry)
346 		return B_BAD_VALUE;
347 	if (InitCheck() != B_OK)
348 		return B_NO_INIT;
349 	return entry->SetTo(this, ".", false);
350 }
351 
352 // IsRootDirectory
353 /*!	\brief Returns whether the directory represented by this BDirectory is a
354 	root directory of a volume.
355 	\return
356 	- \c true, if the BDirectory is properly initialized and represents a
357 	  root directory of some volume,
358 	- \c false, otherwise.
359 */
360 bool
361 BDirectory::IsRootDirectory() const
362 {
363 	// compare the directory's node ID with the ID of the root node of the FS
364 	bool result = false;
365 	node_ref ref;
366 	fs_info info;
367 	if (GetNodeRef(&ref) == B_OK && fs_stat_dev(ref.device, &info) == 0)
368 		result = (ref.node == info.root);
369 	return result;
370 }
371 
372 // FindEntry
373 /*! \brief Finds an entry referred to by a path relative to the directory
374 	represented by this BDirectory.
375 	\a path may be absolute. If the BDirectory is not properly initialized,
376 	the entry is search relative to the current directory.
377 	If the entry couldn't be found, \a entry is Unset().
378 	\param path the entry's path name. May be relative to this directory or
379 		   absolute.
380 	\param entry a pointer to a BEntry to be initialized with the found entry
381 	\param traverse specifies whether to follow it, if the found entry
382 		   is a symbolic link.
383 	\return
384 	- \c B_OK: Everything went fine.
385 	- \c B_BAD_VALUE: \c NULL \a path or \a entry.
386 	- \c B_ENTRY_NOT_FOUND: Entry not found.
387 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
388 	- \c B_NO_MEMORY: Insufficient memory for operation.
389 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
390 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
391 	- \c B_BUSY: A node was busy.
392 	- \c B_FILE_ERROR: A general file error.
393 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
394 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
395 	\note The functionality of this method differs from the one of
396 		  BEntry::SetTo(BDirectory *, const char *, bool) in that the
397 		  latter doesn't require the entry to be existent, whereas this
398 		  function does.
399 */
400 status_t
401 BDirectory::FindEntry(const char *path, BEntry *entry, bool traverse) const
402 {
403 	status_t error = (path && entry ? B_OK : B_BAD_VALUE);
404 	if (entry)
405 		entry->Unset();
406 	if (error == B_OK) {
407 		// init a potentially abstract entry
408 		if (InitCheck() == B_OK)
409 			error = entry->SetTo(this, path, traverse);
410 		else
411 			error = entry->SetTo(path, traverse);
412 		// fail, if entry is abstract
413 		if (error == B_OK && !entry->Exists()) {
414 			error = B_ENTRY_NOT_FOUND;
415 			entry->Unset();
416 		}
417 	}
418 	return error;
419 }
420 
421 // Contains
422 /*!	\brief Returns whether this directory or any of its subdirectories
423 	at any level contain the entry referred to by the supplied path name.
424 	Only entries that match the node flavor specified by \a nodeFlags are
425 	considered.
426 	If the BDirectory is not properly initialized, the method returns \c false.
427 	A non-absolute path is considered relative to the current directory.
428 
429 	\note R5's implementation always returns \c true given an absolute path or
430 	an unitialized directory. This implementation is not compatible with that
431 	behavior. Instead it converts the path into a BEntry and passes it to the
432 	other version of Contains().
433 
434 	\param path the entry's path name. May be relative to this directory or
435 		   absolute.
436 	\param nodeFlags Any of the following:
437 		   - \c B_FILE_NODE: The entry must be a file.
438 		   - \c B_DIRECTORY_NODE: The entry must be a directory.
439 		   - \c B_SYMLINK_NODE: The entry must be a symbolic link.
440 		   - \c B_ANY_NODE: The entry may be of any kind.
441 	\return
442 	- \c true, if the entry exists, its kind does match \nodeFlags and the
443 	  BDirectory is properly initialized and does contain the entry at any
444 	  level,
445 	- \c false, otherwise
446 */
447 bool
448 BDirectory::Contains(const char *path, int32 nodeFlags) const
449 {
450 	// check initialization and parameters
451 	if (InitCheck() != B_OK)
452 		return false;
453 	if (!path)
454 		return true;	// mimic R5 behavior
455 
456 	// turn the path into a BEntry and let the other version do the work
457 	BEntry entry;
458 	if (BPrivate::Storage::is_absolute_path(path))
459 		entry.SetTo(path);
460 	else
461 		entry.SetTo(this, path);
462 
463 	return Contains(&entry, nodeFlags);
464 }
465 
466 // Contains
467 /*!	\brief Returns whether this directory or any of its subdirectories
468 	at any level contain the entry referred to by the supplied BEntry.
469 	Only entries that match the node flavor specified by \a nodeFlags are
470 	considered.
471 	\param entry a BEntry referring to the entry
472 	\param nodeFlags Any of the following:
473 		   - \c B_FILE_NODE: The entry must be a file.
474 		   - \c B_DIRECTORY_NODE: The entry must be a directory.
475 		   - \c B_SYMLINK_NODE: The entry must be a symbolic link.
476 		   - \c B_ANY_NODE: The entry may be of any kind.
477 	\return
478 	- \c true, if the BDirectory is properly initialized and the entry of the
479 	  matching kind could be found,
480 	- \c false, otherwise
481 */
482 bool
483 BDirectory::Contains(const BEntry *entry, int32 nodeFlags) const
484 {
485 	// check, if the entry exists at all
486 	if (entry == NULL || !entry->Exists() || InitCheck() != B_OK)
487 		return false;
488 
489 	if (nodeFlags != B_ANY_NODE) {
490 		// test the node kind
491 		bool result = false;
492 		if ((nodeFlags & B_FILE_NODE) != 0)
493 			result = entry->IsFile();
494 		if (!result && (nodeFlags & B_DIRECTORY_NODE) != 0)
495 			result = entry->IsDirectory();
496 		if (!result && (nodeFlags & B_SYMLINK_NODE) != 0)
497 			result = entry->IsSymLink();
498 		if (!result)
499 			return false;
500 	}
501 
502 	// If the directory is initialized, get the canonical paths of the dir and
503 	// the entry and check, if the latter is a prefix of the first one.
504 	BPath dirPath(this, ".", true);
505 	BPath entryPath(entry);
506 	if (dirPath.InitCheck() == B_OK && entryPath.InitCheck() != B_OK)
507 		return false;
508 
509 	return !strncmp(dirPath.Path(), entryPath.Path(), strlen(dirPath.Path()));
510 }
511 
512 
513 // GetStatFor
514 /*!	\brief Returns the stat structure of the entry referred to by the supplied
515 	path name.
516 	\param path the entry's path name. May be relative to this directory or
517 		   absolute, or \c NULL to get the directories stat info.
518 	\param st a pointer to the stat structure to be filled in by this function
519 	\return
520 	- \c B_OK: Everything went fine.
521 	- \c B_BAD_VALUE: \c NULL \a st.
522 	- \c B_ENTRY_NOT_FOUND: Entry not found.
523 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
524 	- \c B_NO_MEMORY: Insufficient memory for operation.
525 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
526 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
527 	- \c B_BUSY: A node was busy.
528 	- \c B_FILE_ERROR: A general file error.
529 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
530 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
531 */
532 status_t
533 BDirectory::GetStatFor(const char *path, struct stat *st) const
534 {
535 	if (!st)
536 		return B_BAD_VALUE;
537 	if (InitCheck() != B_OK)
538 		return B_NO_INIT;
539 	status_t error = B_OK;
540 	if (path) {
541 		if (strlen(path) == 0)
542 			return B_ENTRY_NOT_FOUND;
543 		error = _kern_read_stat(fDirFd, path, false, st, sizeof(struct stat));
544 	} else
545 		error = GetStat(st);
546 	return error;
547 }
548 
549 // GetNextEntry
550 //! Returns the BDirectory's next entry as a BEntry.
551 /*!	Unlike GetNextDirents() this method ignores the entries "." and "..".
552 	\param entry a pointer to a BEntry to be initialized to the found entry
553 	\param traverse specifies whether to follow it, if the found entry
554 		   is a symbolic link.
555 	\note The iterator used by this method is the same one used by
556 		  GetNextRef(), GetNextDirents(), Rewind() and CountEntries().
557 	\return
558 	- \c B_OK: Everything went fine.
559 	- \c B_BAD_VALUE: \c NULL \a entry.
560 	- \c B_ENTRY_NOT_FOUND: No more entries found.
561 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
562 	- \c B_NO_MEMORY: Insufficient memory for operation.
563 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
564 	- \c B_BUSY: A node was busy.
565 	- \c B_FILE_ERROR: A general file error.
566 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
567 */
568 status_t
569 BDirectory::GetNextEntry(BEntry *entry, bool traverse)
570 {
571 	status_t error = (entry ? B_OK : B_BAD_VALUE);
572 	if (error == B_OK) {
573 		entry_ref ref;
574 		error = GetNextRef(&ref);
575 		if (error == B_OK)
576 			error = entry->SetTo(&ref, traverse);
577 	}
578 	return error;
579 }
580 
581 // GetNextRef
582 //! Returns the BDirectory's next entry as an entry_ref.
583 /*!	Unlike GetNextDirents() this method ignores the entries "." and "..".
584 	\param ref a pointer to an entry_ref to be filled in with the data of the
585 		   found entry
586 	\param traverse specifies whether to follow it, if the found entry
587 		   is a symbolic link.
588 	\note The iterator used be this method is the same one used by
589 		  GetNextEntry(), GetNextDirents(), Rewind() and CountEntries().
590 	\return
591 	- \c B_OK: Everything went fine.
592 	- \c B_BAD_VALUE: \c NULL \a ref.
593 	- \c B_ENTRY_NOT_FOUND: No more entries found.
594 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
595 	- \c B_NO_MEMORY: Insufficient memory for operation.
596 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
597 	- \c B_BUSY: A node was busy.
598 	- \c B_FILE_ERROR: A general file error.
599 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
600 */
601 status_t
602 BDirectory::GetNextRef(entry_ref *ref)
603 {
604 	status_t error = (ref ? B_OK : B_BAD_VALUE);
605 	if (error == B_OK && InitCheck() != B_OK)
606 		error = B_FILE_ERROR;
607 	if (error == B_OK) {
608 		BPrivate::Storage::LongDirEntry entry;
609 		bool next = true;
610 		while (error == B_OK && next) {
611 			if (GetNextDirents(&entry, sizeof(entry), 1) != 1) {
612 				error = B_ENTRY_NOT_FOUND;
613 			} else {
614 				next = (!strcmp(entry.d_name, ".")
615 						|| !strcmp(entry.d_name, ".."));
616 			}
617 		}
618 		if (error == B_OK) {
619 			ref->device = entry.d_pdev;
620 			ref->directory = entry.d_pino;
621 			error = ref->set_name(entry.d_name);
622 		}
623 	}
624 	return error;
625 }
626 
627 // GetNextDirents
628 //! Returns the BDirectory's next entries as dirent structures.
629 /*!	Unlike GetNextEntry() and GetNextRef(), this method returns also
630 	the entries "." and "..".
631 	\param buf a pointer to a buffer to be filled with dirent structures of
632 		   the found entries
633 	\param count the maximal number of entries to be returned.
634 	\note The iterator used by this method is the same one used by
635 		  GetNextEntry(), GetNextRef(), Rewind() and CountEntries().
636 	\return
637 	- The number of dirent structures stored in the buffer, 0 when there are
638 	  no more entries to be returned.
639 	- \c B_BAD_VALUE: \c NULL \a buf.
640 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
641 	- \c B_NO_MEMORY: Insufficient memory for operation.
642 	- \c B_NAME_TOO_LONG: The entry's name is too long for the buffer.
643 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
644 	- \c B_BUSY: A node was busy.
645 	- \c B_FILE_ERROR: A general file error.
646 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
647 */
648 int32
649 BDirectory::GetNextDirents(dirent *buf, size_t bufSize, int32 count)
650 {
651 	if (!buf)
652 		return B_BAD_VALUE;
653 	if (InitCheck() != B_OK)
654 		return B_FILE_ERROR;
655 	return _kern_read_dir(fDirFd, buf, bufSize, count);
656 }
657 
658 // Rewind
659 //!	Rewinds the directory iterator.
660 /*!	\return
661 	- \c B_OK: Everything went fine.
662 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
663 	- \c B_NO_MEMORY: Insufficient memory for operation.
664 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
665 	- \c B_BUSY: A node was busy.
666 	- \c B_FILE_ERROR: A general file error.
667 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
668 	\see GetNextEntry(), GetNextRef(), GetNextDirents(), CountEntries()
669 */
670 status_t
671 BDirectory::Rewind()
672 {
673 	if (InitCheck() != B_OK)
674 		return B_FILE_ERROR;
675 	return _kern_rewind_dir(fDirFd);
676 }
677 
678 // CountEntries
679 //!	Returns the number of entries in this directory.
680 /*!	CountEntries() uses the directory iterator also used by GetNextEntry(),
681 	GetNextRef() and GetNextDirents(). It does a Rewind(), iterates through
682 	the entries and Rewind()s again. The entries "." and ".." are not counted.
683 	\return
684 	- the number of entries in the directory (not counting "." and "..").
685 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
686 	- \c B_NO_MEMORY: Insufficient memory for operation.
687 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
688 	- \c B_BUSY: A node was busy.
689 	- \c B_FILE_ERROR: A general file error.
690 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
691 	\see GetNextEntry(), GetNextRef(), GetNextDirents(), Rewind()
692 */
693 int32
694 BDirectory::CountEntries()
695 {
696 	status_t error = Rewind();
697 	if (error != B_OK)
698 		return error;
699 	int32 count = 0;
700 	BPrivate::Storage::LongDirEntry entry;
701 	while (error == B_OK) {
702 		if (GetNextDirents(&entry, sizeof(entry), 1) != 1)
703 			break;
704 		if (strcmp(entry.d_name, ".") != 0 && strcmp(entry.d_name, "..") != 0)
705 			count++;
706 	}
707 	Rewind();
708 	return (error == B_OK ? count : error);
709 }
710 
711 // CreateDirectory
712 //! Creates a new directory.
713 /*! If an entry with the supplied name does already exist, the method fails.
714 	\param path the new directory's path name. May be relative to this
715 		   directory or absolute.
716 	\param dir a pointer to a BDirectory to be initialized to the newly
717 		   created directory. May be \c NULL.
718 	\return
719 	- \c B_OK: Everything went fine.
720 	- \c B_BAD_VALUE: \c NULL \a path.
721 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
722 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
723 	- \c B_NO_MEMORY: Insufficient memory for operation.
724 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
725 	- \c B_BUSY: A node was busy.
726 	- \c B_FILE_ERROR: A general file error.
727 	- \c B_FILE_EXISTS: An entry with that name does already exist.
728 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
729 */
730 status_t
731 BDirectory::CreateDirectory(const char *path, BDirectory *dir)
732 {
733 	if (!path)
734 		return B_BAD_VALUE;
735 	// create the dir
736 	status_t error = _kern_create_dir(fDirFd, path,
737 		S_IRWXU | S_IRWXG | S_IRWXO);
738 	if (error != B_OK)
739 		return error;
740 	if (!dir)
741 		return B_OK;
742 	// init the supplied BDirectory
743 	if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path))
744 		return dir->SetTo(path);
745 	else
746 		return dir->SetTo(this, path);
747 }
748 
749 // CreateFile
750 //! Creates a new file.
751 /*!	If a file with the supplied name does already exist, the method fails,
752 	unless it is passed \c false to \a failIfExists -- in that case the file
753 	is truncated to zero size. The new BFile will operate in \c B_READ_WRITE
754 	mode.
755 	\param path the new file's path name. May be relative to this
756 		   directory or absolute.
757 	\param file a pointer to a BFile to be initialized to the newly
758 		   created file. May be \c NULL.
759 	\param failIfExists \c true, if the method should fail when the file
760 		   already exists, \c false otherwise
761 	\return
762 	- \c B_OK: Everything went fine.
763 	- \c B_BAD_VALUE: \c NULL \a path.
764 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
765 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
766 	- \c B_NO_MEMORY: Insufficient memory for operation.
767 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
768 	- \c B_BUSY: A node was busy.
769 	- \c B_FILE_ERROR: A general file error.
770 	- \c B_FILE_EXISTS: A file with that name does already exist and
771 	  \c true has been passed for \a failIfExists.
772 	- \c B_IS_A_DIRECTORY: A directory with the supplied name does already
773 	  exist.
774 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
775 */
776 status_t
777 BDirectory::CreateFile(const char *path, BFile *file, bool failIfExists)
778 {
779 	if (!path)
780 		return B_BAD_VALUE;
781 	// Let BFile do the dirty job.
782 	uint32 openMode = B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE
783 		| (failIfExists ? B_FAIL_IF_EXISTS : 0);
784 	BFile tmpFile;
785 	BFile *realFile = (file ? file : &tmpFile);
786 	status_t error = B_OK;
787 	if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path))
788 		error = realFile->SetTo(this, path, openMode);
789 	else
790 		error = realFile->SetTo(path, openMode);
791 	if (error != B_OK && file) // mimic R5 behavior
792 		file->Unset();
793 	return error;
794 }
795 
796 // CreateSymLink
797 //! Creates a new symbolic link.
798 /*! If an entry with the supplied name does already exist, the method fails.
799 	\param path the new symbolic link's path name. May be relative to this
800 		   directory or absolute.
801 	\param linkToPath the path the symbolic link shall point to.
802 	\param dir a pointer to a BSymLink to be initialized to the newly
803 		   created symbolic link. May be \c NULL.
804 	\return
805 	- \c B_OK: Everything went fine.
806 	- \c B_BAD_VALUE: \c NULL \a path or \a linkToPath.
807 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
808 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
809 	- \c B_NO_MEMORY: Insufficient memory for operation.
810 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
811 	- \c B_BUSY: A node was busy.
812 	- \c B_FILE_ERROR: A general file error.
813 	- \c B_FILE_EXISTS: An entry with that name does already exist.
814 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
815 */
816 status_t
817 BDirectory::CreateSymLink(const char *path, const char *linkToPath,
818 						  BSymLink *link)
819 {
820 	if (!path || !linkToPath)
821 		return B_BAD_VALUE;
822 	// create the symlink
823 	status_t error = _kern_create_symlink(fDirFd, path, linkToPath,
824 		S_IRWXU | S_IRWXG | S_IRWXO);
825 	if (error != B_OK)
826 		return error;
827 	if (!link)
828 		return B_OK;
829 	// init the supplied BSymLink
830 	if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path))
831 		return link->SetTo(path);
832 	else
833 		return link->SetTo(this, path);
834 }
835 
836 // =
837 //! Assigns another BDirectory to this BDirectory.
838 /*!	If the other BDirectory is uninitialized, this one wi'll be too. Otherwise
839 	it will refer to the same directory, unless an error occurs.
840 	\param dir the original BDirectory
841 	\return a reference to this BDirectory
842 */
843 BDirectory &
844 BDirectory::operator=(const BDirectory &dir)
845 {
846 	if (&dir != this) {	// no need to assign us to ourselves
847 		Unset();
848 		if (dir.InitCheck() == B_OK)
849 			SetTo(&dir, ".");
850 	}
851 	return *this;
852 }
853 
854 
855 // FBC
856 void BDirectory::_ErectorDirectory1() {}
857 void BDirectory::_ErectorDirectory2() {}
858 void BDirectory::_ErectorDirectory3() {}
859 void BDirectory::_ErectorDirectory4() {}
860 void BDirectory::_ErectorDirectory5() {}
861 void BDirectory::_ErectorDirectory6() {}
862 
863 // close_fd
864 //! Closes the BDirectory's file descriptor.
865 void
866 BDirectory::close_fd()
867 {
868 	if (fDirFd >= 0) {
869 		_kern_close(fDirFd);
870 		fDirFd = -1;
871 	}
872 	BNode::close_fd();
873 }
874 
875 //! Returns the BDirectory's file descriptor.
876 /*!	To be used instead of accessing the BDirectory's private \c fDirFd member
877 	directly.
878 	\return the file descriptor, or -1, if not properly initialized.
879 */
880 int
881 BDirectory::get_fd() const
882 {
883 	return fDirFd;
884 }
885 
886 
887 // C functions
888 
889 // create_directory
890 //! Creates all missing directories along a given path.
891 /*!	\param path the directory path name.
892 	\param mode a permission specification, which shall be used for the
893 		   newly created directories.
894 	\return
895 	- \c B_OK: Everything went fine.
896 	- \c B_BAD_VALUE: \c NULL \a path.
897 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
898 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
899 	- \c B_NO_MEMORY: Insufficient memory for operation.
900 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
901 	- \c B_BUSY: A node was busy.
902 	- \c B_FILE_ERROR: A general file error.
903 	- \c B_NOT_A_DIRECTORY: An entry other than a directory with that name does
904 	  already exist.
905 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
906 	\todo Check for efficency.
907 */
908 status_t
909 create_directory(const char *path, mode_t mode)
910 {
911 	if (!path)
912 		return B_BAD_VALUE;
913 	// That's the strategy: We start with the first component of the supplied
914 	// path, create a BPath object from it and successively add the following
915 	// components. Each time we get a new path, we check, if the entry it
916 	// refers to exists and is a directory. If it doesn't exist, we try
917 	// to create it. This goes on, until we're done with the input path or
918 	// an error occurs.
919 	BPath dirPath;
920 	char *component;
921 	int32 nextComponent;
922 	do {
923 		// get the next path component
924 		status_t error = BPrivate::Storage::parse_first_path_component(path,
925 			component, nextComponent);
926 		if (error != B_OK)
927 			return error;
928 		// append it to the BPath
929 		if (dirPath.InitCheck() == B_NO_INIT)	// first component
930 			error = dirPath.SetTo(component);
931 		else
932 			error = dirPath.Append(component);
933 		delete[] component;
934 		if (error != B_OK)
935 			return error;
936 		path += nextComponent;
937 		// create a BEntry from the BPath
938 		BEntry entry;
939 		error = entry.SetTo(dirPath.Path(), true);
940 		if (error != B_OK)
941 			return error;
942 		// check, if it exists
943 		if (entry.Exists()) {
944 			// yep, it exists
945 			if (!entry.IsDirectory())	// but is no directory
946 				return B_NOT_A_DIRECTORY;
947 		} else {
948 			// it doesn't exist -- create it
949 			error = _kern_create_dir(-1, dirPath.Path(), mode);
950 			if (error != B_OK)
951 				return error;
952 		}
953 	} while (nextComponent != 0);
954 	return B_OK;
955 }
956 
957