xref: /haiku/src/kits/storage/Directory.cpp (revision e84abff2bd741614f8cb40828f46618d4eb100e4)
13e54c13aSAxel Dörfler /*
2872c3d3fSAxel Dörfler  * Copyright 2002-2008, Haiku Inc.
33e54c13aSAxel Dörfler  * Distributed under the terms of the MIT License.
43e54c13aSAxel Dörfler  *
53e54c13aSAxel Dörfler  * Authors:
63e54c13aSAxel Dörfler  *		Tyler Dauwalder
73e54c13aSAxel Dörfler  *		Ingo Weinhold, bonefish@users.sf.net
83e54c13aSAxel Dörfler  *		Axel Dörfler, axeld@pinc-software.de
952a38012Sejakowatz  */
1052a38012Sejakowatz 
113e54c13aSAxel Dörfler 
123e54c13aSAxel Dörfler #include "storage_support.h"
133e54c13aSAxel Dörfler 
143e54c13aSAxel Dörfler #include <syscalls.h>
1552a38012Sejakowatz 
1652a38012Sejakowatz #include <Directory.h>
1752a38012Sejakowatz #include <Entry.h>
1852a38012Sejakowatz #include <File.h>
19b06942c6SIngo Weinhold #include <fs_info.h>
2052a38012Sejakowatz #include <Path.h>
2152a38012Sejakowatz #include <SymLink.h>
22db10640dSIngo Weinhold 
233e54c13aSAxel Dörfler #include <fcntl.h>
243e54c13aSAxel Dörfler #include <string.h>
25db10640dSIngo Weinhold 
2652a38012Sejakowatz 
2743209917SAxel Dörfler extern mode_t __gUmask;
2843209917SAxel Dörfler 	// declared in sys/umask.c
2943209917SAxel Dörfler 
3043209917SAxel Dörfler 
3152a38012Sejakowatz //! Creates an uninitialized BDirectory object.
3252a38012Sejakowatz BDirectory::BDirectory()
333e54c13aSAxel Dörfler 	:
34db10640dSIngo Weinhold 	fDirFd(-1)
3552a38012Sejakowatz {
3652a38012Sejakowatz }
3752a38012Sejakowatz 
3843209917SAxel Dörfler 
3943209917SAxel Dörfler /*!	\brief Creates a copy of the supplied BDirectory.
4043209917SAxel Dörfler 	\param dir the BDirectory object to be copied
4152a38012Sejakowatz */
4252a38012Sejakowatz BDirectory::BDirectory(const BDirectory &dir)
433e54c13aSAxel Dörfler 	:
44db10640dSIngo Weinhold 	fDirFd(-1)
4552a38012Sejakowatz {
4652a38012Sejakowatz 	*this = dir;
4752a38012Sejakowatz }
4852a38012Sejakowatz 
4943209917SAxel Dörfler 
5052a38012Sejakowatz /*! \brief Creates a BDirectory and initializes it to the directory referred
5152a38012Sejakowatz 	to by the supplied entry_ref.
5252a38012Sejakowatz 	\param ref the entry_ref referring to the directory
5352a38012Sejakowatz */
5452a38012Sejakowatz BDirectory::BDirectory(const entry_ref *ref)
553e54c13aSAxel Dörfler 	:
56db10640dSIngo Weinhold 	fDirFd(-1)
5752a38012Sejakowatz {
5852a38012Sejakowatz 	SetTo(ref);
5952a38012Sejakowatz }
6052a38012Sejakowatz 
6143209917SAxel Dörfler 
6252a38012Sejakowatz /*! \brief Creates a BDirectory and initializes it to the directory referred
6352a38012Sejakowatz 	to by the supplied node_ref.
6452a38012Sejakowatz 	\param nref the node_ref referring to the directory
6552a38012Sejakowatz */
6652a38012Sejakowatz BDirectory::BDirectory(const node_ref *nref)
673e54c13aSAxel Dörfler 	:
68db10640dSIngo Weinhold 	fDirFd(-1)
6952a38012Sejakowatz {
7052a38012Sejakowatz 	SetTo(nref);
7152a38012Sejakowatz }
7252a38012Sejakowatz 
7343209917SAxel Dörfler 
7452a38012Sejakowatz /*! \brief Creates a BDirectory and initializes it to the directory referred
7552a38012Sejakowatz 	to by the supplied BEntry.
7652a38012Sejakowatz 	\param entry the BEntry referring to the directory
7752a38012Sejakowatz */
7852a38012Sejakowatz BDirectory::BDirectory(const BEntry *entry)
793e54c13aSAxel Dörfler 	:
80db10640dSIngo Weinhold 	fDirFd(-1)
8152a38012Sejakowatz {
8252a38012Sejakowatz 	SetTo(entry);
8352a38012Sejakowatz }
8452a38012Sejakowatz 
8543209917SAxel Dörfler 
8652a38012Sejakowatz /*! \brief Creates a BDirectory and initializes it to the directory referred
8752a38012Sejakowatz 	to by the supplied path name.
8852a38012Sejakowatz 	\param path the directory's path name
8952a38012Sejakowatz */
9052a38012Sejakowatz BDirectory::BDirectory(const char *path)
913e54c13aSAxel Dörfler 	:
92db10640dSIngo Weinhold 	fDirFd(-1)
9352a38012Sejakowatz {
9452a38012Sejakowatz 	SetTo(path);
9552a38012Sejakowatz }
9652a38012Sejakowatz 
9743209917SAxel Dörfler 
9852a38012Sejakowatz /*! \brief Creates a BDirectory and initializes it to the directory referred
9952a38012Sejakowatz 	to by the supplied path name relative to the specified BDirectory.
10052a38012Sejakowatz 	\param dir the BDirectory, relative to which the directory's path name is
10152a38012Sejakowatz 		   given
10252a38012Sejakowatz 	\param path the directory's path name relative to \a dir
10352a38012Sejakowatz */
10452a38012Sejakowatz BDirectory::BDirectory(const BDirectory *dir, const char *path)
1053e54c13aSAxel Dörfler 	:
106db10640dSIngo Weinhold 	fDirFd(-1)
10752a38012Sejakowatz {
10852a38012Sejakowatz 	SetTo(dir, path);
10952a38012Sejakowatz }
11052a38012Sejakowatz 
11143209917SAxel Dörfler 
11252a38012Sejakowatz /*! If the BDirectory is properly initialized, the directory's file descriptor
11352a38012Sejakowatz 	is closed.
11452a38012Sejakowatz */
11552a38012Sejakowatz BDirectory::~BDirectory()
11652a38012Sejakowatz {
11752a38012Sejakowatz 	// Also called by the BNode destructor, but we rather try to avoid
11852a38012Sejakowatz 	// problems with calling virtual functions in the base class destructor.
11952a38012Sejakowatz 	// Depending on the compiler implementation an object may be degraded to
12052a38012Sejakowatz 	// an object of the base class after the destructor of the derived class
12152a38012Sejakowatz 	// has been executed.
12252a38012Sejakowatz 	close_fd();
12352a38012Sejakowatz }
12452a38012Sejakowatz 
12543209917SAxel Dörfler 
12652a38012Sejakowatz /*! \brief Re-initializes the BDirectory to the directory referred to by the
12752a38012Sejakowatz 	supplied entry_ref.
12852a38012Sejakowatz 	\param ref the entry_ref referring to the directory
12952a38012Sejakowatz 	\return
13052a38012Sejakowatz 	- \c B_OK: Everything went fine.
13152a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a ref.
13252a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: Directory not found.
13352a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
13452a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
13552a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
13652a38012Sejakowatz 	- \c B_BUSY: A node was busy.
13752a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
13852a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
13952a38012Sejakowatz */
14052a38012Sejakowatz status_t
14152a38012Sejakowatz BDirectory::SetTo(const entry_ref *ref)
14252a38012Sejakowatz {
143db10640dSIngo Weinhold 	// open node
144db10640dSIngo Weinhold 	status_t error = _SetTo(ref, true);
145db10640dSIngo Weinhold 	if (error != B_OK)
14652a38012Sejakowatz 		return error;
147b06942c6SIngo Weinhold 
148db10640dSIngo Weinhold 	// open dir
149db10640dSIngo Weinhold 	fDirFd = _kern_open_dir_entry_ref(ref->device, ref->directory, ref->name);
150db10640dSIngo Weinhold 	if (fDirFd < 0) {
151db10640dSIngo Weinhold 		status_t error = fDirFd;
152db10640dSIngo Weinhold 		Unset();
153db10640dSIngo Weinhold 		return (fCStatus = error);
154db10640dSIngo Weinhold 	}
155b06942c6SIngo Weinhold 
156b06942c6SIngo Weinhold 	// set close on exec flag on dir FD
157b06942c6SIngo Weinhold 	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
158b06942c6SIngo Weinhold 
159db10640dSIngo Weinhold 	return B_OK;
16052a38012Sejakowatz }
16152a38012Sejakowatz 
16243209917SAxel Dörfler 
16352a38012Sejakowatz /*! \brief Re-initializes the BDirectory to the directory referred to by the
16452a38012Sejakowatz 	supplied node_ref.
16552a38012Sejakowatz 	\param nref the node_ref referring to the directory
16652a38012Sejakowatz 	\return
16752a38012Sejakowatz 	- \c B_OK: Everything went fine.
16852a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a nref.
16952a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: Directory not found.
17052a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
17152a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
17252a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
17352a38012Sejakowatz 	- \c B_BUSY: A node was busy.
17452a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
17552a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
17652a38012Sejakowatz */
17752a38012Sejakowatz status_t
17852a38012Sejakowatz BDirectory::SetTo(const node_ref *nref)
17952a38012Sejakowatz {
18052a38012Sejakowatz 	Unset();
18152a38012Sejakowatz 	status_t error = (nref ? B_OK : B_BAD_VALUE);
18252a38012Sejakowatz 	if (error == B_OK) {
18352a38012Sejakowatz 		entry_ref ref(nref->device, nref->node, ".");
18452a38012Sejakowatz 		error = SetTo(&ref);
18552a38012Sejakowatz 	}
18652a38012Sejakowatz 	set_status(error);
18752a38012Sejakowatz 	return error;
18852a38012Sejakowatz }
18952a38012Sejakowatz 
19043209917SAxel Dörfler 
19152a38012Sejakowatz /*! \brief Re-initializes the BDirectory to the directory referred to by the
19252a38012Sejakowatz 	supplied BEntry.
19352a38012Sejakowatz 	\param entry the BEntry referring to the directory
19452a38012Sejakowatz 	\return
19552a38012Sejakowatz 	- \c B_OK: Everything went fine.
19652a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a entry.
19752a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: Directory not found.
19852a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
19952a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
20052a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
20152a38012Sejakowatz 	- \c B_BUSY: A node was busy.
20252a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
20352a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
20452a38012Sejakowatz */
20552a38012Sejakowatz status_t
20652a38012Sejakowatz BDirectory::SetTo(const BEntry *entry)
20752a38012Sejakowatz {
208db10640dSIngo Weinhold 	if (!entry) {
20952a38012Sejakowatz 		Unset();
210db10640dSIngo Weinhold 		return (fCStatus = B_BAD_VALUE);
211db10640dSIngo Weinhold 	}
212b06942c6SIngo Weinhold 
213db10640dSIngo Weinhold 	// open node
214db10640dSIngo Weinhold 	status_t error = _SetTo(entry->fDirFd, entry->fName, true);
215db10640dSIngo Weinhold 	if (error != B_OK)
21652a38012Sejakowatz 		return error;
217b06942c6SIngo Weinhold 
218db10640dSIngo Weinhold 	// open dir
219db10640dSIngo Weinhold 	fDirFd = _kern_open_dir(entry->fDirFd, entry->fName);
220db10640dSIngo Weinhold 	if (fDirFd < 0) {
221db10640dSIngo Weinhold 		status_t error = fDirFd;
222db10640dSIngo Weinhold 		Unset();
223db10640dSIngo Weinhold 		return (fCStatus = error);
224db10640dSIngo Weinhold 	}
225b06942c6SIngo Weinhold 
226b06942c6SIngo Weinhold 	// set close on exec flag on dir FD
227b06942c6SIngo Weinhold 	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
228b06942c6SIngo Weinhold 
229db10640dSIngo Weinhold 	return B_OK;
23052a38012Sejakowatz }
23152a38012Sejakowatz 
23243209917SAxel Dörfler 
23352a38012Sejakowatz /*! \brief Re-initializes the BDirectory to the directory referred to by the
23452a38012Sejakowatz 	supplied path name.
23552a38012Sejakowatz 	\param path the directory's path name
23652a38012Sejakowatz 	\return
23752a38012Sejakowatz 	- \c B_OK: Everything went fine.
23852a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a path.
23952a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: Directory not found.
24052a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
24152a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
24252a38012Sejakowatz 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
24352a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
24452a38012Sejakowatz 	- \c B_BUSY: A node was busy.
24552a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
24652a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
24752a38012Sejakowatz 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
24852a38012Sejakowatz */
24952a38012Sejakowatz status_t
25052a38012Sejakowatz BDirectory::SetTo(const char *path)
25152a38012Sejakowatz {
252db10640dSIngo Weinhold 	// open node
253db10640dSIngo Weinhold 	status_t error = _SetTo(-1, path, true);
254db10640dSIngo Weinhold 	if (error != B_OK)
255db10640dSIngo Weinhold 		return error;
256b06942c6SIngo Weinhold 
257db10640dSIngo Weinhold 	// open dir
258db10640dSIngo Weinhold 	fDirFd = _kern_open_dir(-1, path);
259db10640dSIngo Weinhold 	if (fDirFd < 0) {
260db10640dSIngo Weinhold 		status_t error = fDirFd;
26152a38012Sejakowatz 		Unset();
262db10640dSIngo Weinhold 		return (fCStatus = error);
26352a38012Sejakowatz 	}
264b06942c6SIngo Weinhold 
265b06942c6SIngo Weinhold 	// set close on exec flag on dir FD
266b06942c6SIngo Weinhold 	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
267b06942c6SIngo Weinhold 
268db10640dSIngo Weinhold 	return B_OK;
26952a38012Sejakowatz }
27052a38012Sejakowatz 
27143209917SAxel Dörfler 
27252a38012Sejakowatz /*! \brief Re-initializes the BDirectory to the directory referred to by the
27352a38012Sejakowatz 	supplied path name relative to the specified BDirectory.
27452a38012Sejakowatz 	\param dir the BDirectory, relative to which the directory's path name is
27552a38012Sejakowatz 		   given
27652a38012Sejakowatz 	\param path the directory's path name relative to \a dir
27752a38012Sejakowatz 	\return
27852a38012Sejakowatz 	- \c B_OK: Everything went fine.
27952a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a dir or \a path, or \a path is absolute.
28052a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: Directory not found.
28152a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
28252a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
28352a38012Sejakowatz 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
28452a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
28552a38012Sejakowatz 	- \c B_BUSY: A node was busy.
28652a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
28752a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
28852a38012Sejakowatz 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
28952a38012Sejakowatz */
29052a38012Sejakowatz status_t
29152a38012Sejakowatz BDirectory::SetTo(const BDirectory *dir, const char *path)
29252a38012Sejakowatz {
293db10640dSIngo Weinhold 	if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) {
29452a38012Sejakowatz 		Unset();
295db10640dSIngo Weinhold 		return (fCStatus = B_BAD_VALUE);
296db10640dSIngo Weinhold 	}
297b06942c6SIngo Weinhold 
2983e54c13aSAxel Dörfler 	int dirFD = dir->fDirFd;
2993e54c13aSAxel Dörfler 	if (dir == this) {
3003e54c13aSAxel Dörfler 		// prevent that our file descriptor goes away in _SetTo()
3013e54c13aSAxel Dörfler 		fDirFd = -1;
3023e54c13aSAxel Dörfler 	}
3033e54c13aSAxel Dörfler 
304db10640dSIngo Weinhold 	// open node
3053e54c13aSAxel Dörfler 	status_t error = _SetTo(dirFD, path, true);
306db10640dSIngo Weinhold 	if (error != B_OK)
30752a38012Sejakowatz 		return error;
308b06942c6SIngo Weinhold 
309db10640dSIngo Weinhold 	// open dir
3103e54c13aSAxel Dörfler 	fDirFd = _kern_open_dir(dirFD, path);
311db10640dSIngo Weinhold 	if (fDirFd < 0) {
312db10640dSIngo Weinhold 		status_t error = fDirFd;
313db10640dSIngo Weinhold 		Unset();
314db10640dSIngo Weinhold 		return (fCStatus = error);
315db10640dSIngo Weinhold 	}
316b06942c6SIngo Weinhold 
3173e54c13aSAxel Dörfler 	if (dir == this) {
3183e54c13aSAxel Dörfler 		// cleanup after _SetTo()
3196a8e3decSStephan Aßmus 		_kern_close(dirFD);
3203e54c13aSAxel Dörfler 	}
3213e54c13aSAxel Dörfler 
322b06942c6SIngo Weinhold 	// set close on exec flag on dir FD
323b06942c6SIngo Weinhold 	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
324b06942c6SIngo Weinhold 
325db10640dSIngo Weinhold 	return B_OK;
32652a38012Sejakowatz }
32752a38012Sejakowatz 
32843209917SAxel Dörfler 
32943209917SAxel Dörfler /*!	\brief Returns a BEntry referring to the directory represented by this object.
33043209917SAxel Dörfler 	If the initialization of \a entry fails, it is Unset().
33152a38012Sejakowatz 	\param entry a pointer to the entry that shall be set to refer to the
33252a38012Sejakowatz 		   directory
33352a38012Sejakowatz 	\return
33452a38012Sejakowatz 	- \c B_OK: Everything went fine.
33552a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a entry.
33652a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: Directory not found.
33752a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
33852a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
33952a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
34052a38012Sejakowatz 	- \c B_BUSY: A node was busy.
34152a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
34252a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
34352a38012Sejakowatz */
34452a38012Sejakowatz status_t
34552a38012Sejakowatz BDirectory::GetEntry(BEntry *entry) const
34652a38012Sejakowatz {
347db10640dSIngo Weinhold 	if (!entry)
348db10640dSIngo Weinhold 		return B_BAD_VALUE;
349db10640dSIngo Weinhold 	if (InitCheck() != B_OK)
350db10640dSIngo Weinhold 		return B_NO_INIT;
351db10640dSIngo Weinhold 	return entry->SetTo(this, ".", false);
35252a38012Sejakowatz }
35352a38012Sejakowatz 
35443209917SAxel Dörfler 
35552a38012Sejakowatz /*!	\brief Returns whether the directory represented by this BDirectory is a
35652a38012Sejakowatz 	root directory of a volume.
35752a38012Sejakowatz 	\return
35852a38012Sejakowatz 	- \c true, if the BDirectory is properly initialized and represents a
35952a38012Sejakowatz 	  root directory of some volume,
36052a38012Sejakowatz 	- \c false, otherwise.
36152a38012Sejakowatz */
36252a38012Sejakowatz bool
36352a38012Sejakowatz BDirectory::IsRootDirectory() const
36452a38012Sejakowatz {
36552a38012Sejakowatz 	// compare the directory's node ID with the ID of the root node of the FS
36652a38012Sejakowatz 	bool result = false;
36752a38012Sejakowatz 	node_ref ref;
36852a38012Sejakowatz 	fs_info info;
36952a38012Sejakowatz 	if (GetNodeRef(&ref) == B_OK && fs_stat_dev(ref.device, &info) == 0)
37052a38012Sejakowatz 		result = (ref.node == info.root);
37152a38012Sejakowatz 	return result;
37252a38012Sejakowatz }
37352a38012Sejakowatz 
37443209917SAxel Dörfler 
37552a38012Sejakowatz /*! \brief Finds an entry referred to by a path relative to the directory
37652a38012Sejakowatz 	represented by this BDirectory.
37752a38012Sejakowatz 	\a path may be absolute. If the BDirectory is not properly initialized,
37852a38012Sejakowatz 	the entry is search relative to the current directory.
37952a38012Sejakowatz 	If the entry couldn't be found, \a entry is Unset().
38052a38012Sejakowatz 	\param path the entry's path name. May be relative to this directory or
38152a38012Sejakowatz 		   absolute.
38252a38012Sejakowatz 	\param entry a pointer to a BEntry to be initialized with the found entry
38352a38012Sejakowatz 	\param traverse specifies whether to follow it, if the found entry
38452a38012Sejakowatz 		   is a symbolic link.
38552a38012Sejakowatz 	\return
38652a38012Sejakowatz 	- \c B_OK: Everything went fine.
38752a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a path or \a entry.
38852a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: Entry not found.
38952a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
39052a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
39152a38012Sejakowatz 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
39252a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
39352a38012Sejakowatz 	- \c B_BUSY: A node was busy.
39452a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
39552a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
39652a38012Sejakowatz 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
39752a38012Sejakowatz 	\note The functionality of this method differs from the one of
39852a38012Sejakowatz 		  BEntry::SetTo(BDirectory *, const char *, bool) in that the
39952a38012Sejakowatz 		  latter doesn't require the entry to be existent, whereas this
40052a38012Sejakowatz 		  function does.
40152a38012Sejakowatz */
40252a38012Sejakowatz status_t
40352a38012Sejakowatz BDirectory::FindEntry(const char *path, BEntry *entry, bool traverse) const
40452a38012Sejakowatz {
40552a38012Sejakowatz 	status_t error = (path && entry ? B_OK : B_BAD_VALUE);
40652a38012Sejakowatz 	if (entry)
40752a38012Sejakowatz 		entry->Unset();
40852a38012Sejakowatz 	if (error == B_OK) {
40952a38012Sejakowatz 		// init a potentially abstract entry
41052a38012Sejakowatz 		if (InitCheck() == B_OK)
41152a38012Sejakowatz 			error = entry->SetTo(this, path, traverse);
41252a38012Sejakowatz 		else
41352a38012Sejakowatz 			error = entry->SetTo(path, traverse);
41452a38012Sejakowatz 		// fail, if entry is abstract
41552a38012Sejakowatz 		if (error == B_OK && !entry->Exists()) {
41652a38012Sejakowatz 			error = B_ENTRY_NOT_FOUND;
41752a38012Sejakowatz 			entry->Unset();
41852a38012Sejakowatz 		}
41952a38012Sejakowatz 	}
42052a38012Sejakowatz 	return error;
42152a38012Sejakowatz }
42252a38012Sejakowatz 
42343209917SAxel Dörfler 
42452a38012Sejakowatz /*!	\brief Returns whether this directory or any of its subdirectories
42552a38012Sejakowatz 	at any level contain the entry referred to by the supplied path name.
42652a38012Sejakowatz 	Only entries that match the node flavor specified by \a nodeFlags are
42752a38012Sejakowatz 	considered.
4285abde301SIngo Weinhold 	If the BDirectory is not properly initialized, the method returns \c false.
4295abde301SIngo Weinhold 	A non-absolute path is considered relative to the current directory.
4305abde301SIngo Weinhold 
4315abde301SIngo Weinhold 	\note R5's implementation always returns \c true given an absolute path or
4325abde301SIngo Weinhold 	an unitialized directory. This implementation is not compatible with that
4335abde301SIngo Weinhold 	behavior. Instead it converts the path into a BEntry and passes it to the
4345abde301SIngo Weinhold 	other version of Contains().
4355abde301SIngo Weinhold 
43652a38012Sejakowatz 	\param path the entry's path name. May be relative to this directory or
43752a38012Sejakowatz 		   absolute.
43852a38012Sejakowatz 	\param nodeFlags Any of the following:
43952a38012Sejakowatz 		   - \c B_FILE_NODE: The entry must be a file.
44052a38012Sejakowatz 		   - \c B_DIRECTORY_NODE: The entry must be a directory.
44152a38012Sejakowatz 		   - \c B_SYMLINK_NODE: The entry must be a symbolic link.
44252a38012Sejakowatz 		   - \c B_ANY_NODE: The entry may be of any kind.
44352a38012Sejakowatz 	\return
44452a38012Sejakowatz 	- \c true, if the entry exists, its kind does match \nodeFlags and the
4455abde301SIngo Weinhold 	  BDirectory is properly initialized and does contain the entry at any
4465abde301SIngo Weinhold 	  level,
44752a38012Sejakowatz 	- \c false, otherwise
44852a38012Sejakowatz */
44952a38012Sejakowatz bool
45052a38012Sejakowatz BDirectory::Contains(const char *path, int32 nodeFlags) const
45152a38012Sejakowatz {
4525abde301SIngo Weinhold 	// check initialization and parameters
4535abde301SIngo Weinhold 	if (InitCheck() != B_OK)
4545abde301SIngo Weinhold 		return false;
4555abde301SIngo Weinhold 	if (!path)
4565abde301SIngo Weinhold 		return true;	// mimic R5 behavior
457d8de23cdSAxel Dörfler 
4585abde301SIngo Weinhold 	// turn the path into a BEntry and let the other version do the work
45952a38012Sejakowatz 	BEntry entry;
4605abde301SIngo Weinhold 	if (BPrivate::Storage::is_absolute_path(path))
46152a38012Sejakowatz 		entry.SetTo(path);
4625abde301SIngo Weinhold 	else
4635abde301SIngo Weinhold 		entry.SetTo(this, path);
464d8de23cdSAxel Dörfler 
4655abde301SIngo Weinhold 	return Contains(&entry, nodeFlags);
46652a38012Sejakowatz }
46752a38012Sejakowatz 
46843209917SAxel Dörfler 
46952a38012Sejakowatz /*!	\brief Returns whether this directory or any of its subdirectories
47052a38012Sejakowatz 	at any level contain the entry referred to by the supplied BEntry.
47152a38012Sejakowatz 	Only entries that match the node flavor specified by \a nodeFlags are
47252a38012Sejakowatz 	considered.
47352a38012Sejakowatz 	\param entry a BEntry referring to the entry
47452a38012Sejakowatz 	\param nodeFlags Any of the following:
47552a38012Sejakowatz 		   - \c B_FILE_NODE: The entry must be a file.
47652a38012Sejakowatz 		   - \c B_DIRECTORY_NODE: The entry must be a directory.
47752a38012Sejakowatz 		   - \c B_SYMLINK_NODE: The entry must be a symbolic link.
47852a38012Sejakowatz 		   - \c B_ANY_NODE: The entry may be of any kind.
47952a38012Sejakowatz 	\return
48052a38012Sejakowatz 	- \c true, if the BDirectory is properly initialized and the entry of the
48152a38012Sejakowatz 	  matching kind could be found,
48252a38012Sejakowatz 	- \c false, otherwise
48352a38012Sejakowatz */
48452a38012Sejakowatz bool
48552a38012Sejakowatz BDirectory::Contains(const BEntry *entry, int32 nodeFlags) const
48652a38012Sejakowatz {
48752a38012Sejakowatz 	// check, if the entry exists at all
488d8de23cdSAxel Dörfler 	if (entry == NULL || !entry->Exists() || InitCheck() != B_OK)
489d8de23cdSAxel Dörfler 		return false;
490d8de23cdSAxel Dörfler 
491872c3d3fSAxel Dörfler 	if (nodeFlags != B_ANY_NODE) {
49252a38012Sejakowatz 		// test the node kind
493872c3d3fSAxel Dörfler 		bool result = false;
494872c3d3fSAxel Dörfler 		if ((nodeFlags & B_FILE_NODE) != 0)
49552a38012Sejakowatz 			result = entry->IsFile();
496872c3d3fSAxel Dörfler 		if (!result && (nodeFlags & B_DIRECTORY_NODE) != 0)
49752a38012Sejakowatz 			result = entry->IsDirectory();
498872c3d3fSAxel Dörfler 		if (!result && (nodeFlags & B_SYMLINK_NODE) != 0)
49952a38012Sejakowatz 			result = entry->IsSymLink();
500872c3d3fSAxel Dörfler 		if (!result)
501872c3d3fSAxel Dörfler 			return false;
50252a38012Sejakowatz 	}
503d8de23cdSAxel Dörfler 
50452a38012Sejakowatz 	// If the directory is initialized, get the canonical paths of the dir and
50552a38012Sejakowatz 	// the entry and check, if the latter is a prefix of the first one.
506db10640dSIngo Weinhold 	BPath dirPath(this, ".", true);
507db10640dSIngo Weinhold 	BPath entryPath(entry);
508*e84abff2SMichael Lotz 	if (dirPath.InitCheck() != B_OK || entryPath.InitCheck() != B_OK)
509872c3d3fSAxel Dörfler 		return false;
510872c3d3fSAxel Dörfler 
511872c3d3fSAxel Dörfler 	return !strncmp(dirPath.Path(), entryPath.Path(), strlen(dirPath.Path()));
51252a38012Sejakowatz }
513d8de23cdSAxel Dörfler 
51452a38012Sejakowatz 
51552a38012Sejakowatz /*!	\brief Returns the stat structure of the entry referred to by the supplied
51652a38012Sejakowatz 	path name.
51752a38012Sejakowatz 	\param path the entry's path name. May be relative to this directory or
51852a38012Sejakowatz 		   absolute, or \c NULL to get the directories stat info.
51952a38012Sejakowatz 	\param st a pointer to the stat structure to be filled in by this function
52052a38012Sejakowatz 	\return
52152a38012Sejakowatz 	- \c B_OK: Everything went fine.
52252a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a st.
52352a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: Entry not found.
52452a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
52552a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
52652a38012Sejakowatz 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
52752a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
52852a38012Sejakowatz 	- \c B_BUSY: A node was busy.
52952a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
53052a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
53152a38012Sejakowatz 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
53252a38012Sejakowatz */
53352a38012Sejakowatz status_t
53452a38012Sejakowatz BDirectory::GetStatFor(const char *path, struct stat *st) const
53552a38012Sejakowatz {
536db10640dSIngo Weinhold 	if (!st)
537db10640dSIngo Weinhold 		return B_BAD_VALUE;
538db10640dSIngo Weinhold 	if (InitCheck() != B_OK)
539db10640dSIngo Weinhold 		return B_NO_INIT;
54043209917SAxel Dörfler 
54143209917SAxel Dörfler 	if (path != NULL) {
54243209917SAxel Dörfler 		if (path[0] == '\0')
543db10640dSIngo Weinhold 			return B_ENTRY_NOT_FOUND;
54443209917SAxel Dörfler 		return _kern_read_stat(fDirFd, path, false, st, sizeof(struct stat));
54543209917SAxel Dörfler 	}
54643209917SAxel Dörfler 	return GetStat(st);
54752a38012Sejakowatz }
54852a38012Sejakowatz 
54943209917SAxel Dörfler 
55043209917SAxel Dörfler /*!	\brief Returns the BDirectory's next entry as a BEntry.
55143209917SAxel Dörfler 	Unlike GetNextDirents() this method ignores the entries "." and "..".
55252a38012Sejakowatz 	\param entry a pointer to a BEntry to be initialized to the found entry
55352a38012Sejakowatz 	\param traverse specifies whether to follow it, if the found entry
55452a38012Sejakowatz 		   is a symbolic link.
55552a38012Sejakowatz 	\note The iterator used by this method is the same one used by
55652a38012Sejakowatz 		  GetNextRef(), GetNextDirents(), Rewind() and CountEntries().
55752a38012Sejakowatz 	\return
55852a38012Sejakowatz 	- \c B_OK: Everything went fine.
55952a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a entry.
56052a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: No more entries found.
56152a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
56252a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
56352a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
56452a38012Sejakowatz 	- \c B_BUSY: A node was busy.
56552a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
56652a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
56752a38012Sejakowatz */
56852a38012Sejakowatz status_t
56952a38012Sejakowatz BDirectory::GetNextEntry(BEntry *entry, bool traverse)
57052a38012Sejakowatz {
57152a38012Sejakowatz 	status_t error = (entry ? B_OK : B_BAD_VALUE);
57252a38012Sejakowatz 	if (error == B_OK) {
57352a38012Sejakowatz 		entry_ref ref;
57452a38012Sejakowatz 		error = GetNextRef(&ref);
57552a38012Sejakowatz 		if (error == B_OK)
57652a38012Sejakowatz 			error = entry->SetTo(&ref, traverse);
57752a38012Sejakowatz 	}
57852a38012Sejakowatz 	return error;
57952a38012Sejakowatz }
58052a38012Sejakowatz 
58143209917SAxel Dörfler 
58243209917SAxel Dörfler /*!	\brief Returns the BDirectory's next entry as an entry_ref.
58343209917SAxel Dörfler 	Unlike GetNextDirents() this method ignores the entries "." and "..".
58452a38012Sejakowatz 	\param ref a pointer to an entry_ref to be filled in with the data of the
58552a38012Sejakowatz 		   found entry
58652a38012Sejakowatz 	\param traverse specifies whether to follow it, if the found entry
58752a38012Sejakowatz 		   is a symbolic link.
58852a38012Sejakowatz 	\note The iterator used be this method is the same one used by
58952a38012Sejakowatz 		  GetNextEntry(), GetNextDirents(), Rewind() and CountEntries().
59052a38012Sejakowatz 	\return
59152a38012Sejakowatz 	- \c B_OK: Everything went fine.
59252a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a ref.
59352a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: No more entries found.
59452a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
59552a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
59652a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
59752a38012Sejakowatz 	- \c B_BUSY: A node was busy.
59852a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
59952a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
60052a38012Sejakowatz */
60152a38012Sejakowatz status_t
60252a38012Sejakowatz BDirectory::GetNextRef(entry_ref *ref)
60352a38012Sejakowatz {
60452a38012Sejakowatz 	status_t error = (ref ? B_OK : B_BAD_VALUE);
60552a38012Sejakowatz 	if (error == B_OK && InitCheck() != B_OK)
60652a38012Sejakowatz 		error = B_FILE_ERROR;
60752a38012Sejakowatz 	if (error == B_OK) {
60809d84e61STyler Dauwalder 		BPrivate::Storage::LongDirEntry entry;
60952a38012Sejakowatz 		bool next = true;
61052a38012Sejakowatz 		while (error == B_OK && next) {
611db10640dSIngo Weinhold 			if (GetNextDirents(&entry, sizeof(entry), 1) != 1) {
61252a38012Sejakowatz 				error = B_ENTRY_NOT_FOUND;
613db10640dSIngo Weinhold 			} else {
61452a38012Sejakowatz 				next = (!strcmp(entry.d_name, ".")
61552a38012Sejakowatz 					|| !strcmp(entry.d_name, ".."));
61652a38012Sejakowatz 			}
61752a38012Sejakowatz 		}
618db10640dSIngo Weinhold 		if (error == B_OK) {
619db10640dSIngo Weinhold 			ref->device = entry.d_pdev;
620db10640dSIngo Weinhold 			ref->directory = entry.d_pino;
621db10640dSIngo Weinhold 			error = ref->set_name(entry.d_name);
622db10640dSIngo Weinhold 		}
62352a38012Sejakowatz 	}
62452a38012Sejakowatz 	return error;
62552a38012Sejakowatz }
62652a38012Sejakowatz 
62743209917SAxel Dörfler 
62843209917SAxel Dörfler /*!	\brief Returns the BDirectory's next entries as dirent structures.
62943209917SAxel Dörfler 	Unlike GetNextEntry() and GetNextRef(), this method returns also
63052a38012Sejakowatz 	the entries "." and "..".
63152a38012Sejakowatz 	\param buf a pointer to a buffer to be filled with dirent structures of
63252a38012Sejakowatz 		   the found entries
63352a38012Sejakowatz 	\param count the maximal number of entries to be returned.
63452a38012Sejakowatz 	\note The iterator used by this method is the same one used by
63552a38012Sejakowatz 		  GetNextEntry(), GetNextRef(), Rewind() and CountEntries().
63652a38012Sejakowatz 	\return
63752a38012Sejakowatz 	- The number of dirent structures stored in the buffer, 0 when there are
63852a38012Sejakowatz 	  no more entries to be returned.
63952a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a buf.
64052a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
64152a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
64252a38012Sejakowatz 	- \c B_NAME_TOO_LONG: The entry's name is too long for the buffer.
64352a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
64452a38012Sejakowatz 	- \c B_BUSY: A node was busy.
64552a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
64652a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
64752a38012Sejakowatz */
64852a38012Sejakowatz int32
64952a38012Sejakowatz BDirectory::GetNextDirents(dirent *buf, size_t bufSize, int32 count)
65052a38012Sejakowatz {
651db10640dSIngo Weinhold 	if (!buf)
652db10640dSIngo Weinhold 		return B_BAD_VALUE;
653db10640dSIngo Weinhold 	if (InitCheck() != B_OK)
654db10640dSIngo Weinhold 		return B_FILE_ERROR;
655db10640dSIngo Weinhold 	return _kern_read_dir(fDirFd, buf, bufSize, count);
65652a38012Sejakowatz }
65752a38012Sejakowatz 
65843209917SAxel Dörfler 
65943209917SAxel Dörfler /*!	\brief Rewinds the directory iterator.
66043209917SAxel Dörfler 	\return
66152a38012Sejakowatz 	- \c B_OK: Everything went fine.
66252a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
66352a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
66452a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
66552a38012Sejakowatz 	- \c B_BUSY: A node was busy.
66652a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
66752a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
66852a38012Sejakowatz 	\see GetNextEntry(), GetNextRef(), GetNextDirents(), CountEntries()
66952a38012Sejakowatz */
67052a38012Sejakowatz status_t
67152a38012Sejakowatz BDirectory::Rewind()
67252a38012Sejakowatz {
673db10640dSIngo Weinhold 	if (InitCheck() != B_OK)
674db10640dSIngo Weinhold 		return B_FILE_ERROR;
675db10640dSIngo Weinhold 	return _kern_rewind_dir(fDirFd);
67652a38012Sejakowatz }
67752a38012Sejakowatz 
67843209917SAxel Dörfler 
67943209917SAxel Dörfler /*!	\brief Returns the number of entries in this directory.
68043209917SAxel Dörfler 	CountEntries() uses the directory iterator also used by GetNextEntry(),
68152a38012Sejakowatz 	GetNextRef() and GetNextDirents(). It does a Rewind(), iterates through
68252a38012Sejakowatz 	the entries and Rewind()s again. The entries "." and ".." are not counted.
68352a38012Sejakowatz 	\return
68452a38012Sejakowatz 	- the number of entries in the directory (not counting "." and "..").
68552a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
68652a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
68752a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
68852a38012Sejakowatz 	- \c B_BUSY: A node was busy.
68952a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
69052a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
69152a38012Sejakowatz 	\see GetNextEntry(), GetNextRef(), GetNextDirents(), Rewind()
69252a38012Sejakowatz */
69352a38012Sejakowatz int32
69452a38012Sejakowatz BDirectory::CountEntries()
69552a38012Sejakowatz {
69652a38012Sejakowatz 	status_t error = Rewind();
697db10640dSIngo Weinhold 	if (error != B_OK)
698db10640dSIngo Weinhold 		return error;
69952a38012Sejakowatz 	int32 count = 0;
70009d84e61STyler Dauwalder 	BPrivate::Storage::LongDirEntry entry;
70152a38012Sejakowatz 	while (error == B_OK) {
702db10640dSIngo Weinhold 		if (GetNextDirents(&entry, sizeof(entry), 1) != 1)
703db10640dSIngo Weinhold 			break;
704db10640dSIngo Weinhold 		if (strcmp(entry.d_name, ".") != 0 && strcmp(entry.d_name, "..") != 0)
70552a38012Sejakowatz 			count++;
70652a38012Sejakowatz 	}
70752a38012Sejakowatz 	Rewind();
70852a38012Sejakowatz 	return (error == B_OK ? count : error);
70952a38012Sejakowatz }
71052a38012Sejakowatz 
71143209917SAxel Dörfler 
71243209917SAxel Dörfler /*! \brief Creates a new directory.
71343209917SAxel Dörfler 	If an entry with the supplied name does already exist, the method fails.
71452a38012Sejakowatz 	\param path the new directory's path name. May be relative to this
71552a38012Sejakowatz 		   directory or absolute.
71652a38012Sejakowatz 	\param dir a pointer to a BDirectory to be initialized to the newly
71752a38012Sejakowatz 		   created directory. May be \c NULL.
71852a38012Sejakowatz 	\return
71952a38012Sejakowatz 	- \c B_OK: Everything went fine.
72052a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a path.
72152a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
72252a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
72352a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
72452a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
72552a38012Sejakowatz 	- \c B_BUSY: A node was busy.
72652a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
72752a38012Sejakowatz 	- \c B_FILE_EXISTS: An entry with that name does already exist.
72852a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
72952a38012Sejakowatz */
73052a38012Sejakowatz status_t
73152a38012Sejakowatz BDirectory::CreateDirectory(const char *path, BDirectory *dir)
73252a38012Sejakowatz {
733db10640dSIngo Weinhold 	if (!path)
734db10640dSIngo Weinhold 		return B_BAD_VALUE;
73543209917SAxel Dörfler 
736db10640dSIngo Weinhold 	// create the dir
737db10640dSIngo Weinhold 	status_t error = _kern_create_dir(fDirFd, path,
73843209917SAxel Dörfler 		(S_IRWXU | S_IRWXG | S_IRWXO) & ~__gUmask);
739db10640dSIngo Weinhold 	if (error != B_OK)
74052a38012Sejakowatz 		return error;
74143209917SAxel Dörfler 
74243209917SAxel Dörfler 	if (dir == NULL)
743db10640dSIngo Weinhold 		return B_OK;
74443209917SAxel Dörfler 
745db10640dSIngo Weinhold 	// init the supplied BDirectory
746db10640dSIngo Weinhold 	if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path))
747db10640dSIngo Weinhold 		return dir->SetTo(path);
74843209917SAxel Dörfler 
749db10640dSIngo Weinhold 	return dir->SetTo(this, path);
75052a38012Sejakowatz }
75152a38012Sejakowatz 
75243209917SAxel Dörfler 
75343209917SAxel Dörfler /*! \brief Creates a new file.
75443209917SAxel Dörfler 	If a file with the supplied name does already exist, the method fails,
75552a38012Sejakowatz 	unless it is passed \c false to \a failIfExists -- in that case the file
75652a38012Sejakowatz 	is truncated to zero size. The new BFile will operate in \c B_READ_WRITE
75752a38012Sejakowatz 	mode.
75852a38012Sejakowatz 	\param path the new file's path name. May be relative to this
75952a38012Sejakowatz 		   directory or absolute.
76052a38012Sejakowatz 	\param file a pointer to a BFile to be initialized to the newly
76152a38012Sejakowatz 		   created file. May be \c NULL.
76252a38012Sejakowatz 	\param failIfExists \c true, if the method should fail when the file
76352a38012Sejakowatz 		   already exists, \c false otherwise
76452a38012Sejakowatz 	\return
76552a38012Sejakowatz 	- \c B_OK: Everything went fine.
76652a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a path.
76752a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
76852a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
76952a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
77052a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
77152a38012Sejakowatz 	- \c B_BUSY: A node was busy.
77252a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
77352a38012Sejakowatz 	- \c B_FILE_EXISTS: A file with that name does already exist and
77452a38012Sejakowatz 	  \c true has been passed for \a failIfExists.
77552a38012Sejakowatz 	- \c B_IS_A_DIRECTORY: A directory with the supplied name does already
77652a38012Sejakowatz 	  exist.
77752a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
77852a38012Sejakowatz */
77952a38012Sejakowatz status_t
78052a38012Sejakowatz BDirectory::CreateFile(const char *path, BFile *file, bool failIfExists)
78152a38012Sejakowatz {
782db10640dSIngo Weinhold 	if (!path)
783db10640dSIngo Weinhold 		return B_BAD_VALUE;
78452a38012Sejakowatz 	// Let BFile do the dirty job.
7852586d10eSIngo Weinhold 	uint32 openMode = B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE
78652a38012Sejakowatz 		| (failIfExists ? B_FAIL_IF_EXISTS : 0);
78752a38012Sejakowatz 	BFile tmpFile;
78843209917SAxel Dörfler 	BFile *realFile = file ? file : &tmpFile;
789db10640dSIngo Weinhold 	status_t error = B_OK;
79009d84e61STyler Dauwalder 	if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path))
79152a38012Sejakowatz 		error = realFile->SetTo(this, path, openMode);
79252a38012Sejakowatz 	else
79352a38012Sejakowatz 		error = realFile->SetTo(path, openMode);
794db10640dSIngo Weinhold 	if (error != B_OK && file) // mimic R5 behavior
795db10640dSIngo Weinhold 		file->Unset();
79652a38012Sejakowatz 	return error;
79752a38012Sejakowatz }
79852a38012Sejakowatz 
79943209917SAxel Dörfler 
80043209917SAxel Dörfler /*! \brief Creates a new symbolic link.
80143209917SAxel Dörfler 	If an entry with the supplied name does already exist, the method fails.
80252a38012Sejakowatz 	\param path the new symbolic link's path name. May be relative to this
80352a38012Sejakowatz 		   directory or absolute.
80452a38012Sejakowatz 	\param linkToPath the path the symbolic link shall point to.
80552a38012Sejakowatz 	\param dir a pointer to a BSymLink to be initialized to the newly
80652a38012Sejakowatz 		   created symbolic link. May be \c NULL.
80752a38012Sejakowatz 	\return
80852a38012Sejakowatz 	- \c B_OK: Everything went fine.
80952a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a path or \a linkToPath.
81052a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
81152a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
81252a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
81352a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
81452a38012Sejakowatz 	- \c B_BUSY: A node was busy.
81552a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
81652a38012Sejakowatz 	- \c B_FILE_EXISTS: An entry with that name does already exist.
81752a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
81852a38012Sejakowatz */
81952a38012Sejakowatz status_t
82052a38012Sejakowatz BDirectory::CreateSymLink(const char *path, const char *linkToPath,
82152a38012Sejakowatz 	BSymLink *link)
82252a38012Sejakowatz {
823db10640dSIngo Weinhold 	if (!path || !linkToPath)
824db10640dSIngo Weinhold 		return B_BAD_VALUE;
82543209917SAxel Dörfler 
826db10640dSIngo Weinhold 	// create the symlink
827db10640dSIngo Weinhold 	status_t error = _kern_create_symlink(fDirFd, path, linkToPath,
82843209917SAxel Dörfler 		(S_IRWXU | S_IRWXG | S_IRWXO) & ~__gUmask);
829db10640dSIngo Weinhold 	if (error != B_OK)
83052a38012Sejakowatz 		return error;
83143209917SAxel Dörfler 
83243209917SAxel Dörfler 	if (link == NULL)
833db10640dSIngo Weinhold 		return B_OK;
83443209917SAxel Dörfler 
835db10640dSIngo Weinhold 	// init the supplied BSymLink
836db10640dSIngo Weinhold 	if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path))
837db10640dSIngo Weinhold 		return link->SetTo(path);
83843209917SAxel Dörfler 
839db10640dSIngo Weinhold 	return link->SetTo(this, path);
84052a38012Sejakowatz }
84152a38012Sejakowatz 
84243209917SAxel Dörfler 
84343209917SAxel Dörfler /*!	\brief Assigns another BDirectory to this BDirectory.
84443209917SAxel Dörfler 	If the other BDirectory is uninitialized, this one wi'll be too. Otherwise
84552a38012Sejakowatz 	it will refer to the same directory, unless an error occurs.
84652a38012Sejakowatz 	\param dir the original BDirectory
84752a38012Sejakowatz 	\return a reference to this BDirectory
84852a38012Sejakowatz */
84952a38012Sejakowatz BDirectory &
85052a38012Sejakowatz BDirectory::operator=(const BDirectory &dir)
85152a38012Sejakowatz {
85252a38012Sejakowatz 	if (&dir != this) {	// no need to assign us to ourselves
85352a38012Sejakowatz 		Unset();
854db10640dSIngo Weinhold 		if (dir.InitCheck() == B_OK)
855db10640dSIngo Weinhold 			SetTo(&dir, ".");
85652a38012Sejakowatz 	}
85752a38012Sejakowatz 	return *this;
85852a38012Sejakowatz }
85952a38012Sejakowatz 
86052a38012Sejakowatz 
86152a38012Sejakowatz // FBC
8627c44680aSIngo Weinhold void BDirectory::_ErectorDirectory1() {}
8637c44680aSIngo Weinhold void BDirectory::_ErectorDirectory2() {}
8647c44680aSIngo Weinhold void BDirectory::_ErectorDirectory3() {}
8657c44680aSIngo Weinhold void BDirectory::_ErectorDirectory4() {}
8667c44680aSIngo Weinhold void BDirectory::_ErectorDirectory5() {}
8677c44680aSIngo Weinhold void BDirectory::_ErectorDirectory6() {}
86852a38012Sejakowatz 
86943209917SAxel Dörfler 
87052a38012Sejakowatz //! Closes the BDirectory's file descriptor.
87152a38012Sejakowatz void
87252a38012Sejakowatz BDirectory::close_fd()
87352a38012Sejakowatz {
874db10640dSIngo Weinhold 	if (fDirFd >= 0) {
875db10640dSIngo Weinhold 		_kern_close(fDirFd);
876db10640dSIngo Weinhold 		fDirFd = -1;
87752a38012Sejakowatz 	}
87852a38012Sejakowatz 	BNode::close_fd();
87952a38012Sejakowatz }
88052a38012Sejakowatz 
88143209917SAxel Dörfler 
88243209917SAxel Dörfler /*!	\brief Returns the BDirectory's file descriptor.
88343209917SAxel Dörfler 	To be used instead of accessing the BDirectory's private \c fDirFd member
88452a38012Sejakowatz 	directly.
88552a38012Sejakowatz 	\return the file descriptor, or -1, if not properly initialized.
88652a38012Sejakowatz */
887db10640dSIngo Weinhold int
88852a38012Sejakowatz BDirectory::get_fd() const
88952a38012Sejakowatz {
89052a38012Sejakowatz 	return fDirFd;
89152a38012Sejakowatz }
89252a38012Sejakowatz 
89352a38012Sejakowatz 
89443209917SAxel Dörfler //	#pragma mark - C functions
89552a38012Sejakowatz 
89643209917SAxel Dörfler 
89743209917SAxel Dörfler /*!	\brief Creates all missing directories along a given path.
89843209917SAxel Dörfler 	\param path the directory path name.
89952a38012Sejakowatz 	\param mode a permission specification, which shall be used for the
90052a38012Sejakowatz 		   newly created directories.
90152a38012Sejakowatz 	\return
90252a38012Sejakowatz 	- \c B_OK: Everything went fine.
90352a38012Sejakowatz 	- \c B_BAD_VALUE: \c NULL \a path.
90452a38012Sejakowatz 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
90552a38012Sejakowatz 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
90652a38012Sejakowatz 	- \c B_NO_MEMORY: Insufficient memory for operation.
90752a38012Sejakowatz 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
90852a38012Sejakowatz 	- \c B_BUSY: A node was busy.
90952a38012Sejakowatz 	- \c B_FILE_ERROR: A general file error.
91052a38012Sejakowatz 	- \c B_NOT_A_DIRECTORY: An entry other than a directory with that name does
91152a38012Sejakowatz 	  already exist.
91252a38012Sejakowatz 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
91352a38012Sejakowatz 	\todo Check for efficency.
91452a38012Sejakowatz */
91552a38012Sejakowatz status_t
91652a38012Sejakowatz create_directory(const char *path, mode_t mode)
91752a38012Sejakowatz {
918db10640dSIngo Weinhold 	if (!path)
919db10640dSIngo Weinhold 		return B_BAD_VALUE;
92052a38012Sejakowatz 	// That's the strategy: We start with the first component of the supplied
92152a38012Sejakowatz 	// path, create a BPath object from it and successively add the following
92252a38012Sejakowatz 	// components. Each time we get a new path, we check, if the entry it
923db10640dSIngo Weinhold 	// refers to exists and is a directory. If it doesn't exist, we try
92452a38012Sejakowatz 	// to create it. This goes on, until we're done with the input path or
92552a38012Sejakowatz 	// an error occurs.
92652a38012Sejakowatz 	BPath dirPath;
92752a38012Sejakowatz 	char *component;
92852a38012Sejakowatz 	int32 nextComponent;
92952a38012Sejakowatz 	do {
93052a38012Sejakowatz 		// get the next path component
931db10640dSIngo Weinhold 		status_t error = BPrivate::Storage::parse_first_path_component(path,
932db10640dSIngo Weinhold 			component, nextComponent);
933db10640dSIngo Weinhold 		if (error != B_OK)
934db10640dSIngo Weinhold 			return error;
93552a38012Sejakowatz 		// append it to the BPath
93652a38012Sejakowatz 		if (dirPath.InitCheck() == B_NO_INIT)	// first component
93752a38012Sejakowatz 			error = dirPath.SetTo(component);
93852a38012Sejakowatz 		else
93952a38012Sejakowatz 			error = dirPath.Append(component);
94052a38012Sejakowatz 		delete[] component;
941db10640dSIngo Weinhold 		if (error != B_OK)
942db10640dSIngo Weinhold 			return error;
94352a38012Sejakowatz 		path += nextComponent;
94452a38012Sejakowatz 		// create a BEntry from the BPath
94552a38012Sejakowatz 		BEntry entry;
94652a38012Sejakowatz 		error = entry.SetTo(dirPath.Path(), true);
947db10640dSIngo Weinhold 		if (error != B_OK)
948db10640dSIngo Weinhold 			return error;
94952a38012Sejakowatz 		// check, if it exists
95052a38012Sejakowatz 		if (entry.Exists()) {
95152a38012Sejakowatz 			// yep, it exists
95252a38012Sejakowatz 			if (!entry.IsDirectory())	// but is no directory
953db10640dSIngo Weinhold 				return B_NOT_A_DIRECTORY;
954db10640dSIngo Weinhold 		} else {
955db10640dSIngo Weinhold 			// it doesn't exist -- create it
956db10640dSIngo Weinhold 			error = _kern_create_dir(-1, dirPath.Path(), mode);
957db10640dSIngo Weinhold 			if (error != B_OK)
95852a38012Sejakowatz 				return error;
95952a38012Sejakowatz 		}
960db10640dSIngo Weinhold 	} while (nextComponent != 0);
961db10640dSIngo Weinhold 	return B_OK;
962db10640dSIngo Weinhold }
96352a38012Sejakowatz 
964