xref: /haiku/src/kits/storage/Directory.cpp (revision 0d452c8f34013b611a54c746a71c05e28796eae2)
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 #include <umask.h>
28 
29 
30 //! Creates an uninitialized BDirectory object.
31 BDirectory::BDirectory()
32 	:
33 	fDirFd(-1)
34 {
35 }
36 
37 
38 /*!	\brief Creates a copy of the supplied BDirectory.
39 	\param dir the BDirectory object to be copied
40 */
41 BDirectory::BDirectory(const BDirectory& dir)
42 	:
43 	fDirFd(-1)
44 {
45 	*this = dir;
46 }
47 
48 
49 /*! \brief Creates a BDirectory and initializes it to the directory referred
50 	to by the supplied entry_ref.
51 	\param ref the entry_ref referring to the directory
52 */
53 BDirectory::BDirectory(const entry_ref* ref)
54 	:
55 	fDirFd(-1)
56 {
57 	SetTo(ref);
58 }
59 
60 
61 /*! \brief Creates a BDirectory and initializes it to the directory referred
62 	to by the supplied node_ref.
63 	\param nref the node_ref referring to the directory
64 */
65 BDirectory::BDirectory(const node_ref* nref)
66 	:
67 	fDirFd(-1)
68 {
69 	SetTo(nref);
70 }
71 
72 
73 /*! \brief Creates a BDirectory and initializes it to the directory referred
74 	to by the supplied BEntry.
75 	\param entry the BEntry referring to the directory
76 */
77 BDirectory::BDirectory(const BEntry* entry)
78 	:
79 	fDirFd(-1)
80 {
81 	SetTo(entry);
82 }
83 
84 
85 /*! \brief Creates a BDirectory and initializes it to the directory referred
86 	to by the supplied path name.
87 	\param path the directory's path name
88 */
89 BDirectory::BDirectory(const char* path)
90 	:
91 	fDirFd(-1)
92 {
93 	SetTo(path);
94 }
95 
96 
97 /*! \brief Creates a BDirectory and initializes it to the directory referred
98 	to by the supplied path name relative to the specified BDirectory.
99 	\param dir the BDirectory, relative to which the directory's path name is
100 		   given
101 	\param path the directory's path name relative to \a dir
102 */
103 BDirectory::BDirectory(const BDirectory* dir, const char* path)
104 	:
105 	fDirFd(-1)
106 {
107 	SetTo(dir, path);
108 }
109 
110 
111 /*! If the BDirectory is properly initialized, the directory's file descriptor
112 	is closed.
113 */
114 BDirectory::~BDirectory()
115 {
116 	// Also called by the BNode destructor, but we rather try to avoid
117 	// problems with calling virtual functions in the base class destructor.
118 	// Depending on the compiler implementation an object may be degraded to
119 	// an object of the base class after the destructor of the derived class
120 	// has been executed.
121 	close_fd();
122 }
123 
124 
125 /*! \brief Re-initializes the BDirectory to the directory referred to by the
126 	supplied entry_ref.
127 	\param ref the entry_ref referring to the directory
128 	\return
129 	- \c B_OK: Everything went fine.
130 	- \c B_BAD_VALUE: \c NULL \a ref.
131 	- \c B_ENTRY_NOT_FOUND: Directory not found.
132 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
133 	- \c B_NO_MEMORY: Insufficient memory for operation.
134 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
135 	- \c B_BUSY: A node was busy.
136 	- \c B_FILE_ERROR: A general file error.
137 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
138 */
139 status_t
140 BDirectory::SetTo(const entry_ref* ref)
141 {
142 	// open node
143 	status_t error = _SetTo(ref, true);
144 	if (error != B_OK)
145 		return error;
146 
147 	// open dir
148 	fDirFd = _kern_open_dir_entry_ref(ref->device, ref->directory, ref->name);
149 	if (fDirFd < 0) {
150 		status_t error = fDirFd;
151 		Unset();
152 		return (fCStatus = error);
153 	}
154 
155 	// set close on exec flag on dir FD
156 	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
157 
158 	return B_OK;
159 }
160 
161 
162 /*! \brief Re-initializes the BDirectory to the directory referred to by the
163 	supplied node_ref.
164 	\param nref the node_ref referring to the directory
165 	\return
166 	- \c B_OK: Everything went fine.
167 	- \c B_BAD_VALUE: \c NULL \a nref.
168 	- \c B_ENTRY_NOT_FOUND: Directory not found.
169 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
170 	- \c B_NO_MEMORY: Insufficient memory for operation.
171 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
172 	- \c B_BUSY: A node was busy.
173 	- \c B_FILE_ERROR: A general file error.
174 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
175 */
176 status_t
177 BDirectory::SetTo(const node_ref* nref)
178 {
179 	Unset();
180 	status_t error = (nref ? B_OK : B_BAD_VALUE);
181 	if (error == B_OK) {
182 		entry_ref ref(nref->device, nref->node, ".");
183 		error = SetTo(&ref);
184 	}
185 	set_status(error);
186 	return error;
187 }
188 
189 
190 /*! \brief Re-initializes the BDirectory to the directory referred to by the
191 	supplied BEntry.
192 	\param entry the BEntry referring to the directory
193 	\return
194 	- \c B_OK: Everything went fine.
195 	- \c B_BAD_VALUE: \c NULL \a entry.
196 	- \c B_ENTRY_NOT_FOUND: Directory not found.
197 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
198 	- \c B_NO_MEMORY: Insufficient memory for operation.
199 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
200 	- \c B_BUSY: A node was busy.
201 	- \c B_FILE_ERROR: A general file error.
202 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
203 */
204 status_t
205 BDirectory::SetTo(const BEntry* entry)
206 {
207 	if (!entry) {
208 		Unset();
209 		return (fCStatus = B_BAD_VALUE);
210 	}
211 
212 	// open node
213 	status_t error = _SetTo(entry->fDirFd, entry->fName, true);
214 	if (error != B_OK)
215 		return error;
216 
217 	// open dir
218 	fDirFd = _kern_open_dir(entry->fDirFd, entry->fName);
219 	if (fDirFd < 0) {
220 		status_t error = fDirFd;
221 		Unset();
222 		return (fCStatus = error);
223 	}
224 
225 	// set close on exec flag on dir FD
226 	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
227 
228 	return B_OK;
229 }
230 
231 
232 /*! \brief Re-initializes the BDirectory to the directory referred to by the
233 	supplied path name.
234 	\param path the directory's path name
235 	\return
236 	- \c B_OK: Everything went fine.
237 	- \c B_BAD_VALUE: \c NULL \a path.
238 	- \c B_ENTRY_NOT_FOUND: Directory not found.
239 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
240 	- \c B_NO_MEMORY: Insufficient memory for operation.
241 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
242 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
243 	- \c B_BUSY: A node was busy.
244 	- \c B_FILE_ERROR: A general file error.
245 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
246 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
247 */
248 status_t
249 BDirectory::SetTo(const char* path)
250 {
251 	// open node
252 	status_t error = _SetTo(-1, path, true);
253 	if (error != B_OK)
254 		return error;
255 
256 	// open dir
257 	fDirFd = _kern_open_dir(-1, path);
258 	if (fDirFd < 0) {
259 		status_t error = fDirFd;
260 		Unset();
261 		return (fCStatus = error);
262 	}
263 
264 	// set close on exec flag on dir FD
265 	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
266 
267 	return B_OK;
268 }
269 
270 
271 /*! \brief Re-initializes the BDirectory to the directory referred to by the
272 	supplied path name relative to the specified BDirectory.
273 	\param dir the BDirectory, relative to which the directory's path name is
274 		   given
275 	\param path the directory's path name relative to \a dir
276 	\return
277 	- \c B_OK: Everything went fine.
278 	- \c B_BAD_VALUE: \c NULL \a dir or \a path, or \a path is absolute.
279 	- \c B_ENTRY_NOT_FOUND: Directory not found.
280 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
281 	- \c B_NO_MEMORY: Insufficient memory for operation.
282 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
283 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
284 	- \c B_BUSY: A node was busy.
285 	- \c B_FILE_ERROR: A general file error.
286 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
287 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
288 */
289 status_t
290 BDirectory::SetTo(const BDirectory* dir, const char* path)
291 {
292 	if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) {
293 		Unset();
294 		return (fCStatus = B_BAD_VALUE);
295 	}
296 
297 	int dirFD = dir->fDirFd;
298 	if (dir == this) {
299 		// prevent that our file descriptor goes away in _SetTo()
300 		fDirFd = -1;
301 	}
302 
303 	// open node
304 	status_t error = _SetTo(dirFD, path, true);
305 	if (error != B_OK)
306 		return error;
307 
308 	// open dir
309 	fDirFd = _kern_open_dir(dirFD, path);
310 	if (fDirFd < 0) {
311 		status_t error = fDirFd;
312 		Unset();
313 		return (fCStatus = error);
314 	}
315 
316 	if (dir == this) {
317 		// cleanup after _SetTo()
318 		_kern_close(dirFD);
319 	}
320 
321 	// set close on exec flag on dir FD
322 	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
323 
324 	return B_OK;
325 }
326 
327 
328 /*!	\brief Returns a BEntry referring to the directory represented by this object.
329 	If the initialization of \a entry fails, it is Unset().
330 	\param entry a pointer to the entry that shall be set to refer to the
331 		   directory
332 	\return
333 	- \c B_OK: Everything went fine.
334 	- \c B_BAD_VALUE: \c NULL \a entry.
335 	- \c B_ENTRY_NOT_FOUND: Directory not found.
336 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
337 	- \c B_NO_MEMORY: Insufficient memory for operation.
338 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
339 	- \c B_BUSY: A node was busy.
340 	- \c B_FILE_ERROR: A general file error.
341 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
342 */
343 status_t
344 BDirectory::GetEntry(BEntry* entry) const
345 {
346 	if (!entry)
347 		return B_BAD_VALUE;
348 	if (InitCheck() != B_OK)
349 		return B_NO_INIT;
350 	return entry->SetTo(this, ".", false);
351 }
352 
353 
354 /*!	\brief Returns whether the directory represented by this BDirectory is a
355 	root directory of a volume.
356 	\return
357 	- \c true, if the BDirectory is properly initialized and represents a
358 	  root directory of some volume,
359 	- \c false, otherwise.
360 */
361 bool
362 BDirectory::IsRootDirectory() const
363 {
364 	// compare the directory's node ID with the ID of the root node of the FS
365 	bool result = false;
366 	node_ref ref;
367 	fs_info info;
368 	if (GetNodeRef(&ref) == B_OK && fs_stat_dev(ref.device, &info) == 0)
369 		result = (ref.node == info.root);
370 	return result;
371 }
372 
373 
374 /*! \brief Finds an entry referred to by a path relative to the directory
375 	represented by this BDirectory.
376 	\a path may be absolute. If the BDirectory is not properly initialized,
377 	the entry is search relative to the current directory.
378 	If the entry couldn't be found, \a entry is Unset().
379 	\param path the entry's path name. May be relative to this directory or
380 		   absolute.
381 	\param entry a pointer to a BEntry to be initialized with the found entry
382 	\param traverse specifies whether to follow it, if the found entry
383 		   is a symbolic link.
384 	\return
385 	- \c B_OK: Everything went fine.
386 	- \c B_BAD_VALUE: \c NULL \a path or \a entry.
387 	- \c B_ENTRY_NOT_FOUND: Entry not found.
388 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
389 	- \c B_NO_MEMORY: Insufficient memory for operation.
390 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
391 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
392 	- \c B_BUSY: A node was busy.
393 	- \c B_FILE_ERROR: A general file error.
394 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
395 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
396 	\note The functionality of this method differs from the one of
397 		  BEntry::SetTo(BDirectory *, const char *, bool) in that the
398 		  latter doesn't require the entry to be existent, whereas this
399 		  function does.
400 */
401 status_t
402 BDirectory::FindEntry(const char* path, BEntry* entry, bool traverse) const
403 {
404 	if (path == NULL || entry == NULL)
405 		return B_BAD_VALUE;
406 
407 	entry->Unset();
408 
409 	// init a potentially abstract entry
410 	status_t status;
411 	if (InitCheck() == B_OK)
412 		status = entry->SetTo(this, path, traverse);
413 	else
414 		status = entry->SetTo(path, traverse);
415 
416 	// fail, if entry is abstract
417 	if (status == B_OK && !entry->Exists()) {
418 		status = B_ENTRY_NOT_FOUND;
419 		entry->Unset();
420 	}
421 
422 	return status;
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 
782 	// Let BFile do the dirty job.
783 	uint32 openMode = B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE
784 		| (failIfExists ? B_FAIL_IF_EXISTS : 0);
785 	BFile tmpFile;
786 	BFile* realFile = file ? file : &tmpFile;
787 	status_t error = B_OK;
788 	if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path))
789 		error = realFile->SetTo(this, path, openMode);
790 	else
791 		error = realFile->SetTo(path, openMode);
792 	if (error != B_OK && file) // mimic R5 behavior
793 		file->Unset();
794 	return error;
795 }
796 
797 
798 /*! \brief Creates a new symbolic link.
799 	If an entry with the supplied name does already exist, the method fails.
800 	\param path the new symbolic link's path name. May be relative to this
801 		   directory or absolute.
802 	\param linkToPath the path the symbolic link shall point to.
803 	\param dir a pointer to a BSymLink to be initialized to the newly
804 		   created symbolic link. May be \c NULL.
805 	\return
806 	- \c B_OK: Everything went fine.
807 	- \c B_BAD_VALUE: \c NULL \a path or \a linkToPath.
808 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
809 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
810 	- \c B_NO_MEMORY: Insufficient memory for operation.
811 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
812 	- \c B_BUSY: A node was busy.
813 	- \c B_FILE_ERROR: A general file error.
814 	- \c B_FILE_EXISTS: An entry with that name does already exist.
815 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
816 */
817 status_t
818 BDirectory::CreateSymLink(const char* path, const char* linkToPath,
819 	BSymLink* link)
820 {
821 	if (!path || !linkToPath)
822 		return B_BAD_VALUE;
823 
824 	// create the symlink
825 	status_t error = _kern_create_symlink(fDirFd, path, linkToPath,
826 		(S_IRWXU | S_IRWXG | S_IRWXO) & ~__gUmask);
827 	if (error != B_OK)
828 		return error;
829 
830 	if (link == NULL)
831 		return B_OK;
832 
833 	// init the supplied BSymLink
834 	if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path))
835 		return link->SetTo(path);
836 
837 	return link->SetTo(this, path);
838 }
839 
840 
841 /*!	\brief 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 status_t
860 BDirectory::_GetStatFor(const char* path, struct stat* st) const
861 {
862 	if (!st)
863 		return B_BAD_VALUE;
864 	if (InitCheck() != B_OK)
865 		return B_NO_INIT;
866 
867 	if (path != NULL) {
868 		if (path[0] == '\0')
869 			return B_ENTRY_NOT_FOUND;
870 		return _kern_read_stat(fDirFd, path, false, st, sizeof(struct stat));
871 	}
872 	return GetStat(st);
873 }
874 
875 
876 status_t
877 BDirectory::_GetStatFor(const char* path, struct stat_beos* st) const
878 {
879 	struct stat newStat;
880 	status_t error = _GetStatFor(path, &newStat);
881 	if (error != B_OK)
882 		return error;
883 
884 	convert_to_stat_beos(&newStat, st);
885 	return B_OK;
886 }
887 
888 
889 // FBC
890 void BDirectory::_ErectorDirectory1() {}
891 void BDirectory::_ErectorDirectory2() {}
892 void BDirectory::_ErectorDirectory3() {}
893 void BDirectory::_ErectorDirectory4() {}
894 void BDirectory::_ErectorDirectory5() {}
895 void BDirectory::_ErectorDirectory6() {}
896 
897 
898 //! Closes the BDirectory's file descriptor.
899 void
900 BDirectory::close_fd()
901 {
902 	if (fDirFd >= 0) {
903 		_kern_close(fDirFd);
904 		fDirFd = -1;
905 	}
906 	BNode::close_fd();
907 }
908 
909 
910 /*!	\brief Returns the BDirectory's file descriptor.
911 	To be used instead of accessing the BDirectory's private \c fDirFd member
912 	directly.
913 	\return the file descriptor, or -1, if not properly initialized.
914 */
915 int
916 BDirectory::get_fd() const
917 {
918 	return fDirFd;
919 }
920 
921 
922 //	#pragma mark - C functions
923 
924 
925 /*!	\brief Creates all missing directories along a given path.
926 	\param path the directory path name.
927 	\param mode a permission specification, which shall be used for the
928 		   newly created directories.
929 	\return
930 	- \c B_OK: Everything went fine.
931 	- \c B_BAD_VALUE: \c NULL \a path.
932 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
933 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
934 	- \c B_NO_MEMORY: Insufficient memory for operation.
935 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
936 	- \c B_BUSY: A node was busy.
937 	- \c B_FILE_ERROR: A general file error.
938 	- \c B_NOT_A_DIRECTORY: An entry other than a directory with that name does
939 	  already exist.
940 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
941 	\todo Check for efficency.
942 */
943 status_t
944 create_directory(const char* path, mode_t mode)
945 {
946 	if (!path)
947 		return B_BAD_VALUE;
948 
949 	// That's the strategy: We start with the first component of the supplied
950 	// path, create a BPath object from it and successively add the following
951 	// components. Each time we get a new path, we check, if the entry it
952 	// refers to exists and is a directory. If it doesn't exist, we try
953 	// to create it. This goes on, until we're done with the input path or
954 	// an error occurs.
955 	BPath dirPath;
956 	char* component;
957 	int32 nextComponent;
958 	do {
959 		// get the next path component
960 		status_t error = BPrivate::Storage::parse_first_path_component(path,
961 			component, nextComponent);
962 		if (error != B_OK)
963 			return error;
964 
965 		// append it to the BPath
966 		if (dirPath.InitCheck() == B_NO_INIT)	// first component
967 			error = dirPath.SetTo(component);
968 		else
969 			error = dirPath.Append(component);
970 		delete[] component;
971 		if (error != B_OK)
972 			return error;
973 		path += nextComponent;
974 
975 		// create a BEntry from the BPath
976 		BEntry entry;
977 		error = entry.SetTo(dirPath.Path(), true);
978 		if (error != B_OK)
979 			return error;
980 
981 		// check, if it exists
982 		if (entry.Exists()) {
983 			// yep, it exists
984 			if (!entry.IsDirectory())	// but is no directory
985 				return B_NOT_A_DIRECTORY;
986 		} else {
987 			// it doesn't exist -- create it
988 			error = _kern_create_dir(-1, dirPath.Path(), mode & ~__gUmask);
989 			if (error != B_OK)
990 				return error;
991 		}
992 	} while (nextComponent != 0);
993 	return B_OK;
994 }
995 
996 
997 // #pragma mark - symbol versions
998 
999 
1000 #ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST
1001 #	if __GNUC__ == 2	// gcc 2
1002 
1003 	B_DEFINE_SYMBOL_VERSION("_GetStatFor__C10BDirectoryPCcP4stat",
1004 		"GetStatFor__C10BDirectoryPCcP4stat@@LIBBE_TEST");
1005 
1006 #	else	// gcc 4
1007 
1008 	B_DEFINE_SYMBOL_VERSION("_ZNK10BDirectory11_GetStatForEPKcP4stat",
1009 		"_ZNK10BDirectory10GetStatForEPKcP4stat@@LIBBE_TEST");
1010 
1011 #	endif	// gcc 4
1012 #else	// !HAIKU_TARGET_PLATFORM_LIBBE_TEST
1013 #	if __GNUC__ == 2	// gcc 2
1014 
1015 	// BeOS compatible GetStatFor()
1016 	B_DEFINE_SYMBOL_VERSION("_GetStatFor__C10BDirectoryPCcP9stat_beos",
1017 		"GetStatFor__C10BDirectoryPCcP4stat@LIBBE_BASE");
1018 
1019 	// Haiku GetStatFor()
1020 	B_DEFINE_SYMBOL_VERSION("_GetStatFor__C10BDirectoryPCcP4stat",
1021 		"GetStatFor__C10BDirectoryPCcP4stat@@LIBBE_1_ALPHA1");
1022 
1023 #	else	// gcc 4
1024 
1025 	// BeOS compatible GetStatFor()
1026 	B_DEFINE_SYMBOL_VERSION("_ZNK10BDirectory11_GetStatForEPKcP9stat_beos",
1027 		"_ZNK10BDirectory10GetStatForEPKcP4stat@LIBBE_BASE");
1028 
1029 	// Haiku GetStatFor()
1030 	B_DEFINE_SYMBOL_VERSION("_ZNK10BDirectory11_GetStatForEPKcP4stat",
1031 		"_ZNK10BDirectory10GetStatForEPKcP4stat@@LIBBE_1_ALPHA1");
1032 
1033 #	endif	// gcc 4
1034 #endif	// !HAIKU_TARGET_PLATFORM_LIBBE_TEST
1035