From 1621d9945f401a08d3eeed9bc3baf472111393f0 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 4 Feb 2006 01:55:49 +0000 Subject: [PATCH] Tried to improve the attribute support under non-BeOS compatible build platforms a bit. Generally extended attributes seem to be supported up to a very limited size per node, thus a one-to-one mapping isn't a good idea, but I figured, they could at least help to recognize when and attribute directory doesn't belong to a node (in case the original node had been removed and the a new one created with the same node ID). The implementation should ensure that, but I can't really test it, since ReiserFS 3.6 under my SuSE Linux 9.2 installation apparently doesn't support extended attributes. So it's disabled for the time being. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16228 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/build/libroot/fs.cpp | 28 ++++-- src/build/libroot/fs_attr.cpp | 149 ++++++++++++++++++++++++++++--- src/build/libroot/fs_attr_impl.h | 15 +++- 3 files changed, 168 insertions(+), 24 deletions(-) diff --git a/src/build/libroot/fs.cpp b/src/build/libroot/fs.cpp index cd9f5929b3..7db03caacc 100644 --- a/src/build/libroot/fs.cpp +++ b/src/build/libroot/fs.cpp @@ -25,7 +25,6 @@ using namespace BPrivate; static const int kVirtualDescriptorStart = 10000; -static status_t get_path(int fd, const char *name, string &path); static status_t get_path(dev_t device, ino_t node, const char *name, string &path); namespace BPrivate { @@ -506,8 +505,8 @@ get_path(const NodeRef *ref, const char *name, string &path) } // get_path -static status_t -get_path(int fd, const char *name, string &path) +status_t +BPrivate::get_path(int fd, const char *name, string &path) { // get the node ref for the fd, if any, and the path part is not absolute if (fd >= 0 && !(name && name[0] == '/')) { @@ -522,10 +521,10 @@ get_path(int fd, const char *name, string &path) if (error != B_OK) return error; - return get_path(&ref, name, path); + return ::get_path(&ref, name, path); } else // no descriptor or absolute path - return get_path((NodeRef*)NULL, name, path); + return ::get_path((NodeRef*)NULL, name, path); } // get_path @@ -1210,8 +1209,17 @@ _kern_open_attr_dir(int fd, const char *path) } NodeRef ref(st); + // If a path was given, get a usable path. + string realPath; + if (path) { + error = get_path(fd, path, realPath); + if (error != B_OK) + return error; + } + // open the attr dir - DIR *dir = open_attr_dir(ref); + DIR *dir = open_attr_dir(ref, (path ? realPath.c_str() : NULL), + (path ? -1 : fd)); if (!dir) return errno; @@ -1232,8 +1240,14 @@ get_attribute_path(int fd, const char *attribute, string &attrPath, return error; NodeRef ref(st); + // Try to get a path. If we can't get a path, this is must be a "real" + // (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, attribute, attrPath, typePath); + return get_attribute_path(ref, (pathValid ? path.c_str() : NULL), + (pathValid ? -1 : fd), attribute, attrPath, typePath); } // _kern_rename_attr diff --git a/src/build/libroot/fs_attr.cpp b/src/build/libroot/fs_attr.cpp index 39a12ad2fd..39bcca1452 100644 --- a/src/build/libroot/fs_attr.cpp +++ b/src/build/libroot/fs_attr.cpp @@ -9,6 +9,11 @@ # include #endif +// Defined, if the host platform has extended attribute support. +// Unfortunately I don't seem to have extended attribute support under +// SuSE Linux 9.2 (kernel 2.6.8-...) with ReiserFS 3.6. +//#define HAS_EXTENDED_ATTRIBUTE_SUPPORT 1 + #include #include #include @@ -23,6 +28,12 @@ #include "fs_attr_impl.h" +#ifdef HAS_EXTENDED_ATTRIBUTE_SUPPORT +#include + +static const char *kAttributeDirMarkAttributeName = "_has_haiku_attr_dir"; +#endif + using namespace std; using namespace BPrivate; @@ -122,9 +133,90 @@ get_attribute_dir_path(NodeRef ref) return attrDirPath; } +// has_attribute_dir_mark +static bool +has_attribute_dir_mark(const char *path, int fd) +{ + #ifdef HAS_EXTENDED_ATTRIBUTE_SUPPORT + + uint8 value; + if (path) { + return (lgetxattr(path, kAttributeDirMarkAttributeName, &value, 1) + > 0); + } else { + return (fgetxattr(fd, kAttributeDirMarkAttributeName, &value, 1) + > 0); + } + + #else // !HAS_EXTENDED_ATTRIBUTE_SUPPORT + + // No extended attribute support. We can't mark the file and thus + // have to handle it as marked. + return true; + + #endif +} + +// set_attribute_dir_mark +static status_t +set_attribute_dir_mark(const char *path, int fd) +{ + #ifdef HAS_EXTENDED_ATTRIBUTE_SUPPORT + + uint8 value = 1; + if (path) { + if (lsetxattr(path, kAttributeDirMarkAttributeName, &value, 1, 0) + < 0) { + fprintf(stderr, "set_attribute_dir_mark(): lsetxattr() " + "failed on \"%s\"\n", path); + return errno; + } + } else { + if (fsetxattr(fd, kAttributeDirMarkAttributeName, &value, 1, 0) + < 0) { + fprintf(stderr, "set_attribute_dir_mark(): fsetxattr() " + "failed on FD \"%d\"\n", fd); + return errno; + } + } + + #endif + + return B_OK; +} + +// empty_attribute_dir +static status_t +empty_attribute_dir(const char *path) +{ + DIR *dir = opendir(path); + if (!dir) + return errno; + + while (dirent *entry = readdir(dir)) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + + string entryPath(path); + entryPath += '/'; + entryPath += entry->d_name; + + // We assume the attribute dir contains files only (we only create + // files) and thus use unlink(). + if (unlink(entryPath.c_str()) < 0) { + status_t error = errno; + closedir(dir); + return error; + } + } + + closedir(dir); + return B_OK; +} + // ensure_attribute_dir_exists static status_t -ensure_attribute_dir_exists(NodeRef ref) +ensure_attribute_dir_exists(NodeRef ref, const char *path, int fd) { // init the base directory here status_t error = init_attribute_dir_base_dir(); @@ -138,25 +230,45 @@ ensure_attribute_dir_exists(NodeRef ref) if (!S_ISDIR(st.st_mode)) { // the attribute dir is no directory fprintf(stderr, "ensure_attribute_dir_exists(): Attribute " - "directory for node %lld exists, but is no directory!\n"); + "directory for node %lld exists, but is no directory!\n", + ref.node); return B_FILE_ERROR; } - - return B_OK; + + // already exists: Check whether the file is marked. If not, this + // is a stale attribute directory from a deleted node that had the + // same node ID as this one. + if (has_attribute_dir_mark(path, fd)) + return B_OK; + + // empty the attribute dir + error = empty_attribute_dir(attrDirPath.c_str()); + if (error != B_OK) { + fprintf(stderr, "ensure_attribute_dir_exists(): Attribute " + "directory for node %lld exists, the node has no mark, and " + "emptying the attribute directory failed\n", + ref.node); + return error; + } + + // mark the file + return set_attribute_dir_mark(path, fd); } // doesn't exist yet: create it if (mkdir(attrDirPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) < 0) return errno; - return B_OK; + + // mark the file + return set_attribute_dir_mark(path, fd); } // open_attr_dir DIR * -BPrivate::open_attr_dir(NodeRef ref) +BPrivate::open_attr_dir(NodeRef ref, const char *path, int fd) { // make sure the directory exists - status_t error = ensure_attribute_dir_exists(ref); + status_t error = ensure_attribute_dir_exists(ref, path, fd); if (error != B_OK) { errno = error; return NULL; @@ -169,14 +281,14 @@ BPrivate::open_attr_dir(NodeRef ref) // get_attribute_path status_t -BPrivate::get_attribute_path(NodeRef ref, const char *attribute, - string &attrPath, string &typePath) +BPrivate::get_attribute_path(NodeRef ref, const char *path, int fd, + const char *attribute, string &attrPath, string &typePath) { if (!attribute || strlen(attribute) == 0) return B_BAD_VALUE; // make sure the attribute dir for the node exits - status_t error = ensure_attribute_dir_exists(ref); + status_t error = ensure_attribute_dir_exists(ref, path, fd); if (error != B_OK) { errno = error; return -1; @@ -202,7 +314,7 @@ get_attribute_path(int fd, const char *attribute, string &attrPath, return errno; NodeRef ref(st); - return get_attribute_path(ref, attribute, attrPath, typePath); + return get_attribute_path(ref, NULL, fd, attribute, attrPath, typePath); } // fs_open_attr_dir @@ -213,7 +325,7 @@ fs_open_attr_dir(const char *path) if (lstat(path, &st)) return NULL; - return open_attr_dir(NodeRef(st)); + return open_attr_dir(NodeRef(st), path, -1); } // fs_fopen_attr_dir @@ -227,6 +339,8 @@ fs_fopen_attr_dir(int fd) if (fstat(fd, &st) < 0) return NULL; + return open_attr_dir(NodeRef(st), NULL, fd); + #else status_t error = _kern_read_stat(fd, NULL, false, &st, @@ -236,9 +350,16 @@ fs_fopen_attr_dir(int fd) return NULL; } -#endif + // Try to get a path. If we can't get a path, this is must be a "real" + // (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)); - return open_attr_dir(NodeRef(st)); +#endif } // fs_close_attr_dir diff --git a/src/build/libroot/fs_attr_impl.h b/src/build/libroot/fs_attr_impl.h index 6f0b8163bb..ebf2e2761c 100644 --- a/src/build/libroot/fs_attr_impl.h +++ b/src/build/libroot/fs_attr_impl.h @@ -9,10 +9,19 @@ namespace BPrivate { -DIR *open_attr_dir(NodeRef ref); +// defined in fs_attr.cpp -status_t get_attribute_path(NodeRef ref, const char *attribute, - std::string &attrPath, std::string &typePath); +// Note: Only one of path or fd can be supplied. +DIR *open_attr_dir(NodeRef ref, const char *path, int fd); + +// Note: Only one of path or fd can be supplied. +status_t get_attribute_path(NodeRef ref, const char *path, int fd, + const char *attribute, std::string &attrPath, std::string &typePath); + + +// defined in fs.cpp + +status_t get_path(int fd, const char *name, std::string &path); } // namespace BPrivate