/* * Copyright 2017, Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. */ /*! Shim over the host Haiku fs_attr API */ #ifdef BUILDING_FS_SHELL # include "compat.h" # define B_OK 0 # define B_BAD_VALUE EINVAL # define B_FILE_ERROR EBADF # define B_ERROR EINVAL # define B_ENTRY_NOT_FOUND ENOENT # define B_NO_MEMORY ENOMEM #else # include # include "fs_impl.h" # include "fs_descriptors.h" #endif #include #include #include #include #include #include #include #include #include #include namespace BPrivate {} using namespace BPrivate; namespace { // LocalFD #include "LocalFD.h" } // unnamed namspace // # pragma mark - Public API // fs_open_attr_dir extern "C" DIR * _haiku_build_fs_open_attr_dir(const char *path) { return fs_open_attr_dir(path); } // fs_lopen_attr_dir extern "C" DIR* _haiku_build_fs_lopen_attr_dir(const char *path) { return fs_lopen_attr_dir(path); } // fs_fopen_attr_dir extern "C" DIR* _haiku_build_fs_fopen_attr_dir(int fd) { LocalFD localFD; status_t error = localFD.Init(fd); if (error != B_OK) { errno = error; return NULL; } if (localFD.FD() < 0) { return fs_lopen_attr_dir(localFD.Path()); } else { return fs_fopen_attr_dir(localFD.FD()); } } // fs_close_attr_dir extern "C" int _haiku_build_fs_close_attr_dir(DIR *dir) { return fs_close_attr_dir(dir); } // fs_read_attr_dir extern "C" struct dirent * _haiku_build_fs_read_attr_dir(DIR *dir) { return fs_read_attr_dir(dir); } // fs_rewind_attr_dir extern "C" void _haiku_build_fs_rewind_attr_dir(DIR *dir) { return fs_rewind_attr_dir(dir); } // fs_fopen_attr extern "C" int _haiku_build_fs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode) { if (fd < 0) { errno = B_BAD_VALUE; return -1; } LocalFD localFD; status_t error = localFD.Init(fd); if (error != B_OK) { errno = error; return -1; } if (localFD.FD() < 0) { return fs_open_attr(localFD.Path(), attribute, type, openMode | O_NOTRAVERSE); } else { return fs_fopen_attr(localFD.FD(), attribute, type, openMode); } } // fs_close_attr extern "C" int _haiku_build_fs_close_attr(int fd) { return fs_close_attr(fd); } // fs_read_attr extern "C" ssize_t _haiku_build_fs_read_attr(int fd, const char* attribute, uint32 type, off_t pos, void *buffer, size_t readBytes) { LocalFD localFD; status_t error = localFD.Init(fd); if (error != B_OK) { errno = error; return -1; } ssize_t bytesRead; if (localFD.FD() < 0) { int fd = open(localFD.Path(), O_RDONLY | O_NOTRAVERSE); bytesRead = fs_read_attr(fd, attribute, type, pos, buffer, readBytes); close(fd); } else { bytesRead = fs_read_attr(localFD.FD(), attribute, type, pos, buffer, readBytes); } if (bytesRead < 0) { // Make sure, the error code is B_ENTRY_NOT_FOUND, if the attribute // doesn't exist. if (errno == ENOATTR || errno == ENODATA) errno = B_ENTRY_NOT_FOUND; return -1; } return bytesRead; } // fs_write_attr extern "C" ssize_t _haiku_build_fs_write_attr(int fd, const char* attribute, uint32 type, off_t pos, const void *buffer, size_t writeBytes) { LocalFD localFD; status_t error = localFD.Init(fd); if (error != B_OK) { errno = error; return -1; } ssize_t written; if (localFD.FD() < 0) { int fd = open(localFD.Path(), O_NOTRAVERSE | O_WRONLY); written = fs_write_attr(fd, attribute, type, pos, buffer, writeBytes); close(fd); } else { written = fs_write_attr(localFD.FD(), attribute, type, pos, buffer, writeBytes); } return written; } // fs_remove_attr extern "C" int _haiku_build_fs_remove_attr(int fd, const char* attribute) { LocalFD localFD; status_t error = localFD.Init(fd); if (error != B_OK) { errno = error; return -1; } // remove attribute int result; if (localFD.FD() < 0) { int fd = open(localFD.Path(), O_NOTRAVERSE | O_WRONLY); result = fs_remove_attr(fd, attribute); close(fd); } else { result = fs_remove_attr(localFD.FD(), attribute); } if (result < 0) { // Make sure, the error code is B_ENTRY_NOT_FOUND, if the attribute // doesn't exist. if (errno == ENOATTR || errno == ENODATA) errno = B_ENTRY_NOT_FOUND; return -1; } return 0; } // fs_stat_attr extern "C" int _haiku_build_fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo) { if (!attribute || !attrInfo) { errno = B_BAD_VALUE; return -1; } LocalFD localFD; status_t error = localFD.Init(fd); if (error != B_OK) { errno = error; return -1; } int result; if (localFD.FD() < 0) { int fd = open(localFD.Path(), O_NOTRAVERSE | O_RDONLY); result = fs_stat_attr(fd, attribute, attrInfo); close(fd); } else { result = fs_stat_attr(localFD.FD(), attribute, attrInfo); } return result; } // #pragma mark - Private Syscalls #ifndef BUILDING_FS_SHELL // _kern_open_attr_dir int _kern_open_attr_dir(int fd, const char *path) { // get node ref for the node struct stat st; status_t error = _kern_read_stat(fd, path, false, &st, sizeof(struct stat)); if (error != B_OK) { errno = error; return -1; } NodeRef ref(st); DIR* dir; if (path) { // If a path was given, get a usable path. string realPath; status_t error = get_path(fd, path, realPath); if (error != B_OK) return error; dir = _haiku_build_fs_open_attr_dir(realPath.c_str()); } else dir = _haiku_build_fs_fopen_attr_dir(fd); if (!dir) return errno; // create descriptor AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref); return add_descriptor(descriptor); } // _kern_rename_attr status_t _kern_rename_attr(int fromFile, const char *fromName, int toFile, const char *toName) { // not supported ATM return B_BAD_VALUE; } // _kern_remove_attr status_t _kern_remove_attr(int fd, const char *name) { if (!name) return B_BAD_VALUE; if (_haiku_build_fs_remove_attr(fd, name) < 0) return errno; return B_OK; } #endif // ! BUILDING_FS_SHELL