aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/arena.c50
-rw-r--r--src/arena.h15
-rw-r--r--src/bindfs.c150
-rw-r--r--src/misc.c107
-rw-r--r--src/misc.h25
-rw-r--r--src/userinfo.c1
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[])
diff --git a/src/misc.c b/src/misc.c
index dafebed..25fb653 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -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;
diff --git a/src/misc.h b/src/misc.h
index 6bcf865..360ddd1 100644
--- a/src/misc.h
+++ b/src/misc.h
@@ -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>