xref: /haiku/src/kits/storage/Directory.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * Copyright 2002-2007, 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 	bool result = true;
490 
491 	// test the node kind
492 	switch (nodeFlags) {
493 		case B_FILE_NODE:
494 			result = entry->IsFile();
495 			break;
496 		case B_DIRECTORY_NODE:
497 			result = entry->IsDirectory();
498 			break;
499 		case B_SYMLINK_NODE:
500 			result = entry->IsSymLink();
501 			break;
502 		case B_ANY_NODE:
503 			break;
504 
505 		default:
506 			result = false;
507 			break;
508 	}
509 
510 	// If the directory is initialized, get the canonical paths of the dir and
511 	// the entry and check, if the latter is a prefix of the first one.
512 	if (result) {
513 		BPath dirPath(this, ".", true);
514 		BPath entryPath(entry);
515 		if (dirPath.InitCheck() == B_OK && entryPath.InitCheck() == B_OK) {
516 			result = !strncmp(dirPath.Path(), entryPath.Path(),
517 				strlen(dirPath.Path()));
518 		} else
519 			result = false;
520 	}
521 
522 	return result;
523 }
524 
525 // GetStatFor
526 /*!	\brief Returns the stat structure of the entry referred to by the supplied
527 	path name.
528 	\param path the entry's path name. May be relative to this directory or
529 		   absolute, or \c NULL to get the directories stat info.
530 	\param st a pointer to the stat structure to be filled in by this function
531 	\return
532 	- \c B_OK: Everything went fine.
533 	- \c B_BAD_VALUE: \c NULL \a st.
534 	- \c B_ENTRY_NOT_FOUND: Entry not found.
535 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
536 	- \c B_NO_MEMORY: Insufficient memory for operation.
537 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
538 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
539 	- \c B_BUSY: A node was busy.
540 	- \c B_FILE_ERROR: A general file error.
541 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
542 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
543 */
544 status_t
545 BDirectory::GetStatFor(const char *path, struct stat *st) const
546 {
547 	if (!st)
548 		return B_BAD_VALUE;
549 	if (InitCheck() != B_OK)
550 		return B_NO_INIT;
551 	status_t error = B_OK;
552 	if (path) {
553 		if (strlen(path) == 0)
554 			return B_ENTRY_NOT_FOUND;
555 		error = _kern_read_stat(fDirFd, path, false, st, sizeof(struct stat));
556 	} else
557 		error = GetStat(st);
558 	return error;
559 }
560 
561 // GetNextEntry
562 //! Returns the BDirectory's next entry as a BEntry.
563 /*!	Unlike GetNextDirents() this method ignores the entries "." and "..".
564 	\param entry a pointer to a BEntry to be initialized to the found entry
565 	\param traverse specifies whether to follow it, if the found entry
566 		   is a symbolic link.
567 	\note The iterator used by this method is the same one used by
568 		  GetNextRef(), GetNextDirents(), Rewind() and CountEntries().
569 	\return
570 	- \c B_OK: Everything went fine.
571 	- \c B_BAD_VALUE: \c NULL \a entry.
572 	- \c B_ENTRY_NOT_FOUND: No more entries found.
573 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
574 	- \c B_NO_MEMORY: Insufficient memory for operation.
575 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
576 	- \c B_BUSY: A node was busy.
577 	- \c B_FILE_ERROR: A general file error.
578 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
579 */
580 status_t
581 BDirectory::GetNextEntry(BEntry *entry, bool traverse)
582 {
583 	status_t error = (entry ? B_OK : B_BAD_VALUE);
584 	if (error == B_OK) {
585 		entry_ref ref;
586 		error = GetNextRef(&ref);
587 		if (error == B_OK)
588 			error = entry->SetTo(&ref, traverse);
589 	}
590 	return error;
591 }
592 
593 // GetNextRef
594 //! Returns the BDirectory's next entry as an entry_ref.
595 /*!	Unlike GetNextDirents() this method ignores the entries "." and "..".
596 	\param ref a pointer to an entry_ref to be filled in with the data of the
597 		   found entry
598 	\param traverse specifies whether to follow it, if the found entry
599 		   is a symbolic link.
600 	\note The iterator used be this method is the same one used by
601 		  GetNextEntry(), GetNextDirents(), Rewind() and CountEntries().
602 	\return
603 	- \c B_OK: Everything went fine.
604 	- \c B_BAD_VALUE: \c NULL \a ref.
605 	- \c B_ENTRY_NOT_FOUND: No more entries found.
606 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
607 	- \c B_NO_MEMORY: Insufficient memory for operation.
608 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
609 	- \c B_BUSY: A node was busy.
610 	- \c B_FILE_ERROR: A general file error.
611 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
612 */
613 status_t
614 BDirectory::GetNextRef(entry_ref *ref)
615 {
616 	status_t error = (ref ? B_OK : B_BAD_VALUE);
617 	if (error == B_OK && InitCheck() != B_OK)
618 		error = B_FILE_ERROR;
619 	if (error == B_OK) {
620 		BPrivate::Storage::LongDirEntry entry;
621 		bool next = true;
622 		while (error == B_OK && next) {
623 			if (GetNextDirents(&entry, sizeof(entry), 1) != 1) {
624 				error = B_ENTRY_NOT_FOUND;
625 			} else {
626 				next = (!strcmp(entry.d_name, ".")
627 						|| !strcmp(entry.d_name, ".."));
628 			}
629 		}
630 		if (error == B_OK) {
631 			ref->device = entry.d_pdev;
632 			ref->directory = entry.d_pino;
633 			error = ref->set_name(entry.d_name);
634 		}
635 	}
636 	return error;
637 }
638 
639 // GetNextDirents
640 //! Returns the BDirectory's next entries as dirent structures.
641 /*!	Unlike GetNextEntry() and GetNextRef(), this method returns also
642 	the entries "." and "..".
643 	\param buf a pointer to a buffer to be filled with dirent structures of
644 		   the found entries
645 	\param count the maximal number of entries to be returned.
646 	\note The iterator used by this method is the same one used by
647 		  GetNextEntry(), GetNextRef(), Rewind() and CountEntries().
648 	\return
649 	- The number of dirent structures stored in the buffer, 0 when there are
650 	  no more entries to be returned.
651 	- \c B_BAD_VALUE: \c NULL \a buf.
652 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
653 	- \c B_NO_MEMORY: Insufficient memory for operation.
654 	- \c B_NAME_TOO_LONG: The entry's name is too long for the buffer.
655 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
656 	- \c B_BUSY: A node was busy.
657 	- \c B_FILE_ERROR: A general file error.
658 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
659 */
660 int32
661 BDirectory::GetNextDirents(dirent *buf, size_t bufSize, int32 count)
662 {
663 	if (!buf)
664 		return B_BAD_VALUE;
665 	if (InitCheck() != B_OK)
666 		return B_FILE_ERROR;
667 	return _kern_read_dir(fDirFd, buf, bufSize, count);
668 }
669 
670 // Rewind
671 //!	Rewinds the directory iterator.
672 /*!	\return
673 	- \c B_OK: Everything went fine.
674 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
675 	- \c B_NO_MEMORY: Insufficient memory for operation.
676 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
677 	- \c B_BUSY: A node was busy.
678 	- \c B_FILE_ERROR: A general file error.
679 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
680 	\see GetNextEntry(), GetNextRef(), GetNextDirents(), CountEntries()
681 */
682 status_t
683 BDirectory::Rewind()
684 {
685 	if (InitCheck() != B_OK)
686 		return B_FILE_ERROR;
687 	return _kern_rewind_dir(fDirFd);
688 }
689 
690 // CountEntries
691 //!	Returns the number of entries in this directory.
692 /*!	CountEntries() uses the directory iterator also used by GetNextEntry(),
693 	GetNextRef() and GetNextDirents(). It does a Rewind(), iterates through
694 	the entries and Rewind()s again. The entries "." and ".." are not counted.
695 	\return
696 	- the number of entries in the directory (not counting "." and "..").
697 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
698 	- \c B_NO_MEMORY: Insufficient memory for operation.
699 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
700 	- \c B_BUSY: A node was busy.
701 	- \c B_FILE_ERROR: A general file error.
702 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
703 	\see GetNextEntry(), GetNextRef(), GetNextDirents(), Rewind()
704 */
705 int32
706 BDirectory::CountEntries()
707 {
708 	status_t error = Rewind();
709 	if (error != B_OK)
710 		return error;
711 	int32 count = 0;
712 	BPrivate::Storage::LongDirEntry entry;
713 	while (error == B_OK) {
714 		if (GetNextDirents(&entry, sizeof(entry), 1) != 1)
715 			break;
716 		if (strcmp(entry.d_name, ".") != 0 && strcmp(entry.d_name, "..") != 0)
717 			count++;
718 	}
719 	Rewind();
720 	return (error == B_OK ? count : error);
721 }
722 
723 // CreateDirectory
724 //! Creates a new directory.
725 /*! If an entry with the supplied name does already exist, the method fails.
726 	\param path the new directory's path name. May be relative to this
727 		   directory or absolute.
728 	\param dir a pointer to a BDirectory to be initialized to the newly
729 		   created directory. May be \c NULL.
730 	\return
731 	- \c B_OK: Everything went fine.
732 	- \c B_BAD_VALUE: \c NULL \a path.
733 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
734 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
735 	- \c B_NO_MEMORY: Insufficient memory for operation.
736 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
737 	- \c B_BUSY: A node was busy.
738 	- \c B_FILE_ERROR: A general file error.
739 	- \c B_FILE_EXISTS: An entry with that name does already exist.
740 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
741 */
742 status_t
743 BDirectory::CreateDirectory(const char *path, BDirectory *dir)
744 {
745 	if (!path)
746 		return B_BAD_VALUE;
747 	// create the dir
748 	status_t error = _kern_create_dir(fDirFd, path,
749 		S_IRWXU | S_IRWXG | S_IRWXU);
750 	if (error != B_OK)
751 		return error;
752 	if (!dir)
753 		return B_OK;
754 	// init the supplied BDirectory
755 	if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path))
756 		return dir->SetTo(path);
757 	else
758 		return dir->SetTo(this, path);
759 }
760 
761 // CreateFile
762 //! Creates a new file.
763 /*!	If a file with the supplied name does already exist, the method fails,
764 	unless it is passed \c false to \a failIfExists -- in that case the file
765 	is truncated to zero size. The new BFile will operate in \c B_READ_WRITE
766 	mode.
767 	\param path the new file's path name. May be relative to this
768 		   directory or absolute.
769 	\param file a pointer to a BFile to be initialized to the newly
770 		   created file. May be \c NULL.
771 	\param failIfExists \c true, if the method should fail when the file
772 		   already exists, \c false otherwise
773 	\return
774 	- \c B_OK: Everything went fine.
775 	- \c B_BAD_VALUE: \c NULL \a path.
776 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
777 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
778 	- \c B_NO_MEMORY: Insufficient memory for operation.
779 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
780 	- \c B_BUSY: A node was busy.
781 	- \c B_FILE_ERROR: A general file error.
782 	- \c B_FILE_EXISTS: A file with that name does already exist and
783 	  \c true has been passed for \a failIfExists.
784 	- \c B_IS_A_DIRECTORY: A directory with the supplied name does already
785 	  exist.
786 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
787 */
788 status_t
789 BDirectory::CreateFile(const char *path, BFile *file, bool failIfExists)
790 {
791 	if (!path)
792 		return B_BAD_VALUE;
793 	// Let BFile do the dirty job.
794 	uint32 openMode = B_READ_WRITE | B_CREATE_FILE
795 					  | (failIfExists ? B_FAIL_IF_EXISTS : 0);
796 	BFile tmpFile;
797 	BFile *realFile = (file ? file : &tmpFile);
798 	status_t error = B_OK;
799 	if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path))
800 		error = realFile->SetTo(this, path, openMode);
801 	else
802 		error = realFile->SetTo(path, openMode);
803 	if (error != B_OK && file) // mimic R5 behavior
804 		file->Unset();
805 	return error;
806 }
807 
808 // CreateSymLink
809 //! Creates a new symbolic link.
810 /*! If an entry with the supplied name does already exist, the method fails.
811 	\param path the new symbolic link's path name. May be relative to this
812 		   directory or absolute.
813 	\param linkToPath the path the symbolic link shall point to.
814 	\param dir a pointer to a BSymLink to be initialized to the newly
815 		   created symbolic link. May be \c NULL.
816 	\return
817 	- \c B_OK: Everything went fine.
818 	- \c B_BAD_VALUE: \c NULL \a path or \a linkToPath.
819 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
820 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
821 	- \c B_NO_MEMORY: Insufficient memory for operation.
822 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
823 	- \c B_BUSY: A node was busy.
824 	- \c B_FILE_ERROR: A general file error.
825 	- \c B_FILE_EXISTS: An entry with that name does already exist.
826 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
827 */
828 status_t
829 BDirectory::CreateSymLink(const char *path, const char *linkToPath,
830 						  BSymLink *link)
831 {
832 	if (!path || !linkToPath)
833 		return B_BAD_VALUE;
834 	// create the symlink
835 	status_t error = _kern_create_symlink(fDirFd, path, linkToPath,
836 		S_IRWXU | S_IRWXG | S_IRWXU);
837 	if (error != B_OK)
838 		return error;
839 	if (!link)
840 		return B_OK;
841 	// init the supplied BSymLink
842 	if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path))
843 		return link->SetTo(path);
844 	else
845 		return link->SetTo(this, path);
846 }
847 
848 // =
849 //! Assigns another BDirectory to this BDirectory.
850 /*!	If the other BDirectory is uninitialized, this one wi'll be too. Otherwise
851 	it will refer to the same directory, unless an error occurs.
852 	\param dir the original BDirectory
853 	\return a reference to this BDirectory
854 */
855 BDirectory &
856 BDirectory::operator=(const BDirectory &dir)
857 {
858 	if (&dir != this) {	// no need to assign us to ourselves
859 		Unset();
860 		if (dir.InitCheck() == B_OK)
861 			SetTo(&dir, ".");
862 	}
863 	return *this;
864 }
865 
866 
867 // FBC
868 void BDirectory::_ErectorDirectory1() {}
869 void BDirectory::_ErectorDirectory2() {}
870 void BDirectory::_ErectorDirectory3() {}
871 void BDirectory::_ErectorDirectory4() {}
872 void BDirectory::_ErectorDirectory5() {}
873 void BDirectory::_ErectorDirectory6() {}
874 
875 // close_fd
876 //! Closes the BDirectory's file descriptor.
877 void
878 BDirectory::close_fd()
879 {
880 	if (fDirFd >= 0) {
881 		_kern_close(fDirFd);
882 		fDirFd = -1;
883 	}
884 	BNode::close_fd();
885 }
886 
887 //! Returns the BDirectory's file descriptor.
888 /*!	To be used instead of accessing the BDirectory's private \c fDirFd member
889 	directly.
890 	\return the file descriptor, or -1, if not properly initialized.
891 */
892 int
893 BDirectory::get_fd() const
894 {
895 	return fDirFd;
896 }
897 
898 
899 // C functions
900 
901 // create_directory
902 //! Creates all missing directories along a given path.
903 /*!	\param path the directory path name.
904 	\param mode a permission specification, which shall be used for the
905 		   newly created directories.
906 	\return
907 	- \c B_OK: Everything went fine.
908 	- \c B_BAD_VALUE: \c NULL \a path.
909 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
910 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
911 	- \c B_NO_MEMORY: Insufficient memory for operation.
912 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
913 	- \c B_BUSY: A node was busy.
914 	- \c B_FILE_ERROR: A general file error.
915 	- \c B_NOT_A_DIRECTORY: An entry other than a directory with that name does
916 	  already exist.
917 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
918 	\todo Check for efficency.
919 */
920 status_t
921 create_directory(const char *path, mode_t mode)
922 {
923 	if (!path)
924 		return B_BAD_VALUE;
925 	// That's the strategy: We start with the first component of the supplied
926 	// path, create a BPath object from it and successively add the following
927 	// components. Each time we get a new path, we check, if the entry it
928 	// refers to exists and is a directory. If it doesn't exist, we try
929 	// to create it. This goes on, until we're done with the input path or
930 	// an error occurs.
931 	BPath dirPath;
932 	char *component;
933 	int32 nextComponent;
934 	do {
935 		// get the next path component
936 		status_t error = BPrivate::Storage::parse_first_path_component(path,
937 			component, nextComponent);
938 		if (error != B_OK)
939 			return error;
940 		// append it to the BPath
941 		if (dirPath.InitCheck() == B_NO_INIT)	// first component
942 			error = dirPath.SetTo(component);
943 		else
944 			error = dirPath.Append(component);
945 		delete[] component;
946 		if (error != B_OK)
947 			return error;
948 		path += nextComponent;
949 		// create a BEntry from the BPath
950 		BEntry entry;
951 		error = entry.SetTo(dirPath.Path(), true);
952 		if (error != B_OK)
953 			return error;
954 		// check, if it exists
955 		if (entry.Exists()) {
956 			// yep, it exists
957 			if (!entry.IsDirectory())	// but is no directory
958 				return B_NOT_A_DIRECTORY;
959 		} else {
960 			// it doesn't exist -- create it
961 			error = _kern_create_dir(-1, dirPath.Path(), mode);
962 			if (error != B_OK)
963 				return error;
964 		}
965 	} while (nextComponent != 0);
966 	return B_OK;
967 }
968 
969