13e54c13aSAxel Dörfler/*
2bcfe344cSIngo Weinhold * Copyright 2002-2009, 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
93e54c13aSAxel Dörfler */
1052a38012Sejakowatz
113e54c13aSAxel Dörfler
123e54c13aSAxel Dörfler#include "storage_support.h"
133e54c13aSAxel Dörfler
14bcfe344cSIngo Weinhold#include <fcntl.h>
15bcfe344cSIngo Weinhold#include <string.h>
16bcfe344cSIngo Weinhold
17bcfe344cSIngo Weinhold#include <compat/sys/stat.h>
1852a38012Sejakowatz
1952a38012Sejakowatz#include <Directory.h>
2052a38012Sejakowatz#include <Entry.h>
2152a38012Sejakowatz#include <File.h>
22b06942c6SIngo Weinhold#include <fs_info.h>
2352a38012Sejakowatz#include <Path.h>
2452a38012Sejakowatz#include <SymLink.h>
25db10640dSIngo Weinhold
26bcfe344cSIngo Weinhold#include <syscalls.h>
27160f2d10SAxel Dörfler#include <umask.h>
2843209917SAxel Dörfler
2943209917SAxel Dörfler
3052a38012SejakowatzBDirectory::BDirectory()
313e54c13aSAxel Dörfler	:
323e54c13aSAxel Dörfler	fDirFd(-1)
3352a38012Sejakowatz{
3452a38012Sejakowatz}
3552a38012Sejakowatz
3643209917SAxel Dörfler
37160f2d10SAxel DörflerBDirectory::BDirectory(const BDirectory& dir)
383e54c13aSAxel Dörfler	:
393e54c13aSAxel Dörfler	fDirFd(-1)
4052a38012Sejakowatz{
4152a38012Sejakowatz	*this = dir;
4252a38012Sejakowatz}
4352a38012Sejakowatz
4443209917SAxel Dörfler
45160f2d10SAxel DörflerBDirectory::BDirectory(const entry_ref* ref)
463e54c13aSAxel Dörfler	:
473e54c13aSAxel Dörfler	fDirFd(-1)
4852a38012Sejakowatz{
4952a38012Sejakowatz	SetTo(ref);
5052a38012Sejakowatz}
5152a38012Sejakowatz
5243209917SAxel Dörfler
53160f2d10SAxel DörflerBDirectory::BDirectory(const node_ref* nref)
543e54c13aSAxel Dörfler	:
553e54c13aSAxel Dörfler	fDirFd(-1)
5652a38012Sejakowatz{
5752a38012Sejakowatz	SetTo(nref);
5852a38012Sejakowatz}
5952a38012Sejakowatz
6043209917SAxel Dörfler
61160f2d10SAxel DörflerBDirectory::BDirectory(const BEntry* entry)
623e54c13aSAxel Dörfler	:
633e54c13aSAxel Dörfler	fDirFd(-1)
6452a38012Sejakowatz{
6552a38012Sejakowatz	SetTo(entry);
6652a38012Sejakowatz}
6752a38012Sejakowatz
6843209917SAxel Dörfler
69160f2d10SAxel DörflerBDirectory::BDirectory(const char* path)
703e54c13aSAxel Dörfler	:
713e54c13aSAxel Dörfler	fDirFd(-1)
7252a38012Sejakowatz{
7352a38012Sejakowatz	SetTo(path);
7452a38012Sejakowatz}
7552a38012Sejakowatz
7643209917SAxel Dörfler
77160f2d10SAxel DörflerBDirectory::BDirectory(const BDirectory* dir, const char* path)
783e54c13aSAxel Dörfler	:
793e54c13aSAxel Dörfler	fDirFd(-1)
8052a38012Sejakowatz{
8152a38012Sejakowatz	SetTo(dir, path);
8252a38012Sejakowatz}
8352a38012Sejakowatz
8443209917SAxel Dörfler
8552a38012SejakowatzBDirectory::~BDirectory()
8652a38012Sejakowatz{
8752a38012Sejakowatz	// Also called by the BNode destructor, but we rather try to avoid
8852a38012Sejakowatz	// problems with calling virtual functions in the base class destructor.
8952a38012Sejakowatz	// Depending on the compiler implementation an object may be degraded to
9052a38012Sejakowatz	// an object of the base class after the destructor of the derived class
9152a38012Sejakowatz	// has been executed.
9252a38012Sejakowatz	close_fd();
9352a38012Sejakowatz}
9452a38012Sejakowatz
9543209917SAxel Dörfler
9652a38012Sejakowatzstatus_t
97160f2d10SAxel DörflerBDirectory::SetTo(const entry_ref* ref)
9852a38012Sejakowatz{
99db10640dSIngo Weinhold	// open node
100db10640dSIngo Weinhold	status_t error = _SetTo(ref, true);
101db10640dSIngo Weinhold	if (error != B_OK)
102db10640dSIngo Weinhold		return error;
103b06942c6SIngo Weinhold
104db10640dSIngo Weinhold	// open dir
105db10640dSIngo Weinhold	fDirFd = _kern_open_dir_entry_ref(ref->device, ref->directory, ref->name);
106db10640dSIngo Weinhold	if (fDirFd < 0) {
107db10640dSIngo Weinhold		status_t error = fDirFd;
108db10640dSIngo Weinhold		Unset();
109db10640dSIngo Weinhold		return (fCStatus = error);
11052a38012Sejakowatz	}
111b06942c6SIngo Weinhold
112b06942c6SIngo Weinhold	// set close on exec flag on dir FD
113b06942c6SIngo Weinhold	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
114b06942c6SIngo Weinhold
115db10640dSIngo Weinhold	return B_OK;
11652a38012Sejakowatz}
11752a38012Sejakowatz
11843209917SAxel Dörfler
11952a38012Sejakowatzstatus_t
120160f2d10SAxel DörflerBDirectory::SetTo(const node_ref* nref)
12152a38012Sejakowatz{
122872c3d3fSAxel Dörfler	Unset();
12352a38012Sejakowatz	status_t error = (nref ? B_OK : B_BAD_VALUE);
12452a38012Sejakowatz	if (error == B_OK) {
12552a38012Sejakowatz		entry_ref ref(nref->device, nref->node, ".");
12652a38012Sejakowatz		error = SetTo(&ref);
12752a38012Sejakowatz	}
12852a38012Sejakowatz	set_status(error);
12952a38012Sejakowatz	return error;
13052a38012Sejakowatz}
13152a38012Sejakowatz
13243209917SAxel Dörfler
13352a38012Sejakowatzstatus_t
134160f2d10SAxel DörflerBDirectory::SetTo(const BEntry* entry)
13552a38012Sejakowatz{
136db10640dSIngo Weinhold	if (!entry) {
137db10640dSIngo Weinhold		Unset();
138db10640dSIngo Weinhold		return (fCStatus = B_BAD_VALUE);
139db10640dSIngo Weinhold	}
140b06942c6SIngo Weinhold
141db10640dSIngo Weinhold	// open node
142db10640dSIngo Weinhold	status_t error = _SetTo(entry->fDirFd, entry->fName, true);
143db10640dSIngo Weinhold	if (error != B_OK)
144db10640dSIngo Weinhold		return error;
145b06942c6SIngo Weinhold
146db10640dSIngo Weinhold	// open dir
147db10640dSIngo Weinhold	fDirFd = _kern_open_dir(entry->fDirFd, entry->fName);
148db10640dSIngo Weinhold	if (fDirFd < 0) {
149db10640dSIngo Weinhold		status_t error = fDirFd;
150db10640dSIngo Weinhold		Unset();
151db10640dSIngo Weinhold		return (fCStatus = error);
152db10640dSIngo Weinhold	}
153b06942c6SIngo Weinhold
154b06942c6SIngo Weinhold	// set close on exec flag on dir FD
155b06942c6SIngo Weinhold	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
156b06942c6SIngo Weinhold
157db10640dSIngo Weinhold	return B_OK;
15852a38012Sejakowatz}
15952a38012Sejakowatz
16043209917SAxel Dörfler
16152a38012Sejakowatzstatus_t
162160f2d10SAxel DörflerBDirectory::SetTo(const char* path)
16352a38012Sejakowatz{
164db10640dSIngo Weinhold	// open node
165db10640dSIngo Weinhold	status_t error = _SetTo(-1, path, true);
166db10640dSIngo Weinhold	if (error != B_OK)
167db10640dSIngo Weinhold		return error;
168b06942c6SIngo Weinhold
169db10640dSIngo Weinhold	// open dir
170db10640dSIngo Weinhold	fDirFd = _kern_open_dir(-1, path);
171db10640dSIngo Weinhold	if (fDirFd < 0) {
172db10640dSIngo Weinhold		status_t error = fDirFd;
173db10640dSIngo Weinhold		Unset();
174db10640dSIngo Weinhold		return (fCStatus = error);
17552a38012Sejakowatz	}
176b06942c6SIngo Weinhold
177b06942c6SIngo Weinhold	// set close on exec flag on dir FD
178b06942c6SIngo Weinhold	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
179b06942c6SIngo Weinhold
180db10640dSIngo Weinhold	return B_OK;
18152a38012Sejakowatz}
18252a38012Sejakowatz
18343209917SAxel Dörfler
18452a38012Sejakowatzstatus_t
185160f2d10SAxel DörflerBDirectory::SetTo(const BDirectory* dir, const char* path)
18652a38012Sejakowatz{
187db10640dSIngo Weinhold	if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) {
188db10640dSIngo Weinhold		Unset();
189db10640dSIngo Weinhold		return (fCStatus = B_BAD_VALUE);
190db10640dSIngo Weinhold	}
191b06942c6SIngo Weinhold
1923e54c13aSAxel Dörfler	int dirFD = dir->fDirFd;
1933e54c13aSAxel Dörfler	if (dir == this) {
1943e54c13aSAxel Dörfler		// prevent that our file descriptor goes away in _SetTo()
1953e54c13aSAxel Dörfler		fDirFd = -1;
1963e54c13aSAxel Dörfler	}
1973e54c13aSAxel Dörfler
198db10640dSIngo Weinhold	// open node
1993e54c13aSAxel Dörfler	status_t error = _SetTo(dirFD, path, true);
200db10640dSIngo Weinhold	if (error != B_OK)
201db10640dSIngo Weinhold		return error;
202b06942c6SIngo Weinhold
203db10640dSIngo Weinhold	// open dir
2043e54c13aSAxel Dörfler	fDirFd = _kern_open_dir(dirFD, path);
205db10640dSIngo Weinhold	if (fDirFd < 0) {
206db10640dSIngo Weinhold		status_t error = fDirFd;
207db10640dSIngo Weinhold		Unset();
208db10640dSIngo Weinhold		return (fCStatus = error);
209db10640dSIngo Weinhold	}
210b06942c6SIngo Weinhold
2113e54c13aSAxel Dörfler	if (dir == this) {
2123e54c13aSAxel Dörfler		// cleanup after _SetTo()
2136a8e3decSStephan Aßmus		_kern_close(dirFD);
2143e54c13aSAxel Dörfler	}
2153e54c13aSAxel Dörfler
216b06942c6SIngo Weinhold	// set close on exec flag on dir FD
217b06942c6SIngo Weinhold	fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
218b06942c6SIngo Weinhold
219db10640dSIngo Weinhold	return B_OK;
22052a38012Sejakowatz}
22152a38012Sejakowatz
22243209917SAxel Dörfler
22352a38012Sejakowatzstatus_t
224160f2d10SAxel DörflerBDirectory::GetEntry(BEntry* entry) const
22552a38012Sejakowatz{
226db10640dSIngo Weinhold	if (!entry)
227db10640dSIngo Weinhold		return B_BAD_VALUE;
228db10640dSIngo Weinhold	if (InitCheck() != B_OK)
229db10640dSIngo Weinhold		return B_NO_INIT;
230db10640dSIngo Weinhold	return entry->SetTo(this, ".", false);
23152a38012Sejakowatz}
23252a38012Sejakowatz
23343209917SAxel Dörfler
23452a38012Sejakowatzbool
23552a38012SejakowatzBDirectory::IsRootDirectory() const
23652a38012Sejakowatz{
23752a38012Sejakowatz	// compare the directory's node ID with the ID of the root node of the FS
23852a38012Sejakowatz	bool result = false;
23952a38012Sejakowatz	node_ref ref;
24052a38012Sejakowatz	fs_info info;
24152a38012Sejakowatz	if (GetNodeRef(&ref) == B_OK && fs_stat_dev(ref.device, &info) == 0)
24252a38012Sejakowatz		result = (ref.node == info.root);
24352a38012Sejakowatz	return result;
24452a38012Sejakowatz}
24552a38012Sejakowatz
24643209917SAxel Dörfler
24752a38012Sejakowatzstatus_t
248160f2d10SAxel DörflerBDirectory::FindEntry(const char* path, BEntry* entry, bool traverse) const
24952a38012Sejakowatz{
250160f2d10SAxel Dörfler	if (path == NULL || entry == NULL)
251160f2d10SAxel Dörfler		return B_BAD_VALUE;
252160f2d10SAxel Dörfler
253160f2d10SAxel Dörfler	entry->Unset();
254160f2d10SAxel Dörfler
255160f2d10SAxel Dörfler	// init a potentially abstract entry
256160f2d10SAxel Dörfler	status_t status;
257160f2d10SAxel Dörfler	if (InitCheck() == B_OK)
258160f2d10SAxel Dörfler		status = entry->SetTo(this, path, traverse);
259160f2d10SAxel Dörfler	else
260160f2d10SAxel Dörfler		status = entry->SetTo(path, traverse);
261160f2d10SAxel Dörfler
262160f2d10SAxel Dörfler	// fail, if entry is abstract
263160f2d10SAxel Dörfler	if (status == B_OK && !entry->Exists()) {
264160f2d10SAxel Dörfler		status = B_ENTRY_NOT_FOUND;
26552a38012Sejakowatz		entry->Unset();
26652a38012Sejakowatz	}
267160f2d10SAxel Dörfler
268160f2d10SAxel Dörfler	return status;
26952a38012Sejakowatz}
27052a38012Sejakowatz
27143209917SAxel Dörfler
27252a38012Sejakowatzbool
273160f2d10SAxel DörflerBDirectory::Contains(const char* path, int32 nodeFlags) const
27452a38012Sejakowatz{
2755abde301SIngo Weinhold	// check initialization and parameters
2765abde301SIngo Weinhold	if (InitCheck() != B_OK)
2775abde301SIngo Weinhold		return false;
2785abde301SIngo Weinhold	if (!path)
2795abde301SIngo Weinhold		return true;	// mimic R5 behavior
280d8de23cdSAxel Dörfler
2815abde301SIngo Weinhold	// turn the path into a BEntry and let the other version do the work
2825abde301SIngo Weinhold	BEntry entry;
2835abde301SIngo Weinhold	if (BPrivate::Storage::is_absolute_path(path))
2845abde301SIngo Weinhold		entry.SetTo(path);
2855abde301SIngo Weinhold	else
2865abde301SIngo Weinhold		entry.SetTo(this, path);
287d8de23cdSAxel Dörfler
2885abde301SIngo Weinhold	return Contains(&entry, nodeFlags);
28952a38012Sejakowatz}
29052a38012Sejakowatz
29143209917SAxel Dörfler
29252a38012Sejakowatzbool
293160f2d10SAxel DörflerBDirectory::Contains(const BEntry* entry, int32 nodeFlags) const
29452a38012Sejakowatz{
29552a38012Sejakowatz	// check, if the entry exists at all
296d8de23cdSAxel Dörfler	if (entry == NULL || !entry->Exists() || InitCheck() != B_OK)
297d8de23cdSAxel Dörfler		return false;
298d8de23cdSAxel Dörfler
299872c3d3fSAxel Dörfler	if (nodeFlags != B_ANY_NODE) {
300872c3d3fSAxel Dörfler		// test the node kind
301872c3d3fSAxel Dörfler		bool result = false;
302872c3d3fSAxel Dörfler		if ((nodeFlags & B_FILE_NODE) != 0)
303d8de23cdSAxel Dörfler			result = entry->IsFile();
304872c3d3fSAxel Dörfler		if (!result && (nodeFlags & B_DIRECTORY_NODE) != 0)
305d8de23cdSAxel Dörfler			result = entry->IsDirectory();
306872c3d3fSAxel Dörfler		if (!result && (nodeFlags & B_SYMLINK_NODE) != 0)
307d8de23cdSAxel Dörfler			result = entry->IsSymLink();
308872c3d3fSAxel Dörfler		if (!result)
309872c3d3fSAxel Dörfler			return false;
31052a38012Sejakowatz	}
311d8de23cdSAxel Dörfler
31252a38012Sejakowatz	// If the directory is initialized, get the canonical paths of the dir and
31352a38012Sejakowatz	// the entry and check, if the latter is a prefix of the first one.
314872c3d3fSAxel Dörfler	BPath dirPath(this, ".", true);
315872c3d3fSAxel Dörfler	BPath entryPath(entry);
316e84abff2SMichael Lotz	if (dirPath.InitCheck() != B_OK || entryPath.InitCheck() != B_OK)
317872c3d3fSAxel Dörfler		return false;
318d8de23cdSAxel Dörfler
3196020e8a4SRene Gollent	uint32 dirLen = strlen(dirPath.Path());
320bcfe344cSIngo Weinhold
3216020e8a4SRene Gollent	if (!strncmp(dirPath.Path(), entryPath.Path(), dirLen)) {
32291da3218SRene Gollent		// if the paths are identical, return a match to stay consistent with
32391da3218SRene Gollent		// BeOS behavior.
32491da3218SRene Gollent		if (entryPath.Path()[dirLen] == '\0' || entryPath.Path()[dirLen] == '/')
3256020e8a4SRene Gollent			return true;
3266020e8a4SRene Gollent	}
3276020e8a4SRene Gollent	return false;
32852a38012Sejakowatz}
32952a38012Sejakowatz
330872c3d3fSAxel Dörfler
33152a38012Sejakowatzstatus_t
332160f2d10SAxel DörflerBDirectory::GetNextEntry(BEntry* entry, bool traverse)
33352a38012Sejakowatz{
334901de869SAugustin Cavalier	if (entry == NULL)
335901de869SAugustin Cavalier		return B_BAD_VALUE;
336901de869SAugustin Cavalier
337901de869SAugustin Cavalier	entry_ref ref;
338901de869SAugustin Cavalier	status_t status = GetNextRef(&ref);
339901de869SAugustin Cavalier	if (status != B_OK) {
34026d14a31SAugustin Cavalier		entry->Unset();
341901de869SAugustin Cavalier		return status;
342901de869SAugustin Cavalier	}
343901de869SAugustin Cavalier	return entry->SetTo(&ref, traverse);
34452a38012Sejakowatz}
34552a38012Sejakowatz
34643209917SAxel Dörfler
34752a38012Sejakowatzstatus_t
348160f2d10SAxel DörflerBDirectory::GetNextRef(entry_ref* ref)
34952a38012Sejakowatz{
350901de869SAugustin Cavalier	if (ref == NULL)
351901de869SAugustin Cavalier		return B_BAD_VALUE;
352901de869SAugustin Cavalier	if (InitCheck() != B_OK)
353901de869SAugustin Cavalier		return B_FILE_ERROR;
354901de869SAugustin Cavalier
355901de869SAugustin Cavalier	BPrivate::Storage::LongDirEntry entry;
356901de869SAugustin Cavalier	bool next = true;
357901de869SAugustin Cavalier	while (next) {
358901de869SAugustin Cavalier		if (GetNextDirents(&entry, sizeof(entry), 1) != 1)
359901de869SAugustin Cavalier			return B_ENTRY_NOT_FOUND;
360901de869SAugustin Cavalier
361901de869SAugustin Cavalier		next = (!strcmp(entry.d_name, ".")
362901de869SAugustin Cavalier			|| !strcmp(entry.d_name, ".."));
36352a38012Sejakowatz	}
364901de869SAugustin Cavalier
365901de869SAugustin Cavalier	ref->device = entry.d_pdev;
366901de869SAugustin Cavalier	ref->directory = entry.d_pino;
367901de869SAugustin Cavalier	return ref->set_name(entry.d_name);
36852a38012Sejakowatz}
36952a38012Sejakowatz
37043209917SAxel Dörfler
37152a38012Sejakowatzint32
372160f2d10SAxel DörflerBDirectory::GetNextDirents(dirent* buf, size_t bufSize, int32 count)
37352a38012Sejakowatz{
374901de869SAugustin Cavalier	if (buf == NULL)
375db10640dSIngo Weinhold		return B_BAD_VALUE;
376db10640dSIngo Weinhold	if (InitCheck() != B_OK)
377db10640dSIngo Weinhold		return B_FILE_ERROR;
378db10640dSIngo Weinhold	return _kern_read_dir(fDirFd, buf, bufSize, count);
37952a38012Sejakowatz}
38052a38012Sejakowatz
38143209917SAxel Dörfler
38252a38012Sejakowatzstatus_t
38352a38012SejakowatzBDirectory::Rewind()
38452a38012Sejakowatz{
385db10640dSIngo Weinhold	if (InitCheck() != B_OK)
386db10640dSIngo Weinhold		return B_FILE_ERROR;
387db10640dSIngo Weinhold	return _kern_rewind_dir(fDirFd);
38852a38012Sejakowatz}
38952a38012Sejakowatz
39043209917SAxel Dörfler
39152a38012Sejakowatzint32
39252a38012SejakowatzBDirectory::CountEntries()
39352a38012Sejakowatz{
39452a38012Sejakowatz	status_t error = Rewind();
395db10640dSIngo Weinhold	if (error != B_OK)
396db10640dSIngo Weinhold		return error;
39752a38012Sejakowatz	int32 count = 0;
398db10640dSIngo Weinhold	BPrivate::Storage::LongDirEntry entry;
399db10640dSIngo Weinhold	while (error == B_OK) {
400db10640dSIngo Weinhold		if (GetNextDirents(&entry, sizeof(entry), 1) != 1)
401db10640dSIngo Weinhold			break;
402db10640dSIngo Weinhold		if (strcmp(entry.d_name, ".") != 0 && strcmp(entry.d_name, "..") != 0)
403db10640dSIngo Weinhold			count++;
40452a38012Sejakowatz	}
40552a38012Sejakowatz	Rewind();
40652a38012Sejakowatz	return (error == B_OK ? count : error);
40752a38012Sejakowatz}
40852a38012Sejakowatz
40943209917SAxel Dörfler
41052a38012Sejakowatzstatus_t
411160f2d10SAxel DörflerBDirectory::CreateDirectory(const char* path, BDirectory* dir)
41252a38012Sejakowatz{
413db10640dSIngo Weinhold	if (!path)
414db10640dSIngo Weinhold		return B_BAD_VALUE;
41543209917SAxel Dörfler
416db10640dSIngo Weinhold	// create the dir
417db10640dSIngo Weinhold	status_t error = _kern_create_dir(fDirFd, path,
41843209917SAxel Dörfler		(S_IRWXU | S_IRWXG | S_IRWXO) & ~__gUmask);
419db10640dSIngo Weinhold	if (error != B_OK)
420db10640dSIngo Weinhold		return error;
42143209917SAxel Dörfler
42243209917SAxel Dörfler	if (dir == NULL)
423db10640dSIngo Weinhold		return B_OK;
42443209917SAxel Dörfler
425db10640dSIngo Weinhold	// init the supplied BDirectory
426db10640dSIngo Weinhold	if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path))
427db10640dSIngo Weinhold		return dir->SetTo(path);
42843209917SAxel Dörfler
42943209917SAxel Dörfler	return dir->SetTo(this, path);
43052a38012Sejakowatz}
43152a38012Sejakowatz
43243209917SAxel Dörfler
43352a38012Sejakowatzstatus_t
434160f2d10SAxel DörflerBDirectory::CreateFile(const char* path, BFile* file, bool failIfExists)
43552a38012Sejakowatz{
436db10640dSIngo Weinhold	if (!path)
437db10640dSIngo Weinhold		return B_BAD_VALUE;
438160f2d10SAxel Dörfler
439db10640dSIngo Weinhold	// Let BFile do the dirty job.
4402586d10eSIngo Weinhold	uint32 openMode = B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE
4412586d10eSIngo Weinhold		| (failIfExists ? B_FAIL_IF_EXISTS : 0);
442db10640dSIngo Weinhold	BFile tmpFile;
443160f2d10SAxel Dörfler	BFile* realFile = file ? file : &tmpFile;
444db10640dSIngo Weinhold	status_t error = B_OK;
445db10640dSIngo Weinhold	if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path))
446db10640dSIngo Weinhold		error = realFile->SetTo(this, path, openMode);
447db10640dSIngo Weinhold	else
448db10640dSIngo Weinhold		error = realFile->SetTo(path, openMode);
449db10640dSIngo Weinhold	if (error != B_OK && file) // mimic R5 behavior
450db10640dSIngo Weinhold		file->Unset();
45152a38012Sejakowatz	return error;
45252a38012Sejakowatz}
45352a38012Sejakowatz
45443209917SAxel Dörfler
45552a38012Sejakowatzstatus_t
456160f2d10SAxel DörflerBDirectory::CreateSymLink(const char* path, const char* linkToPath,
457160f2d10SAxel Dörfler	BSymLink* link)
45852a38012Sejakowatz{
459db10640dSIngo Weinhold	if (!path || !linkToPath)
460db10640dSIngo Weinhold		return B_BAD_VALUE;
46143209917SAxel Dörfler
462db10640dSIngo Weinhold	// create the symlink
463db10640dSIngo Weinhold	status_t error = _kern_create_symlink(fDirFd, path, linkToPath,
46443209917SAxel Dörfler		(S_IRWXU | S_IRWXG | S_IRWXO) & ~__gUmask);
465db10640dSIngo Weinhold	if (error != B_OK)
466db10640dSIngo Weinhold		return error;
46743209917SAxel Dörfler
46843209917SAxel Dörfler	if (link == NULL)
469db10640dSIngo Weinhold		return B_OK;
47043209917SAxel Dörfler
471db10640dSIngo Weinhold	// init the supplied BSymLink
472db10640dSIngo Weinhold	if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path))
473db10640dSIngo Weinhold		return link->SetTo(path);
47443209917SAxel Dörfler
47543209917SAxel Dörfler	return link->SetTo(this, path);
47652a38012Sejakowatz}
47752a38012Sejakowatz
47843209917SAxel Dörfler
479160f2d10SAxel DörflerBDirectory&
480160f2d10SAxel DörflerBDirectory::operator=(const BDirectory& dir)
48152a38012Sejakowatz{
48252a38012Sejakowatz	if (&dir != this) {	// no need to assign us to ourselves
48352a38012Sejakowatz		Unset();
484db10640dSIngo Weinhold		if (dir.InitCheck() == B_OK)
485db10640dSIngo Weinhold			SetTo(&dir, ".");
48652a38012Sejakowatz	}
48752a38012Sejakowatz	return *this;
48852a38012Sejakowatz}
48952a38012Sejakowatz
49052a38012Sejakowatz
491bcfe344cSIngo Weinholdstatus_t
492160f2d10SAxel DörflerBDirectory::_GetStatFor(const char* path, struct stat* st) const
493bcfe344cSIngo Weinhold{
494bcfe344cSIngo Weinhold	if (!st)
495bcfe344cSIngo Weinhold		return B_BAD_VALUE;
496bcfe344cSIngo Weinhold	if (InitCheck() != B_OK)
497bcfe344cSIngo Weinhold		return B_NO_INIT;
498bcfe344cSIngo Weinhold
499bcfe344cSIngo Weinhold	if (path != NULL) {
500bcfe344cSIngo Weinhold		if (path[0] == '\0')
501bcfe344cSIngo Weinhold			return B_ENTRY_NOT_FOUND;
502bcfe344cSIngo Weinhold		return _kern_read_stat(fDirFd, path, false, st, sizeof(struct stat));
503bcfe344cSIngo Weinhold	}
504bcfe344cSIngo Weinhold	return GetStat(st);
505bcfe344cSIngo Weinhold}
506bcfe344cSIngo Weinhold
507bcfe344cSIngo Weinhold
508bcfe344cSIngo Weinholdstatus_t
509160f2d10SAxel DörflerBDirectory::_GetStatFor(const char* path, struct stat_beos* st) const
510bcfe344cSIngo Weinhold{
511bcfe344cSIngo Weinhold	struct stat newStat;
512bcfe344cSIngo Weinhold	status_t error = _GetStatFor(path, &newStat);
513bcfe344cSIngo Weinhold	if (error != B_OK)
514bcfe344cSIngo Weinhold		return error;
515bcfe344cSIngo Weinhold
516bcfe344cSIngo Weinhold	convert_to_stat_beos(&newStat, st);
517bcfe344cSIngo Weinhold	return B_OK;
518bcfe344cSIngo Weinhold}
519bcfe344cSIngo Weinhold
520bcfe344cSIngo Weinhold
52152a38012Sejakowatz// FBC
5227c44680aSIngo Weinholdvoid BDirectory::_ErectorDirectory1() {}
5237c44680aSIngo Weinholdvoid BDirectory::_ErectorDirectory2() {}
5247c44680aSIngo Weinholdvoid BDirectory::_ErectorDirectory3() {}
5257c44680aSIngo Weinholdvoid BDirectory::_ErectorDirectory4() {}
5267c44680aSIngo Weinholdvoid BDirectory::_ErectorDirectory5() {}
5277c44680aSIngo Weinholdvoid BDirectory::_ErectorDirectory6() {}
52852a38012Sejakowatz
52943209917SAxel Dörfler
53052a38012Sejakowatz//! Closes the BDirectory's file descriptor.
53152a38012Sejakowatzvoid
53252a38012SejakowatzBDirectory::close_fd()
53352a38012Sejakowatz{
534db10640dSIngo Weinhold	if (fDirFd >= 0) {
535db10640dSIngo Weinhold		_kern_close(fDirFd);
536db10640dSIngo Weinhold		fDirFd = -1;
53752a38012Sejakowatz	}
53852a38012Sejakowatz	BNode::close_fd();
53952a38012Sejakowatz}
54052a38012Sejakowatz
54143209917SAxel Dörfler
542db10640dSIngo Weinholdint
54352a38012SejakowatzBDirectory::get_fd() const
54452a38012Sejakowatz{
54552a38012Sejakowatz	return fDirFd;
54652a38012Sejakowatz}
54752a38012Sejakowatz
54852a38012Sejakowatz
54943209917SAxel Dörfler//	#pragma mark - C functions
55043209917SAxel Dörfler
55152a38012Sejakowatz
5522ac1eb67SJohn Scipione// TODO: Check this method for efficiency.
55352a38012Sejakowatzstatus_t
554160f2d10SAxel Dörflercreate_directory(const char* path, mode_t mode)
55552a38012Sejakowatz{
556db10640dSIngo Weinhold	if (!path)
557db10640dSIngo Weinhold		return B_BAD_VALUE;
558160f2d10SAxel Dörfler
55952a38012Sejakowatz	// That's the strategy: We start with the first component of the supplied
56052a38012Sejakowatz	// path, create a BPath object from it and successively add the following
56152a38012Sejakowatz	// components. Each time we get a new path, we check, if the entry it
562db10640dSIngo Weinhold	// refers to exists and is a directory. If it doesn't exist, we try
56352a38012Sejakowatz	// to create it. This goes on, until we're done with the input path or
56452a38012Sejakowatz	// an error occurs.
565db10640dSIngo Weinhold	BPath dirPath;
566160f2d10SAxel Dörfler	char* component;
567db10640dSIngo Weinhold	int32 nextComponent;
568db10640dSIngo Weinhold	do {
569db10640dSIngo Weinhold		// get the next path component
570db10640dSIngo Weinhold		status_t error = BPrivate::Storage::parse_first_path_component(path,
571db10640dSIngo Weinhold			component, nextComponent);
572db10640dSIngo Weinhold		if (error != B_OK)
573db10640dSIngo Weinhold			return error;
574160f2d10SAxel Dörfler
575db10640dSIngo Weinhold		// append it to the BPath
576db10640dSIngo Weinhold		if (dirPath.InitCheck() == B_NO_INIT)	// first component
577db10640dSIngo Weinhold			error = dirPath.SetTo(component);
578db10640dSIngo Weinhold		else
579db10640dSIngo Weinhold			error = dirPath.Append(component);
580db10640dSIngo Weinhold		delete[] component;
581db10640dSIngo Weinhold		if (error != B_OK)
582db10640dSIngo Weinhold			return error;
583db10640dSIngo Weinhold		path += nextComponent;
584160f2d10SAxel Dörfler
585db10640dSIngo Weinhold		// create a BEntry from the BPath
586db10640dSIngo Weinhold		BEntry entry;
587db10640dSIngo Weinhold		error = entry.SetTo(dirPath.Path(), true);
588db10640dSIngo Weinhold		if (error != B_OK)
589db10640dSIngo Weinhold			return error;
590160f2d10SAxel Dörfler
591db10640dSIngo Weinhold		// check, if it exists
592db10640dSIngo Weinhold		if (entry.Exists()) {
593db10640dSIngo Weinhold			// yep, it exists
594db10640dSIngo Weinhold			if (!entry.IsDirectory())	// but is no directory
595db10640dSIngo Weinhold				return B_NOT_A_DIRECTORY;
596db10640dSIngo Weinhold		} else {
597db10640dSIngo Weinhold			// it doesn't exist -- create it
5980bb8521bSAxel Dörfler			error = _kern_create_dir(-1, dirPath.Path(), mode & ~__gUmask);
599db10640dSIngo Weinhold			if (error != B_OK)
600db10640dSIngo Weinhold				return error;
601db10640dSIngo Weinhold		}
602db10640dSIngo Weinhold	} while (nextComponent != 0);
603db10640dSIngo Weinhold	return B_OK;
60452a38012Sejakowatz}
60552a38012Sejakowatz
606bcfe344cSIngo Weinhold
607bcfe344cSIngo Weinhold// #pragma mark - symbol versions
608bcfe344cSIngo Weinhold
609bcfe344cSIngo Weinhold
6102c69b5b6SAxel Dörfler#ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST
61123f83f8cSStephan Aßmus#	if __GNUC__ == 2	// gcc 2
6122c69b5b6SAxel Dörfler
61323f83f8cSStephan Aßmus	B_DEFINE_SYMBOL_VERSION("_GetStatFor__C10BDirectoryPCcP4stat",
61423f83f8cSStephan Aßmus		"GetStatFor__C10BDirectoryPCcP4stat@@LIBBE_TEST");
6152c69b5b6SAxel Dörfler
61623f83f8cSStephan Aßmus#	else	// gcc 4
617bcfe344cSIngo Weinhold
61823f83f8cSStephan Aßmus	B_DEFINE_SYMBOL_VERSION("_ZNK10BDirectory11_GetStatForEPKcP4stat",
61923f83f8cSStephan Aßmus		"_ZNK10BDirectory10GetStatForEPKcP4stat@@LIBBE_TEST");
620bcfe344cSIngo Weinhold
62123f83f8cSStephan Aßmus#	endif	// gcc 4
62223f83f8cSStephan Aßmus#else	// !HAIKU_TARGET_PLATFORM_LIBBE_TEST
62323f83f8cSStephan Aßmus#	if __GNUC__ == 2	// gcc 2
624bcfe344cSIngo Weinhold
62523f83f8cSStephan Aßmus	// BeOS compatible GetStatFor()
62623f83f8cSStephan Aßmus	B_DEFINE_SYMBOL_VERSION("_GetStatFor__C10BDirectoryPCcP9stat_beos",
62723f83f8cSStephan Aßmus		"GetStatFor__C10BDirectoryPCcP4stat@LIBBE_BASE");
628bcfe344cSIngo Weinhold
62923f83f8cSStephan Aßmus	// Haiku GetStatFor()
63023f83f8cSStephan Aßmus	B_DEFINE_SYMBOL_VERSION("_GetStatFor__C10BDirectoryPCcP4stat",
63123f83f8cSStephan Aßmus		"GetStatFor__C10BDirectoryPCcP4stat@@LIBBE_1_ALPHA1");
632bcfe344cSIngo Weinhold
63323f83f8cSStephan Aßmus#	else	// gcc 4
634bcfe344cSIngo Weinhold
63523f83f8cSStephan Aßmus	// BeOS compatible GetStatFor()
63623f83f8cSStephan Aßmus	B_DEFINE_SYMBOL_VERSION("_ZNK10BDirectory11_GetStatForEPKcP9stat_beos",
63723f83f8cSStephan Aßmus		"_ZNK10BDirectory10GetStatForEPKcP4stat@LIBBE_BASE");
63823f83f8cSStephan Aßmus
63923f83f8cSStephan Aßmus	// Haiku GetStatFor()
64023f83f8cSStephan Aßmus	B_DEFINE_SYMBOL_VERSION("_ZNK10BDirectory11_GetStatForEPKcP4stat",
64123f83f8cSStephan Aßmus		"_ZNK10BDirectory10GetStatForEPKcP4stat@@LIBBE_1_ALPHA1");
64223f83f8cSStephan Aßmus
64323f83f8cSStephan Aßmus#	endif	// gcc 4
64423f83f8cSStephan Aßmus#endif	// !HAIKU_TARGET_PLATFORM_LIBBE_TEST
645