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