libbe_build: Synchronize Directory.cpp with the main one.

The set_dir_fd code appears to be libbe_build specific, so that
and accompanying logic is preserved.
This commit is contained in:
Augustin Cavalier
2021-11-18 12:13:47 -05:00
parent 28c8a16a5a
commit ec21dc91b1
2 changed files with 283 additions and 654 deletions
+9 -25
View File
@@ -1,15 +1,11 @@
//---------------------------------------------------------------------- /*
// This software is part of the Haiku distribution and is covered * Copyright 2002-2006, Haiku, Inc. All Rights Reserved.
// by the MIT License. * Distributed under the terms of the MIT License.
//---------------------------------------------------------------------
/*!
\file Directory.h
BDirectory interface declaration.
*/ */
#ifndef _DIRECTORY_H #ifndef _DIRECTORY_H
#define _DIRECTORY_H #define _DIRECTORY_H
#include <Node.h> #include <Node.h>
#include <EntryList.h> #include <EntryList.h>
#include <StorageDefs.h> #include <StorageDefs.h>
@@ -17,18 +13,9 @@
class BFile; class BFile;
class BSymLink; class BSymLink;
struct stat_beos;
/*!
\class BDirectory
\brief A directory in the filesystem
Provides an interface for manipulating directories and their contents.
\author <a href='mailto:[email protected]'>Ingo Weinhold</a>
\author <a href="mailto:[email protected]">Tyler Dauwalder</a>
\version 0.0.0
*/
class BDirectory : public BNode, public BEntryList { class BDirectory : public BNode, public BEntryList {
public: public:
BDirectory(); BDirectory();
@@ -49,6 +36,8 @@ public:
status_t GetEntry(BEntry *entry) const; status_t GetEntry(BEntry *entry) const;
bool IsRootDirectory() const;
status_t FindEntry(const char *path, BEntry *entry, status_t FindEntry(const char *path, BEntry *entry,
bool traverse = false) const; bool traverse = false) const;
@@ -74,6 +63,8 @@ public:
private: private:
friend class BNode; friend class BNode;
friend class BEntry;
friend class BFile;
virtual void _ErectorDirectory1(); virtual void _ErectorDirectory1();
virtual void _ErectorDirectory2(); virtual void _ErectorDirectory2();
@@ -92,15 +83,8 @@ private:
uint32 _reservedData[7]; uint32 _reservedData[7];
int fDirFd; int fDirFd;
node_ref fDirNodeRef; node_ref fDirNodeRef;
friend class BEntry;
friend class BFile;
}; };
// C functions
status_t create_directory(const char *path, mode_t mode); status_t create_directory(const char *path, mode_t mode);
#endif // _DIRECTORY_H #endif // _DIRECTORY_H
+165 -520
View File
@@ -1,15 +1,21 @@
//---------------------------------------------------------------------- /*
// This software is part of the Haiku distribution and is covered * Copyright 2002-2009, Haiku Inc.
// by the MIT License. * Distributed under the terms of the MIT License.
//--------------------------------------------------------------------- *
/*! * Authors:
\file Directory.cpp * Tyler Dauwalder
BDirectory implementation. * Ingo Weinhold, [email protected]
* Axel Dörfler, [email protected]
*/ */
#include "storage_support.h"
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
#include <compat/sys/stat.h>
#include <Directory.h> #include <Directory.h>
#include <Entry.h> #include <Entry.h>
#include <File.h> #include <File.h>
@@ -19,105 +25,62 @@
#include <syscalls.h> #include <syscalls.h>
#include "storage_support.h"
#ifdef USE_OPENBEOS_NAMESPACE
namespace OpenBeOS {
#endif
// constructor
//! Creates an uninitialized BDirectory object.
BDirectory::BDirectory() BDirectory::BDirectory()
: BNode(), :
BEntryList(),
fDirFd(-1) fDirFd(-1)
{ {
} }
// copy constructor
//! Creates a copy of the supplied BDirectory.
/*! \param dir the BDirectory object to be copied
*/
BDirectory::BDirectory(const BDirectory& dir) BDirectory::BDirectory(const BDirectory& dir)
: BNode(), :
BEntryList(),
fDirFd(-1) fDirFd(-1)
{ {
*this = dir; *this = dir;
} }
// constructor
/*! \brief Creates a BDirectory and initializes it to the directory referred
to by the supplied entry_ref.
\param ref the entry_ref referring to the directory
*/
BDirectory::BDirectory(const entry_ref* ref) BDirectory::BDirectory(const entry_ref* ref)
: BNode(), :
BEntryList(),
fDirFd(-1) fDirFd(-1)
{ {
SetTo(ref); SetTo(ref);
} }
// constructor
/*! \brief Creates a BDirectory and initializes it to the directory referred
to by the supplied node_ref.
\param nref the node_ref referring to the directory
*/
BDirectory::BDirectory(const node_ref* nref) BDirectory::BDirectory(const node_ref* nref)
: BNode(), :
BEntryList(),
fDirFd(-1) fDirFd(-1)
{ {
SetTo(nref); SetTo(nref);
} }
// constructor
/*! \brief Creates a BDirectory and initializes it to the directory referred
to by the supplied BEntry.
\param entry the BEntry referring to the directory
*/
BDirectory::BDirectory(const BEntry* entry) BDirectory::BDirectory(const BEntry* entry)
: BNode(), :
BEntryList(),
fDirFd(-1) fDirFd(-1)
{ {
SetTo(entry); SetTo(entry);
} }
// constructor
/*! \brief Creates a BDirectory and initializes it to the directory referred
to by the supplied path name.
\param path the directory's path name
*/
BDirectory::BDirectory(const char* path) BDirectory::BDirectory(const char* path)
: BNode(), :
BEntryList(),
fDirFd(-1) fDirFd(-1)
{ {
SetTo(path); SetTo(path);
} }
// constructor
/*! \brief Creates a BDirectory and initializes it to the directory referred
to by the supplied path name relative to the specified BDirectory.
\param dir the BDirectory, relative to which the directory's path name is
given
\param path the directory's path name relative to \a dir
*/
BDirectory::BDirectory(const BDirectory* dir, const char* path) BDirectory::BDirectory(const BDirectory* dir, const char* path)
: BNode(), :
BEntryList(),
fDirFd(-1) fDirFd(-1)
{ {
SetTo(dir, path); SetTo(dir, path);
} }
// destructor
//! Frees all allocated resources.
/*! If the BDirectory is properly initialized, the directory's file descriptor
is closed.
*/
BDirectory::~BDirectory() BDirectory::~BDirectory()
{ {
// Also called by the BNode destructor, but we rather try to avoid // Also called by the BNode destructor, but we rather try to avoid
@@ -128,21 +91,7 @@ BDirectory::~BDirectory()
close_fd(); close_fd();
} }
// SetTo
/*! \brief Re-initializes the BDirectory to the directory referred to by the
supplied entry_ref.
\param ref the entry_ref referring to the directory
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a ref.
- \c B_ENTRY_NOT_FOUND: Directory not found.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
*/
status_t status_t
BDirectory::SetTo(const entry_ref* ref) BDirectory::SetTo(const entry_ref* ref)
{ {
@@ -164,21 +113,7 @@ BDirectory::SetTo(const entry_ref *ref)
return B_OK; return B_OK;
} }
// SetTo
/*! \brief Re-initializes the BDirectory to the directory referred to by the
supplied node_ref.
\param nref the node_ref referring to the directory
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a nref.
- \c B_ENTRY_NOT_FOUND: Directory not found.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
*/
status_t status_t
BDirectory::SetTo(const node_ref* nref) BDirectory::SetTo(const node_ref* nref)
{ {
@@ -192,21 +127,7 @@ BDirectory::SetTo(const node_ref *nref)
return error; return error;
} }
// SetTo
/*! \brief Re-initializes the BDirectory to the directory referred to by the
supplied BEntry.
\param entry the BEntry referring to the directory
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a entry.
- \c B_ENTRY_NOT_FOUND: Directory not found.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
*/
status_t status_t
BDirectory::SetTo(const BEntry* entry) BDirectory::SetTo(const BEntry* entry)
{ {
@@ -233,23 +154,7 @@ BDirectory::SetTo(const BEntry *entry)
return B_OK; return B_OK;
} }
// SetTo
/*! \brief Re-initializes the BDirectory to the directory referred to by the
supplied path name.
\param path the directory's path name
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a path.
- \c B_ENTRY_NOT_FOUND: Directory not found.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
*/
status_t status_t
BDirectory::SetTo(const char* path) BDirectory::SetTo(const char* path)
{ {
@@ -271,25 +176,7 @@ BDirectory::SetTo(const char *path)
return B_OK; return B_OK;
} }
// SetTo
/*! \brief Re-initializes the BDirectory to the directory referred to by the
supplied path name relative to the specified BDirectory.
\param dir the BDirectory, relative to which the directory's path name is
given
\param path the directory's path name relative to \a dir
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a dir or \a path, or \a path is absolute.
- \c B_ENTRY_NOT_FOUND: Directory not found.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
*/
status_t status_t
BDirectory::SetTo(const BDirectory* dir, const char* path) BDirectory::SetTo(const BDirectory* dir, const char* path)
{ {
@@ -298,8 +185,14 @@ BDirectory::SetTo(const BDirectory *dir, const char *path)
return (fCStatus = B_BAD_VALUE); return (fCStatus = B_BAD_VALUE);
} }
int dirFD = dir->fDirFd;
if (dir == this) {
// prevent that our file descriptor goes away in _SetTo()
fDirFd = -1;
}
// open node // open node
status_t error = _SetTo(dir->fDirFd, path, true); status_t error = _SetTo(dirFD, path, true);
if (error != B_OK) if (error != B_OK)
return error; return error;
@@ -310,28 +203,18 @@ BDirectory::SetTo(const BDirectory *dir, const char *path)
return (fCStatus = error); return (fCStatus = error);
} }
if (dir == this) {
// cleanup after _SetTo()
_kern_close(dirFD);
}
// set close on exec flag on dir FD // set close on exec flag on dir FD
fcntl(fDirFd, F_SETFD, FD_CLOEXEC); fcntl(fDirFd, F_SETFD, FD_CLOEXEC);
return B_OK; return B_OK;
} }
// GetEntry
//! Returns a BEntry referring to the directory represented by this object.
/*! If the initialization of \a entry fails, it is Unset().
\param entry a pointer to the entry that shall be set to refer to the
directory
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a entry.
- \c B_ENTRY_NOT_FOUND: Directory not found.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
*/
status_t status_t
BDirectory::GetEntry(BEntry* entry) const BDirectory::GetEntry(BEntry* entry) const
{ {
@@ -342,81 +225,45 @@ BDirectory::GetEntry(BEntry *entry) const
return entry->SetTo(this, ".", false); return entry->SetTo(this, ".", false);
} }
// FindEntry
/*! \brief Finds an entry referred to by a path relative to the directory bool
represented by this BDirectory. BDirectory::IsRootDirectory() const
\a path may be absolute. If the BDirectory is not properly initialized, {
the entry is search relative to the current directory. // compare the directory's node ID with the ID of the root node of the FS
If the entry couldn't be found, \a entry is Unset(). bool result = false;
\param path the entry's path name. May be relative to this directory or node_ref ref;
absolute. fs_info info;
\param entry a pointer to a BEntry to be initialized with the found entry if (GetNodeRef(&ref) == B_OK && fs_stat_dev(ref.device, &info) == 0)
\param traverse specifies whether to follow it, if the found entry result = (ref.node == info.root);
is a symbolic link. return result;
\return }
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a path or \a entry.
- \c B_ENTRY_NOT_FOUND: Entry not found.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
\note The functionality of this method differs from the one of
BEntry::SetTo(BDirectory *, const char *, bool) in that the
latter doesn't require the entry to be existent, whereas this
function does.
*/
status_t status_t
BDirectory::FindEntry(const char* path, BEntry* entry, bool traverse) const BDirectory::FindEntry(const char* path, BEntry* entry, bool traverse) const
{ {
status_t error = (path && entry ? B_OK : B_BAD_VALUE); if (path == NULL || entry == NULL)
if (entry) return B_BAD_VALUE;
entry->Unset(); entry->Unset();
if (error == B_OK) {
// init a potentially abstract entry // init a potentially abstract entry
status_t status;
if (InitCheck() == B_OK) if (InitCheck() == B_OK)
error = entry->SetTo(this, path, traverse); status = entry->SetTo(this, path, traverse);
else else
error = entry->SetTo(path, traverse); status = entry->SetTo(path, traverse);
// fail, if entry is abstract // fail, if entry is abstract
if (error == B_OK && !entry->Exists()) { if (status == B_OK && !entry->Exists()) {
error = B_ENTRY_NOT_FOUND; status = B_ENTRY_NOT_FOUND;
entry->Unset(); entry->Unset();
} }
}
return error; return status;
} }
// Contains
/*! \brief Returns whether this directory or any of its subdirectories
at any level contain the entry referred to by the supplied path name.
Only entries that match the node flavor specified by \a nodeFlags are
considered.
If the BDirectory is not properly initialized, the method returns \c false.
A non-absolute path is considered relative to the current directory.
\note R5's implementation always returns \c true given an absolute path or
an unitialized directory. This implementation is not compatible with that
behavior. Instead it converts the path into a BEntry and passes it to the
other version of Contains().
\param path the entry's path name. May be relative to this directory or
absolute.
\param nodeFlags Any of the following:
- \c B_FILE_NODE: The entry must be a file.
- \c B_DIRECTORY_NODE: The entry must be a directory.
- \c B_SYMLINK_NODE: The entry must be a symbolic link.
- \c B_ANY_NODE: The entry may be of any kind.
\return
- \c true, if the entry exists, its kind does match \nodeFlags and the
BDirectory is properly initialized and does contain the entry at any
level,
- \c false, otherwise
*/
bool bool
BDirectory::Contains(const char* path, int32 nodeFlags) const BDirectory::Contains(const char* path, int32 nodeFlags) const
{ {
@@ -425,228 +272,108 @@ BDirectory::Contains(const char *path, int32 nodeFlags) const
return false; return false;
if (!path) if (!path)
return true; // mimic R5 behavior return true; // mimic R5 behavior
// turn the path into a BEntry and let the other version do the work // turn the path into a BEntry and let the other version do the work
BEntry entry; BEntry entry;
if (BPrivate::Storage::is_absolute_path(path)) if (BPrivate::Storage::is_absolute_path(path))
entry.SetTo(path); entry.SetTo(path);
else else
entry.SetTo(this, path); entry.SetTo(this, path);
return Contains(&entry, nodeFlags); return Contains(&entry, nodeFlags);
} }
// Contains
/*! \brief Returns whether this directory or any of its subdirectories
at any level contain the entry referred to by the supplied BEntry.
Only entries that match the node flavor specified by \a nodeFlags are
considered.
\param entry a BEntry referring to the entry
\param nodeFlags Any of the following:
- \c B_FILE_NODE: The entry must be a file.
- \c B_DIRECTORY_NODE: The entry must be a directory.
- \c B_SYMLINK_NODE: The entry must be a symbolic link.
- \c B_ANY_NODE: The entry may be of any kind.
\return
- \c true, if the BDirectory is properly initialized and the entry of the
matching kind could be found,
- \c false, otherwise
*/
bool bool
BDirectory::Contains(const BEntry* entry, int32 nodeFlags) const BDirectory::Contains(const BEntry* entry, int32 nodeFlags) const
{ {
bool result = (entry);
// check, if the entry exists at all // check, if the entry exists at all
if (result) if (entry == NULL || !entry->Exists() || InitCheck() != B_OK)
result = entry->Exists(); return false;
if (nodeFlags != B_ANY_NODE) {
// test the node kind // test the node kind
if (result) { bool result = false;
switch (nodeFlags) { if ((nodeFlags & B_FILE_NODE) != 0)
case B_FILE_NODE:
result = entry->IsFile(); result = entry->IsFile();
break; if (!result && (nodeFlags & B_DIRECTORY_NODE) != 0)
case B_DIRECTORY_NODE:
result = entry->IsDirectory(); result = entry->IsDirectory();
break; if (!result && (nodeFlags & B_SYMLINK_NODE) != 0)
case B_SYMLINK_NODE:
result = entry->IsSymLink(); result = entry->IsSymLink();
break; if (!result)
case B_ANY_NODE: return false;
break;
default:
result = false;
break;
}
} }
// If the directory is initialized, get the canonical paths of the dir and // If the directory is initialized, get the canonical paths of the dir and
// the entry and check, if the latter is a prefix of the first one. // the entry and check, if the latter is a prefix of the first one.
if (result && InitCheck() == B_OK) {
BPath dirPath(this, ".", true); BPath dirPath(this, ".", true);
BPath entryPath(entry); BPath entryPath(entry);
if (dirPath.InitCheck() == B_OK && entryPath.InitCheck() == B_OK) { if (dirPath.InitCheck() != B_OK || entryPath.InitCheck() != B_OK)
result = !strncmp(dirPath.Path(), entryPath.Path(), return false;
strlen(dirPath.Path()));
} else uint32 dirLen = strlen(dirPath.Path());
result = false;
if (!strncmp(dirPath.Path(), entryPath.Path(), dirLen)) {
// if the paths are identical, return a match to stay consistent with
// BeOS behavior.
if (entryPath.Path()[dirLen] == '\0' || entryPath.Path()[dirLen] == '/')
return true;
} }
return result; return false;
} }
// GetStatFor
/*! \brief Returns the stat structure of the entry referred to by the supplied
path name.
\param path the entry's path name. May be relative to this directory or
absolute, or \c NULL to get the directories stat info.
\param st a pointer to the stat structure to be filled in by this function
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a st.
- \c B_ENTRY_NOT_FOUND: Entry not found.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
*/
status_t
BDirectory::GetStatFor(const char *path, struct stat *st) const
{
if (!st)
return B_BAD_VALUE;
if (InitCheck() != B_OK)
return B_NO_INIT;
status_t error = B_OK;
if (path) {
if (strlen(path) == 0)
return B_ENTRY_NOT_FOUND;
error = _kern_read_stat(fDirFd, path, false, st, sizeof(struct stat));
} else
error = GetStat(st);
return error;
}
// GetNextEntry
//! Returns the BDirectory's next entry as a BEntry.
/*! Unlike GetNextDirents() this method ignores the entries "." and "..".
\param entry a pointer to a BEntry to be initialized to the found entry
\param traverse specifies whether to follow it, if the found entry
is a symbolic link.
\note The iterator used by this method is the same one used by
GetNextRef(), GetNextDirents(), Rewind() and CountEntries().
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a entry.
- \c B_ENTRY_NOT_FOUND: No more entries found.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
*/
status_t status_t
BDirectory::GetNextEntry(BEntry* entry, bool traverse) BDirectory::GetNextEntry(BEntry* entry, bool traverse)
{ {
status_t error = (entry ? B_OK : B_BAD_VALUE); if (entry == NULL)
if (error == B_OK) { return B_BAD_VALUE;
entry_ref ref; entry_ref ref;
error = GetNextRef(&ref); status_t status = GetNextRef(&ref);
if (error == B_OK) if (status != B_OK) {
error = entry->SetTo(&ref, traverse); entry->Unset();
return status;
} }
return error; return entry->SetTo(&ref, traverse);
} }
// GetNextRef
//! Returns the BDirectory's next entry as an entry_ref.
/*! Unlike GetNextDirents() this method ignores the entries "." and "..".
\param ref a pointer to an entry_ref to be filled in with the data of the
found entry
\param traverse specifies whether to follow it, if the found entry
is a symbolic link.
\note The iterator used be this method is the same one used by
GetNextEntry(), GetNextDirents(), Rewind() and CountEntries().
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a ref.
- \c B_ENTRY_NOT_FOUND: No more entries found.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
*/
status_t status_t
BDirectory::GetNextRef(entry_ref* ref) BDirectory::GetNextRef(entry_ref* ref)
{ {
status_t error = (ref ? B_OK : B_BAD_VALUE); if (ref == NULL)
if (error == B_OK && InitCheck() != B_OK) return B_BAD_VALUE;
error = B_FILE_ERROR; if (InitCheck() != B_OK)
if (error == B_OK) { return B_FILE_ERROR;
BPrivate::Storage::LongDirEntry entry; BPrivate::Storage::LongDirEntry entry;
bool next = true; bool next = true;
while (error == B_OK && next) { while (next) {
if (GetNextDirents(&entry, sizeof(entry), 1) != 1) { if (GetNextDirents(&entry, sizeof(entry), 1) != 1)
error = B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
} else {
next = (!strcmp(entry.d_name, ".") next = (!strcmp(entry.d_name, ".")
|| !strcmp(entry.d_name, "..")); || !strcmp(entry.d_name, ".."));
} }
}
if (error == B_OK) {
ref->device = fDirNodeRef.device; ref->device = fDirNodeRef.device;
ref->directory = fDirNodeRef.node; ref->directory = fDirNodeRef.node;
error = ref->set_name(entry.d_name); return ref->set_name(entry.d_name);
}
}
return error;
} }
// GetNextDirents
//! Returns the BDirectory's next entries as dirent structures.
/*! Unlike GetNextEntry() and GetNextRef(), this method returns also
the entries "." and "..".
\param buf a pointer to a buffer to be filled with dirent structures of
the found entries
\param count the maximal number of entries to be returned.
\note The iterator used by this method is the same one used by
GetNextEntry(), GetNextRef(), Rewind() and CountEntries().
\return
- The number of dirent structures stored in the buffer, 0 when there are
no more entries to be returned.
- \c B_BAD_VALUE: \c NULL \a buf.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_NAME_TOO_LONG: The entry's name is too long for the buffer.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
*/
int32 int32
BDirectory::GetNextDirents(dirent* buf, size_t bufSize, int32 count) BDirectory::GetNextDirents(dirent* buf, size_t bufSize, int32 count)
{ {
if (!buf) if (buf == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
if (InitCheck() != B_OK) if (InitCheck() != B_OK)
return B_FILE_ERROR; return B_FILE_ERROR;
return _kern_read_dir(fDirFd, buf, bufSize, count); return _kern_read_dir(fDirFd, buf, bufSize, count);
} }
// Rewind
//! Rewinds the directory iterator.
/*! \return
- \c B_OK: Everything went fine.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
\see GetNextEntry(), GetNextRef(), GetNextDirents(), CountEntries()
*/
status_t status_t
BDirectory::Rewind() BDirectory::Rewind()
{ {
@@ -655,21 +382,7 @@ BDirectory::Rewind()
return _kern_rewind_dir(fDirFd); return _kern_rewind_dir(fDirFd);
} }
// CountEntries
//! Returns the number of entries in this directory.
/*! CountEntries() uses the directory iterator also used by GetNextEntry(),
GetNextRef() and GetNextDirents(). It does a Rewind(), iterates through
the entries and Rewind()s again. The entries "." and ".." are not counted.
\return
- the number of entries in the directory (not counting "." and "..").
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
\see GetNextEntry(), GetNextRef(), GetNextDirents(), Rewind()
*/
int32 int32
BDirectory::CountEntries() BDirectory::CountEntries()
{ {
@@ -688,81 +401,41 @@ BDirectory::CountEntries()
return (error == B_OK ? count : error); return (error == B_OK ? count : error);
} }
// CreateDirectory
//! Creates a new directory.
/*! If an entry with the supplied name does already exist, the method fails.
\param path the new directory's path name. May be relative to this
directory or absolute.
\param dir a pointer to a BDirectory to be initialized to the newly
created directory. May be \c NULL.
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a path.
- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_FILE_EXISTS: An entry with that name does already exist.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
*/
status_t status_t
BDirectory::CreateDirectory(const char* path, BDirectory* dir) BDirectory::CreateDirectory(const char* path, BDirectory* dir)
{ {
if (!path) if (!path)
return B_BAD_VALUE; return B_BAD_VALUE;
// create the dir // create the dir
status_t error = _kern_create_dir(fDirFd, path, status_t error = _kern_create_dir(fDirFd, path,
S_IRWXU | S_IRWXG | S_IRWXU); (S_IRWXU | S_IRWXG | S_IRWXO));
if (error != B_OK) if (error != B_OK)
return error; return error;
if (!dir)
if (dir == NULL)
return B_OK; return B_OK;
// init the supplied BDirectory // init the supplied BDirectory
if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path)) if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path))
return dir->SetTo(path); return dir->SetTo(path);
else
return dir->SetTo(this, path); return dir->SetTo(this, path);
} }
// CreateFile
//! Creates a new file.
/*! If a file with the supplied name does already exist, the method fails,
unless it is passed \c false to \a failIfExists -- in that case the file
is truncated to zero size. The new BFile will operate in \c B_READ_WRITE
mode.
\param path the new file's path name. May be relative to this
directory or absolute.
\param file a pointer to a BFile to be initialized to the newly
created file. May be \c NULL.
\param failIfExists \c true, if the method should fail when the file
already exists, \c false otherwise
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a path.
- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_FILE_EXISTS: A file with that name does already exist and
\c true has been passed for \a failIfExists.
- \c B_IS_A_DIRECTORY: A directory with the supplied name does already
exist.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
*/
status_t status_t
BDirectory::CreateFile(const char* path, BFile* file, bool failIfExists) BDirectory::CreateFile(const char* path, BFile* file, bool failIfExists)
{ {
if (!path) if (!path)
return B_BAD_VALUE; return B_BAD_VALUE;
// Let BFile do the dirty job. // Let BFile do the dirty job.
uint32 openMode = B_READ_WRITE | B_CREATE_FILE uint32 openMode = B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE
| (failIfExists ? B_FAIL_IF_EXISTS : 0); | (failIfExists ? B_FAIL_IF_EXISTS : 0);
BFile tmpFile; BFile tmpFile;
BFile *realFile = (file ? file : &tmpFile); BFile* realFile = file ? file : &tmpFile;
status_t error = B_OK; status_t error = B_OK;
if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path)) if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path))
error = realFile->SetTo(this, path, openMode); error = realFile->SetTo(this, path, openMode);
@@ -773,53 +446,31 @@ BDirectory::CreateFile(const char *path, BFile *file, bool failIfExists)
return error; return error;
} }
// CreateSymLink
//! Creates a new symbolic link.
/*! If an entry with the supplied name does already exist, the method fails.
\param path the new symbolic link's path name. May be relative to this
directory or absolute.
\param linkToPath the path the symbolic link shall point to.
\param dir a pointer to a BSymLink to be initialized to the newly
created symbolic link. May be \c NULL.
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a path or \a linkToPath.
- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_FILE_EXISTS: An entry with that name does already exist.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
*/
status_t status_t
BDirectory::CreateSymLink(const char* path, const char* linkToPath, BDirectory::CreateSymLink(const char* path, const char* linkToPath,
BSymLink* link) BSymLink* link)
{ {
if (!path || !linkToPath) if (!path || !linkToPath)
return B_BAD_VALUE; return B_BAD_VALUE;
// create the symlink // create the symlink
status_t error = _kern_create_symlink(fDirFd, path, linkToPath, status_t error = _kern_create_symlink(fDirFd, path, linkToPath,
S_IRWXU | S_IRWXG | S_IRWXU); (S_IRWXU | S_IRWXG | S_IRWXO));
if (error != B_OK) if (error != B_OK)
return error; return error;
if (!link)
if (link == NULL)
return B_OK; return B_OK;
// init the supplied BSymLink // init the supplied BSymLink
if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path)) if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path))
return link->SetTo(path); return link->SetTo(path);
else
return link->SetTo(this, path); return link->SetTo(this, path);
} }
// =
//! Assigns another BDirectory to this BDirectory.
/*! If the other BDirectory is uninitialized, this one wi'll be too. Otherwise
it will refer to the same directory, unless an error occurs.
\param dir the original BDirectory
\return a reference to this BDirectory
*/
BDirectory& BDirectory&
BDirectory::operator=(const BDirectory& dir) BDirectory::operator=(const BDirectory& dir)
{ {
@@ -832,6 +483,23 @@ BDirectory::operator=(const BDirectory &dir)
} }
status_t
BDirectory::GetStatFor(const char* path, struct stat* st) const
{
if (!st)
return B_BAD_VALUE;
if (InitCheck() != B_OK)
return B_NO_INIT;
if (path != NULL) {
if (path[0] == '\0')
return B_ENTRY_NOT_FOUND;
return _kern_read_stat(fDirFd, path, false, st, sizeof(struct stat));
}
return GetStat(st);
}
// FBC // FBC
void BDirectory::_ErectorDirectory1() {} void BDirectory::_ErectorDirectory1() {}
void BDirectory::_ErectorDirectory2() {} void BDirectory::_ErectorDirectory2() {}
@@ -840,7 +508,7 @@ void BDirectory::_ErectorDirectory4() {}
void BDirectory::_ErectorDirectory5() {} void BDirectory::_ErectorDirectory5() {}
void BDirectory::_ErectorDirectory6() {} void BDirectory::_ErectorDirectory6() {}
// close_fd
//! Closes the BDirectory's file descriptor. //! Closes the BDirectory's file descriptor.
void void
BDirectory::close_fd() BDirectory::close_fd()
@@ -852,17 +520,14 @@ BDirectory::close_fd()
BNode::close_fd(); BNode::close_fd();
} }
//! Returns the BDirectory's file descriptor.
/*! To be used instead of accessing the BDirectory's private \c fDirFd member
directly.
\return the file descriptor, or -1, if not properly initialized.
*/
int int
BDirectory::get_fd() const BDirectory::get_fd() const
{ {
return fDirFd; return fDirFd;
} }
status_t status_t
BDirectory::set_dir_fd(int fd) BDirectory::set_dir_fd(int fd)
{ {
@@ -879,33 +544,16 @@ BDirectory::set_dir_fd(int fd)
} }
// #pragma mark - C functions
// C functions
// create_directory // TODO: Check this method for efficiency.
//! Creates all missing directories along a given path.
/*! \param path the directory path name.
\param mode a permission specification, which shall be used for the
newly created directories.
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a path.
- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
- \c B_NO_MEMORY: Insufficient memory for operation.
- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
- \c B_BUSY: A node was busy.
- \c B_FILE_ERROR: A general file error.
- \c B_NOT_A_DIRECTORY: An entry other than a directory with that name does
already exist.
- \c B_NO_MORE_FDS: The application has run out of file descriptors.
\todo Check for efficency.
*/
status_t status_t
create_directory(const char* path, mode_t mode) create_directory(const char* path, mode_t mode)
{ {
if (!path) if (!path)
return B_BAD_VALUE; return B_BAD_VALUE;
// That's the strategy: We start with the first component of the supplied // That's the strategy: We start with the first component of the supplied
// path, create a BPath object from it and successively add the following // path, create a BPath object from it and successively add the following
// components. Each time we get a new path, we check, if the entry it // components. Each time we get a new path, we check, if the entry it
@@ -921,6 +569,7 @@ create_directory(const char *path, mode_t mode)
component, nextComponent); component, nextComponent);
if (error != B_OK) if (error != B_OK)
return error; return error;
// append it to the BPath // append it to the BPath
if (dirPath.InitCheck() == B_NO_INIT) // first component if (dirPath.InitCheck() == B_NO_INIT) // first component
error = dirPath.SetTo(component); error = dirPath.SetTo(component);
@@ -930,11 +579,13 @@ create_directory(const char *path, mode_t mode)
if (error != B_OK) if (error != B_OK)
return error; return error;
path += nextComponent; path += nextComponent;
// create a BEntry from the BPath // create a BEntry from the BPath
BEntry entry; BEntry entry;
error = entry.SetTo(dirPath.Path(), true); error = entry.SetTo(dirPath.Path(), true);
if (error != B_OK) if (error != B_OK)
return error; return error;
// check, if it exists // check, if it exists
if (entry.Exists()) { if (entry.Exists()) {
// yep, it exists // yep, it exists
@@ -949,9 +600,3 @@ create_directory(const char *path, mode_t mode)
} while (nextComponent != 0); } while (nextComponent != 0);
return B_OK; return B_OK;
} }
#ifdef USE_OPENBEOS_NAMESPACE
}; // namespace OpenBeOS
#endif