diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/arena.c | 50 | ||||
-rw-r--r-- | src/arena.h | 15 | ||||
-rw-r--r-- | src/bindfs.c | 150 | ||||
-rw-r--r-- | src/misc.c | 107 | ||||
-rw-r--r-- | src/misc.h | 25 | ||||
-rw-r--r-- | src/userinfo.c | 1 |
7 files changed, 216 insertions, 136 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 904943a..7e25193 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,8 +2,8 @@ bin_PROGRAMS = bindfs -noinst_HEADERS = debug.h permchain.h userinfo.h misc.h usermap.h rate_limiter.h -bindfs_SOURCES = bindfs.c debug.c permchain.c userinfo.c misc.c usermap.c rate_limiter.c +noinst_HEADERS = debug.h permchain.h userinfo.h arena.h misc.h usermap.h rate_limiter.h +bindfs_SOURCES = bindfs.c debug.c permchain.c userinfo.c arena.c misc.c usermap.c rate_limiter.c AM_CPPFLAGS = ${my_CPPFLAGS} ${fuse_CFLAGS} ${fuse3_CFLAGS} AM_CFLAGS = ${my_CFLAGS} diff --git a/src/arena.c b/src/arena.c new file mode 100644 index 0000000..2221616 --- /dev/null +++ b/src/arena.c @@ -0,0 +1,50 @@ +#include "arena.h" + +struct block { + size_t size; + size_t used; + struct block *next; + char data_start[]; +}; + +static const size_t min_block_room = 16 * 1024 - sizeof(struct block); + +static void add_block(struct arena* a, size_t room_wanted) +{ + if (room_wanted < min_block_room) { + room_wanted = min_block_room; + } + struct block *new_block = malloc(sizeof(struct block) + room_wanted); + new_block->size = room_wanted; + new_block->used = 0; + new_block->next = a->cur_block; + a->cur_block = new_block; +} + +void arena_init(struct arena *a) +{ + a->cur_block = NULL; +} + +void* arena_malloc(struct arena *a, size_t amount) +{ + struct block* b = a->cur_block; + if (b == NULL || b->size - b->used < amount) { + add_block(a, amount); + b = a->cur_block; + } + void* result = &b->data_start[b->used]; + b->used += amount; + return result; +} + +void arena_free(struct arena *a) +{ + struct block* b = a->cur_block; + while (b != NULL) { + struct block* next = b->next; + free(b); + b = next; + } + a->cur_block = NULL; +} diff --git a/src/arena.h b/src/arena.h new file mode 100644 index 0000000..f862dbf --- /dev/null +++ b/src/arena.h @@ -0,0 +1,15 @@ +#ifndef INC_BINDFS_ARENA_H +#define INC_BINDFS_ARENA_H + +#include <stdlib.h> + +struct block; +struct arena { + struct block *cur_block; +}; + +void arena_init(struct arena *a); +void* arena_malloc(struct arena *a, size_t amount); +void arena_free(struct arena *a); + +#endif diff --git a/src/bindfs.c b/src/bindfs.c index 57d0a8e..96f909b 100644 --- a/src/bindfs.c +++ b/src/bindfs.c @@ -31,20 +31,6 @@ #include <config.h> -/* For >= 500 for pread/pwrite; >= 700 for utimensat */ -#define _XOPEN_SOURCE 700 - -/* For flock() on FreeBSD. It otherwise gets hidden by _XOPEN_SOURCE */ -#define __BSD_VISIBLE 1 - -/* For stat() nanosecond precision and lutimes() */ -#define _BSD_SOURCE -/* The new non-deprecated version of _BSD_SOURCE */ -#define _DEFAULT_SOURCE - -/* Fix MacOS realpath() broken around Catalina (#83) */ -#define _DARWIN_BETTER_REALPATH - #include <stdlib.h> #include <stddef.h> #include <stdio.h> @@ -97,6 +83,7 @@ #include <fuse.h> #include <fuse_opt.h> +#include "arena.h" #include "debug.h" #include "misc.h" #include "permchain.h" @@ -367,6 +354,7 @@ Why? Because some of those options like "nofail" are special ones interpreted by systemd in /etc/fstab */ struct fuse_args filter_special_opts(struct fuse_args *args); +static bool keep_option(const char* opt); static int is_mirroring_enabled() { @@ -2085,8 +2073,8 @@ static int parse_map_file(UserMap *map, UserMap *reverse_map, char *file, int as UsermapStatus status; // Toggle between UID (passwd) and GID (group) - const int (*value_to_id)(const char *username, uid_t *ret); - const UsermapStatus (*usermap_add)(UserMap *map, uid_t from, uid_t to); + int (*value_to_id)(const char *username, uid_t *ret); + UsermapStatus (*usermap_add)(UserMap *map, uid_t from, uid_t to); const char *label_name, *label_id; if (as_gid) { value_to_id = &group_gid; @@ -2336,11 +2324,27 @@ static void atexit_func() struct fuse_args filter_special_opts(struct fuse_args *args) { - bool ignore; + struct arena arena; + arena_init(&arena); + int tmp_argc = args->argc; + char **tmp_argv; + + filter_o_opts(&keep_option, args->argc, (const char * const *)args->argv, &tmp_argc, &tmp_argv, &arena); + struct fuse_args new_args = FUSE_ARGS_INIT(0, (void*)0); + for (int i = 0; i < tmp_argc; i++) { + fuse_opt_add_arg(&new_args, tmp_argv[i]); + } + + arena_free(&arena); + fuse_opt_free_args(args); + return new_args; +} +static bool keep_option(const char* opt) +{ // Copied from "libfuse/util/mount.fuse.c" (fuse-3.10.1) - const char *ignore_opts[] = { + static const char * const ignored_opts[] = { "", "user", "nofail", @@ -2352,114 +2356,12 @@ struct fuse_args filter_special_opts(struct fuse_args *args) NULL }; - for (int i = 0; i < args->argc; i++) { - ignore = false; - - /* If current element is exactly "-o" modify/check the following element */ - if (strcmp(args->argv[i], "-o") == 0 && (i+1) < args->argc) { - - /* remove ignored option from a comma separated list */ - if (strchr(args->argv[i+1], ',') != NULL) { - char *tmpStr = (char*) calloc(strlen(args->argv[i+1]) + 1, sizeof(char)); - char *ptr = strtok(args->argv[i+1], ","); - while (ptr != NULL) { - ignore = false; - for (int j = 0; ignore_opts[j]; j++) { - if (strcmp(ptr, ignore_opts[j]) == 0) { - ignore = true; - break; - } - } - if (!ignore) { - if (strlen(tmpStr) > 0) strcat(tmpStr, ","); - strcat(tmpStr, ptr); - } - ptr = strtok(NULL, ","); - } - if (strlen(tmpStr) > 0) { - args->argv[i+1] = (char*) calloc(strlen(tmpStr) + 1, sizeof(char)); - strcpy(args->argv[i+1], tmpStr); - free(tmpStr); - ignore = false; - } - else { - ignore = true; - ++i; - } - } - - /* ignore this and the following element if it has exactly the ignored option */ - else { - for (int j = 0; ignore_opts[j]; j++) { - if (strcmp(args->argv[i+1], ignore_opts[j]) == 0) { - ignore = true; - ++i; - break; - } - } - } - } - - /* else if element starts with "-o" */ - else if (strncmp(args->argv[i], "-o", 2) == 0) { - - /* remove ignored option from a comma seperated list */ - if (strchr(args->argv[i], ',') != NULL) { - char *tmpStr = (char*) calloc(strlen(args->argv[i]) + 1, sizeof(char)); - char *tmpStr2 = (char*) calloc(strlen(args->argv[i]) + 1 - 2, sizeof(char)); - // remove first 2 chars from args->argv[i] and save this to tmpStr2 - memcpy(tmpStr2, args->argv[i] + 2, strlen(args->argv[i]) - 2); - char *ptr = strtok(tmpStr2, ","); - while (ptr != NULL) { - ignore = false; - for (int j = 0; ignore_opts[j]; j++) { - if (strcmp(ptr, ignore_opts[j]) == 0) { - ignore = true; - break; - } - } - if (!ignore) { - if (strlen(tmpStr) > 0) strcat(tmpStr, ","); - strcat(tmpStr, ptr); - } - ptr = strtok(NULL, ","); - } - if (strlen(tmpStr) > 0) { - args->argv[i] = (char*) calloc(2 + strlen(tmpStr) + 1, sizeof(char)); - strcat(args->argv[i], "-o"); - strcat(args->argv[i], tmpStr); - free(tmpStr); - free(tmpStr2); - ignore = false; - } - else { - ignore = true; - } - } - - /* ignore this element if it has exactly the ignored option */ - else { - for (int j = 0; ignore_opts[j]; j++) { - char* tmpStr = (char*) calloc(2 + strlen(ignore_opts[j]) + 1, sizeof(char)); - strcat(tmpStr, "-o"); - strcat(tmpStr, ignore_opts[j]); - if (strcmp(args->argv[i], tmpStr) == 0) { - ignore = true; - free(tmpStr); - break; - } - free(tmpStr); - } - } - } - if (!ignore) { - fuse_opt_add_arg(&new_args, strdup(args->argv[i])); + for (int i = 0; ignored_opts[i] != NULL; ++i) { + if (strcmp(ignored_opts[i], opt) == 0) { + return false; } } - - fuse_opt_free_args(args); - - return new_args; + return true; } int main(int argc, char *argv[]) @@ -135,6 +135,102 @@ const char *my_dirname(char *path) } } +static char **dup_argv(int argc, const char * const *argv, struct arena *arena) +{ + char **pointer_list = arena_malloc(arena, (argc + 1) * sizeof(char*)); + char **next_ptr = pointer_list; + + for (int i = 0; i < argc; ++i) { + int len = strlen(argv[i]); + char *str = arena_malloc(arena, len + 1); + memcpy(str, argv[i], len + 1); + *next_ptr = str; + ++next_ptr; + } + *next_ptr = NULL; + + return pointer_list; +} + +/* Converts all ("-o", "...") into ("-o..."). */ +static void merge_o_args( + int *argc, + char **argv, + struct arena *arena +) +{ + int i = 0; + while (i < *argc) { + char *arg = argv[i]; + if (strcmp(arg, "-o") == 0) { + if (i + 1 < *argc) { + char *merged = arena_malloc(arena, 2 + strlen(argv[i + 1]) + 1); + merged[0] = '-'; + merged[1] = 'o'; + strcpy(&merged[2], argv[i + 1]); + argv[i] = merged; + + for (int j = i + 1; j < *argc - 1; ++j) { + argv[j] = argv[j + 1]; + } + } + --*argc; + } + ++i; + } +} + +void filter_o_opts( + bool (*keep)(const char* opt), + int orig_argc, + const char * const *orig_argv, + int *new_argc, + char ***new_argv, + struct arena* arena +) +{ + int argc = orig_argc; + char **argv = dup_argv(argc, orig_argv, arena); + + merge_o_args(&argc, argv, arena); + + for (int i = 0; i < argc; i++) { + char *arg = argv[i]; + if (strncmp(arg, "-o", 2) == 0) { + char *filtered = arena_malloc(arena, strlen(arg) + 1); + char *filtered_end = filtered; + + const char *tok = strtok(arg + 2, ","); + while (tok != NULL) { + size_t tok_len = strlen(tok); + if ((*keep)(tok)) { + if (filtered_end == filtered) { + *(filtered_end++) = '-'; + *(filtered_end++) = 'o'; + } else { + *(filtered_end++) = ','; + } + memcpy(filtered_end, tok, tok_len + 1); + filtered_end += tok_len; // We'll overwrite the null terminator if we append more. + } + tok = strtok(NULL, ","); + } + + if (filtered != filtered_end) { + argv[i] = filtered; + } else { + for (int j = i; j < argc - 1; ++j) { + argv[j] = argv[j + 1]; + } + --argc; + } + } + } + + *new_argc = argc; + *new_argv = argv; +} + void grow_array_impl(void **array, int *capacity, int member_size) { int new_cap = *capacity; @@ -170,7 +266,8 @@ int parse_byte_count(const char *str, double *result) return 1; } -void init_memory_block(struct memory_block *a, int initial_capacity) + +void init_memory_block(struct memory_block *a, size_t initial_capacity) { a->size = 0; a->capacity = initial_capacity; @@ -181,9 +278,9 @@ void init_memory_block(struct memory_block *a, int initial_capacity) } } -void grow_memory_block(struct memory_block *a, int amount) +void grow_memory_block(struct memory_block *a, size_t amount) { - int new_cap; + size_t new_cap; a->size += amount; if (a->size >= a->capacity) { @@ -204,9 +301,9 @@ void grow_memory_block(struct memory_block *a, int amount) } } -int append_to_memory_block(struct memory_block *a, void *src, int src_size) +int append_to_memory_block(struct memory_block *a, const void *src, size_t src_size) { - int dest = a->size; + size_t dest = a->size; grow_memory_block(a, src_size); memcpy(&a->ptr[dest], src, src_size); return dest; @@ -20,6 +20,10 @@ #ifndef INC_BINDFS_MISC_H #define INC_BINDFS_MISC_H +#include <stdbool.h> +#include <stdlib.h> + +#include "arena.h" /* Counts the number of times ch occurs in s. */ int count_chars(const char *s, char ch); @@ -49,6 +53,17 @@ const char *my_basename(const char *path); Otherwise, returns ".". */ const char *my_dirname(char *path); +/* Filters arguments in comma-separated lists prefixed by '-o'. + * Allocates 'new_argv' and its strings, as well as some temporary data, into 'arena'. */ +void filter_o_opts( + bool (*keep)(const char* opt), + int argc, + const char * const *argv, + int *new_argc, + char ***new_argv, + struct arena *arena +); + /* Reallocs `*array` (may be NULL) to be at least one larger than `*capacity` (may be 0) and stores the new capacity in `*capacity`. */ @@ -62,15 +77,15 @@ int parse_byte_count(const char *str, double *result); growing it and appending to it. */ struct memory_block { char *ptr; - int size; - int capacity; + size_t size; + size_t capacity; }; #define MEMORY_BLOCK_INITIALIZER { NULL, 0, 0 } -void init_memory_block(struct memory_block *a, int initial_capacity); -void grow_memory_block(struct memory_block *a, int amount); -int append_to_memory_block(struct memory_block *a, void *src, int src_size); +void init_memory_block(struct memory_block *a, size_t initial_capacity); +void grow_memory_block(struct memory_block *a, size_t amount); +int append_to_memory_block(struct memory_block *a, const void *src, size_t src_size); void free_memory_block(struct memory_block *a); #define MEMORY_BLOCK_GET(a, offset) (&(a).ptr[(offset)]) diff --git a/src/userinfo.c b/src/userinfo.c index 3adadea..2a72bf3 100644 --- a/src/userinfo.c +++ b/src/userinfo.c @@ -20,6 +20,7 @@ #include "userinfo.h" #include "misc.h" #include "debug.h" + #include <stdlib.h> #include <string.h> #include <errno.h> |