From db10640de90f7f9519ba2da9577b7c1af3c64f6b Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 28 Aug 2004 20:14:46 +0000 Subject: [PATCH] Got rid of the Storage Kit's kernel abstraction layer, which was unfortunately quite slow and made some things more complicated than they needed to be. Implemented a few missing things (e.g. BSymLink and node locking). git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8694 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/storage/Directory.h | 7 +- headers/os/storage/Entry.h | 17 +- headers/os/storage/File.h | 2 +- headers/os/storage/Node.h | 10 +- headers/os/storage/Query.h | 6 +- headers/os/storage/SymLink.h | 24 +- headers/private/storage/storage_support.h | 54 ++ src/kits/storage/AppFileInfo.cpp | 11 + src/kits/storage/Directory.cpp | 439 ++++++-------- src/kits/storage/Entry.cpp | 637 +++++++++---------- src/kits/storage/File.cpp | 203 +++---- src/kits/storage/LibBeAdapter.cpp | 672 ++++++++++++++++++++- src/kits/storage/Node.cpp | 285 +++++---- src/kits/storage/Path.cpp | 31 +- src/kits/storage/Query.cpp | 94 +-- src/kits/storage/ResourceStrings.cpp | 11 +- src/kits/storage/Statable.cpp | 1 - src/kits/storage/SymLink.cpp | 164 +---- src/kits/storage/Volume.cpp | 53 +- src/kits/storage/VolumeRoster.cpp | 1 - src/kits/storage/mime/AssociatedTypes.cpp | 10 +- src/kits/storage/mime/MimeUpdateThread.cpp | 6 +- src/kits/storage/storage.src | 2 - src/kits/storage/storage_support.cpp | 119 +++- src/servers/registrar/RecentEntries.cpp | 9 +- 25 files changed, 1731 insertions(+), 1137 deletions(-) diff --git a/headers/os/storage/Directory.h b/headers/os/storage/Directory.h index 628ddc4e1c..4a89247d7c 100644 --- a/headers/os/storage/Directory.h +++ b/headers/os/storage/Directory.h @@ -78,6 +78,8 @@ public: BDirectory &operator=(const BDirectory &dir); private: + friend class BNode; + virtual void _ErectorDirectory1(); virtual void _ErectorDirectory2(); virtual void _ErectorDirectory3(); @@ -87,13 +89,14 @@ private: private: virtual void close_fd(); - BPrivate::Storage::FileDescriptor get_fd() const; + int get_fd() const; private: uint32 _reservedData[7]; - BPrivate::Storage::FileDescriptor fDirFd; + int fDirFd; friend class BEntry; + friend class BFile; }; diff --git a/headers/os/storage/Entry.h b/headers/os/storage/Entry.h index b8aad31fd9..58a1208ad0 100644 --- a/headers/os/storage/Entry.h +++ b/headers/os/storage/Entry.h @@ -14,7 +14,6 @@ #include #include -#include #ifdef USE_OPENBEOS_NAMESPACE namespace OpenBeOS { @@ -77,6 +76,11 @@ public: BEntry &operator=(const BEntry &item); private: + friend class BDirectory; + friend class BFile; + friend class BNode; + friend class BSymLink; + virtual void _PennyEntry1(); virtual void _PennyEntry2(); virtual void _PennyEntry3(); @@ -90,11 +94,10 @@ private: /*! BEntry implementation of BStatable::set_stat() */ virtual status_t set_stat(struct stat &st, uint32 what); - status_t set(BPrivate::Storage::FileDescriptor dir, const char *path, - bool traverse); + status_t set(int dir, const char *path, bool traverse); /*! File descriptor for the entry's parent directory. */ - BPrivate::Storage::FileDescriptor fDirFd; + int fDirFd; /*! Leaf name of the entry. */ char *fName; @@ -104,6 +107,8 @@ private: status_t set_name(const char *name); + status_t _Rename(BEntry& target, bool clobber); + void Dump(const char *name = NULL); }; @@ -118,7 +123,3 @@ bool operator<(const entry_ref &a, const entry_ref &b); #endif #endif // _ENTRY_H - - - - diff --git a/headers/os/storage/File.h b/headers/os/storage/File.h index f0d470182d..f9c7f187bd 100644 --- a/headers/os/storage/File.h +++ b/headers/os/storage/File.h @@ -71,7 +71,7 @@ private: uint32 _reservedData[8]; private: - BPrivate::Storage::FileDescriptor get_fd() const; + int get_fd() const; private: //! The file's open mode. diff --git a/headers/os/storage/Node.h b/headers/os/storage/Node.h index b34b54c915..91f533a015 100644 --- a/headers/os/storage/Node.h +++ b/headers/os/storage/Node.h @@ -11,7 +11,6 @@ #define _NODE_H #include -#include #ifdef USE_OPENBEOS_NAMESPACE namespace OpenBeOS { @@ -115,14 +114,17 @@ private: uint32 rudeData[4]; private: - status_t set_fd(BPrivate::Storage::FileDescriptor fd); + status_t set_fd(int fd); virtual void close_fd(); void set_status(status_t newStatus); + status_t _SetTo(int fd, const char *path, bool traverse); + status_t _SetTo(const entry_ref *ref, bool traverse); + virtual status_t set_stat(struct stat &st, uint32 what); - BPrivate::Storage::FileDescriptor fFd; - BPrivate::Storage::FileDescriptor fAttrFd; + int fFd; + int fAttrFd; status_t fCStatus; status_t InitAttrDir(); diff --git a/headers/os/storage/Query.h b/headers/os/storage/Query.h index bad607399d..1bf5888d64 100644 --- a/headers/os/storage/Query.h +++ b/headers/os/storage/Query.h @@ -15,8 +15,6 @@ #include #include -#include - class BVolume; struct entry_ref; @@ -119,9 +117,7 @@ private: bool fLive; port_id fPort; long fToken; - BPrivate::Storage::FileDescriptor fQueryFd; + int fQueryFd; }; #endif // _QUERY_H - - diff --git a/headers/os/storage/SymLink.h b/headers/os/storage/SymLink.h index 09cb14b648..6d00925982 100644 --- a/headers/os/storage/SymLink.h +++ b/headers/os/storage/SymLink.h @@ -39,15 +39,6 @@ public: BSymLink(const BDirectory *dir, const char *path); virtual ~BSymLink(); - // WORKAROUND - // SetTo() methods: Part of a work around until someone has an idea how to - // get BPrivate::Storage::read_link(FileDescriptor,...) to work. - status_t SetTo(const entry_ref *ref); - status_t SetTo(const BEntry *entry); - status_t SetTo(const char *path); - status_t SetTo(const BDirectory *dir, const char *path); - void Unset(); - ssize_t ReadLink(char *buf, size_t size); ssize_t MakeLinkedPath(const char *dirPath, BPath *path); @@ -55,11 +46,6 @@ public: bool IsAbsolute(); - // WORKAROUND - // operator=(): Part of a work around until someone has an idea how to - // get BPrivate::Storage::read_link(FileDescriptor,...) to work. - BSymLink &operator=(const BSymLink &link); - private: virtual void _MissingSymLink1(); virtual void _MissingSymLink2(); @@ -68,15 +54,11 @@ private: virtual void _MissingSymLink5(); virtual void _MissingSymLink6(); - // WORKAROUND - // fSecretEntry: Part of a work around until someone has an idea how to - // get BPrivate::Storage::read_link(FileDescriptor,...) to work. -// uint32 _reservedData[4]; - uint32 _reservedData[3]; + uint32 _reservedData[4]; BEntry *fSecretEntry; private: - BPrivate::Storage::FileDescriptor get_fd() const; + int get_fd() const; }; #ifdef USE_OPENBEOS_NAMESPACE @@ -84,5 +66,3 @@ private: #endif #endif // _SYM_LINK_H - - diff --git a/headers/private/storage/storage_support.h b/headers/private/storage/storage_support.h index befc6763cd..d8a1c3e350 100644 --- a/headers/private/storage/storage_support.h +++ b/headers/private/storage/storage_support.h @@ -11,14 +11,22 @@ #ifndef _STORAGE_SUPPORT_H #define _STORAGE_SUPPORT_H +#include #include namespace BPrivate { namespace Storage { +// For convenience: +struct LongDirEntry : dirent { char _buffer[B_FILE_NAME_LENGTH]; }; + //! Returns whether the supplied path is absolute. bool is_absolute_path(const char *path); +status_t parse_path(const char *fullPath, int &dirEnd, int &leafStart, + int &leafEnd); +status_t parse_path(const char *fullPath, char *dirPath, char *leaf); + //! splits a path name into directory path and leaf name status_t split_path(const char *fullPath, char *&path, char *&leaf); @@ -84,9 +92,55 @@ void escape_path(const char *str, char *result); */ void escape_path(char *str); +/*! \brief Returns whether the supplied device ID refers to the root FS. +*/ +bool device_is_root_device(dev_t device); + +// FDCloser +class FDCloser { +public: + FDCloser(int fd) + : fFD(fd) + { + } + + ~FDCloser() + { + Close(); + } + + void SetTo(int fd) + { + Close(); + fFD = fd; + } + +// implemented in the source file to not expose syscalls to the unit tests +// which include this file too + void Close(); +// void Close() +// { +// if (fFD >= 0) +// _kern_close(fFD); +// fFD = -1; +// } + + int Detach() + { + int fd = fFD; + fFD = -1; + return fd; + } + +private: + int fFD; +}; + }; // namespace Storage }; // namespace BPrivate +using BPrivate::Storage::FDCloser; + #endif // _STORAGE_SUPPORT_H diff --git a/src/kits/storage/AppFileInfo.cpp b/src/kits/storage/AppFileInfo.cpp index d555b44752..6b4e253bd5 100644 --- a/src/kits/storage/AppFileInfo.cpp +++ b/src/kits/storage/AppFileInfo.cpp @@ -427,6 +427,7 @@ BAppFileInfo::GetSupportedTypes(BMessage *types) const - \c B_NO_INIT: The object is not properly initialized. - other error codes */ +#include status_t BAppFileInfo::SetSupportedTypes(const BMessage *types, bool syncAll) { @@ -434,19 +435,23 @@ BAppFileInfo::SetSupportedTypes(const BMessage *types, bool syncAll) status_t error = B_OK; if (error == B_OK && InitCheck() != B_OK) error = B_NO_INIT; +printf("check\n"); BMimeType mimeType; if (error == B_OK) error = GetMetaMime(&mimeType); +printf("check\n"); if (error == B_OK) { if (types) { // check param -- supported types must be valid const char *type; +printf("check1\n"); for (int32 i = 0; error == B_OK && types->FindString("types", i, &type) == B_OK; i++) { if (!BMimeType::IsValid(type)) error = B_BAD_VALUE; } +printf("check1\n"); // get flattened size ssize_t size = 0; if (error == B_OK) { @@ -454,6 +459,7 @@ BAppFileInfo::SetSupportedTypes(const BMessage *types, bool syncAll) if (size < 0) error = size; } +printf("check1\n"); // allocate a buffer for the flattened data char *buffer = NULL; if (error == B_OK) { @@ -461,23 +467,28 @@ BAppFileInfo::SetSupportedTypes(const BMessage *types, bool syncAll) if (!buffer) error = B_NO_MEMORY; } +printf("check1\n"); // flatten the message if (error == B_OK) error = types->Flatten(buffer, size); +printf("check1\n"); // write the data if (error == B_OK) { error = _WriteData(kSupportedTypesAttribute, kSupportedTypesResourceID, B_MESSAGE_TYPE, buffer, size); } +printf("check1\n"); // clean up if (buffer) delete[] buffer; } else error = _RemoveData(kSupportedTypesAttribute, B_MESSAGE_TYPE); +printf("check\n"); // update the MIME database, if the app signature is installed if (error == B_OK && mimeType.IsInstalled()) error = mimeType.SetSupportedTypes(types, syncAll); +printf("check\n"); } return error; } diff --git a/src/kits/storage/Directory.cpp b/src/kits/storage/Directory.cpp index 84e1d5ef5a..34c7f52ee2 100644 --- a/src/kits/storage/Directory.cpp +++ b/src/kits/storage/Directory.cpp @@ -15,8 +15,10 @@ #include #include #include + +#include + #include "storage_support.h" -#include "kernel_interface.h" #ifdef USE_OPENBEOS_NAMESPACE namespace OpenBeOS { @@ -27,7 +29,7 @@ namespace OpenBeOS { BDirectory::BDirectory() : BNode(), BEntryList(), - fDirFd(BPrivate::Storage::NullFd) + fDirFd(-1) { } @@ -38,7 +40,7 @@ BDirectory::BDirectory() BDirectory::BDirectory(const BDirectory &dir) : BNode(), BEntryList(), - fDirFd(BPrivate::Storage::NullFd) + fDirFd(-1) { *this = dir; } @@ -51,7 +53,7 @@ BDirectory::BDirectory(const BDirectory &dir) BDirectory::BDirectory(const entry_ref *ref) : BNode(), BEntryList(), - fDirFd(BPrivate::Storage::NullFd) + fDirFd(-1) { SetTo(ref); } @@ -64,7 +66,7 @@ BDirectory::BDirectory(const entry_ref *ref) BDirectory::BDirectory(const node_ref *nref) : BNode(), BEntryList(), - fDirFd(BPrivate::Storage::NullFd) + fDirFd(-1) { SetTo(nref); } @@ -77,7 +79,7 @@ BDirectory::BDirectory(const node_ref *nref) BDirectory::BDirectory(const BEntry *entry) : BNode(), BEntryList(), - fDirFd(BPrivate::Storage::NullFd) + fDirFd(-1) { SetTo(entry); } @@ -90,7 +92,7 @@ BDirectory::BDirectory(const BEntry *entry) BDirectory::BDirectory(const char *path) : BNode(), BEntryList(), - fDirFd(BPrivate::Storage::NullFd) + fDirFd(-1) { SetTo(path); } @@ -105,7 +107,7 @@ BDirectory::BDirectory(const char *path) BDirectory::BDirectory(const BDirectory *dir, const char *path) : BNode(), BEntryList(), - fDirFd(BPrivate::Storage::NullFd) + fDirFd(-1) { SetTo(dir, path); } @@ -139,23 +141,22 @@ BDirectory::~BDirectory() - \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. - \todo Currently implemented using BPrivate::Storage::entry_ref_to_path(). - Reimplement! */ status_t BDirectory::SetTo(const entry_ref *ref) { - Unset(); - char path[B_PATH_NAME_LENGTH]; - status_t error = (ref ? B_OK : B_BAD_VALUE); - if (error == B_OK) { - error = BPrivate::Storage::entry_ref_to_path(ref, path, - B_PATH_NAME_LENGTH); + // open node + status_t error = _SetTo(ref, true); + if (error != B_OK) + return error; + // open dir + fDirFd = _kern_open_dir_entry_ref(ref->device, ref->directory, ref->name); + if (fDirFd < 0) { + status_t error = fDirFd; + Unset(); + return (fCStatus = error); } - if (error == B_OK) - error = SetTo(path); - set_status(error); - return error; + return B_OK; } // SetTo @@ -200,23 +201,26 @@ BDirectory::SetTo(const node_ref *nref) - \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. - \todo Implemented using SetTo(entry_ref*). Check, if necessary to - reimplement! */ status_t BDirectory::SetTo(const BEntry *entry) { - Unset(); - entry_ref ref; - status_t error = (entry ? B_OK : B_BAD_VALUE); - if (error == B_OK && entry->InitCheck() != B_OK) - error = B_BAD_VALUE; - if (error == B_OK) - error = entry->GetRef(&ref); - if (error == B_OK) - error = SetTo(&ref); - set_status(error); - return error; + if (!entry) { + Unset(); + return (fCStatus = B_BAD_VALUE); + } + // open node + status_t error = _SetTo(entry->fDirFd, entry->fName, true); + if (error != B_OK) + return error; + // open dir + fDirFd = _kern_open_dir(entry->fDirFd, entry->fName); + if (fDirFd < 0) { + status_t error = fDirFd; + Unset(); + return (fCStatus = error); + } + return B_OK; } // SetTo @@ -239,30 +243,18 @@ BDirectory::SetTo(const BEntry *entry) status_t BDirectory::SetTo(const char *path) { - Unset(); - status_t result = (path ? B_OK : B_BAD_VALUE); - BPrivate::Storage::FileDescriptor newDirFd = BPrivate::Storage::NullFd; - if (result == B_OK) - result = BPrivate::Storage::open_dir(path, newDirFd); - if (result == B_OK) { - // We have to take care that BNode doesn't stick to a symbolic link. - // open_dir() does always traverse those. Therefore we open the FD for - // BNode (without the O_NOTRAVERSE flag). - BPrivate::Storage::FileDescriptor fd = BPrivate::Storage::NullFd; - result = BPrivate::Storage::open(path, O_RDWR, fd, true); - if (result == B_OK) { - result = set_fd(fd); - if (result != B_OK) - BPrivate::Storage::close(fd); - } - if (result == B_OK) - fDirFd = newDirFd; - else - BPrivate::Storage::close_dir(newDirFd); + // open node + status_t error = _SetTo(-1, path, true); + if (error != B_OK) + return error; + // open dir + fDirFd = _kern_open_dir(-1, path); + if (fDirFd < 0) { + status_t error = fDirFd; + Unset(); + return (fCStatus = error); } - // finally set the BNode status - set_status(result); - return result; + return B_OK; } // SetTo @@ -283,22 +275,26 @@ BDirectory::SetTo(const char *path) - \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. - \todo Implemented using SetTo(BEntry*). Check, if necessary to reimplement! */ status_t BDirectory::SetTo(const BDirectory *dir, const char *path) { - Unset(); - status_t error = (dir && path ? B_OK : B_BAD_VALUE); - if (error == B_OK && BPrivate::Storage::is_absolute_path(path)) - error = B_BAD_VALUE; - BEntry entry; - if (error == B_OK) - error = entry.SetTo(dir, path); - if (error == B_OK) - error = SetTo(&entry); - set_status(error); - return error; + if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) { + Unset(); + return (fCStatus = B_BAD_VALUE); + } + // open node + status_t error = _SetTo(dir->fDirFd, path, true); + if (error != B_OK) + return error; + // open dir + fDirFd = _kern_open_dir(dir->fDirFd, path); + if (fDirFd < 0) { + status_t error = fDirFd; + Unset(); + return (fCStatus = error); + } + return B_OK; } // GetEntry @@ -316,23 +312,15 @@ BDirectory::SetTo(const BDirectory *dir, const char *path) - \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. - \todo Implemented using BPrivate::Storage::dir_to_self_entry_ref(). Check, if - there is a better alternative. */ status_t BDirectory::GetEntry(BEntry *entry) const { - status_t error = (entry ? B_OK : B_BAD_VALUE); - if (entry) - entry->Unset(); - if (error == B_OK && InitCheck() != B_OK) - error = B_NO_INIT; - entry_ref ref; - if (error == B_OK) - error = BPrivate::Storage::dir_to_self_entry_ref(fDirFd, &ref); - if (error == B_OK) - error = entry->SetTo(&ref); - return error; + if (!entry) + return B_BAD_VALUE; + if (InitCheck() != B_OK) + return B_NO_INIT; + return entry->SetTo(this, ".", false); } // IsRootDirectory @@ -492,20 +480,13 @@ BDirectory::Contains(const BEntry *entry, int32 nodeFlags) const // 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. if (result && InitCheck() == B_OK) { - char dirPath[B_PATH_NAME_LENGTH]; - char entryPath[B_PATH_NAME_LENGTH]; - result = (BPrivate::Storage::dir_to_path(fDirFd, dirPath, - B_PATH_NAME_LENGTH) == B_OK); - entry_ref ref; - if (result) - result = (entry->GetRef(&ref) == B_OK); - if (result) { - result = (BPrivate::Storage::entry_ref_to_path(&ref, entryPath, - B_PATH_NAME_LENGTH) - == B_OK); - } - if (result) - result = !strncmp(dirPath, entryPath, strlen(dirPath)); + BPath dirPath(this, ".", true); + BPath entryPath(entry); + if (dirPath.InitCheck() == B_OK && entryPath.InitCheck() == B_OK) { + result = !strncmp(dirPath.Path(), entryPath.Path(), + strlen(dirPath.Path())); + } else + result = false; } return result; } @@ -532,22 +513,17 @@ BDirectory::Contains(const BEntry *entry, int32 nodeFlags) const status_t BDirectory::GetStatFor(const char *path, struct stat *st) const { - status_t error = (st ? B_OK : B_BAD_VALUE); - if (error == B_OK && InitCheck() != B_OK) - error = B_NO_INIT; - if (error == B_OK) { - if (path) { - if (strlen(path) == 0) - error = B_ENTRY_NOT_FOUND; - else { - BEntry entry(this, path); - error = entry.InitCheck(); - if (error == B_OK) - error = entry.GetStat(st); - } - } else - error = GetStat(st); - } + 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; } @@ -613,15 +589,18 @@ BDirectory::GetNextRef(entry_ref *ref) BPrivate::Storage::LongDirEntry entry; bool next = true; while (error == B_OK && next) { - if (BPrivate::Storage::read_dir(fDirFd, &entry, sizeof(entry), 1) != 1) + if (GetNextDirents(&entry, sizeof(entry), 1) != 1) { error = B_ENTRY_NOT_FOUND; - if (error == B_OK) { + } else { next = (!strcmp(entry.d_name, ".") || !strcmp(entry.d_name, "..")); } } - if (error == B_OK) - *ref = entry_ref(entry.d_pdev, entry.d_pino, entry.d_name); + if (error == B_OK) { + ref->device = entry.d_pdev; + ref->directory = entry.d_pino; + error = ref->set_name(entry.d_name); + } } return error; } @@ -650,12 +629,11 @@ BDirectory::GetNextRef(entry_ref *ref) int32 BDirectory::GetNextDirents(dirent *buf, size_t bufSize, int32 count) { - int32 result = (buf ? B_OK : B_BAD_VALUE); - if (result == B_OK && InitCheck() != B_OK) - result = B_FILE_ERROR; - if (result == B_OK) - result = BPrivate::Storage::read_dir(fDirFd, buf, bufSize, count); - return result; + if (!buf) + return B_BAD_VALUE; + if (InitCheck() != B_OK) + return B_FILE_ERROR; + return _kern_read_dir(fDirFd, buf, bufSize, count); } // Rewind @@ -673,12 +651,9 @@ BDirectory::GetNextDirents(dirent *buf, size_t bufSize, int32 count) status_t BDirectory::Rewind() { - status_t error = B_OK; - if (error == B_OK && InitCheck() != B_OK) - error = B_FILE_ERROR; - if (error == B_OK) - error = BPrivate::Storage::rewind_dir(fDirFd); - return error; + if (InitCheck() != B_OK) + return B_FILE_ERROR; + return _kern_rewind_dir(fDirFd); } // CountEntries @@ -700,19 +675,15 @@ int32 BDirectory::CountEntries() { status_t error = Rewind(); + if (error != B_OK) + return error; int32 count = 0; - if (error == B_OK) { - BPrivate::Storage::LongDirEntry entry; - while (error == B_OK) { - if (BPrivate::Storage::read_dir(fDirFd, &entry, sizeof(entry), 1) != 1) - error = B_ENTRY_NOT_FOUND; - if (error == B_OK - && strcmp(entry.d_name, ".") && strcmp(entry.d_name, "..")) { - count++; - } - } - if (error == B_ENTRY_NOT_FOUND) - error = B_OK; + BPrivate::Storage::LongDirEntry entry; + while (error == B_OK) { + if (GetNextDirents(&entry, sizeof(entry), 1) != 1) + break; + if (strcmp(entry.d_name, ".") != 0 && strcmp(entry.d_name, "..") != 0) + count++; } Rewind(); return (error == B_OK ? count : error); @@ -740,24 +711,20 @@ BDirectory::CountEntries() status_t BDirectory::CreateDirectory(const char *path, BDirectory *dir) { - status_t error = (path ? B_OK : B_BAD_VALUE); - if (error == B_OK) { - // get the actual (absolute) path using BEntry's help - BEntry entry; - if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path)) - entry.SetTo(this, path); - else - entry.SetTo(path); - error = entry.InitCheck(); - BPath realPath; - if (error == B_OK) - error = entry.GetPath(&realPath); - if (error == B_OK) - error = BPrivate::Storage::create_dir(realPath.Path()); - if (error == B_OK && dir) - error = dir->SetTo(realPath.Path()); - } - return error; + if (!path) + return B_BAD_VALUE; + // create the dir + status_t error = _kern_create_dir(fDirFd, path, + S_IRWXU | S_IRWXG | S_IRWXU); + if (error != B_OK) + return error; + if (!dir) + return B_OK; + // init the supplied BDirectory + if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path)) + return dir->SetTo(path); + else + return dir->SetTo(this, path); } // CreateFile @@ -790,20 +757,20 @@ BDirectory::CreateDirectory(const char *path, BDirectory *dir) status_t BDirectory::CreateFile(const char *path, BFile *file, bool failIfExists) { - status_t error (path ? B_OK : B_BAD_VALUE); - if (error == B_OK) { - // Let BFile do the dirty job. - uint32 openMode = B_READ_WRITE | B_CREATE_FILE - | (failIfExists ? B_FAIL_IF_EXISTS : 0); - BFile tmpFile; - BFile *realFile = (file ? file : &tmpFile); - if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path)) - error = realFile->SetTo(this, path, openMode); - else - error = realFile->SetTo(path, openMode); - if (error != B_OK) - realFile->Unset(); - } + if (!path) + return B_BAD_VALUE; + // Let BFile do the dirty job. + uint32 openMode = B_READ_WRITE | B_CREATE_FILE + | (failIfExists ? B_FAIL_IF_EXISTS : 0); + BFile tmpFile; + BFile *realFile = (file ? file : &tmpFile); + status_t error = B_OK; + if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path)) + error = realFile->SetTo(this, path, openMode); + else + error = realFile->SetTo(path, openMode); + if (error != B_OK && file) // mimic R5 behavior + file->Unset(); return error; } @@ -831,29 +798,25 @@ status_t BDirectory::CreateSymLink(const char *path, const char *linkToPath, BSymLink *link) { - status_t error = (path && linkToPath ? B_OK : B_BAD_VALUE); - if (error == B_OK) { - // get the actual (absolute) path using BEntry's help - BEntry entry; - if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path)) - entry.SetTo(this, path); - else - entry.SetTo(path); - error = entry.InitCheck(); - BPath realPath; - if (error == B_OK) - error = entry.GetPath(&realPath); - if (error == B_OK) - error = BPrivate::Storage::create_link(realPath.Path(), linkToPath); - if (error == B_OK && link) - error = link->SetTo(realPath.Path()); - } - return error; + if (!path || !linkToPath) + return B_BAD_VALUE; + // create the symlink + status_t error = _kern_create_symlink(fDirFd, path, linkToPath, + S_IRWXU | S_IRWXG | S_IRWXU); + if (error != B_OK) + return error; + if (!link) + return B_OK; + // init the supplied BSymLink + if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path)) + return link->SetTo(path); + else + return link->SetTo(this, path); } // = //! Assigns another BDirectory to this BDirectory. -/*! If the other BDirectory is uninitialized, this one will be too. Otherwise +/*! 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 @@ -863,16 +826,8 @@ BDirectory::operator=(const BDirectory &dir) { if (&dir != this) { // no need to assign us to ourselves Unset(); - if (dir.InitCheck() == B_OK) { - *((BNode*)this) = dir; - if (InitCheck() == B_OK) { - // duplicate the file descriptor - status_t status = BPrivate::Storage::dup_dir(dir.fDirFd, fDirFd); - if (status != B_OK) - Unset(); - set_status(status); - } - } + if (dir.InitCheck() == B_OK) + SetTo(&dir, "."); } return *this; } @@ -891,9 +846,9 @@ void BDirectory::_ErectorDirectory6() {} void BDirectory::close_fd() { - if (fDirFd != BPrivate::Storage::NullFd) { - BPrivate::Storage::close_dir(fDirFd); - fDirFd = BPrivate::Storage::NullFd; + if (fDirFd >= 0) { + _kern_close(fDirFd); + fDirFd = -1; } BNode::close_fd(); } @@ -903,7 +858,7 @@ BDirectory::close_fd() directly. \return the file descriptor, or -1, if not properly initialized. */ -BPrivate::Storage::FileDescriptor +int BDirectory::get_fd() const { return fDirFd; @@ -934,46 +889,50 @@ BDirectory::get_fd() const status_t create_directory(const char *path, mode_t mode) { + if (!path) + return B_BAD_VALUE; // 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 // components. Each time we get a new path, we check, if the entry it - // refers to exists and is a directory. If it doesn't exist, then we try + // refers to exists and is a directory. If it doesn't exist, we try // to create it. This goes on, until we're done with the input path or // an error occurs. - status_t error = (path ? B_OK : B_BAD_VALUE); - if (error == B_OK) { - BPath dirPath; - char *component; - int32 nextComponent; - do { - // get the next path component - error = BPrivate::Storage::parse_first_path_component(path, component, - nextComponent); - if (error == B_OK) { - // append it to the BPath - if (dirPath.InitCheck() == B_NO_INIT) // first component - error = dirPath.SetTo(component); - else - error = dirPath.Append(component); - delete[] component; - path += nextComponent; - // create a BEntry from the BPath - BEntry entry; - if (error == B_OK) - error = entry.SetTo(dirPath.Path(), true); - // check, if it exists - if (error == B_OK) { - if (entry.Exists()) { - // yep, it exists - if (!entry.IsDirectory()) // but is no directory - error = B_NOT_A_DIRECTORY; - } else // it doesn't exists -- create it - error = BPrivate::Storage::create_dir(dirPath.Path(), mode); - } - } - } while (error == B_OK && nextComponent != 0); - } - return error; + BPath dirPath; + char *component; + int32 nextComponent; + do { + // get the next path component + status_t error = BPrivate::Storage::parse_first_path_component(path, + component, nextComponent); + if (error != B_OK) + return error; + // append it to the BPath + if (dirPath.InitCheck() == B_NO_INIT) // first component + error = dirPath.SetTo(component); + else + error = dirPath.Append(component); + delete[] component; + if (error != B_OK) + return error; + path += nextComponent; + // create a BEntry from the BPath + BEntry entry; + error = entry.SetTo(dirPath.Path(), true); + if (error != B_OK) + return error; + // check, if it exists + if (entry.Exists()) { + // yep, it exists + if (!entry.IsDirectory()) // but is no directory + return B_NOT_A_DIRECTORY; + } else { + // it doesn't exist -- create it + error = _kern_create_dir(-1, dirPath.Path(), mode); + if (error != B_OK) + return error; + } + } while (nextComponent != 0); + return B_OK; } @@ -981,5 +940,3 @@ create_directory(const char *path, mode_t mode) }; // namespace OpenBeOS #endif - - diff --git a/src/kits/storage/Entry.cpp b/src/kits/storage/Entry.cpp index c28d1f8e5f..c6d3089024 100644 --- a/src/kits/storage/Entry.cpp +++ b/src/kits/storage/Entry.cpp @@ -10,14 +10,17 @@ #include #include +#include #include +#include #include #include #include -#include "kernel_interface.h" #include "storage_support.h" +#include + #ifdef USE_OPENBEOS_NAMESPACE using namespace OpenBeOS; #endif @@ -97,8 +100,7 @@ entry_ref::entry_ref(const entry_ref &ref) //! Destroys the object and frees the storage allocated for the leaf name, if necessary. entry_ref::~entry_ref() { - if (name != NULL) - delete [] name; + free(name); } /*! \brief Set the entry_ref's leaf name, freeing the storage allocated for any previous @@ -109,17 +111,14 @@ entry_ref::~entry_ref() */ status_t entry_ref::set_name(const char *name) { - if (this->name != NULL) { - delete [] this->name; - } + free(this->name); if (name == NULL) { this->name = NULL; } else { - this->name = new(nothrow) char[strlen(name)+1]; - if (this->name == NULL) + this->name = strdup(name); + if (!this->name) return B_NO_MEMORY; - strcpy(this->name, name); } return B_OK; @@ -220,7 +219,7 @@ entry_ref::operator=(const entry_ref &ref) - operator=(const BEntry&) */ BEntry::BEntry() - : fDirFd(BPrivate::Storage::NullFd), + : fDirFd(-1), fName(NULL), fCStatus(B_NO_INIT) { @@ -237,7 +236,7 @@ BEntry::BEntry() */ BEntry::BEntry(const BDirectory *dir, const char *path, bool traverse) - : fDirFd(BPrivate::Storage::NullFd), + : fDirFd(-1), fName(NULL), fCStatus(B_NO_INIT) { @@ -255,7 +254,7 @@ BEntry::BEntry(const BDirectory *dir, const char *path, bool traverse) */ BEntry::BEntry(const entry_ref *ref, bool traverse) - : fDirFd(BPrivate::Storage::NullFd), + : fDirFd(-1), fName(NULL), fCStatus(B_NO_INIT) { @@ -274,7 +273,7 @@ BEntry::BEntry(const entry_ref *ref, bool traverse) */ BEntry::BEntry(const char *path, bool traverse) - : fDirFd(BPrivate::Storage::NullFd), + : fDirFd(-1), fName(NULL), fCStatus(B_NO_INIT) { @@ -286,7 +285,7 @@ BEntry::BEntry(const char *path, bool traverse) \see operator=(const BEntry&) */ BEntry::BEntry(const BEntry &entry) - : fDirFd(BPrivate::Storage::NullFd), + : fDirFd(-1), fName(NULL), fCStatus(B_NO_INIT) { @@ -321,12 +320,9 @@ BEntry::InitCheck() const bool BEntry::Exists() const { - if (fCStatus != B_OK) - return false; - - // Attempt to find the entry in our current directory - BPrivate::Storage::LongDirEntry entry; - return BPrivate::Storage::find_dir(fDirFd, fName, &entry, sizeof(entry)) == B_OK; + // just stat the beast + struct stat st; + return (GetStat(&st) == B_OK); } /*! \brief Fills in a stat structure for the entry. The information is copied into @@ -345,13 +341,7 @@ BEntry::GetStat(struct stat *result) const { if (fCStatus != B_OK) return B_NO_INIT; - - entry_ref ref; - status_t status = GetRef(&ref); - if (status != B_OK) - return status; - - return BPrivate::Storage::get_stat(ref, result); + return _kern_read_stat(fDirFd, fName, false, result, sizeof(struct stat)); } /*! \brief Reinitializes the BEntry to the path or directory path combination, @@ -360,45 +350,30 @@ BEntry::GetStat(struct stat *result) const \return - \c B_OK - Success - "error code" - Failure - - \todo Reimplement! Concatenating dir and leaf to an absolute path prevents - the user from accessing entries with longer absolute path. - R5 handles this without problems. */ status_t BEntry::SetTo(const BDirectory *dir, const char *path, bool traverse) { - Unset(); - if (dir == NULL) + // check params + if (!dir) return (fCStatus = B_BAD_VALUE); + if (path && path[0] == '\0') // R5 behaviour + path = NULL; - fCStatus = B_OK; - if (BPrivate::Storage::is_absolute_path(path)) { - SetTo(path, traverse); - } else { - if (dir->InitCheck() != B_OK) - fCStatus = B_BAD_VALUE; - // get the dir's path - char rootPath[B_PATH_NAME_LENGTH]; - if (fCStatus == B_OK) { - fCStatus = BPrivate::Storage::dir_to_path(dir->get_fd(), rootPath, - B_PATH_NAME_LENGTH); - } - // Concatenate our two path strings together - if (fCStatus == B_OK && path) { - // The concatenated strings must fit into our buffer. - if (strlen(rootPath) + strlen(path) + 2 > B_PATH_NAME_LENGTH) - fCStatus = B_NAME_TOO_LONG; - else { - strcat(rootPath, "/"); - strcat(rootPath, path); - } - } - // set the resulting path - if (fCStatus == B_OK) - SetTo(rootPath, traverse); - } - return fCStatus; + // if path is absolute, let the path-only SetTo() do the job + if (BPrivate::Storage::is_absolute_path(path)) + return SetTo(path, traverse); + + Unset(); + + if (dir->InitCheck() != B_OK) + fCStatus = B_BAD_VALUE; + + // dup() the dir's FD and let set() do the rest + int dirFD = _kern_dup(dir->get_fd()); + if (dirFD < 0) + return (fCStatus = dirFD); + return (fCStatus = set(dirFD, path, traverse)); } /*! \brief Reinitializes the BEntry to the entry_ref, resolving symlinks if @@ -407,22 +382,19 @@ BEntry::SetTo(const BDirectory *dir, const char *path, bool traverse) \return - \c B_OK - Success - "error code" - Failure - - \todo Implemented using entry_ref_to_path(). Reimplement! */ status_t BEntry::SetTo(const entry_ref *ref, bool traverse) { Unset(); - if (ref == NULL) { + if (ref == NULL) return (fCStatus = B_BAD_VALUE); - } - char path[B_PATH_NAME_LENGTH]; - - fCStatus = BPrivate::Storage::entry_ref_to_path(ref, path, - B_PATH_NAME_LENGTH); - return (fCStatus == B_OK) ? SetTo(path, traverse) : fCStatus ; + // open the directory and let set() do the rest + int dirFD = _kern_open_dir_entry_ref(ref->device, ref->directory, NULL); + if (dirFD < 0) + return (fCStatus = dirFD); + return (fCStatus = set(dirFD, ref->name, traverse)); } /*! \brief Reinitializes the BEntry object to the path, resolving symlinks if @@ -431,35 +403,15 @@ BEntry::SetTo(const entry_ref *ref, bool traverse) \return - \c B_OK - Success - "error code" - Failure - */ status_t BEntry::SetTo(const char *path, bool traverse) { Unset(); // check the argument - fCStatus = (path ? B_OK : B_BAD_VALUE); - if (fCStatus == B_OK) - fCStatus = BPrivate::Storage::check_path_name(path); - if (fCStatus == B_OK) { - // Get the path and leaf portions of the given path - char *pathStr, *leafStr; - pathStr = leafStr = NULL; - fCStatus = BPrivate::Storage::split_path(path, pathStr, leafStr); - if (fCStatus == B_OK) { - // Open the directory - BPrivate::Storage::FileDescriptor dirFd; - fCStatus = BPrivate::Storage::open_dir(pathStr, dirFd); - if (fCStatus == B_OK) { - fCStatus = set(dirFd, leafStr, traverse); - if (fCStatus != B_OK) - BPrivate::Storage::close_dir(dirFd); - } - } - delete [] pathStr; - delete [] leafStr; - } - return fCStatus; + if (!path) + return (fCStatus = B_BAD_VALUE); + return (fCStatus = set(-1, path, traverse)); } /*! \brief Reinitializes the BEntry to an uninitialized BEntry object */ @@ -467,16 +419,15 @@ void BEntry::Unset() { // Close the directory - if (fDirFd != BPrivate::Storage::NullFd) { - BPrivate::Storage::close_dir(fDirFd); + if (fDirFd >= 0) { + _kern_close(fDirFd); +// BPrivate::Storage::close_dir(fDirFd); } // Free our leaf name - if (fName != NULL) { - delete [] fName; - } + free(fName); - fDirFd = BPrivate::Storage::NullFd; + fDirFd = -1; fName = NULL; fCStatus = B_NO_INIT; } @@ -499,7 +450,8 @@ BEntry::GetRef(entry_ref *ref) const return B_BAD_VALUE; struct stat st; - status_t error = BPrivate::Storage::get_stat(fDirFd, &st); + status_t error = _kern_read_stat(fDirFd, NULL, false, &st, + sizeof(struct stat)); if (error == B_OK) { ref->device = st.st_dev; ref->directory = st.st_ino; @@ -563,44 +515,30 @@ BEntry::GetPath(BPath *path) const - \c B_OK - Success - \c B_ENTRY_NOT_FOUND - Attempted to get the parent of the root directory \c "/" - "error code" - Failure - */ status_t BEntry::GetParent(BEntry *entry) const { + // check parameter and initialization if (fCStatus != B_OK) return B_NO_INIT; - if (entry == NULL) return B_BAD_VALUE; - - // Convert ourselves to a entry_ref and change the - // leaf name to "." - - entry_ref ref; - status_t status; - - status = GetRef(&ref); - if (status == B_OK) { - - // Verify we aren't an entry representing "/" - status = BPrivate::Storage::entry_ref_is_root_dir(&ref) ? (status_t)B_ENTRY_NOT_FOUND - : (status_t)B_OK ; - if (status == B_OK) { - - status = ref.set_name("."); - if (status == B_OK) { - - entry->SetTo(&ref); - return entry->InitCheck(); - - } - } - } - - // If we get this far, an error occured, so we Unset() the - // argument as dictated by the BeBook + // check whether we are the root directory + // It is sufficient to check whether our leaf name is ".". + if (strcmp(fName, ".") == 0) + return B_ENTRY_NOT_FOUND; + // open the parent directory + char leafName[B_FILE_NAME_LENGTH]; + int parentFD = _kern_open_parent_dir(fDirFd, leafName, B_FILE_NAME_LENGTH); + if (parentFD < 0) + return parentFD; + // init the entry entry->Unset(); - return status; + entry->fDirFd = parentFD; + entry->fCStatus = entry->set_name(leafName); + if (entry->fCStatus != B_OK) + entry->Unset(); + return entry->fCStatus; } /*! \brief Gets the parent of the BEntry as a BDirectory. @@ -612,40 +550,32 @@ status_t BEntry::GetParent(BEntry *entry) const - \c B_OK - Success - \c B_ENTRY_NOT_FOUND - Attempted to get the parent of the root directory \c "/" - "error code" - Failure - */ status_t BEntry::GetParent(BDirectory *dir) const { + // check initialization and parameter if (fCStatus != B_OK) return B_NO_INIT; - if (dir == NULL) return B_BAD_VALUE; - - entry_ref ref; - status_t status; - - status = GetRef(&ref); - if (status == B_OK) { - - // Verify we aren't an entry representing "/" - status = BPrivate::Storage::entry_ref_is_root_dir(&ref) ? (status_t)B_ENTRY_NOT_FOUND : (status_t)B_OK ; - if (status == B_OK) { - - // Now point the entry_ref to the parent directory (instead of ourselves) - status = ref.set_name("."); - if (status == B_OK) { - dir->SetTo(&ref); - return dir->InitCheck(); - } - } - } - - // If we get this far, an error occured, so we Unset() the - // argument as dictated by the BeBook - dir->Unset(); - return status; + // check whether we are the root directory + // It is sufficient to check whether our leaf name is ".". + if (strcmp(fName, ".") == 0) + return B_ENTRY_NOT_FOUND; + // get a node ref for the directory and init it + struct stat st; + status_t error = _kern_read_stat(fDirFd, NULL, false, &st, + sizeof(struct stat)); + if (error != B_OK) + return error; + node_ref ref; + ref.device = st.st_dev; + ref.node = st.st_ino; + return dir->SetTo(&ref); + // TODO: This can be optimized: We already have a FD for the directory, + // so we could dup() it and set it on the directory. We just need a private + // API for being able to do that. } /*! \brief Gets the name of the entry's leaf. @@ -657,7 +587,6 @@ BEntry::GetParent(BDirectory *dir) const \return - \c B_OK - Success - "error code" - Failure - */ status_t BEntry::GetName(char *buffer) const @@ -696,47 +625,26 @@ BEntry::GetName(char *buffer) const status_t BEntry::Rename(const char *path, bool clobber) { + // check parameter and initialization if (path == NULL) return B_BAD_VALUE; if (fCStatus != B_OK) return B_NO_INIT; - - status_t status = B_OK; - // Convert the given path to an absolute path, if it isn't already. - char fullPath[B_PATH_NAME_LENGTH]; - if (!BPrivate::Storage::is_absolute_path(path)) { - // Convert our directory to an absolute pathname - status = BPrivate::Storage::dir_to_path(fDirFd, fullPath, - B_PATH_NAME_LENGTH); - if (status == B_OK) { - // Concatenate our pathname to it - strcat(fullPath, "/"); - strcat(fullPath, path); - path = fullPath; - } + // get an entry representing the target location + BEntry target; + status_t error; + if (BPrivate::Storage::is_absolute_path(path)) { + error = target.SetTo(path); + } else { + int dirFD = _kern_dup(fDirFd); + if (dirFD < 0) + return dirFD; + // init the entry + error = target.fCStatus = target.set(dirFD, path, false); } - // Check, whether the file does already exist, if clobber is false. - if (status == B_OK && !clobber) { - // We're not supposed to kill an already-existing file, - // so we'll try to figure out if it exists by stat()ing it. - BPrivate::Storage::Stat s; - status = BPrivate::Storage::get_stat(path, &s); - if (status == B_OK) - status = B_FILE_EXISTS; - else if (status == B_ENTRY_NOT_FOUND) - status = B_OK; - } - // Turn ourselves into a pathname, rename ourselves - if (status == B_OK) { - BPath oldPath; - status = GetPath(&oldPath); - if (status == B_OK) { - status = BPrivate::Storage::rename(oldPath.Path(), path); - if (status == B_OK) - status = SetTo(path, false); - } - } - return status; + if (error != B_OK) + return error; + return _Rename(target, clobber); } /*! \brief Moves the BEntry to directory or directory+path combination, replacing an existing entry if clobber is true. @@ -755,41 +663,26 @@ BEntry::Rename(const char *path, bool clobber) - \c B_ENTRY_EXISTS - The new location is already taken and \c clobber was \c false - \c B_ENTRY_NOT_FOUND - Attempted to move an abstract entry - "error code" - Failure - - */ status_t BEntry::MoveTo(BDirectory *dir, const char *path, bool clobber) { + // check parameters and initialization if (fCStatus != B_OK) return B_NO_INIT; - else if (dir == NULL) + if (dir == NULL) return B_BAD_VALUE; - else if (dir->InitCheck() != B_OK) + if (dir->InitCheck() != B_OK) return B_BAD_VALUE; - // NULL path simply means move without renaming if (path == NULL) path = fName; - - status_t status = B_OK; - // Determine the absolute path of the target entry. - if (!BPrivate::Storage::is_absolute_path(path)) { - // Convert our directory to an absolute pathname - char fullPath[B_PATH_NAME_LENGTH]; - status = BPrivate::Storage::dir_to_path(dir->get_fd(), fullPath, - B_PATH_NAME_LENGTH); - // Concatenate our pathname to it - if (status == B_OK) { - strcat(fullPath, "/"); - strcat(fullPath, path); - path = fullPath; - } - } - // Now let rename do the dirty work - if (status == B_OK) - status = Rename(path, clobber); - return status; + // get an entry representing the target location + BEntry target; + status_t error = target.SetTo(dir, path); + if (error != B_OK) + return error; + return _Rename(target, clobber); } /*! \brief Removes the entry from the file system. @@ -802,22 +695,13 @@ BEntry::MoveTo(BDirectory *dir, const char *path, bool clobber) \return - B_OK - Success - "error code" - Failure - */ status_t BEntry::Remove() { if (fCStatus != B_OK) return B_NO_INIT; - - BPath path; - status_t status; - - status = GetPath(&path); - if (status != B_OK) - return status; - - return BPrivate::Storage::remove(path.Path()); + return _kern_unlink(fDirFd, fName); } @@ -827,7 +711,6 @@ BEntry::Remove() \return - true - Both BEntry objects refer to the same entry or they are both uninitialzed - false - The BEntry objects refer to different entries - */ bool BEntry::operator==(const BEntry &item) const @@ -858,7 +741,6 @@ BEntry::operator==(const BEntry &item) const \return - true - The BEntry objects refer to different entries - false - Both BEntry objects refer to the same entry or they are both uninitialzed - */ bool BEntry::operator!=(const BEntry &item) const @@ -870,7 +752,6 @@ BEntry::operator!=(const BEntry &item) const \return - A reference to the copy - */ BEntry& BEntry::operator=(const BEntry &item) @@ -880,10 +761,14 @@ BEntry::operator=(const BEntry &item) Unset(); if (item.fCStatus == B_OK) { - fCStatus = BPrivate::Storage::dup_dir(item.fDirFd, fDirFd); - if (fCStatus == B_OK) { + fDirFd = _kern_dup(item.fDirFd); + if (fDirFd >= 0) fCStatus = set_name(item.fName); - } + else + fCStatus = fDirFd; + + if (fCStatus != B_OK) + Unset(); } return *this; @@ -909,121 +794,146 @@ BEntry::set_stat(struct stat &st, uint32 what) { if (fCStatus != B_OK) return B_FILE_ERROR; - - BPath path; - status_t status; - - status = GetPath(&path); - if (status != B_OK) - return status; - - return BPrivate::Storage::set_stat(path.Path(), st, what); + + return _kern_write_stat(fDirFd, fName, false, &st, sizeof(struct stat), + what); } -/*! Sets the Entry to point to the entry named by \c leaf in the given directory. If \c traverse - is \c true and the given entry is a symlink, the object is recursively set to point to the - entry pointed to by the symlink. +/*! Sets the Entry to point to the entry specified by the path \a path relative + to the given directory. If \a traverse is \c true and the given entry is a + symlink, the object is recursively set to point to the entry pointed to by + the symlink. + + If \a path is an absolute path, \a dirFD is ignored. + If \a dirFD is -1, path is considered relative to the current directory + (unless it is an absolute path, that is). - \c leaf must be a leaf-name only (i.e. it must contain no '/' characters), - otherwise this function will return \c B_BAD_VALUE. If \c B_OK is returned, - the caller is no longer responsible for closing the directory file descriptor - with a call to BPrivate::Storage::close_dir. - - \param dirFd File descriptor of the directory in which the entry resides - \param leaf Pointer to a string containing the entry's leaf name - \param traverse If \c true and the given entry is a symlink, the object is recursively - set to point to the entry linked to by the symlink. + The ownership of the file descriptor \a dirFD is transferred to the + function, regardless of whether it succeeds or fails. The caller must not + close the FD afterwards. + + \param dirFD File descriptor of a directory relative to which path is to + be considered. May be -1, when the current directory shall be + considered. + \param path Pointer to a path relative to the given directory. + \param traverse If \c true and the given entry is a symlink, the object is + recursively set to point to the entry linked to by the symlink. \return - B_OK - Success - "error code" - Failure - */ status_t -BEntry::set(BPrivate::Storage::FileDescriptor dirFd, const char *leaf, bool traverse) +BEntry::set(int dirFD, const char *path, bool traverse) { - // Verify that path is valid - status_t error = BPrivate::Storage::check_entry_name(leaf); + bool requireConcrete = false; + FDCloser fdCloser(dirFD); + char tmpPath[B_PATH_NAME_LENGTH]; + char leafName[B_FILE_NAME_LENGTH]; + int32 linkLimit = B_MAX_SYMLINKS; + while (true) { + if (!path || strcmp(path, ".") == 0) { + // "." + // if no dir FD is supplied, we need to open the current directory + // first + if (dirFD < 0) { + dirFD = _kern_open_dir(-1, "."); + if (dirFD < 0) + return dirFD; + fdCloser.SetTo(dirFD); + } + // get the parent directory + int parentFD = _kern_open_parent_dir(dirFD, leafName, + B_FILE_NAME_LENGTH); + if (parentFD < 0) + return parentFD; + dirFD = parentFD; + fdCloser.SetTo(dirFD); + break; + } else if (strcmp(path, "..") == 0) { + // ".." + // open the parent directory + int parentFD = _kern_open_dir(dirFD, ".."); + if (parentFD < 0) + return parentFD; + dirFD = parentFD; + fdCloser.SetTo(dirFD); + // get the parent's parent directory + parentFD = _kern_open_parent_dir(dirFD, leafName, + B_FILE_NAME_LENGTH); + if (parentFD < 0) + return parentFD; + dirFD = parentFD; + fdCloser.SetTo(dirFD); + break; + } else { + // an ordinary path; analyze it + char dirPath[B_PATH_NAME_LENGTH]; + status_t error = BPrivate::Storage::parse_path(path, dirPath, + leafName); + if (error != B_OK) + return error; + // special case: root directory ("/") + if (leafName[0] == '\0' && dirPath[0] == '/') + strcpy(leafName, "."); + if (leafName[0] == '\0') { + // the supplied path is already a leaf + error = BPrivate::Storage::check_entry_name(dirPath); + if (error != B_OK) + return error; + strcpy(leafName, dirPath); + // if no directory was given, we need to open the current dir + // now + if (dirFD < 0) { + char *cwd = getcwd(tmpPath, B_PATH_NAME_LENGTH); + if (!cwd) + return B_ERROR; + dirFD = _kern_open_dir(-1, cwd); + if (dirFD < 0) + return dirFD; + fdCloser.SetTo(dirFD); + } + } else { + int parentFD = _kern_open_dir(dirFD, dirPath); + if (parentFD < 0) + return parentFD; + dirFD = parentFD; + fdCloser.SetTo(dirFD); + } + // traverse symlinks, if desired + if (!traverse) + break; + struct stat st; + error = _kern_read_stat(dirFD, leafName, false, &st, + sizeof(struct stat)); + if (error == B_ENTRY_NOT_FOUND && !requireConcrete) { + // that's fine -- the entry is abstract and was not target of + // a symlink we resolved + break; + } + if (error != B_OK) + return error; + // the entry is concrete + if (!S_ISLNK(st.st_mode)) + break; + requireConcrete = true; + // we need to traverse the symlink + if (--linkLimit < 0) + return B_LINK_LIMIT; + ssize_t readBytes = _kern_read_link(dirFD, leafName, tmpPath, + B_PATH_NAME_LENGTH); + if (readBytes < 0) + return readBytes; + path = tmpPath; + // next round... + } + } + // set the result + status_t error = set_name(leafName); if (error != B_OK) return error; - // Check whether the entry is abstract or concrete. - // We try traversing concrete entries only. - BPrivate::Storage::LongDirEntry dirEntry; - bool isConcrete = (BPrivate::Storage::find_dir(dirFd, leaf, &dirEntry, - sizeof(dirEntry)) == B_OK); - if (traverse && isConcrete) { - // Though the link traversing strategy is iterative, we introduce - // some recursion, since we are using BSymLink, which may be - // (currently is) implemented using BEntry. Nevertheless this is - // harmless, because BSymLink does, of course, not want to traverse - // the link. - - // convert the dir FD into a BPath - entry_ref ref; - error = BPrivate::Storage::dir_to_self_entry_ref(dirFd, &ref); - char dirPathname[B_PATH_NAME_LENGTH]; - if (error == B_OK) { - error = BPrivate::Storage::entry_ref_to_path(&ref, dirPathname, - sizeof(dirPathname)); - } - BPath dirPath(dirPathname); - if (error == B_OK) - error = dirPath.InitCheck(); - BPath linkPath; - if (error == B_OK) - linkPath.SetTo(dirPath.Path(), leaf); - if (error == B_OK) { - // Here comes the link traversing loop: A BSymLink is created - // from the dir and the leaf name, the link target is determined, - // the target's dir and leaf name are got and so on. - bool isLink = true; - int32 linkLimit = B_MAX_SYMLINKS; - while (error == B_OK && isLink && linkLimit > 0) { - linkLimit--; - // that's OK with any node, even if it's not a symlink - BSymLink link(linkPath.Path()); - error = link.InitCheck(); - if (error == B_OK) { - isLink = link.IsSymLink(); - if (isLink) { - // get the path to the link target - ssize_t linkSize = link.MakeLinkedPath(dirPath.Path(), - &linkPath); - if (linkSize < 0) - error = linkSize; - // get the link target's dir path - if (error == B_OK) - error = linkPath.GetParent(&dirPath); - } - } - } - // set the new values - if (error == B_OK) { - if (isLink) - error = B_LINK_LIMIT; - else { - BPrivate::Storage::FileDescriptor newDirFd = BPrivate::Storage::NullFd; - error = BPrivate::Storage::open_dir(dirPath.Path(), newDirFd); - if (error == B_OK) { - // If we are successful, we are responsible for the - // supplied FD. Thus we close it. - BPrivate::Storage::close_dir(dirFd); - dirFd = BPrivate::Storage::NullFd; - fDirFd = newDirFd; - // handle "/", which has a "" Leaf() - if (linkPath == "/") - set_name("."); - else - set_name(linkPath.Leaf()); - } - } - } - } // getting the dir path for the FD - } else { - // don't traverse: either the flag is not set or the entry is abstract - fDirFd = dirFd; - set_name(leaf); - } - return error; + fdCloser.Detach(); + fDirFd = dirFD; + return B_OK; } /*! \brief Handles string allocation, deallocation, and copying for the entry's leaf name. @@ -1038,19 +948,51 @@ BEntry::set_name(const char *name) if (name == NULL) return B_BAD_VALUE; - if (fName != NULL) { - delete [] fName; - } + free(fName); - fName = new(nothrow) char[strlen(name)+1]; - if (fName == NULL) + fName = strdup(name); + if (!fName) return B_NO_MEMORY; - - strcpy(fName, name); return B_OK; } +// _Rename +/*! \brief Renames the entry referred to by this object to the location + specified by \a target. + + If an entry exists at the target location, the method fails, unless + \a clobber is \c true, in which case that entry is overwritten (doesn't + work for non-empty directories, though). + + If the operation was successful, this entry is made a clone of the + supplied one and the supplied one is uninitialized. + + \param target The entry specifying the target location. + \param clobber If \c true, the an entry existing at the target location + will be overwritten. + \return \c B_OK, if everything went fine, another error code otherwise. +*/ +status_t +BEntry::_Rename(BEntry& target, bool clobber) +{ + // check, if there's an entry in the way + if (!clobber && target.Exists()) + return B_FILE_EXISTS; + // rename + status_t error = _kern_rename(fDirFd, fName, target.fDirFd, target.fName); + if (error == B_OK) { + Unset(); + fCStatus = target.fCStatus; + fDirFd = target.fDirFd; + fName = target.fName; + target.fCStatus = B_NO_INIT; + target.fDirFd = -1; + target.fName = NULL; + } + return error; +} + /*! Debugging function, dumps the given entry to stdout. This function is not part of the R5 implementation, and thus calls to it will mean you can't link with the @@ -1071,11 +1013,12 @@ BEntry::Dump(const char *name) printf("fCStatus == %ld\n", fCStatus); - BPrivate::Storage::LongDirEntry entry; + struct stat st; if (fDirFd != -1 - && BPrivate::Storage::find_dir(fDirFd, ".", &entry, sizeof(entry)) == B_OK) { - printf("dir.device == %ld\n", entry.d_pdev); - printf("dir.inode == %lld\n", entry.d_pino); + && _kern_read_stat(fDirFd, NULL, false, &st, + sizeof(struct stat)) == B_OK) { + printf("dir.device == %ld\n", st.st_dev); + printf("dir.inode == %lld\n", st.st_ino); } else { printf("dir == NullFd\n"); } diff --git a/src/kits/storage/File.cpp b/src/kits/storage/File.cpp index 2bea92bce2..34a7525193 100644 --- a/src/kits/storage/File.cpp +++ b/src/kits/storage/File.cpp @@ -9,9 +9,11 @@ #include +#include #include #include -#include "kernel_interface.h" + +#include #ifdef USE_OPENBEOS_NAMESPACE namespace OpenBeOS { @@ -143,23 +145,22 @@ BFile::~BFile() - \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. - \todo Currently implemented using BPrivate::Storage::entry_ref_to_path(). - Reimplement! */ status_t BFile::SetTo(const entry_ref *ref, uint32 openMode) { Unset(); - char path[B_PATH_NAME_LENGTH]; - status_t error = (ref ? B_OK : B_BAD_VALUE); - if (error == B_OK) { - error = BPrivate::Storage::entry_ref_to_path(ref, path, - B_PATH_NAME_LENGTH); - } - if (error == B_OK) - error = SetTo(path, openMode); - set_status(error); - return error; + if (!ref) + return (fCStatus = B_BAD_VALUE); + int fd = _kern_open_entry_ref(ref->device, ref->directory, ref->name, + openMode); + if (fd >= 0) { + set_fd(fd); + fMode = openMode; + fCStatus = B_OK; + } else + fCStatus = fd; + return fCStatus; } // SetTo @@ -185,14 +186,18 @@ status_t BFile::SetTo(const BEntry *entry, uint32 openMode) { Unset(); - entry_ref ref; - status_t error = (entry ? B_OK : B_BAD_VALUE); - if (error == B_OK) - error = entry->GetRef(&ref); - if (error == B_OK) - error = SetTo(&ref, openMode); - set_status(error); - return error; + if (!entry) + return (fCStatus = B_BAD_VALUE); + if (entry->InitCheck() != B_OK) + return (fCStatus = entry->InitCheck()); + int fd = _kern_open(entry->fDirFd, entry->fName, openMode); + if (fd >= 0) { + set_fd(fd); + fMode = openMode; + fCStatus = B_OK; + } else + fCStatus = fd; + return fCStatus; } // SetTo @@ -216,54 +221,16 @@ status_t BFile::SetTo(const char *path, uint32 openMode) { Unset(); - status_t result = B_OK; - BPrivate::Storage::FileDescriptor newFd = BPrivate::Storage::NullFd; - if (path) { - // analyze openMode - // Well, it's a bit schizophrenic to convert the B_* style openMode - // to POSIX style openFlags, but to use O_RWMASK to filter openMode. - BPrivate::Storage::OpenFlags openFlags = 0; - switch (openMode & O_RWMASK) { - case B_READ_ONLY: - openFlags = O_RDONLY; - break; - case B_WRITE_ONLY: - openFlags = O_WRONLY; - break; - case B_READ_WRITE: - openFlags = O_RDWR; - break; - default: - result = B_BAD_VALUE; - break; - } - if (result == B_OK) { - if (openMode & B_ERASE_FILE) - openFlags |= O_TRUNC; - if (openMode & B_OPEN_AT_END) - openFlags |= O_APPEND; - if (openMode & B_CREATE_FILE) { - openFlags |= O_CREAT; - if (openMode & B_FAIL_IF_EXISTS) - openFlags |= O_EXCL; - result = BPrivate::Storage::open(path, openFlags, S_IREAD | S_IWRITE, - newFd); - } else - result = BPrivate::Storage::open(path, openFlags, newFd); - if (result == B_OK) - fMode = openFlags; - } + if (!path) + return (fCStatus = B_BAD_VALUE); + int fd = _kern_open(-1, path, openMode); + if (fd >= 0) { + set_fd(fd); + fMode = openMode; + fCStatus = B_OK; } else - result = B_BAD_VALUE; - // set the new file descriptor - if (result == B_OK) { - result = set_fd(newFd); - if (result != B_OK) - BPrivate::Storage::close(newFd); - } - // finally set the BNode status - set_status(result); - return result; + fCStatus = fd; + return fCStatus; } // SetTo @@ -291,14 +258,16 @@ status_t BFile::SetTo(const BDirectory *dir, const char *path, uint32 openMode) { Unset(); - status_t error = (dir && path ? B_OK : B_BAD_VALUE); - BEntry entry; - if (error == B_OK) - error = entry.SetTo(dir, path); - if (error == B_OK) - error = SetTo(&entry, openMode); - set_status(error); - return error; + if (!dir) + return (fCStatus = B_BAD_VALUE); + int fd = _kern_open(dir->fDirFd, path, openMode); + if (fd >= 0) { + set_fd(fd); + fMode = openMode; + fCStatus = B_OK; + } else + fCStatus = fd; + return fCStatus; } // IsReadable @@ -340,10 +309,9 @@ BFile::IsWritable() const ssize_t BFile::Read(void *buffer, size_t size) { - ssize_t result = InitCheck(); - if (result == B_OK) - result = BPrivate::Storage::read(get_fd(), buffer, size); - return result; + if (InitCheck() != B_OK) + return InitCheck(); + return _kern_read(get_fd(), -1, buffer, size); } // ReadAt @@ -358,10 +326,11 @@ BFile::Read(void *buffer, size_t size) ssize_t BFile::ReadAt(off_t location, void *buffer, size_t size) { - ssize_t result = InitCheck(); - if (result == B_OK) - result = BPrivate::Storage::read(get_fd(), buffer, location, size); - return result; + if (InitCheck() != B_OK) + return InitCheck(); + if (location < 0) + return B_BAD_VALUE; + return _kern_read(get_fd(), location, buffer, size); } // Write @@ -373,10 +342,9 @@ BFile::ReadAt(off_t location, void *buffer, size_t size) ssize_t BFile::Write(const void *buffer, size_t size) { - ssize_t result = InitCheck(); - if (result == B_OK) - result = BPrivate::Storage::write(get_fd(), buffer, size); - return result; + if (InitCheck() != B_OK) + return InitCheck(); + return _kern_write(get_fd(), -1, buffer, size); } // WriteAt @@ -391,10 +359,11 @@ BFile::Write(const void *buffer, size_t size) ssize_t BFile::WriteAt(off_t location, const void *buffer, size_t size) { - ssize_t result = InitCheck(); - if (result == B_OK) - result = BPrivate::Storage::write(get_fd(), buffer, location, size); - return result; + if (InitCheck() != B_OK) + return InitCheck(); + if (location < 0) + return B_BAD_VALUE; + return _kern_write(get_fd(), location, buffer, size); } // Seek @@ -417,10 +386,9 @@ BFile::WriteAt(off_t location, const void *buffer, size_t size) off_t BFile::Seek(off_t offset, uint32 seekMode) { - off_t result = (InitCheck() == B_OK ? (off_t)B_OK : (off_t)B_FILE_ERROR); - if (result == B_OK) - result = BPrivate::Storage::seek(get_fd(), offset, seekMode); - return result; + if (InitCheck() != B_OK) + return B_FILE_ERROR; + return _kern_seek(get_fd(), offset, seekMode); } // Position @@ -433,10 +401,9 @@ BFile::Seek(off_t offset, uint32 seekMode) off_t BFile::Position() const { - off_t result = (InitCheck() == B_OK ? (off_t)B_OK : (off_t)B_FILE_ERROR); - if (result == B_OK) - result = BPrivate::Storage::get_position(get_fd()); - return result; + if (InitCheck() != B_OK) + return B_FILE_ERROR; + return _kern_seek(get_fd(), 0, SEEK_CUR); } // SetSize @@ -456,15 +423,13 @@ BFile::Position() const status_t BFile::SetSize(off_t size) { - status_t result = InitCheck(); - if (result == B_OK && size < 0) - result = B_BAD_VALUE; + if (InitCheck() != B_OK) + return InitCheck(); + if (size < 0) + return B_BAD_VALUE; struct stat statData; - if (result == B_OK) { - statData.st_size = size; - result = set_stat(statData, WSTAT_SIZE); - } - return result; + statData.st_size = size; + return set_stat(statData, WSTAT_SIZE); } // = @@ -481,17 +446,14 @@ BFile::operator=(const BFile &file) Unset(); if (file.InitCheck() == B_OK) { // duplicate the file descriptor - BPrivate::Storage::FileDescriptor fd = -1; - status_t status = BPrivate::Storage::dup(file.get_fd(), fd); + int fd = _kern_dup(file.get_fd()); // set it - if (status == B_OK) { - status = set_fd(fd); - if (status == B_OK) - fMode = file.fMode; - else - BPrivate::Storage::close(fd); - } - set_status(status); + if (fd >= 0) { + fFd = fd; + fMode = file.fMode; + fCStatus = B_OK; + } else + fCStatus = fd; } } return *this; @@ -512,7 +474,7 @@ void BFile::_PhiloFile6() {} To be used instead of accessing the BNode's private \c fFd member directly. \return the file descriptor, or -1, if not properly initialized. */ -BPrivate::Storage::FileDescriptor +int BFile::get_fd() const { return fFd; @@ -523,6 +485,3 @@ BFile::get_fd() const }; // namespace OpenBeOS #endif - - - diff --git a/src/kits/storage/LibBeAdapter.cpp b/src/kits/storage/LibBeAdapter.cpp index 9e046a344a..f6268521f9 100644 --- a/src/kits/storage/LibBeAdapter.cpp +++ b/src/kits/storage/LibBeAdapter.cpp @@ -1,41 +1,60 @@ // LibBeAdapter.cpp +#include +#include +#include +#include +#include +#include +#include + #include #include +#include +#include #include -#include #include +enum { + FD_TYPE_UNKNOWN, + FD_TYPE_DIR, + FD_TYPE_ATTR_DIR, + FD_TYPE_QUERY, +}; -extern "C" status_t -_kern_dir_node_ref_to_path(dev_t device, ino_t inode, char *buffer, size_t size) -{ - if (buffer == NULL) - return B_BAD_VALUE; +static const int kFDTableSlotCount = 1024; +static uint8 sFDTable[kFDTableSlotCount]; - node_ref nodeRef; - nodeRef.device = device; - nodeRef.node = inode; - - BDirectory directory; - status_t error = directory.SetTo(&nodeRef); - - BEntry entry; - if (error == B_OK) - error = directory.GetEntry(&entry); - - BPath path; - if (error == B_OK) - error = entry.GetPath(&path); - - if (error == B_OK) { - if (size >= strlen(path.Path()) + 1) - strcpy(buffer, path.Path()); - else - error = B_BAD_VALUE; +static struct InitDirFDTable { + InitDirFDTable() + { + memset(sFDTable, FD_TYPE_UNKNOWN, sizeof(sFDTable)); } - return error; +} sInitDirFDTable; + +// _kern_entry_ref_to_path +extern "C" +status_t +_kern_entry_ref_to_path(dev_t device, ino_t inode, const char *leaf, + char *userPath, size_t pathLength) +{ + // check buffer + if (!userPath) + return B_BAD_VALUE; + // construct an entry_ref + if (!leaf) + leaf = "."; + entry_ref ref(device, inode, leaf); + // get the path + BPath path; + status_t error = path.SetTo(&ref); + if (error != B_OK) + return error; + // copy the path into the buffer + if (strlcpy(userPath, path.Path(), pathLength) >= pathLength) + return B_BUFFER_OVERFLOW; + return B_OK; } @@ -43,7 +62,27 @@ _kern_dir_node_ref_to_path(dev_t device, ino_t inode, char *buffer, size_t size) // private libroot.so functions -extern "C" status_t _kwfsstat_(dev_t device, const struct fs_info *info, long mask); +extern "C" status_t _kclosedir_(int fd); + +extern "C" status_t _kclose_attr_dir_(int fd); + +extern "C" status_t _kclose_query_(int fd); + +extern "C" ssize_t _kreadlink_(int fd, const char *path, char *buffer, + size_t bufferSize); + +extern "C" status_t _krstat_(int fd, const char *path, struct stat *st, + int16 unknown); + +extern "C" status_t _kwstat_(int fd, const char *path, const struct stat *st, + uint32 mask, uint16 unknown); + +extern "C" status_t _kwfsstat_(dev_t device, const struct fs_info *info, + long mask); + +extern "C" status_t _klock_node_(int fd); + +extern "C" status_t _kunlock_node_(int fd); extern "C" status_t _kstart_watching_vnode_(dev_t device, ino_t node, uint32 flags, port_id port, @@ -86,3 +125,580 @@ _kern_stop_watching(dev_t device, ino_t node, uint32 flags, return _kstop_watching_vnode_(device, node, port, token); } +// init_dir +static +status_t +init_dir(BDirectory &dir, int fd) +{ + // get a node_ref for the dir + struct stat st; + if (fstat(fd, &st) < 0) + return errno; + node_ref ref; + ref.device = st.st_dev; + ref.node = st.st_ino; + // init the dir + return dir.SetTo(&ref); +} + +// open_dir_hack +static +int +open_dir_hack(const char *path) +{ + DIR *dirHandle = opendir(path); + if (!dirHandle) + return errno; + int dirFD = dirHandle->fd; + if (dirFD < 0 || dirFD >= kFDTableSlotCount) { + closedir(dirHandle); + return B_ERROR; + } + free(dirHandle); + sFDTable[dirFD] = FD_TYPE_DIR; + return dirFD; +} + +// get_path +static +int +get_path(int fd, const char *relPath, BPath &path) +{ + if (fd < 0 || relPath && relPath[0] == '/') + return path.SetTo(relPath); + BDirectory dir; + status_t error = init_dir(dir, fd); + if (error != B_OK) + return error; + return path.SetTo(&dir, relPath); +} + +// _kern_open +int +_kern_open(int fd, const char *path, int omode) +{ + status_t error; + BPath fullPath; + if (!path) + path = "."; + if (fd >= 0) { + // construct the full path + error = get_path(fd, path, fullPath); + if (error != B_OK) + return error; + path = fullPath.Path(); + } + // open the file + int result = open(path, omode); + if (result < 0) + return errno; + return result; +} + + +// _kern_open_entry_ref +extern "C" +int +_kern_open_entry_ref(dev_t device, ino_t inode, const char *name, int omode) +{ + BPath fullPath; + node_ref ref; + ref.device = device; + ref.node = inode; + // init the dir and get the path + BDirectory dir; + status_t error = dir.SetTo(&ref); + if (error != B_OK) + return error; + error = fullPath.SetTo(&dir, name); + if (error != B_OK) + return error; + // open the file + int fd = open(fullPath.Path(), omode); + if (fd < 0) + return errno; + return fd; +} + +// _kern_open_dir +extern "C" +int +_kern_open_dir(int fd, const char *path) +{ + status_t error; + BPath fullPath; + if (fd >= 0) { + if (!path) + return _kern_dup(fd); + // construct the full path + error = get_path(fd, path, fullPath); + if (error != B_OK) + return error; + path = fullPath.Path(); + } + // open the dir + return open_dir_hack(path); +} + +// _kern_open_dir_entry_ref +extern "C" +int +_kern_open_dir_entry_ref(dev_t device, ino_t inode, const char *path) +{ + BPath fullPath; + node_ref ref; + ref.device = device; + ref.node = inode; + // init the dir and get the path + BDirectory dir; + status_t error = dir.SetTo(&ref); + if (error != B_OK) + return error; + error = fullPath.SetTo(&dir, path); + if (error != B_OK) + return error; + path = fullPath.Path(); + // open the dir + return open_dir_hack(path); +} + +// _kern_open_parent_dir +extern "C" +int +_kern_open_parent_dir(int fd, char *name, size_t pathLength) +{ + if (fd < 0) + return B_BAD_VALUE; + // get the dir + BDirectory dir; + status_t error = init_dir(dir, fd); + if (error != B_OK) + return error; + // get an entry + BEntry entry; + error = entry.SetTo(&dir, NULL); + if (error != B_OK) + return error; + // copy back the path + if (name) { + char tmpName[B_FILE_NAME_LENGTH]; + error = entry.GetName(tmpName); + if (error != B_OK) + return error; + if (strlcpy(name, tmpName, pathLength) >= pathLength) + return B_BUFFER_OVERFLOW; + } + // get the parent dir path + BPath path; + error = path.SetTo(&dir, ".."); + if (error != B_OK) + return error; + // open the dir + return open_dir_hack(path.Path()); +} + +// _kern_open_query +extern "C" +int +_kern_open_query(dev_t device, const char *query, uint32 flags, port_id port, + int32 token) +{ + // check params + if (!query || device < 0) + return B_BAD_VALUE; + if (flags & B_LIVE_QUERY && port < 0) + return B_BAD_VALUE; + // open query + DIR *dirHandle; + if (flags & B_LIVE_QUERY) + dirHandle = fs_open_live_query(device, query, flags, port, token); + else + dirHandle = fs_open_query(device, query, flags); + if (!dirHandle) + return errno; + // get FD and return result + int dirFD = dirHandle->fd; + if (dirFD < 0 || dirFD >= kFDTableSlotCount) { + fs_close_query(dirHandle); + return B_ERROR; + } + free(dirHandle); + sFDTable[dirFD] = FD_TYPE_QUERY; + return dirFD; +} + +// _kern_create_dir +extern "C" +status_t +_kern_create_dir(int fd, const char *path, int perms) +{ + if (!path) + return B_BAD_VALUE; + status_t error; + BPath fullPath; + if (fd >= 0) { + // construct the full path + error = get_path(fd, path, fullPath); + if (error != B_OK) + return error; + path = fullPath.Path(); + } + // create the dir + return (mkdir(path, perms) < 0 ? errno : B_OK); +} + +// _kern_create_symlink +extern "C" +status_t +_kern_create_symlink(int fd, const char *path, const char *toPath, int mode) +{ + (void)mode; + if (!path) + return B_BAD_VALUE; + status_t error; + BPath fullPath; + if (fd >= 0) { + // construct the full path + error = get_path(fd, path, fullPath); + if (error != B_OK) + return error; + path = fullPath.Path(); + } + // create the symlink + return (symlink(toPath, path) < 0 ? errno : B_OK); +} + +// _kern_close +extern "C" +status_t +_kern_close(int fd) +{ + if (fd >= 0 && fd < kFDTableSlotCount && sFDTable[fd] != FD_TYPE_UNKNOWN) { + status_t error; + switch (sFDTable[fd]) { + case FD_TYPE_DIR: + error = _kclosedir_(fd); + break; + case FD_TYPE_ATTR_DIR: + error = _kclose_attr_dir_(fd); + break; + case FD_TYPE_QUERY: + error = _kclose_query_(fd); + break; + default: + error = B_BAD_VALUE; + break; + } + sFDTable[fd] = FD_TYPE_UNKNOWN; + if (error != B_OK) + return error; + } else if (close(fd) < 0) + return errno; + return B_OK; +} + +// _kern_dup +extern "C" +int +_kern_dup(int fd) +{ + int clonedFD = dup(fd); + if (clonedFD < 0) + return errno; + if (fd >= 0 && fd < kFDTableSlotCount && sFDTable[fd] != FD_TYPE_UNKNOWN + && clonedFD >= 0 && clonedFD < kFDTableSlotCount) { + sFDTable[clonedFD] = sFDTable[fd]; + } + return clonedFD; +} + +// _kern_read +extern "C" +ssize_t +_kern_read(int fd, off_t pos, void *buffer, size_t bufferSize) +{ + if (!buffer) + return B_BAD_VALUE; + ssize_t result; + if (pos == -1) + result = read(fd, buffer, bufferSize); + else + result = read_pos(fd, pos, buffer, bufferSize); + return (result < 0 ? errno : result); +} + +// _kern_write +extern "C" +ssize_t +_kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize) +{ + if (!buffer) + return B_BAD_VALUE; + ssize_t result; + if (pos == -1) + result = write(fd, buffer, bufferSize); + else + result = write_pos(fd, pos, buffer, bufferSize); + return (result < 0 ? errno : result); +} + +// _kern_seek +extern "C" +off_t +_kern_seek(int fd, off_t pos, int seekType) +{ + off_t result = lseek(fd, pos, seekType); + return (result < 0 ? errno : result); +} + +// _kern_read_dir +extern "C" +ssize_t +_kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, + uint32 maxCount) +{ + if (fd < 0 || !buffer) + return B_BAD_VALUE; + if (fd >= kFDTableSlotCount || sFDTable[fd] == FD_TYPE_UNKNOWN) + return B_BAD_VALUE; + if (maxCount < 1) + return 0; + char tmpBuffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH]; + DIR *dirDir = (DIR*)tmpBuffer; + dirDir->fd = fd; + dirent *entry = NULL; + switch (sFDTable[fd]) { + case FD_TYPE_DIR: + entry = readdir(dirDir); + break; + case FD_TYPE_ATTR_DIR: + entry = fs_read_attr_dir(dirDir); + break; + case FD_TYPE_QUERY: + entry = fs_read_query(dirDir); + break; + } + if (!entry) + return 0; + // Don't trust entry->d_reclen. + // Unlike stated in BeBook::BEntryList, the value is not the length + // of the whole structure, but only of the name. Some FSs count + // the terminating '\0', others don't. + // So we calculate the size ourselves (including the '\0'): + size_t entryLen = entry->d_name + strlen(entry->d_name) + 1 + - (char*)entry; + if (bufferSize >= entryLen) { + memcpy(buffer, entry, entryLen); + return 1; + } else // buffer too small + return B_BUFFER_OVERFLOW; +} + +// _kern_rewind_dir +extern "C" +status_t +_kern_rewind_dir(int fd) +{ + if (fd < 0 || fd >= kFDTableSlotCount || sFDTable[fd] == FD_TYPE_UNKNOWN) + return B_BAD_VALUE; + char tmpBuffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH]; + DIR *dirDir = (DIR*)tmpBuffer; + dirDir->fd = fd; + switch (sFDTable[fd]) { + case FD_TYPE_DIR: + rewinddir(dirDir); + break; + case FD_TYPE_ATTR_DIR: + fs_rewind_attr_dir(dirDir); + break; + case FD_TYPE_QUERY: + return B_BAD_VALUE; + break; + } + return B_OK; +} + +// _kern_read_link +extern "C" +ssize_t +_kern_read_link(int fd, const char *path, char *buffer, size_t bufferSize) +{ + ssize_t result = _kreadlink_(fd, path, buffer, bufferSize); + if (result >= 0) + buffer[result] = '\0'; + + return result; +} + +// _kern_unlink +extern "C" +status_t +_kern_unlink(int fd, const char *relPath) +{ + BPath path; + status_t error = get_path(fd, relPath, path); + if (error != B_OK) + return error; + if (unlink(path.Path()) < 0) { + error = errno; + if (error == B_IS_A_DIRECTORY) { + if (rmdir(path.Path()) < 0) + return errno; + } else + return error; + } + return B_OK; +} + +// _kern_rename +extern "C" +status_t +_kern_rename(int oldDir, const char *oldRelPath, int newDir, + const char *newRelPath) +{ + // get old path + BPath oldPath; + status_t error = get_path(oldDir, oldRelPath, oldPath); + if (error != B_OK) + return error; + // get new path + BPath newPath; + error = get_path(newDir, newRelPath, newPath); + if (error != B_OK) + return error; + // rename + if (rename(oldPath.Path(), newPath.Path()) < 0) + return errno; + return B_OK; +} + + +// _kern_read_stat +extern "C" +status_t +_kern_read_stat(int fd, const char *path, bool traverseLink, struct stat *st, + size_t statSize) +{ + if (traverseLink) + return B_ERROR; // unsupported + return _krstat_(fd, path, st, 0); +} + +// _kern_write_stat +extern "C" +status_t +_kern_write_stat(int fd, const char *path, bool traverseLink, + const struct stat *st, size_t statSize, int statMask) +{ + if (traverseLink) + return B_ERROR; // unsupported + return _kwstat_(fd, path, st, statMask, 0); +} + +// _kern_lock_node +extern "C" +status_t +_kern_lock_node(int fd) +{ + return _klock_node_(fd); +} + +// _kern_unlock_node +extern "C" +status_t +_kern_unlock_node(int fd) +{ + return _kunlock_node_(fd); +} + +// _kern_fsync +extern "C" +status_t +_kern_fsync(int fd) +{ + return (fsync(fd) < 0) ? errno : B_OK ; +} + +// _kern_open_attr_dir +extern "C" +int +_kern_open_attr_dir(int fd, const char *path) +{ + if (fd < 0 && !path) + return B_BAD_VALUE; + if (fd >= 0 && path) + return B_ERROR; // unsupported + DIR *dirHandle = (fd >= 0 ? fs_fopen_attr_dir(fd) : fs_open_attr_dir(path)); + if (!dirHandle) + return errno; + int dirFD = dirHandle->fd; + if (dirFD < 0 || dirFD >= kFDTableSlotCount) { + fs_close_attr_dir(dirHandle); + return B_ERROR; + } + free(dirHandle); + sFDTable[dirFD] = FD_TYPE_ATTR_DIR; + return dirFD; +} + +// _kern_remove_attr +extern "C" +status_t +_kern_remove_attr(int fd, const char *name) +{ + return fs_remove_attr(fd, name) == -1 ? errno : B_OK ; +} + +// _kern_rename_attr +extern "C" +status_t +_kern_rename_attr(int fromFile, const char *fromName, int toFile, + const char *toName) +{ + status_t error = (fromName && toName ? B_OK : B_BAD_VALUE); + // Figure out how much data there is + attr_info info; + if (error == B_OK) { + if (fs_stat_attr(fromFile, fromName, &info) < 0) + error = B_BAD_VALUE; // This is what R5::BNode returns... + } + // Alloc a buffer + char *data = NULL; + if (error == B_OK) { + // alloc at least one byte + data = new(nothrow) char[info.size >= 1 ? info.size : 1]; + if (data == NULL) + error = B_NO_MEMORY; + } + // Read in the data + if (error == B_OK) { + ssize_t size = fs_read_attr(fromFile, fromName, info.type, 0, data, + info.size); + if (size != info.size) { + if (size < 0) + error = errno; + else + error = B_ERROR; + } + } + // Write it to the new attribute + if (error == B_OK) { + ssize_t size = 0; + if (info.size > 0) + size = fs_write_attr(toFile, toName, info.type, 0, data, info.size); + if (size != info.size) { + if (size < 0) + error = errno; + else + error = B_ERROR; + } + } + // free the buffer + if (data) + delete[] data; + // Remove the old attribute + if (error == B_OK) + error = _kern_remove_attr(fromFile, fromName); + return error; +} + diff --git a/src/kits/storage/Node.cpp b/src/kits/storage/Node.cpp index 3a4e85509d..5641a03758 100644 --- a/src/kits/storage/Node.cpp +++ b/src/kits/storage/Node.cpp @@ -7,15 +7,20 @@ BNode implementation. */ +#include #include // for struct attr_info #include #include #include -#include +#include #include +#include +#include +#include + +#include -#include "kernel_interface.h" #include "storage_support.h" //---------------------------------------------------------------------- @@ -84,8 +89,8 @@ node_ref::operator=(const node_ref &ref) /*! \brief Creates an uninitialized BNode object */ BNode::BNode() - : fFd(BPrivate::Storage::NullFd), - fAttrFd(BPrivate::Storage::NullFd), + : fFd(-1), + fAttrFd(-1), fCStatus(B_NO_INIT) { } @@ -95,8 +100,8 @@ BNode::BNode() \param ref the entry_ref referring to the entry */ BNode::BNode(const entry_ref *ref) - : fFd(BPrivate::Storage::NullFd), - fAttrFd(BPrivate::Storage::NullFd), + : fFd(-1), + fAttrFd(-1), fCStatus(B_NO_INIT) { SetTo(ref); @@ -107,8 +112,8 @@ BNode::BNode(const entry_ref *ref) \param entry the BEntry representing the entry */ BNode::BNode(const BEntry *entry) - : fFd(BPrivate::Storage::NullFd), - fAttrFd(BPrivate::Storage::NullFd), + : fFd(-1), + fAttrFd(-1), fCStatus(B_NO_INIT) { SetTo(entry); @@ -119,8 +124,8 @@ BNode::BNode(const BEntry *entry) \param path the path referring to the entry */ BNode::BNode(const char *path) - : fFd(BPrivate::Storage::NullFd), - fAttrFd(BPrivate::Storage::NullFd), + : fFd(-1), + fAttrFd(-1), fCStatus(B_NO_INIT) { SetTo(path); @@ -133,8 +138,8 @@ BNode::BNode(const char *path) \param path the entry's path name relative to \a dir */ BNode::BNode(const BDirectory *dir, const char *path) - : fFd(BPrivate::Storage::NullFd), - fAttrFd(BPrivate::Storage::NullFd), + : fFd(-1), + fAttrFd(-1), fCStatus(B_NO_INIT) { SetTo(dir, path); @@ -144,8 +149,8 @@ BNode::BNode(const BDirectory *dir, const char *path) \param node the BNode to be copied */ BNode::BNode(const BNode &node) - : fFd(BPrivate::Storage::NullFd), - fAttrFd(BPrivate::Storage::NullFd), + : fFd(-1), + fAttrFd(-1), fCStatus(B_NO_INIT) { *this = node; @@ -180,7 +185,9 @@ BNode::InitCheck() const status_t BNode::GetStat(struct stat *st) const { - return (fCStatus != B_OK) ? fCStatus : BPrivate::Storage::get_stat(fFd, st) ; + return (fCStatus != B_OK) + ? fCStatus + : _kern_read_stat(fFd, NULL, false, st, sizeof(struct stat)); } /*! \brief Reinitializes the object to the specified entry_ref. @@ -190,23 +197,11 @@ BNode::GetStat(struct stat *st) const - \c B_BAD_VALUE: \c NULL \a ref. - \c B_ENTRY_NOT_FOUND: The entry could not be found. - \c B_BUSY: The entry is locked. - \todo Currently implemented using BPrivate::Storage::entry_ref_to_path(). - Reimplement! */ status_t BNode::SetTo(const entry_ref *ref) { - Unset(); - char path[B_PATH_NAME_LENGTH]; - status_t error = (ref ? B_OK : B_BAD_VALUE); - if (error == B_OK) { - error = BPrivate::Storage::entry_ref_to_path(ref, path, - B_PATH_NAME_LENGTH); - } - if (error == B_OK) - error = SetTo(path); - fCStatus = error; - return error; + return _SetTo(ref, false); } /*! \brief Reinitializes the object to the specified filesystem entry. @@ -216,23 +211,15 @@ BNode::SetTo(const entry_ref *ref) - \c B_BAD_VALUE: \c NULL \a entry. - \c B_ENTRY_NOT_FOUND: The entry could not be found. - \c B_BUSY: The entry is locked. - \todo Implemented using SetTo(entry_ref*). Check, if necessary to - reimplement! */ status_t BNode::SetTo(const BEntry *entry) { - Unset(); - entry_ref ref; - status_t error = (entry ? B_OK : B_BAD_VALUE); - if (error == B_OK && entry->InitCheck() != B_OK) - error = B_BAD_VALUE; - if (error == B_OK) - error = entry->GetRef(&ref); - if (error == B_OK) - error = SetTo(&ref); - fCStatus = error; - return error; + if (!entry) { + Unset(); + return (fCStatus = B_BAD_VALUE); + } + return _SetTo(entry->fDirFd, entry->fName, false); } /*! \brief Reinitializes the object to the entry referred to by the specified @@ -247,12 +234,7 @@ BNode::SetTo(const BEntry *entry) status_t BNode::SetTo(const char *path) { - Unset(); - if (path != NULL) { - fCStatus = BPrivate::Storage::open(path, O_RDWR | O_NOTRAVERSE, fFd, - true); - } - return fCStatus; + return _SetTo(-1, path, false); } /*! \brief Reinitializes the object to the entry referred to by the specified @@ -265,22 +247,15 @@ BNode::SetTo(const char *path) - \c B_BAD_VALUE: \c NULL \a dir or \a path. - \c B_ENTRY_NOT_FOUND: The entry could not be found. - \c B_BUSY: The entry is locked. - \todo Implemented using SetTo(BEntry*). Check, if necessary to reimplement! */ status_t BNode::SetTo(const BDirectory *dir, const char *path) { - Unset(); - status_t error = (dir && path ? B_OK : B_BAD_VALUE); - if (error == B_OK && BPrivate::Storage::is_absolute_path(path)) - error = B_BAD_VALUE; - BEntry entry; - if (error == B_OK) - error = entry.SetTo(dir, path); - if (error == B_OK) - error = SetTo(&entry); - fCStatus = error; - return error; + if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) { + Unset(); + return (fCStatus = B_BAD_VALUE); + } + return _SetTo(dir->fDirFd, path, false); } /*! \brief Returns the object to an uninitialized state. @@ -298,21 +273,13 @@ BNode::Unset() - \c B_OK: Everything went fine. - \c B_FILE_ERROR: The object is not initialized. - \c B_BUSY: The node is already locked. - \todo Currently unimplemented; requires new kernel. */ status_t BNode::Lock() { if (fCStatus != B_OK) return fCStatus; - - // This will have to wait for the new kenel - return B_FILE_ERROR; - - // We'll need to keep lock around if the kernel function - // doesn't just work on file descriptors -// BPrivate::Storage::FileLock lock; -// return BPrivate::Storage::lock(fFd, BPrivate::Storage::READ_WRITE, &lock); + return _kern_lock_node(fFd); } /*! \brief Unlocks the node. @@ -320,15 +287,13 @@ BNode::Lock() - \c B_OK: Everything went fine. - \c B_FILE_ERROR: The object is not initialized. - \c B_BAD_VALUE: The node is not locked. - \todo Currently unimplemented; requires new kernel. */ status_t BNode::Unlock() { if (fCStatus != B_OK) return fCStatus; - // This will have to wait for the new kenel - return B_FILE_ERROR; + return _kern_unlock_node(fFd); } /*! \brief Immediately performs any pending disk actions on the node. @@ -339,7 +304,7 @@ BNode::Unlock() status_t BNode::Sync() { - return (fCStatus != B_OK) ? B_FILE_ERROR : BPrivate::Storage::sync(fFd) ; + return (fCStatus != B_OK) ? B_FILE_ERROR : _kern_fsync(fFd); } /*! \brief Writes data from a buffer to an attribute. @@ -368,11 +333,10 @@ BNode::WriteAttr(const char *attr, type_code type, off_t offset, { if (fCStatus != B_OK) return B_FILE_ERROR; - else { - ssize_t result = BPrivate::Storage::write_attr(fFd, attr, type, offset, - buffer, len); - return result; - } + if (!attr || !buffer) + return B_BAD_VALUE; + ssize_t result = fs_write_attr (fFd, attr, type, offset, buffer, len); + return (result < 0 ? errno : result); } /*! \brief Reads data from an attribute into a buffer. @@ -396,11 +360,10 @@ BNode::ReadAttr(const char *attr, type_code type, off_t offset, { if (fCStatus != B_OK) return B_FILE_ERROR; - else { - ssize_t result = BPrivate::Storage::read_attr(fFd, attr, type, offset, buffer, - len); - return result; - } + if (!attr || !buffer) + return B_BAD_VALUE; + ssize_t result = fs_read_attr(fFd, attr, type, offset, buffer, len ); + return (result == -1 ? errno : result); } /*! \brief Deletes the attribute given by \a name. @@ -415,8 +378,7 @@ BNode::ReadAttr(const char *attr, type_code type, off_t offset, status_t BNode::RemoveAttr(const char *name) { - return (fCStatus != B_OK) ? B_FILE_ERROR - : BPrivate::Storage::remove_attr(fFd, name); + return (fCStatus != B_OK) ? B_FILE_ERROR : _kern_remove_attr(fFd, name); } /*! \brief Moves the attribute given by \a oldname to \a newname. @@ -436,7 +398,7 @@ BNode::RenameAttr(const char *oldname, const char *newname) { if (fCStatus != B_OK) return B_FILE_ERROR; - return BPrivate::Storage::rename_attr(fFd, oldname, newname); + return _kern_rename_attr(fFd, oldname, fFd, newname); } @@ -453,8 +415,11 @@ BNode::RenameAttr(const char *oldname, const char *newname) status_t BNode::GetAttrInfo(const char *name, struct attr_info *info) const { - return (fCStatus != B_OK) ? B_FILE_ERROR - : BPrivate::Storage::stat_attr(fFd, name, info); + if (fCStatus != B_OK) + return B_FILE_ERROR; + if (!name || !info) + return B_BAD_VALUE; + return (fs_stat_attr(fFd, name, info) < 0) ? errno : B_OK ; } /*! \brief Returns the next attribute in the node's list of attributes. @@ -486,12 +451,13 @@ BNode::GetNextAttrName(char *buffer) return B_FILE_ERROR; BPrivate::Storage::LongDirEntry entry; - status_t error = BPrivate::Storage::read_attr_dir(fAttrFd, entry); - if (error == B_OK) { - strncpy(buffer, entry.d_name, B_ATTR_NAME_LENGTH); - return B_OK; - } - return error; + ssize_t result = _kern_read_dir(fAttrFd, &entry, sizeof(entry), 1); + if (result < 0) + return result; + if (result == 0) + return B_ENTRY_NOT_FOUND; + strlcpy(buffer, entry.d_name, B_ATTR_NAME_LENGTH); + return B_OK; } /*! \brief Resets the object's attribute pointer to the first attribute in the @@ -505,8 +471,7 @@ BNode::RewindAttrs() { if (InitAttrDir() != B_OK) return B_FILE_ERROR; - BPrivate::Storage::rewind_attr_dir(fAttrFd); - return B_OK; + return _kern_rewind_dir(fAttrFd); } /*! Writes the specified string to the specified attribute, clobbering any @@ -590,8 +555,8 @@ BNode::operator=(const BNode &node) Unset(); // We have to manually dup the node, because R5::BNode::Dup() // is not declared to be const (which IMO is retarded). - fFd = BPrivate::Storage::dup(node.fFd); - fCStatus = (fFd == BPrivate::Storage::NullFd) ? B_NO_INIT : B_OK ; + fFd = _kern_dup(node.fFd); + fCStatus = (fFd < 0) ? B_NO_INIT : B_OK ; return *this; } @@ -607,13 +572,13 @@ BNode::operator==(const BNode &node) const if (fCStatus == B_NO_INIT && node.InitCheck() == B_NO_INIT) return true; if (fCStatus == B_OK && node.InitCheck() == B_OK) { - // Check if they're identical - BPrivate::Storage::Stat s1, s2; - if (GetStat(&s1) != B_OK) + // compare the node_refs + node_ref ref1, ref2; + if (GetNodeRef(&ref1) != B_OK) return false; - if (node.GetStat(&s2) != B_OK) + if (node.GetNodeRef(&ref2) != B_OK) return false; - return (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino); + return (ref1 == ref2); } return false; } @@ -638,7 +603,8 @@ BNode::operator!=(const BNode &node) const int BNode::Dup() { - return BPrivate::Storage::dup(fFd); + int fd = _kern_dup(fFd); + return (fd >= 0 ? fd : -1); // comply with R5 return value } @@ -662,7 +628,7 @@ void BNode::_RudeNode6() { } thereafter. */ status_t -BNode::set_fd(BPrivate::Storage::FileDescriptor fd) +BNode::set_fd(int fd) { if (fFd != -1) close_fd(); @@ -673,20 +639,19 @@ BNode::set_fd(BPrivate::Storage::FileDescriptor fd) /*! \brief Closes the node's file descriptor(s). To be implemented by subclasses to close the file descriptor using the proper system call for the given file-type. This implementation calls - BPrivate::Storage::close(fFd) and also BPrivate::Storage::close_attr_dir(fAttrDir) - if necessary. + _kern_close(fFd) and also _kern_close(fAttrDir) if necessary. */ void BNode::close_fd() { - if (fAttrFd != BPrivate::Storage::NullFd) + if (fAttrFd >= 0) { - BPrivate::Storage::close_attr_dir(fAttrFd); - fAttrFd = BPrivate::Storage::NullFd; + _kern_close(fAttrFd); + fAttrFd = -1; } - if (fFd != BPrivate::Storage::NullFd) { - close(fFd); - fFd = BPrivate::Storage::NullFd; + if (fFd >= 0) { + _kern_close(fFd); + fFd = -1; } } @@ -702,6 +667,84 @@ BNode::set_status(status_t newStatus) fCStatus = newStatus; } +// _SetTo +/*! \brief Initializes the BNode's file descriptor to the node referred to + by the given FD and path combo. + + \a path must either be \c NULL, an absolute or a relative path. + In the first case, \a fd must not be \c NULL; the node it refers to will + be opened. If absolute, \a fd is ignored. If relative and \a fd is >= 0, + it will be reckoned off the directory identified by \a fd, otherwise off + the current working directory. + + The method will first try to open the node with read and write permission. + If that fails due to a read-only FS or because the user has no write + permission for the node, it will re-try opening the node read-only. + + The \a fCStatus member will be set to the return value of this method. + + \param fd Either a directory FD or a value < 0. In the latter case \a path + must be specified. + \param path Either \a NULL in which case \a fd must be given, absolute, or + relative to the directory specified by \a fd (if given) or to the + current working directory. + \param traverse If the node identified by \a fd and \a path is a symlink + and \a traverse is \c true, the symlink will be resolved recursively. + \return \c B_OK, if everything went fine, another error code otherwise. +*/ +status_t +BNode::_SetTo(int fd, const char *path, bool traverse) +{ + Unset(); + status_t error = (fd >= 0 || path ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + int traverseFlag = (traverse ? 0 : O_NOTRAVERSE); + fFd = _kern_open(fd, path, O_RDWR | traverseFlag); + if (fFd == B_READ_ONLY_DEVICE || fFd == B_PERMISSION_DENIED) { + // opening read-write failed, re-try read-only + fFd = _kern_open(fd, path, O_RDONLY | traverseFlag); + } + if (fFd < 0) + error = fFd; + } + return fCStatus = error; +} + +// _SetTo +/*! \brief Initializes the BNode's file descriptor to the node referred to + by the given entry_ref. + + The method will first try to open the node with read and write permission. + If that fails due to a read-only FS or because the user has no write + permission for the node, it will re-try opening the node read-only. + + The \a fCStatus member will be set to the return value of this method. + + \param ref An entry_ref identifying the node to be opened. + \param traverse If the node identified by \a ref is a symlink + and \a traverse is \c true, the symlink will be resolved recursively. + \return \c B_OK, if everything went fine, another error code otherwise. +*/ +status_t +BNode::_SetTo(const entry_ref *ref, bool traverse) +{ + Unset(); + status_t error = (ref ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + int traverseFlag = (traverse ? 0 : O_NOTRAVERSE); + fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name, + O_RDWR | traverseFlag); + if (fFd == B_READ_ONLY_DEVICE || fFd == B_PERMISSION_DENIED) { + // opening read-write failed, re-try read-only + fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name, + O_RDONLY | traverseFlag); + } + if (fFd < 0) + error = fFd; + } + return fCStatus = error; +} + /*! \brief Modifies a certain setting for this node based on \a what and the corresponding value in \a st. Inherited from and called by BStatable. @@ -714,7 +757,8 @@ BNode::set_stat(struct stat &st, uint32 what) { if (fCStatus != B_OK) return B_FILE_ERROR; - return BPrivate::Storage::set_stat(fFd, st, what); + return _kern_write_stat(fFd, NULL, false, &st, sizeof(struct stat), + what); } /*! \brief Verifies that the BNode has been properly initialized, and then @@ -725,8 +769,11 @@ BNode::set_stat(struct stat &st, uint32 what) status_t BNode::InitAttrDir() { - if (fCStatus == B_OK && fAttrFd == BPrivate::Storage::NullFd) - return BPrivate::Storage::open_attr_dir(fFd, fAttrFd); + if (fCStatus == B_OK && fAttrFd < 0) { + fAttrFd = _kern_open_attr_dir(fFd, NULL); + if (fAttrFd < 0) + return fAttrFd; + } return fCStatus; } @@ -735,16 +782,10 @@ BNode::InitAttrDir() */ /*! \var BNode::fAttrFd - This appears to be passed to the attribute directory functions - like a BPrivate::Storage::Dir would be, but it's actually a file descriptor. - Best I can figure, the R5 syscall for reading attributes must've - just taken a file descriptor. Depending on what our kernel ends up - providing, this may or may not be replaced with an Dir* + File descriptor for the attribute directory of the node. Initialized lazily. */ /*! \var BNode::fCStatus The object's initialization status. */ - - diff --git a/src/kits/storage/Path.cpp b/src/kits/storage/Path.cpp index c4f89002b5..f5844229b9 100644 --- a/src/kits/storage/Path.cpp +++ b/src/kits/storage/Path.cpp @@ -14,7 +14,9 @@ #include #include #include -#include "kernel_interface.h" + +#include + #include "storage_support.h" using namespace std; @@ -125,15 +127,16 @@ status_t BPath::SetTo(const entry_ref *ref) { Unset(); - status_t error = (ref ? B_OK : B_BAD_VALUE); - if (error == B_OK) { - char path[B_PATH_NAME_LENGTH]; - error = BPrivate::Storage::entry_ref_to_path(ref, path, sizeof(path)); - if (error == B_OK) - error = set_path(path); // the path is already normalized - } - fCStatus = error; - return error; + if (!ref) + return (fCStatus = B_BAD_VALUE); + + char path[B_PATH_NAME_LENGTH]; + status_t error = _kern_entry_ref_to_path(ref->device, ref->directory, + ref->name, path, sizeof(path)); + if (error != B_OK) + return (fCStatus = error); + fCStatus = set_path(path); // the path is already normalized + return fCStatus; } /*! \brief Reinitializes the object to the specified filesystem entry. @@ -214,11 +217,11 @@ BPath::SetTo(const char *path, const char *leaf, bool normalize) // normalize the path, if necessary, otherwise just set it if (error == B_OK) { if (normalize) { - char normalizedPath[B_PATH_NAME_LENGTH]; - error = BPrivate::Storage::get_canonical_path(newPath, normalizedPath, - sizeof(normalizedPath)); + // create a BEntry and initialize us with this entry + BEntry entry; + error = entry.SetTo(newPath, false); if (error == B_OK) - error = set_path(normalizedPath); + return SetTo(&entry); } else error = set_path(newPath); } diff --git a/src/kits/storage/Query.cpp b/src/kits/storage/Query.cpp index 736d7974ad..acd7f171d7 100644 --- a/src/kits/storage/Query.cpp +++ b/src/kits/storage/Query.cpp @@ -6,7 +6,6 @@ \file Query.cpp BQuery implementation. */ -#include #include #include @@ -14,18 +13,17 @@ #include #include +#include #include -#include "kernel_interface.h" +#include +#include + #include "QueryPredicate.h" +#include "storage_support.h" -using namespace BPrivate::Storage; using namespace std; - - -enum { - NOT_IMPLEMENTED = B_ERROR, -}; +using namespace BPrivate::Storage; // BQuery @@ -40,7 +38,7 @@ BQuery::BQuery() fLive(false), fPort(B_ERROR), fToken(0), - fQueryFd(NullFd) + fQueryFd(-1) { } @@ -61,9 +59,9 @@ BQuery::Clear() { // close the currently open query status_t error = B_OK; - if (fQueryFd != NullFd) { - error = close_query(fQueryFd); - fQueryFd = NullFd; + if (fQueryFd >= 0) { + error = _kern_close(fQueryFd); + fQueryFd = -1; } // delete the predicate stack and the predicate delete fStack; @@ -314,10 +312,8 @@ BQuery::PushDate(const char *date) time_t t; time(&t); t = parsedate(date, t); - if (t < 0) { -// error = t; + if (t < 0) error = B_BAD_VALUE; - } } if (error == B_OK) error = _PushNode(new(nothrow) DateNode(date), true); @@ -391,8 +387,10 @@ BQuery::SetTarget(BMessenger messenger) if (error == B_OK && _HasFetched()) error = B_NOT_ALLOWED; if (error == B_OK) { - fPort = messenger.fPort; - fToken = messenger.fHandlerToken; + BMessenger::Private messengerPrivate(messenger); + fPort = messengerPrivate.Port(); + fToken = (messengerPrivate.IsPreferredTarget() + ? -1 : messengerPrivate.Token()); fLive = true; } return error; @@ -428,7 +426,6 @@ BQuery::GetPredicate(char *buffer, size_t length) { status_t error = (buffer ? B_OK : B_BAD_VALUE); if (error == B_OK) -// error = _EvaluateStack(); _EvaluateStack(); if (error == B_OK && !fPredicate) error = B_NO_INIT; @@ -458,7 +455,6 @@ BQuery::GetPredicate(BString *predicate) { status_t error = (predicate ? B_OK : B_BAD_VALUE); if (error == B_OK) -// error = _EvaluateStack(); _EvaluateStack(); if (error == B_OK && !fPredicate) error = B_NO_INIT; @@ -518,20 +514,19 @@ BQuery::TargetDevice() const status_t BQuery::Fetch() { - status_t error = (_HasFetched() ? B_NOT_ALLOWED : B_OK); - if (error == B_OK) -// error = _EvaluateStack(); - _EvaluateStack(); - if (error == B_OK && (!fPredicate || fDevice < 0)) - error = B_NO_INIT; - if (error == B_OK) { - if (fLive) { - error = open_live_query(fDevice, fPredicate, B_LIVE_QUERY, fPort, - fToken, fQueryFd); - } else - error = open_query(fDevice, fPredicate, 0, fQueryFd); - } - return error; + if (_HasFetched()) + return B_NOT_ALLOWED; + _EvaluateStack(); + if (!fPredicate || fDevice < 0) + return B_NO_INIT; + if (fLive) { + fQueryFd = _kern_open_query(fDevice, fPredicate, B_LIVE_QUERY, + fPort, fToken); + } else + fQueryFd = _kern_open_query(fDevice, fPredicate, 0, -1, -1); + if (fQueryFd < 0) + return fQueryFd; + return B_OK; } @@ -586,10 +581,20 @@ BQuery::GetNextRef(entry_ref *ref) error = B_FILE_ERROR; if (error == B_OK) { BPrivate::Storage::LongDirEntry entry; - if (BPrivate::Storage::read_query(fQueryFd, &entry, sizeof(entry), 1) != 1) - error = B_ENTRY_NOT_FOUND; - if (error == B_OK) - *ref = entry_ref(entry.d_pdev, entry.d_pino, entry.d_name); + bool next = true; + while (error == B_OK && next) { + if (GetNextDirents(&entry, sizeof(entry), 1) != 1) { + error = B_ENTRY_NOT_FOUND; + } else { + next = (!strcmp(entry.d_name, ".") + || !strcmp(entry.d_name, "..")); + } + } + if (error == B_OK) { + ref->device = entry.d_pdev; + ref->directory = entry.d_pino; + error = ref->set_name(entry.d_name); + } } return error; } @@ -614,12 +619,11 @@ BQuery::GetNextRef(entry_ref *ref) int32 BQuery::GetNextDirents(struct dirent *buf, size_t length, int32 count) { - int32 result = (buf ? B_OK : B_BAD_VALUE); - if (result == B_OK && !_HasFetched()) - result = B_FILE_ERROR; - if (result == B_OK) - result = read_query(fQueryFd, buf, length, count); - return result; + if (!buf) + return B_BAD_VALUE; + if (!_HasFetched()) + return B_FILE_ERROR; + return _kern_read_dir(fQueryFd, buf, length, count); } // Rewind @@ -650,7 +654,7 @@ BQuery::CountEntries() bool BQuery::_HasFetched() const { - return (fQueryFd != NullFd); + return (fQueryFd >= 0); } // _PushNode @@ -758,5 +762,3 @@ void BQuery::_QwertyQuery4() {} void BQuery::_QwertyQuery5() {} void BQuery::_QwertyQuery6() {} - - diff --git a/src/kits/storage/ResourceStrings.cpp b/src/kits/storage/ResourceStrings.cpp index 11b0dc4f96..10ae4bebc7 100644 --- a/src/kits/storage/ResourceStrings.cpp +++ b/src/kits/storage/ResourceStrings.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -17,7 +18,7 @@ #include #include -#include "kernel_interface.h" +#include using namespace std; @@ -139,12 +140,8 @@ BResourceStrings::SetStringFile(const entry_ref *ref) if (ref) { fileRef = *ref; fFileRef = *ref; - } else { - char appPath[B_PATH_NAME_LENGTH]; - error = BPrivate::Storage::get_app_path(appPath); - if (error == B_OK) - error = get_ref_for_path(appPath, &fileRef); - } + } else + error = BPrivate::get_app_ref(&fileRef); // get the BResources if (error == B_OK) { BFile file(&fileRef, B_READ_ONLY); diff --git a/src/kits/storage/Statable.cpp b/src/kits/storage/Statable.cpp index b1124413dc..149c4f5c80 100644 --- a/src/kits/storage/Statable.cpp +++ b/src/kits/storage/Statable.cpp @@ -14,7 +14,6 @@ #include #include "fsproto.h" -#include "kernel_interface.h" /*! \fn status_t GetStat(struct stat *st) const \brief Returns the stat stucture for the node. diff --git a/src/kits/storage/SymLink.cpp b/src/kits/storage/SymLink.cpp index d17867cedf..7a2a197bad 100644 --- a/src/kits/storage/SymLink.cpp +++ b/src/kits/storage/SymLink.cpp @@ -13,7 +13,9 @@ #include #include #include -#include "kernel_interface.h" + +#include + #include "storage_support.h" using namespace std; @@ -26,8 +28,6 @@ namespace OpenBeOS { //! Creates an uninitialized BSymLink object. BSymLink::BSymLink() : BNode() - // WORKAROUND - , fSecretEntry(new(nothrow) BEntry) { } @@ -36,11 +36,8 @@ BSymLink::BSymLink() /*! \param link the BSymLink object to be copied */ BSymLink::BSymLink(const BSymLink &link) - : BNode() - // WORKAROUND - , fSecretEntry(new(nothrow) BEntry) + : BNode(link) { - *this = link; } // constructor @@ -49,11 +46,8 @@ BSymLink::BSymLink(const BSymLink &link) \param ref the entry_ref referring to the symbolic link */ BSymLink::BSymLink(const entry_ref *ref) - : BNode() - // WORKAROUND - , fSecretEntry(new(nothrow) BEntry) + : BNode(ref) { - SetTo(ref); } // constructor @@ -62,11 +56,8 @@ BSymLink::BSymLink(const entry_ref *ref) \param entry the BEntry referring to the symbolic link */ BSymLink::BSymLink(const BEntry *entry) - : BNode() - // WORKAROUND - , fSecretEntry(new(nothrow) BEntry) + : BNode(entry) { - SetTo(entry); } // constructor @@ -75,11 +66,8 @@ BSymLink::BSymLink(const BEntry *entry) \param path the symbolic link's path name */ BSymLink::BSymLink(const char *path) - : BNode() - // WORKAROUND - , fSecretEntry(new(nothrow) BEntry) + : BNode(path) { - SetTo(path); } // constructor @@ -90,11 +78,8 @@ BSymLink::BSymLink(const char *path) \param path the symbolic link's path name relative to \a dir */ BSymLink::BSymLink(const BDirectory *dir, const char *path) - : BNode() - // WORKAROUND - , fSecretEntry(new(nothrow) BEntry) + : BNode(dir, path) { - SetTo(dir, path); } // destructor @@ -104,76 +89,8 @@ BSymLink::BSymLink(const BDirectory *dir, const char *path) */ BSymLink::~BSymLink() { - // WORKAROUND - delete fSecretEntry; } -// WORKAROUND -status_t -BSymLink::SetTo(const entry_ref *ref) -{ - status_t error = BNode::SetTo(ref); - if (fSecretEntry) { - fSecretEntry->Unset(); - if (error == B_OK) - fSecretEntry->SetTo(ref); - } else - error = B_NO_MEMORY; - return error; -} - -// WORKAROUND -status_t -BSymLink::SetTo(const BEntry *entry) -{ - status_t error = BNode::SetTo(entry); - if (fSecretEntry) { - fSecretEntry->Unset(); - if (error == B_OK) - *fSecretEntry = *entry; - } else - error = B_NO_MEMORY; - return error; -} - -// WORKAROUND -status_t -BSymLink::SetTo(const char *path) -{ - status_t error = BNode::SetTo(path); - if (fSecretEntry) { - fSecretEntry->Unset(); - if (error == B_OK) - fSecretEntry->SetTo(path); - } else - error = B_NO_MEMORY; - return error; -} - -// WORKAROUND -status_t -BSymLink::SetTo(const BDirectory *dir, const char *path) -{ - status_t error = BNode::SetTo(dir, path); - if (fSecretEntry) { - fSecretEntry->Unset(); - if (error == B_OK) - fSecretEntry->SetTo(dir, path); - } else - error = B_NO_MEMORY; - return error; -} - -// WORKAROUND -void -BSymLink::Unset() -{ - BNode::Unset(); - if (fSecretEntry) - fSecretEntry->Unset(); -} - - // ReadLink //! Reads the contents of the symbolic link into a buffer. /*! \param buf the buffer @@ -188,30 +105,11 @@ BSymLink::Unset() ssize_t BSymLink::ReadLink(char *buf, size_t size) { -/* - status_t error = (buf ? B_OK : B_BAD_VALUE); - if (error == B_OK && InitCheck() != B_OK) - error = B_FILE_ERROR; - if (error == B_OK) - error = BPrivate::Storage::read_link(get_fd(), buf, size); - return error; -*/ -// WORKAROUND - status_t error = (buf ? B_OK : B_BAD_VALUE); - if (error == B_OK && (InitCheck() != B_OK - || !fSecretEntry - || fSecretEntry->InitCheck() != B_OK)) { - error = B_FILE_ERROR; - } - entry_ref ref; - if (error == B_OK) - error = fSecretEntry->GetRef(&ref); - char path[B_PATH_NAME_LENGTH]; - if (error == B_OK) - error = BPrivate::Storage::entry_ref_to_path(&ref, path, sizeof(path)); - if (error == B_OK) - error = BPrivate::Storage::read_link(path, buf, size); - return error; + if (!buf) + return B_BAD_VALUE; + if (InitCheck() != B_OK) + return B_FILE_ERROR; + return _kern_read_link(get_fd(), NULL, buf, size); } // MakeLinkedPath @@ -233,13 +131,12 @@ BSymLink::MakeLinkedPath(const char *dirPath, BPath *path) // R5 seems to convert the dirPath to a BDirectory, which causes links to // be resolved, i.e. a "/tmp" dirPath expands to "/boot/var/tmp". // That does also mean, that the dirPath must exists! - ssize_t result = (dirPath && path ? B_OK : B_BAD_VALUE); - if (result == B_OK) { - BDirectory dir(dirPath); - result = dir.InitCheck(); - if (result == B_OK) - result = MakeLinkedPath(&dir, path); - } + if (!dirPath || !path) + return B_BAD_VALUE; + BDirectory dir(dirPath); + ssize_t result = dir.InitCheck(); + if (result == B_OK) + result = MakeLinkedPath(&dir, path); return result; } @@ -259,10 +156,10 @@ BSymLink::MakeLinkedPath(const char *dirPath, BPath *path) ssize_t BSymLink::MakeLinkedPath(const BDirectory *dir, BPath *path) { - ssize_t result = (dir && path ? 0 : B_BAD_VALUE); + if (!dir || !path) + return B_BAD_VALUE; char contents[B_PATH_NAME_LENGTH]; - if (result == 0) - result = ReadLink(contents, sizeof(contents)); + ssize_t result = ReadLink(contents, sizeof(contents)); if (result >= 0) { if (BPrivate::Storage::is_absolute_path(contents)) result = path->SetTo(contents); @@ -291,19 +188,6 @@ BSymLink::IsAbsolute() return result; } -// WORKAROUND -BSymLink & -BSymLink::operator=(const BSymLink &link) -{ - if (&link != this) { // no need to assign us to ourselves - Unset(); - static_cast(*this) = link; - if (fSecretEntry && link.fSecretEntry) - *fSecretEntry = *link.fSecretEntry; - } - return *this; -} - void BSymLink::_MissingSymLink1() {} void BSymLink::_MissingSymLink2() {} @@ -316,7 +200,7 @@ void BSymLink::_MissingSymLink6() {} /*! To be used instead of accessing the BNode's private \c fFd member directly. \return the file descriptor, or -1, if not properly initialized. */ -BPrivate::Storage::FileDescriptor +int BSymLink::get_fd() const { return fFd; @@ -327,5 +211,3 @@ BSymLink::get_fd() const }; // namespace OpenBeOS #endif - - diff --git a/src/kits/storage/Volume.cpp b/src/kits/storage/Volume.cpp index d128177e4f..6448c096f0 100644 --- a/src/kits/storage/Volume.cpp +++ b/src/kits/storage/Volume.cpp @@ -12,14 +12,18 @@ */ #include +#include #include #include #include -#include +#include #include +#include #include +#include +#include #ifdef USE_OPENBEOS_NAMESPACE namespace OpenBeOS { @@ -272,13 +276,46 @@ status_t BVolume::SetName(const char *name) { // check initialization - status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); - if (error == B_OK) - error = BPrivate::Storage::set_volume_name(fDevice, name); - - // ToDo: change the name of the mount point, too - // (or the link to the boot volume, if that name has been changed) - + if (!name || InitCheck() != B_OK) + return B_BAD_VALUE; + if (strlen(name) >= B_FILE_NAME_LENGTH) + return B_NAME_TOO_LONG; + // get the FS stat (including the old name) first + fs_info oldInfo; + if (fs_stat_dev(fDevice, &oldInfo) != 0) + return errno; + if (strcmp(name, oldInfo.volume_name) == 0) + return B_OK; + // set the volume name + fs_info newInfo; + strlcpy(newInfo.volume_name, name, sizeof(newInfo.volume_name)); + status_t error = _kern_write_fs_info(fDevice, &newInfo, + FS_WRITE_FSINFO_NAME); + if (error != B_OK) + return error; + // change the name of the mount point + // R5 implementation checks, if an entry with the volume's old name + // exists in the root directory and renames that entry, if it is indeed + // the mount point of the volume (or a link referring to it). In all other + // cases, nothing is done (even if the mount point is named like the + // volume, but lives in a different directory). + // We follow suit for the time being. + // create the entry + BPath entryPath; + BEntry entry; + BEntry traversedEntry; + node_ref entryNodeRef; + if (BPrivate::Storage::check_entry_name(name) == B_OK + && BPrivate::Storage::check_entry_name(oldInfo.volume_name) == B_OK + && entryPath.SetTo("/", oldInfo.volume_name) == B_OK + && entry.SetTo(entryPath.Path(), false) == B_OK + && entry.Exists() + && traversedEntry.SetTo(entryPath.Path(), true) == B_OK + && traversedEntry.GetNodeRef(&entryNodeRef) == B_OK + && entryNodeRef.device == fDevice + && entryNodeRef.node == oldInfo.root) { + traversedEntry.Rename(name, false); + } return error; } diff --git a/src/kits/storage/VolumeRoster.cpp b/src/kits/storage/VolumeRoster.cpp index 1cc03c073f..a04bdcd952 100644 --- a/src/kits/storage/VolumeRoster.cpp +++ b/src/kits/storage/VolumeRoster.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/src/kits/storage/mime/AssociatedTypes.cpp b/src/kits/storage/mime/AssociatedTypes.cpp index 2621f8975f..4429e1b757 100644 --- a/src/kits/storage/mime/AssociatedTypes.cpp +++ b/src/kits/storage/mime/AssociatedTypes.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -144,11 +143,12 @@ status_t AssociatedTypes::GuessMimeType(const entry_ref *ref, BString *result) { // Convert the entry_ref to a filename and then do the check - /*! \todo If the ref is invalid, */ - char path[B_PATH_NAME_LENGTH]; - status_t err = entry_ref_to_path(ref, path, B_PATH_NAME_LENGTH); + if (!ref) + return B_BAD_VALUE; + BPath path; + status_t err = path.SetTo(ref); if (!err) - err = GuessMimeType(path, result); + err = GuessMimeType(path.Path(), result); return err; } diff --git a/src/kits/storage/mime/MimeUpdateThread.cpp b/src/kits/storage/mime/MimeUpdateThread.cpp index 3770a75b3a..2a63b3e539 100644 --- a/src/kits/storage/mime/MimeUpdateThread.cpp +++ b/src/kits/storage/mime/MimeUpdateThread.cpp @@ -7,16 +7,16 @@ MimeUpdateThread implementation */ -#include "mime/MimeUpdateThread.h" +#include #include -#include #include #include #include #include -#include +#include +#include "mime/MimeUpdateThread.h" //#define DBG(x) x #define DBG(x) diff --git a/src/kits/storage/storage.src b/src/kits/storage/storage.src index afe3ba291e..ddbb029239 100644 --- a/src/kits/storage/storage.src +++ b/src/kits/storage/storage.src @@ -2,7 +2,6 @@ STORAGE_KIT_SOURCE = # storage AppFileInfo.cpp Directory.cpp -# DiskScannerAddOn.cpp Entry.cpp EntryList.cpp File.cpp @@ -25,7 +24,6 @@ STORAGE_KIT_SOURCE = SymLink.cpp Volume.cpp VolumeRoster.cpp - kernel_interface.POSIX.cpp storage_support.cpp # storage/mime diff --git a/src/kits/storage/storage_support.cpp b/src/kits/storage/storage_support.cpp index 3e9e3f7eee..c1b18eddca 100644 --- a/src/kits/storage/storage_support.cpp +++ b/src/kits/storage/storage_support.cpp @@ -13,6 +13,9 @@ #include #include + +#include + #include "storage_support.h" using namespace std; @@ -30,9 +33,105 @@ is_absolute_path(const char *path) } // parse_path +/*! \brief Parses the supplied path and returns the position of the leaf name + part of the path and the length of its directory path part. + + The value returned in \a fullPath is guaranteed to be > 0, i.e. the + function always returns a non-empty directory path part. The leaf name + part may be empty though (i.e. \code leafStart == leafEnd \endcode), which + will happen, if the supplied path consists only of one component. + + \param fullPath The path to be parsed. + \param dirEnd Reference to a variable into which the end index of the + directory part shall be written. The index is exclusive. + \param leafStart Reference to a variable into which the start index of + the leaf name part shall be written. The index is inclusive. + \param leafEnd Reference to a variable into which the end index of + the leaf name part shall be written. The index is exclusive. + \return \c B_OK, if everything went fine, B_BAD_VALUE, if the supplied + path is invalid. +*/ +status_t +parse_path(const char *fullPath, int &dirEnd, int &leafStart, int &leafEnd) +{ + // check path and get length + if (!fullPath) + return B_BAD_VALUE; + int pathLen = strlen(fullPath); + if (pathLen == 0) + return B_BAD_VALUE; + // find then end of the leaf name (skip trailing '/') + int i = pathLen - 1; + while (i >= 0 && fullPath[i] == '/') + i--; + leafEnd = i + 1; + if (leafEnd == 0) { + // fullPath consists of slashes only + dirEnd = leafStart = leafEnd = 1; + return B_OK; + } + // find the start of the leaf name + while (i >= 0 && fullPath[i] != '/') + i--; + leafStart = i + 1; + if (leafStart == 0) { + // fullPath contains only one component + dirEnd = leafStart = leafEnd; + return B_OK; + } + // find the end of the dir path + while (i >= 0 && fullPath[i] == '/') + i--; + dirEnd = i + 1; + if (dirEnd == 0) // => fullPath[0] == '/' (an absolute path) + dirEnd = 1; + return B_OK; +} + +// parse_path +/*! \brief Parses the supplied path and returns the leaf name part of the path + and its directory path part. + + The value returned in \a fullPath is guaranteed to be > 0, i.e. the + function always returns a non-empty directory path part. The leaf name + part may be empty though (i.e. \code leafStart == leafEnd \endcode), which + will happen, if the supplied path consists only of one component. + + \param fullPath The path to be parsed. + \param dirPath Pointer to a character array of size \c B_PATH_NAME_LENGTH + or greater, into which the directory part shall be written. + May be \c NULL. + \param leaf Pointer to a character array of size \c B_FILE_NAME_LENGTH + or greater, into which the leaf name part shall be written. + May be \c NULL. + \return \c B_OK, if everything went fine, B_BAD_VALUE, if the supplied + path is invalid. +*/ +status_t +parse_path(const char *fullPath, char *dirPath, char *leaf) +{ + // parse the path and check the lengths + int leafStart, leafEnd, dirEnd; + status_t error = parse_path(fullPath, dirEnd, leafStart, leafEnd); + if (error != B_OK) + return error; + if (dirEnd >= B_PATH_NAME_LENGTH + || leafEnd - leafStart >= B_FILE_NAME_LENGTH) { + return B_NAME_TOO_LONG; + } + // copy the result strings + if (dirPath) + strlcpy(dirPath, fullPath, dirEnd + 1); + if (leaf) + strlcpy(leaf, fullPath + leafStart, leafEnd - leafStart + 1); + return B_OK; +} + +// internal_parse_path static void -parse_path(const char *fullPath, int &leafStart, int &leafEnd, int &pathEnd) +internal_parse_path(const char *fullPath, int &leafStart, int &leafEnd, + int &pathEnd) { if (fullPath == NULL) return; @@ -109,7 +208,7 @@ split_path(const char *fullPath, char **path, char **leaf) return B_BAD_VALUE; int leafStart, leafEnd, pathEnd, len; - parse_path(fullPath, leafStart, leafEnd, pathEnd); + internal_parse_path(fullPath, leafStart, leafEnd, pathEnd); try { // Tidy up/handle special cases @@ -387,6 +486,22 @@ void escape_path(char *str) } } +// device_is_root_device +bool +device_is_root_device(dev_t device) +{ + return device == 1; +} + +// Close +void +FDCloser::Close() +{ + if (fFD >= 0) + _kern_close(fFD); + fFD = -1; +} + }; // namespace Storage }; // namespace BPrivate diff --git a/src/servers/registrar/RecentEntries.cpp b/src/servers/registrar/RecentEntries.cpp index d5bc68fb20..7fd2121d00 100644 --- a/src/servers/registrar/RecentEntries.cpp +++ b/src/servers/registrar/RecentEntries.cpp @@ -32,9 +32,9 @@ #include #include #include -#include // From the Storage Kit #include #include +#include #include #include #include @@ -309,12 +309,11 @@ RecentEntries::Save(FILE* file, const char *description, const char *tag) // We're going to need to properly escape the path name we // get, which will at absolute worst double the length of // the string. - char path[B_PATH_NAME_LENGTH]; + BPath path; char escapedPath[B_PATH_NAME_LENGTH*2]; - status_t outputError = BPrivate::Storage::entry_ref_to_path(&mapItem->first, - path, B_PATH_NAME_LENGTH); + status_t outputError = path.SetTo(&mapItem->first); if (!outputError) { - BPrivate::Storage::escape_path(path, escapedPath); + BPrivate::Storage::escape_path(path.Path(), escapedPath); fprintf(file, "%s %s", tag, escapedPath); std::list &list = mapItem->second; int32 i = 0;