diff -r 2a42ba73ecdd -r 9f69e4b8b695 src/server/util/libxattr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/util/libxattr.c Sat Mar 18 15:52:35 2023 +0100 @@ -0,0 +1,576 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2018 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _GNU_SOURCE + +#include +#include + +#include "libxattr.h" + +#include +#include + +#include + +#define LIST_BUF_LEN 1024 +#define LIST_ARRAY_LEN 8 +#define ATTR_BUF_LEN 1024 + +#define ARRAY_ADD(array, pos, len, obj) if(pos >= len) { \ + len *= 2; /* TODO: missing error handling for realloc() */ \ + array = realloc(array, len * sizeof(char*)); \ + } \ + array[pos] = obj; \ + pos++; + +static void* libxattr_malloc(void *unused, size_t size) { + return malloc(size); +} + +static void libxattr_free(void *unused, void *ptr) { + free(ptr); +} + + +#ifdef __linux__ +#define XATTR_SUPPORTED +#include + +static char ** parse_xattrlist(char *buf, ssize_t length, ssize_t *nelm) { + size_t arraylen = LIST_ARRAY_LEN; + size_t arraypos = 0; + char **array = malloc(LIST_ARRAY_LEN * sizeof(char*)); + + char *begin = buf; + char *name = NULL; + for(int i=0;i 0) { + // second try + list = realloc(list, newlen); + len = listxattr(path, list, newlen); + if(len != -1) { + // this time it worked + break; + } + } + } + default: { + free(list); + *nelm = -1; + return NULL; + } + } + } + + char **ret = parse_xattrlist(list, len, nelm); + free(list); + return ret; +} + +static char* name2nsname(const char *name) { + // add the 'user' namespace to the name + size_t namelen = strlen(name); + char *attrname = malloc(8 + namelen); + if(!attrname) { + return NULL; + } + memcpy(attrname, "user.", 5); + memcpy(attrname+5, name, namelen + 1); + return attrname; +} + +char * xattr_get_alloc( + void *pool, + libxattr_malloc_func malloc_func, + libxattr_free_func free_func, + const char *path, + const char *attr, + ssize_t *len) +{ + char *buf = malloc_func(pool, ATTR_BUF_LEN); + if(!buf) { + *len = -1; + return NULL; + } + + char *attrname = name2nsname(attr); + if(!attrname) { + free_func(pool, buf); + *len = -1; + return NULL; + } + + ssize_t vlen = getxattr(path, attrname, buf, ATTR_BUF_LEN - 1); + if(vlen < 0) { + switch(errno) { + case ERANGE: { + ssize_t attrlen = getxattr(path, attrname, NULL, 0); + if(attrlen > 0) { + free_func(pool, buf); + buf = malloc_func(pool, attrlen + 1); + if(!buf) { + free(attrname); + *len = -1; + return NULL; + } + vlen = getxattr(path, attrname, buf, attrlen); + if(vlen > 0) { + break; + } + } + } + default: { + *len = -1; + free_func(pool, buf); + free(attrname); + return NULL; + } + } + } + buf[vlen] = 0; + + free(attrname); + *len = vlen; + return buf; +} + +int xattr_set(const char *path, const char *name, const void *value, size_t len) { + char *attrname = name2nsname(name); + int ret = setxattr(path, attrname, value, len, 0); + free(attrname); + return ret; +} + +int xattr_remove(const char *path, const char *name) { + char *attrname = name2nsname(name); + int ret = removexattr(path, attrname); + free(attrname); + return ret; +} + +#endif /* Linux */ + +#ifdef __APPLE__ +#define XATTR_SUPPORTED +#include + +static char ** parse_xattrlist(char *buf, ssize_t length, ssize_t *nelm) { + size_t arraylen = LIST_ARRAY_LEN; + size_t arraypos = 0; + char **array = malloc(LIST_ARRAY_LEN * sizeof(char*)); + + char *name = buf; + for(int i=0;i 0) { + // second try + list = realloc(list, newlen); + len = listxattr(path, list, newlen, 0); + if(len != -1) { + // this time it worked + break; + } + } + } + default: { + free(list); + *nelm = -1; + return NULL; + } + } + } + + char **ret = parse_xattrlist(list, len, nelm); + free(list); + return ret; +} + +char * xattr_get_alloc( + void *pool, + libxattr_malloc_func malloc_func, + libxattr_free_func free_func, + const char *path, + const char *attr, + ssize_t *len) +{ + // get attribute length + ssize_t attrlen = getxattr(path, attr, NULL, 0, 0, 0); + if(attrlen < 0) { + *len = -1; + return NULL; + } + + char *buf = malloc_func(pool, attrlen + 1); + if(!buf) { + *len = -1; + return NULL; + } + + ssize_t vlen = getxattr(path, attr, buf, attrlen, 0, 0); + if(vlen < 0) { + *len = -1; + free_func(pool, buf); + return NULL; + } + buf[attrlen] = 0; + + *len = vlen; + return buf; +} + +int xattr_set(const char *path, const char *name, const void *value, size_t len) { + int ret = setxattr(path, name, value, len, 0, 0); + return ret; +} + +int xattr_remove(const char *path, const char *name) { + return removexattr(path, name, 0); +} + +#endif /* Apple */ + +#ifdef __sun +#define XATTR_SUPPORTED +#include +#include +#include +#include +#include + +static int open_attrfile(const char *path, const char *attr, int oflag) { + int file = open(path, O_RDONLY); + if(file == -1) { + return -1; + } + + int attrfile = openat(file, attr, oflag, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + close(file); + return attrfile; +} + +char ** xattr_list(const char *path, ssize_t *nelm) { + *nelm = -1; + + int attrdir = open_attrfile(path, ".", O_RDONLY|O_XATTR); + if(attrdir == -1) { + return NULL; + } + + DIR *dir = fdopendir(attrdir); + if(!dir) { + close(attrdir); + return NULL; + } + + size_t arraylen = LIST_ARRAY_LEN; + size_t arraypos = 0; + char **array = malloc(LIST_ARRAY_LEN * sizeof(char*)); + + struct dirent *ent; + while((ent = readdir(dir)) != NULL) { + if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "SUNWattr_ro") || !strcmp(ent->d_name, "SUNWattr_rw")) { + continue; + } + char *name = strdup(ent->d_name); + ARRAY_ADD(array, arraypos, arraylen, name); + } + closedir(dir); + + *nelm = arraypos; + return array; +} + +char * xattr_get_alloc( + void *pool, + libxattr_malloc_func malloc_func, + libxattr_free_func free_func, + const char *path, + const char *attr, + ssize_t *len) +{ + *len = -1; + + int attrfile = open_attrfile(path, attr, O_RDONLY|O_XATTR); + if(attrfile == -1) { + return NULL; + } + + struct stat s; + if(fstat(attrfile, &s)) { + close(attrfile); + return NULL; + } + + size_t bufsize = (size_t)s.st_size; + char *buf = malloc_func(pool, bufsize); + + char *b = buf; + size_t cur = 0; + while(cur < bufsize) { + ssize_t r = read(attrfile, buf + cur, bufsize - cur); + if(r <= 0) { + break; + } + cur += r; + } + + close(attrfile); + if(cur != bufsize) { + free_func(pool, buf); + return NULL; + } + + *len = (ssize_t)bufsize; + return buf; +} + +int xattr_set(const char *path, const char *name, const void *value, size_t len) { + int attrfile = open_attrfile(path, name, O_CREAT|O_WRONLY|O_XATTR|O_TRUNC); + if(attrfile == -1) { + return -1; + } + + const char *p = value; + size_t remaining = len; + while(remaining > 0) { + ssize_t w = write(attrfile, p, remaining); + if(w <= 0) { + break; + } + p += w; + remaining -= w; + } + + close(attrfile); + + return remaining > 0 ? -1 : 0; +} + +int xattr_remove(const char *path, const char *name) { + int attrdir = open_attrfile(path, ".", O_RDONLY|O_XATTR); + if(attrdir == -1) { + return -1; + } + + int ret = unlinkat(attrdir, name, 0); + close(attrdir); + return ret; +} + +#endif /* Sun */ + + +#ifdef __FreeBSD__ +#define XATTR_SUPPORTED + +#include +#include + +static char ** parse_xattrlist(char *buf, ssize_t length, ssize_t *nelm) { + size_t arraylen = LIST_ARRAY_LEN; + size_t arraypos = 0; + char **array = malloc(LIST_ARRAY_LEN * sizeof(char*)); + + char *name = buf; + for(int i=0;i