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