Sat, 18 Mar 2023 15:52:35 +0100
add libxattr
--- /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 <stdio.h> +#include <stdlib.h> + +#include "libxattr.h" + +#include <errno.h> +#include <sys/types.h> + +#include <string.h> + +#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 <sys/xattr.h> + +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<length;i++) { + if(!name && buf[i] == '.') { + int nslen = (buf+i-begin); + //printf("%.*s\n", nslen, begin); + name = buf + i + 1; + } + if(buf[i] == '\0') { + char *attrname = strdup(name); + ARRAY_ADD(array, arraypos, arraylen, attrname); + begin = buf + i + 1; + name = 0; + } + } + + if(arraypos == 0) { + free(array); + array = NULL; + } + + *nelm = arraypos; + return array; +} + +char ** xattr_list(const char *path, ssize_t *nelm) { + char *list = malloc(LIST_BUF_LEN); + ssize_t len = listxattr(path, list, LIST_BUF_LEN); + if(len == -1) { + switch(errno) { + case ERANGE: { + // buffer too, get size of attribute list + ssize_t newlen = listxattr(path, NULL, 0); + if(newlen > 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 <sys/xattr.h> + +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<length;i++) { + if(buf[i] == '\0') { + char *attrname = strdup(name); + ARRAY_ADD(array, arraypos, arraylen, attrname); + name = buf + i + 1; + } + } + + if(arraypos == 0) { + free(array); + array = NULL; + } + + *nelm = arraypos; + return array; +} + +char ** xattr_list(const char *path, ssize_t *nelm) { + char *list = malloc(LIST_BUF_LEN); + ssize_t len = listxattr(path, list, LIST_BUF_LEN, 0); + if(len == -1) { + switch(errno) { + case ERANGE: { + // buffer too, get size of attribute list + ssize_t newlen = listxattr(path, NULL, 0, 0); + if(newlen > 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 <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <fcntl.h> + +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 <sys/types.h> +#include <sys/extattr.h> + +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<length;i++) { + char namelen = buf[i]; + char *name = buf + i + 1; + char *attrname = malloc(namelen + 1); + memcpy(attrname, name, namelen); + attrname[namelen] = 0; + ARRAY_ADD(array, arraypos, arraylen, attrname); + i += namelen; + } + + if(arraypos == 0) { + free(array); + array = NULL; + } + + *nelm = arraypos; + return array; +} + +char ** xattr_list(const char *path, ssize_t *nelm) { + *nelm = -1; + ssize_t lslen = extattr_list_file(path, EXTATTR_NAMESPACE_USER, NULL, 0); + if(lslen <= 0) { + if(lslen == 0) { + *nelm = 0; + } + return NULL; + } + + char *list = malloc(lslen); + ssize_t len = extattr_list_file(path, EXTATTR_NAMESPACE_USER, list, lslen); + if(len == -1) { + free(list); + 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 = extattr_get_file(path, EXTATTR_NAMESPACE_USER, attr, NULL, 0); + if(attrlen < 0) { + *len = -1; + return NULL; + } + + char *buf = malloc_func(pool, attrlen + 1); + ssize_t vlen = extattr_get_file(path, EXTATTR_NAMESPACE_USER, attr, buf, attrlen); + 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 = extattr_set_file(path, EXTATTR_NAMESPACE_USER, name, value, len); + return ret; +} + +int xattr_remove(const char *path, const char *name) { + return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, name); +} + +#endif /* FreeBSD */ + + +#ifndef XATTR_SUPPORTED + +char ** xattr_list(const char *path, ssize_t *nelm) { + *nelm = -1; + return NULL; +} + +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; + return NULL; +} + +int xattr_set(const char *path, const char *name, const void *value, size_t len) { + return -1; +} + +int xattr_remove(const char *path, const char *name) { + return -1; +} + +#endif /* unsupported platform */ + + +char * xattr_get(const char *path, const char *attr, ssize_t *len) { + return xattr_get_alloc(NULL, libxattr_malloc, libxattr_free, path, attr, len); +} + +void xattr_free_list(char **attrnames, ssize_t nelm) { + if(attrnames) { + for(int i=0;i<nelm;i++) { + free(attrnames[i]); + } + free(attrnames); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/util/libxattr.h Sat Mar 18 15:52:35 2023 +0100 @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef LIBXATTR_H +#define LIBXATTR_H + +#include <sys/types.h> +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void*(*libxattr_malloc_func)(void *pool, size_t size); +typedef void(*libxattr_free_func)(void *pool, void *ptr); + + +char ** xattr_list(const char *path, ssize_t *nelm); + +char * xattr_get(const char *path, const char *attr, ssize_t *len); + +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); + +int xattr_set(const char *path, const char *name, const void *value, size_t len); + +int xattr_remove(const char *path, const char *name); + +void xattr_free_list(char **attrnames, ssize_t nelm); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXATTR_H */ +
--- a/src/server/util/objs.mk Sat Mar 18 14:16:05 2023 +0100 +++ b/src/server/util/objs.mk Sat Mar 18 15:52:35 2023 +0100 @@ -43,6 +43,7 @@ UTILOBJ += util.o UTILOBJ += date.o UTILOBJ += writer.o +UTILOBJ += libxattr.o UTILOBJS = $(UTILOBJ:%=$(UTIL_OBJPRE)%) UTILSOURCE = $(UTILOBJ:%.o=util/%.c)
--- a/src/server/webdav/xattrbackend.c Sat Mar 18 14:16:05 2023 +0100 +++ b/src/server/webdav/xattrbackend.c Sat Mar 18 15:52:35 2023 +0100 @@ -29,6 +29,9 @@ #include "xattrbackend.h" +#include "../util/util.h" +#include "../util/libxattr.h" + static WebdavBackend webdav_xattr_backend = { webdav_xattr_propfind_init, @@ -61,6 +64,7 @@ } // TODO: config + repo->xattr_name = "webdav_properties"; return repo; } @@ -93,6 +97,22 @@ const char *href, WebdavPList **outplist) { + // make sure the sys vfs is used, because currently only + // native sysfs xattr is supported + if(rq->rq->vfs) { + log_ereport(LOG_FAILURE, "webdav-propfind: xattr backend unsupported with non-native VFS"); + return 1; + } + + XAttrPropfind *xprop = pool_malloc(rq->sn->pool, sizeof(XAttrPropfind)); + if(!xprop) { + return 1; + } + rq->userdata = xprop; + + xprop->base_href = href; + xprop->base_path = path; + return 0; } @@ -103,6 +123,47 @@ WebdavResource *resource, struct stat *s) { + Session *sn = request->sn; + Request *rq = request->rq; + + WebdavXAttrBackend *xdav = request->dav->instance; + WebdavXAttrRepository *repo = xdav->repo; + XAttrPropfind *xprop = request->userdata; + + const char *path; + char *path_dp = NULL; + if(!parent) { + // use base path + path = xprop->base_path; + } else { + size_t base_href_len = strlen(xprop->base_href); + size_t base_path_len = strlen(xprop->base_path); + char *res_path = resource->href + base_href_len; + size_t res_path_len = strlen(res_path); + + path_dp = pool_malloc(sn->pool, base_path_len + res_path_len + 2); + memcpy(path_dp, xprop->base_path, base_path_len); + int s = 0; + if(path_dp[base_path_len-1] != '/' && res_path[0] != '/') { + path_dp[base_path_len] = '/'; + s = 1; + } + memcpy(path_dp + base_path_len + s, res_path, res_path_len); + path_dp[base_path_len + s + res_path_len] = 0; + + path = path_dp; + } + + ssize_t xattr_data_len = 0; + char *xattr_data = xattr_get_alloc( + sn->pool, + (libxattr_malloc_func)pool_malloc, + (libxattr_free_func)pool_free, + path, + repo->xattr_name, + &xattr_data_len); + + return 0; }
--- a/src/server/webdav/xattrbackend.h Sat Mar 18 14:16:05 2023 +0100 +++ b/src/server/webdav/xattrbackend.h Sat Mar 18 15:52:35 2023 +0100 @@ -37,12 +37,17 @@ #endif typedef struct WebdavXAttrRepository { - int a; + char *xattr_name; } WebdavXAttrRepository; typedef struct WebdavXAttrBackend { WebdavXAttrRepository *repo; } WebdavXAttrBackend; + +typedef struct XAttrPropfind { + const char *base_href; + const char *base_path; +} XAttrPropfind; int webdav_init_xattr_backend(void);