From d9516a06cccdc8a5d0d88ccb658b98080b2af5f0 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 20:21:53 +0200 Subject: [PATCH] Open/close attribute support for xattrs backend For the xattr/BSD (untyped) attribute backend implement fs_fopen_attr() and fs_close_attr(). A new AttributeDescriptor is created. It is currently used in write_pos() only. --- src/build/libroot/fs.cpp | 111 ++++++++++--------- src/build/libroot/fs_attr_generic.cpp | 54 +++++----- src/build/libroot/fs_attr_untyped.cpp | 44 ++++++-- src/build/libroot/fs_descriptors.cpp | 147 ++++++++++++++++++++++++++ src/build/libroot/fs_descriptors.h | 36 ++++++- 5 files changed, 305 insertions(+), 87 deletions(-) diff --git a/src/build/libroot/fs.cpp b/src/build/libroot/fs.cpp index 35351ae01c..f8c0af2798 100644 --- a/src/build/libroot/fs.cpp +++ b/src/build/libroot/fs.cpp @@ -130,17 +130,17 @@ normalize_dir_path(string path, NodeRef ref, string &normalizedPath) status_t error = find_dir_entry(path.c_str(), ref, name, true) ; if (error != B_OK) return error; - + // recurse to get the parent dir path, if found error = normalize_dir_path(path, parentRef, normalizedPath); if (error != 0) return error; - // construct the normalizedPath + // construct the normalizedPath if (normalizedPath.length() > 1) // don't append "/", if parent is root normalizedPath += '/'; normalizedPath += name; - + return 0; } @@ -152,7 +152,7 @@ normalize_dir_path(const char *path, string &normalizedPath) struct stat st; if (stat(path, &st) < 0) return errno; - + return normalize_dir_path(path, NodeRef(st), normalizedPath); } @@ -162,7 +162,7 @@ normalize_entry_path(const char *path, string &normalizedPath) { const char *dirPath = NULL; const char *leafName = NULL; - + string dirPathString; if (const char *lastSlash = strrchr(path, '/')) { // found a slash: decompose into dir path and leaf name @@ -184,7 +184,7 @@ normalize_entry_path(const char *path, string &normalizedPath) // catch special case: no leaf, or leaf is a directory if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0) return normalize_dir_path(path, normalizedPath); - + // normalize the dir path status_t error = normalize_dir_path(dirPath, normalizedPath); if (error != B_OK) @@ -222,7 +222,7 @@ get_path(const NodeRef *ref, const char *name, string &path) DirPathMap::iterator it = sDirPathMap.find(*ref); if (it == sDirPathMap.end()) return B_ENTRY_NOT_FOUND; - + path = it->second; // stat the path to check, if it is still valid @@ -250,7 +250,7 @@ get_path(const NodeRef *ref, const char *name, string &path) path += '/'; path += name; } - + return B_OK; } @@ -272,7 +272,7 @@ BPrivate::get_path(int fd, const char *name, string &path) return error; return ::get_path(&ref, name, path); - + } else // no descriptor or absolute path return ::get_path((NodeRef*)NULL, name, path); } @@ -284,7 +284,7 @@ get_path(dev_t device, ino_t directory, const char *name, string &path) NodeRef ref; ref.device = device; ref.node = directory; - + return get_path(&ref, name, path); } @@ -315,7 +315,7 @@ _kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf, // copy it back to the user buffer if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength) return B_BUFFER_OVERFLOW; - + return B_OK; } @@ -334,8 +334,8 @@ _kern_create_dir(int fd, const char *path, int perms) // mkdir if (mkdir(realPath.c_str(), perms) < 0) - return errno; - + return errno; + return B_OK; } @@ -352,8 +352,8 @@ _kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name, // mkdir if (mkdir(realPath.c_str(), perms) < 0) - return errno; - + return errno; + return B_OK; } @@ -382,7 +382,7 @@ open_dir(const char *path) NodeRef ref(st); add_dir_path(path, ref); - // create descriptor + // create descriptor DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref); return add_descriptor(descriptor); } @@ -443,7 +443,7 @@ _kern_open_parent_dir(int fd, char *name, size_t nameLength) return B_BUFFER_OVERFLOW; // open the parent directory - + return open_dir(realPath.c_str()); } @@ -455,7 +455,7 @@ _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, if (maxCount <= 0) return B_BAD_VALUE; - // get the descriptor + // get the descriptor DirectoryDescriptor *descriptor = dynamic_cast(get_descriptor(fd)); if (!descriptor) @@ -484,7 +484,7 @@ _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, status_t _kern_rewind_dir(int fd) { - // get the descriptor + // get the descriptor DirectoryDescriptor *descriptor = dynamic_cast(get_descriptor(fd)); if (!descriptor) @@ -523,7 +523,7 @@ open_file(const char *path, int openMode, int perms) status_t error = normalize_entry_path(path, normalizedPath); if (error != B_OK) return error; - + descriptor = new SymlinkDescriptor(normalizedPath.c_str()); } else { // open the file @@ -534,11 +534,11 @@ open_file(const char *path, int openMode, int perms) descriptor = new FileDescriptor(newFD); } - + // cache path, if this is a directory if (exists && S_ISDIR(st.st_mode)) add_dir_path(path, NodeRef(st)); - + return add_descriptor(descriptor); } @@ -603,7 +603,7 @@ _kern_read(int fd, off_t pos, void *buffer, size_t bufferSize) if (result < 0) return errno; } - + // read ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer, bufferSize); @@ -629,7 +629,7 @@ _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize) if (result < 0) return errno; } - + // read ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer, bufferSize); @@ -706,10 +706,10 @@ _kern_read_stat(int fd, const char *path, bool traverseLink, Descriptor *descriptor = get_descriptor(fd); if (!descriptor) return B_FILE_ERROR; - + return descriptor->GetStat(traverseLink, st); } - + return B_OK; } @@ -734,7 +734,7 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, return errno; isSymlink = S_ISLNK(tmpStat.st_mode); - + } else { Descriptor *descriptor = get_descriptor(fd); if (!descriptor) @@ -743,17 +743,17 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, if (FileDescriptor *fileFD = dynamic_cast(descriptor)) { realFD = fileFD->fd; - + } else if (dynamic_cast(descriptor)) { error = get_path(fd, NULL, realPath); if (error != B_OK) return error; - + } else if (SymlinkDescriptor *linkFD = dynamic_cast(descriptor)) { realPath = linkFD->path; isSymlink = true; - + } else return B_FILE_ERROR; } @@ -762,23 +762,23 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, // available functions traverse symlinks. if (isSymlink && !traverseLink) return B_ERROR; - + if (realFD >= 0) { if (statMask & B_STAT_MODE) { if (fchmod(realFD, st->st_mode) < 0) return errno; } - + if (statMask & B_STAT_UID) { if (fchown(realFD, st->st_uid, (gid_t)-1) < 0) return errno; } - + if (statMask & B_STAT_GID) { if (fchown(realFD, (uid_t)-1, st->st_gid) < 0) return errno; } - + if (statMask & B_STAT_SIZE) { if (ftruncate(realFD, st->st_size) < 0) return errno; @@ -790,25 +790,25 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, | B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) { return B_ERROR; } - + return 0; - + } else { if (statMask & B_STAT_MODE) { if (chmod(realPath.c_str(), st->st_mode) < 0) return errno; } - + if (statMask & B_STAT_UID) { if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0) return errno; } - + if (statMask & B_STAT_GID) { if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0) return errno; } - + if (statMask & B_STAT_SIZE) { if (truncate(realPath.c_str(), st->st_size) < 0) return errno; @@ -822,18 +822,18 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, if (stat(realPath.c_str(), &oldStat) < 0) return errno; } - + utimbuf buffer; buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime; buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime; if (utime(realPath.c_str(), &buffer) < 0) return errno; } - - // not supported + + // not supported if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) return B_ERROR; - } + } return B_OK; } @@ -878,7 +878,7 @@ _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize) if (*_bufferSize > 0) { if ((size_t)bytesRead == *_bufferSize) bytesRead--; - + buffer[bytesRead] = '\0'; } @@ -918,7 +918,7 @@ _kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath) error = get_path(newDir, newPath, realNewPath); if (error != B_OK) return error; - + // rename if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0) return errno; @@ -954,7 +954,7 @@ read_pos(int fd, off_t pos, void *buffer, size_t bufferSize) off_t result = lseek(fd, pos, SEEK_SET); if (result < 0) return errno; - + // read ssize_t bytesRead = haiku_host_platform_read(fd, buffer, bufferSize); if (bytesRead < 0) { @@ -969,12 +969,25 @@ read_pos(int fd, off_t pos, void *buffer, size_t bufferSize) ssize_t write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize) { + // If this is an attribute descriptor, let it do the job. + AttributeDescriptor* descriptor + = dynamic_cast(get_descriptor(fd)); + if (descriptor != NULL) { + status_t error = descriptor->Write(pos, buffer, bufferSize); + if (error != B_OK) { + errno = error; + return -1; + } + + return 0; + } + // seek off_t result = lseek(fd, pos, SEEK_SET); if (result < 0) return errno; - // read + // write ssize_t bytesWritten = haiku_host_platform_write(fd, buffer, bufferSize); if (bytesWritten < 0) { errno = bytesWritten; @@ -992,7 +1005,7 @@ readv_pos(int fd, off_t pos, const struct iovec *vec, size_t count) off_t result = lseek(fd, pos, SEEK_SET); if (result < 0) return errno; - + // read ssize_t bytesRead = haiku_host_platform_readv(fd, vec, count); if (bytesRead < 0) { @@ -1011,7 +1024,7 @@ writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count) off_t result = lseek(fd, pos, SEEK_SET); if (result < 0) return errno; - + // read ssize_t bytesWritten = haiku_host_platform_writev(fd, vec, count); if (bytesWritten < 0) { diff --git a/src/build/libroot/fs_attr_generic.cpp b/src/build/libroot/fs_attr_generic.cpp index e42eb5eb12..ee18e65bb8 100644 --- a/src/build/libroot/fs_attr_generic.cpp +++ b/src/build/libroot/fs_attr_generic.cpp @@ -33,7 +33,7 @@ init_attribute_dir_base_dir() if (initialized) return initError; - + // stat the dir struct stat st; initError = B_OK; @@ -44,7 +44,7 @@ init_attribute_dir_base_dir() "directory base directory exists, but is no directory!\n"); initError = B_FILE_ERROR; } - + } else { // doesn't exist yet: create it if (mkdir(sAttributeDirBasePath, S_IRWXU | S_IRWXG | S_IRWXO) < 0) @@ -68,7 +68,7 @@ escape_attr_name(const char *name) escapedName += "__"; else escapedName += *name; - + name++; } @@ -84,7 +84,7 @@ deescape_attr_name(const char *name) return "___"; } name++; - + string deescapedName; while (*name != '\0') { if (*name == '_') { @@ -100,11 +100,11 @@ deescape_attr_name(const char *name) } } else deescapedName += *name; - + name++; } - return deescapedName; + return deescapedName; } // get_attribute_dir_path @@ -179,7 +179,7 @@ get_attribute_path(NodeRef ref, const char *path, int fd, errno = error; return -1; } - + // construct the attribute path attrPath = get_attribute_dir_path(ref) + '/'; string attrName(escape_attr_name(attribute)); @@ -206,7 +206,7 @@ get_attribute_path_virtual_fd(int fd, const char *attribute, string &attrPath, // (i.e. system) file descriptor, which is just as well. string path; bool pathValid = (get_path(fd, NULL, path) == B_OK); - + // get the attribute path return get_attribute_path(ref, (pathValid ? path.c_str() : NULL), (pathValid ? -1 : fd), attribute, attrPath, typePath); @@ -269,7 +269,7 @@ fs_fopen_attr_dir(int fd) // (i.e. system) file descriptor, which is just as well. string path; bool pathValid = (get_path(fd, NULL, path) == B_OK); - + // get the attribute path return open_attr_dir(NodeRef(st), (pathValid ? path.c_str() : NULL), (pathValid ? -1 : fd)); @@ -292,8 +292,8 @@ fs_read_attr_dir(DIR *dir) entry = readdir(dir); if (!entry) return NULL; - - // ignore administrative entries; the + + // ignore administrative entries; the if (entry->d_name[0] == '_') { string attrName = deescape_attr_name(entry->d_name); strcpy(entry->d_name, attrName.c_str()); @@ -309,15 +309,15 @@ fs_rewind_attr_dir(DIR *dir) rewinddir(dir); } -// fs_open_attr +// fs_fopen_attr int -fs_open_attr(int fd, const char *attribute, uint32 type, int openMode) +fs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode) { if (!attribute) { errno = B_BAD_VALUE; return -1; } - + // get the attribute path string attrPath; string typePath; @@ -344,7 +344,7 @@ fs_open_attr(int fd, const char *attribute, uint32 type, int openMode) // write the type into the file if (write(typeFD, &type, sizeof(type)) < 0) error = errno; - + close(typeFD); } else @@ -355,10 +355,10 @@ fs_open_attr(int fd, const char *attribute, uint32 type, int openMode) if (typeFD > 0) { unlink(typePath.c_str()); } - + close(attrFD); unlink(attrPath.c_str()); - + errno = error; return -1; } @@ -395,7 +395,7 @@ fs_read_attr(int fd, const char *attribute, uint32 type, off_t pos, errno = error; return -1; } - + return bytesRead; } @@ -421,7 +421,7 @@ fs_write_attr(int fd, const char *attribute, uint32 type, off_t pos, errno = error; return -1; } - + return bytesWritten; } @@ -433,7 +433,7 @@ fs_remove_attr(int fd, const char *attribute) errno = B_BAD_VALUE; return -1; } - + // get the attribute path string attrPath; string typePath; @@ -446,9 +446,9 @@ fs_remove_attr(int fd, const char *attribute) // remove the attribute if (unlink(attrPath.c_str()) < 0) return -1; - + unlink(typePath.c_str()); - + return B_OK; } @@ -474,7 +474,7 @@ fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo) struct stat st; if (lstat(attrPath.c_str(), &st) < 0) return -1; - + attrInfo->size = st.st_size; // now open the attribute type file and read the attribute's type @@ -496,7 +496,7 @@ fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo) return -1; } - return 0; + return 0; } @@ -524,14 +524,14 @@ _kern_open_attr_dir(int fd, const char *path) if (error != B_OK) return error; } - + // open the attr dir DIR *dir = open_attr_dir(ref, (path ? realPath.c_str() : NULL), (path ? -1 : fd)); if (!dir) return errno; - // create descriptor + // create descriptor AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref); return add_descriptor(descriptor); } @@ -571,7 +571,7 @@ _kern_rename_attr(int fromFile, const char *fromName, int toFile, return error; } - + return B_OK; } diff --git a/src/build/libroot/fs_attr_untyped.cpp b/src/build/libroot/fs_attr_untyped.cpp index 0a3472f012..6276dcff26 100644 --- a/src/build/libroot/fs_attr_untyped.cpp +++ b/src/build/libroot/fs_attr_untyped.cpp @@ -452,22 +452,50 @@ fs_rewind_attr_dir(DIR *dir) attrDir->RewindDir(); } -// fs_open_attr +// fs_fopen_attr int -fs_open_attr(int fd, const char *attribute, uint32 type, int openMode) +fs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode) { - // not supported ATM - errno = B_BAD_VALUE; - return -1; + if (fd < 0) { + errno = B_BAD_VALUE; + return -1; + } + + AttributeDescriptor* descriptor = new(std::nothrow) AttributeDescriptor(fd, + attribute, type, openMode); + if (descriptor == NULL) { + errno = B_NO_MEMORY; + return -1; + } + + status_t error = descriptor->Init(); + if (error != B_OK) { + delete descriptor; + errno = error; + return -1; + } + + int attributeFD = add_descriptor(descriptor); + if (attributeFD < 0) { + delete descriptor; + errno = B_NO_MEMORY; + return -1; + } + + return attributeFD; } // fs_close_attr int fs_close_attr(int fd) { - // not supported ATM - errno = B_BAD_VALUE; - return -1; + status_t error = delete_descriptor(fd); + if (error != 0) { + errno = error; + return -1; + } + + return 0; } // fs_read_attr diff --git a/src/build/libroot/fs_descriptors.cpp b/src/build/libroot/fs_descriptors.cpp index d4599e289d..2bf311dca6 100644 --- a/src/build/libroot/fs_descriptors.cpp +++ b/src/build/libroot/fs_descriptors.cpp @@ -11,7 +11,9 @@ #include +#include #include +#include #include #include @@ -250,6 +252,151 @@ SymlinkDescriptor::GetPath(string& path) const } +// #pragma mark - AttributeDescriptor + + +AttributeDescriptor::AttributeDescriptor(int fileFD, const char* attribute, + uint32 type, int openMode) + : + fFileFD(dup(fileFD)), + fType(type), + fOpenMode(openMode), + fData(NULL), + fDataSize(0) + +{ + strlcpy(fAttribute, attribute, sizeof(fAttribute)); +} + + +AttributeDescriptor::~AttributeDescriptor() +{ + Close(); +} + + +status_t +AttributeDescriptor::Init() +{ + if (fFileFD < 0) + return B_IO_ERROR; + + // stat the attribute + attr_info info; + if (fs_stat_attr(fFileFD, fAttribute, &info) < 0) { + if (errno == B_ENTRY_NOT_FOUND) { + if ((fOpenMode & O_CREAT) == 0) + return errno; + + // create the attribute + if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0) + return errno; + return B_OK; + } + return errno; + } + + if ((fOpenMode & O_TRUNC) == 0) { + // truncate the attribute + if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0) + return errno; + return B_OK; + } + + // we have to read in the attribute data + if (info.size == 0) + return B_OK; + + fData = (uint8*)malloc(info.size); + if (fData == NULL) + return B_NO_MEMORY; + + fDataSize = info.size; + + ssize_t bytesRead = fs_read_attr(fFileFD, fAttribute, fType, 0, fData, + fDataSize); + if (bytesRead < 0) + return errno; + if ((size_t)bytesRead != fDataSize) + return B_IO_ERROR; + + return B_OK; +} + + +status_t +AttributeDescriptor::Write(off_t offset, const void* buffer, size_t bufferSize) +{ + if (offset < 0) + return B_BAD_VALUE; + + if ((fOpenMode & O_ACCMODE) != O_WRONLY + && (fOpenMode & O_ACCMODE) != O_RDWR) { + return B_NOT_ALLOWED; + } + + // we may need to resize the buffer + size_t minSize = (size_t)offset + bufferSize; + if (minSize > fDataSize) { + uint8* data = (uint8*)realloc(fData, minSize); + if (data == NULL) + return B_NO_MEMORY; + + if ((size_t)offset > fDataSize) + memset(data + offset, 0, offset - fDataSize); + + fData = data; + fDataSize = minSize; + } + + // copy the data and write all of it + if (bufferSize == 0) + return B_OK; + + memcpy((uint8*)fData + offset, buffer, bufferSize); + + ssize_t bytesWritten = fs_write_attr(fFileFD, fAttribute, fType, 0, + fData, fDataSize); + if (bytesWritten < 0) + return errno; + if ((size_t)bytesWritten != fDataSize) + return B_IO_ERROR; + + return B_OK; +} + + +status_t +AttributeDescriptor::Close() +{ + if (fFileFD < 0) + return B_BAD_VALUE; + + close(fFileFD); + fFileFD = -1; + + free(fData); + fData = NULL; + fDataSize = 0; + + return B_OK; +} + + +status_t +AttributeDescriptor::Dup(Descriptor*& clone) +{ + return B_NOT_SUPPORTED; +} + + +status_t +AttributeDescriptor::GetStat(bool traverseLink, struct stat* st) +{ + return B_NOT_SUPPORTED; +} + + // #pragma mark - AttrDirDescriptor diff --git a/src/build/libroot/fs_descriptors.h b/src/build/libroot/fs_descriptors.h index 56dcb4c1d6..608f6f6fc6 100644 --- a/src/build/libroot/fs_descriptors.h +++ b/src/build/libroot/fs_descriptors.h @@ -5,6 +5,7 @@ #include +#include #include #include "NodeRef.h" @@ -35,7 +36,7 @@ struct Descriptor { struct FileDescriptor : Descriptor { FileDescriptor(int fd); virtual ~FileDescriptor(); - + virtual status_t Close(); virtual status_t Dup(Descriptor *&clone); virtual status_t GetStat(bool traverseLink, struct stat *st); @@ -50,7 +51,7 @@ struct DirectoryDescriptor : Descriptor { DirectoryDescriptor(DIR *dir, const NodeRef &ref); virtual ~DirectoryDescriptor(); - + virtual status_t Close(); virtual status_t Dup(Descriptor *&clone); virtual status_t GetStat(bool traverseLink, struct stat *st); @@ -71,12 +72,41 @@ struct SymlinkDescriptor : Descriptor { virtual status_t GetPath(string& path) const; }; +// AttributeDescriptor +struct AttributeDescriptor : Descriptor { + AttributeDescriptor(int fileFD, + const char* attribute, uint32 type, + int openMode); + virtual ~AttributeDescriptor(); + + status_t Init(); + status_t Write(off_t offset, const void* buffer, + size_t bufferSize); + + int FileFD() const { return fFileFD; } + const char* Attribute() const { return fAttribute; } + uint32 Type() const { return fType; } + int OpenMode() const { return fOpenMode; } + + virtual status_t Close(); + virtual status_t Dup(Descriptor*& clone); + virtual status_t GetStat(bool traverseLink, struct stat* st); + +private: + int fFileFD; + char fAttribute[B_ATTR_NAME_LENGTH]; + uint32 fType; + int fOpenMode; + uint8* fData; + size_t fDataSize; +}; + // AttrDirDescriptor struct AttrDirDescriptor : DirectoryDescriptor { AttrDirDescriptor(DIR *dir, const NodeRef &ref); virtual ~AttrDirDescriptor(); - + virtual status_t Close(); virtual status_t Dup(Descriptor *&clone); virtual status_t GetStat(bool traverseLink, struct stat *st);