From 9996b69b8b31eb721eb19dad5bdb5e8d943f9e71 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 15 Aug 2009 21:29:02 +0000 Subject: [PATCH] * Added new library libgnu.so, which will contain GNU compatibility interfaces (analoguously to libbsd.so). * Added an implementation of the GNU/Linux xattr interface. xattrs are mapped to Haiku attributes with type B_XATTR_TYPE. Haiku attributes are mapped to xattrs by moving them into the "user.haiku." namespace and appending the type to their name. Complete, but utterly untested yet. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32427 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/gnu/sys/xattr.h | 50 ++++++ src/libs/Jamfile | 1 + src/libs/gnu/Jamfile | 7 + src/libs/gnu/xattr.cpp | 341 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 399 insertions(+) create mode 100644 headers/gnu/sys/xattr.h create mode 100644 src/libs/gnu/Jamfile create mode 100644 src/libs/gnu/xattr.cpp diff --git a/headers/gnu/sys/xattr.h b/headers/gnu/sys/xattr.h new file mode 100644 index 0000000000..a1316ce824 --- /dev/null +++ b/headers/gnu/sys/xattr.h @@ -0,0 +1,50 @@ +/* + * Copyright 2009, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * The GNU/Linux xattr interface. Actual xattrs are identity-mapped into the + * Haiku attribute namespace with type B_XATTR_TYPE. Haiku attributes are mapped + * into a user xattr namespace, the attribute types encoded in the names. + */ +#ifndef _GNU_SYS_CDEFS_H +#define _GNU_SYS_CDEFS_H + + +#include +#include + + +/* constants for [l,f]setxattr() */ +#define XATTR_CREATE 1 /* fail if attribute exists */ +#define XATTR_REPLACE 2 /* fail if attribute doesn't exist yet */ + + +__BEGIN_DECLS + + +ssize_t getxattr(const char* path, const char* attribute, void* buffer, + size_t size); +ssize_t lgetxattr(const char* path, const char* attribute, void* buffer, + size_t size); +ssize_t fgetxattr(int fd, const char* attribute, void* buffer, size_t size); + +int setxattr(const char* path, const char* attribute, const void* buffer, + size_t size, int flags); +int lsetxattr(const char* path, const char* attribute, const void* buffer, + size_t size, int flags); +int fsetxattr(int fd, const char* attribute, const void* buffer, + size_t size, int flags); + +int removexattr (const char* path, const char* attribute); +int lremovexattr (const char* path, const char* attribute); +int fremovexattr (int fd, const char* attribute); + +ssize_t listxattr(const char* path, char* buffer, size_t size); +ssize_t llistxattr(const char* path, char* buffer, size_t size); +ssize_t flistxattr(int fd, char* buffer, size_t size); + + +__END_DECLS + + +#endif /* _GNU_SYS_CDEFS_H */ diff --git a/src/libs/Jamfile b/src/libs/Jamfile index 35a3535bd2..15fb3c0b53 100644 --- a/src/libs/Jamfile +++ b/src/libs/Jamfile @@ -9,6 +9,7 @@ SubInclude HAIKU_TOP src libs edit ; SubInclude HAIKU_TOP src libs expat ; SubInclude HAIKU_TOP src libs fluidsynth ; SubInclude HAIKU_TOP src libs freetype2 ; +SubInclude HAIKU_TOP src libs gnu ; SubInclude HAIKU_TOP src libs icon ; SubInclude HAIKU_TOP src libs iconv ; SubInclude HAIKU_TOP src libs libtelnet ; diff --git a/src/libs/gnu/Jamfile b/src/libs/gnu/Jamfile new file mode 100644 index 0000000000..3e83d3beee --- /dev/null +++ b/src/libs/gnu/Jamfile @@ -0,0 +1,7 @@ +SubDir HAIKU_TOP src libs gnu ; + +UsePrivateHeaders shared ; + +SharedLibrary libgnu.so : + xattr.cpp +; diff --git a/src/libs/gnu/xattr.cpp b/src/libs/gnu/xattr.cpp new file mode 100644 index 0000000000..bebb2654b7 --- /dev/null +++ b/src/libs/gnu/xattr.cpp @@ -0,0 +1,341 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + + +static const char* const kXattrNamespace = "user.haiku."; +static const size_t kXattrNamespaceLength = 11; + + +namespace { + + +struct AttributeName { + char name[B_ATTR_NAME_LENGTH + 32]; + uint32 type; + + void Init(const char* haikuName, uint32 type) + { + if (type == B_XATTR_TYPE) { + // a simple xattr -- copy the name verbatim + strlcpy(name, haikuName, sizeof(name)); + this->type = type; + } else { + // a Haiku attribute -- map the name + + // create a type string -- if the four bytes of the type are + // printable, just use them as the type string, otherwise convert + // to hex + char typeString[9]; + uint8 typeBytes[4] = { type >> 24, type >> 16, type >> 8, type }; + if (isprint(typeBytes[0]) && isprint(typeBytes[1]) + && isprint(typeBytes[2]) && isprint(typeBytes[3])) { + typeString[0] = typeBytes[0]; + typeString[1] = typeBytes[1]; + typeString[2] = typeBytes[2]; + typeString[3] = typeBytes[3]; + typeString[4] = '\0'; + } else + sprintf(typeString, "%08lx", type); + + snprintf(name, sizeof(name), "%s%s#%s\n", kXattrNamespace, + haikuName, typeString); + } + } + + void Init(const char* xattrName) + { + if (strncmp(xattrName, kXattrNamespace, kXattrNamespaceLength) == 0) { + // a Haiku attribute -- extract the actual name and type + xattrName += kXattrNamespaceLength; + + if (_DecodeNameAndType(xattrName)) + return; + + } + + // a simple xattr + strlcpy(name, xattrName, sizeof(name)); + this->type = B_XATTR_TYPE; + } + +private: + + bool _DecodeNameAndType(const char* xattrName) + { + const char* typeString = strrchr(xattrName, '#'); + if (typeString == NULL || typeString == xattrName) + return false; + typeString++; + + size_t typeStringLength = strlen(typeString); + if (typeStringLength == 4) { + // the type string consists of the literal type bytes + type = ((uint32)typeString[0] << 24) | ((uint32)typeString[1] << 16) + | ((uint32)typeString[2] << 8) | (uint32)typeString[3]; + } else if (typeStringLength == 8) { + // must be hex-encoded + char* numberEnd; + type = strtoul(typeString, &numberEnd, 16); + if (numberEnd != typeString + 8) + return false; + } else + return false; + + strlcpy(name, xattrName, + std::min(sizeof(name), (size_t)(typeString - xattrName - 1))); + return true; + } +}; + + +struct Node { + Node(const char* path, bool traverseSymlinks) + { + fFileFD = open(path, O_RDWR | (traverseSymlinks ? 0 : O_NOTRAVERSE)); + fOwnsFileFD = true; + } + + Node(int fileFD) + { + fFileFD = fileFD; + fOwnsFileFD = false; + + if (fileFD < 0) + errno = B_FILE_ERROR; + } + + ~Node() + { + if (fFileFD >= 0 && fOwnsFileFD) + close(fFileFD); + } + + int Set(const char* attribute, int flags, const void* buffer, size_t size) + { + if (fFileFD < 0) + return -1; + + // flags to open mode + int openMode = O_WRONLY | O_TRUNC; + if (flags == XATTR_CREATE) { + openMode |= O_CREAT | O_EXCL; + } else if (flags == XATTR_REPLACE) { + // pure open -- attribute must exist + } else + openMode |= O_CREAT; + + AttributeName attributeName; + attributeName.Init(attribute); + + int attributeFD = fs_fopen_attr(fFileFD, attributeName.name, + B_XATTR_TYPE, openMode); + if (attributeFD < 0) { + // translate B_ENTRY_NOT_FOUND to ENOATTR + if (errno == B_ENTRY_NOT_FOUND) + errno = ENOATTR; + + return -1; + } + + ssize_t written = write(attributeFD, buffer, size); + + fs_close_attr(attributeFD); + + if (written < 0) + return -1; + if ((size_t)written != size) + RETURN_AND_SET_ERRNO(B_FILE_ERROR); + + return 0; + } + + ssize_t Get(const char* attribute, void* buffer, size_t size) + { + if (fFileFD < 0) + return -1; + + AttributeName attributeName; + attributeName.Init(attribute); + + ssize_t bytesRead = fs_read_attr(fFileFD, attributeName.name, + B_XATTR_TYPE, 0, buffer, size); + + // translate B_ENTRY_NOT_FOUND to ENOATTR + if (bytesRead < 0 && errno == B_ENTRY_NOT_FOUND) + errno = ENOATTR; + + return bytesRead; + } + + int Remove(const char* attribute) + { + if (fFileFD < 0) + return -1; + + AttributeName attributeName; + attributeName.Init(attribute); + + int result = fs_remove_attr(fFileFD, attributeName.name); + + // translate B_ENTRY_NOT_FOUND to ENOATTR + if (result != 0 && errno == B_ENTRY_NOT_FOUND) + errno = ENOATTR; + + return result; + } + + ssize_t GetList(void* buffer, size_t size) + { + if (fFileFD < 0) + return -1; + + // open attribute directory + DIR* dir = fs_fopen_attr_dir(fFileFD); + if (dir == NULL) + return -1; + + // read the attributes + size_t remainingSize = size; + size_t totalSize = 0; + while (struct dirent* entry = readdir(dir)) { + attr_info info; + if (fs_stat_attr(fFileFD, entry->d_name, &info) != 0) + continue; + + AttributeName attributeName; + attributeName.Init(entry->d_name, info.type); + + size_t nameLength = strlen(attributeName.name); + totalSize += nameLength + 1; + + if (remainingSize > nameLength) { + strcpy((char*)buffer, attributeName.name); + remainingSize -= nameLength + 1; + } else + remainingSize = 0; + } + + closedir(dir); + + // If the buffer was too small, fail. + if (size != 0 && totalSize > size) { + errno = ERANGE; + return -1; + } + + return totalSize; + } + +private: + int fFileFD; + bool fOwnsFileFD; +}; + + +} // namespace + + +// #pragma mark - + + +ssize_t +getxattr(const char* path, const char* attribute, void* buffer, size_t size) +{ + return Node(path, true).Get(attribute, buffer, size); +} + + +ssize_t +lgetxattr(const char* path, const char* attribute, void* buffer, size_t size) +{ + return Node(path, false).Get(attribute, buffer, size); +} + + +ssize_t +fgetxattr(int fd, const char* attribute, void* buffer, size_t size) +{ + return Node(fd).Get(attribute, buffer, size); +} + + +int +setxattr(const char* path, const char* attribute, const void* buffer, + size_t size, int flags) +{ + return Node(path, true).Set(attribute, flags, buffer, size); +} + + +int +lsetxattr(const char* path, const char* attribute, const void* buffer, size_t size, + int flags) +{ + return Node(path, false).Set(attribute, flags, buffer, size); +} + + +int +fsetxattr(int fd, const char* attribute, const void* buffer, size_t size, int flags) +{ + return Node(fd).Set(attribute, flags, buffer, size); +} + + +int +removexattr (const char* path, const char* attribute) +{ + return Node(path, true).Remove(attribute); +} + + +int +lremovexattr (const char* path, const char* attribute) +{ + return Node(path, false).Remove(attribute); +} + + +int +fremovexattr (int fd, const char* attribute) +{ + return Node(fd).Remove(attribute); +} + + +ssize_t +listxattr(const char* path, char* buffer, size_t size) +{ + return Node(path, true).GetList(buffer, size); +} + + +ssize_t +llistxattr(const char* path, char* buffer, size_t size) +{ + return Node(path, false).GetList(buffer, size); +} + + +ssize_t +flistxattr(int fd, char* buffer, size_t size) +{ + return Node(fd).GetList(buffer, size); +}