diff --git a/Makefile.am b/Makefile.am index 061912b..2a48744 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,7 +11,7 @@ CLEANFILES = fuse-overlayfs.1 fuse_overlayfs_CFLAGS = -I . -I $(abs_srcdir)/lib $(FUSE_CFLAGS) fuse_overlayfs_LDFLAGS = fuse_overlayfs_LDADD = lib/libgnu.a $(FUSE_LIBS) -fuse_overlayfs_SOURCES = main.c +fuse_overlayfs_SOURCES = main.c direct.c utils.c WD := $(shell pwd) diff --git a/direct.c b/direct.c new file mode 100644 index 0000000..9a5de81 --- /dev/null +++ b/direct.c @@ -0,0 +1,170 @@ +/* fuse-overlayfs: Overlay Filesystem in Userspace + + Copyright (C) 2018 Giuseppe Scrivano + Copyright (C) 2018-2019 Red Hat Inc. + Copyright (C) 2001-2007 Miklos Szeredi + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#define _GNU_SOURCE + +#include + +#include "fuse-overlayfs.h" + +#include +#include +#include + +#include + +#include "utils.h" + +static int +direct_file_exists (struct ovl_layer *l, const char *pathname) +{ + return file_exists_at (l->fd, pathname); +} + +static int +direct_listxattr (struct ovl_layer *l, const char *path, char *buf, size_t size) +{ + cleanup_close int fd = -1; + char full_path[PATH_MAX]; + int ret; + + full_path[0] = '\0'; + ret = open_fd_or_get_path (l, path, full_path, &fd, O_RDONLY); + if (ret < 0) + return ret; + + if (fd >= 0) + return flistxattr (fd, buf, size); + + return llistxattr (full_path, buf, size); +} + +static int +direct_getxattr (struct ovl_layer *l, const char *path, const char *name, char *buf, size_t size) +{ + cleanup_close int fd = -1; + char full_path[PATH_MAX]; + int ret; + + full_path[0] = '\0'; + ret = open_fd_or_get_path (l, path, full_path, &fd, O_RDONLY); + if (ret < 0) + return ret; + + if (fd >= 0) + return fgetxattr (fd, name, buf, size); + + return lgetxattr (full_path, name, buf, size); +} + +static int +direct_fstat (struct ovl_layer *l, int fd, const char *path, struct stat *st) +{ + return fstat (fd, st); +} + +static int +direct_statat (struct ovl_layer *l, const char *path, struct stat *st, int flags) +{ + return TEMP_FAILURE_RETRY (fstatat (l->fd, path, st, flags)); +} + +static struct dirent * +direct_readdir (void *dirp) +{ + return readdir (dirp); +} + +static void * +direct_opendir (struct ovl_layer *l, const char *path) +{ + cleanup_close int cleanup_fd = -1; + DIR *dp = NULL; + + cleanup_fd = TEMP_FAILURE_RETRY (openat (l->fd, path, O_DIRECTORY)); + if (cleanup_fd < 0) + return NULL; + + dp = fdopendir (cleanup_fd); + if (dp == NULL) + return NULL; + + cleanup_fd = -1; + + return dp; +} + +static int +direct_closedir (void *dirp) +{ + return closedir (dirp); +} + +static int +direct_openat (struct ovl_layer *l, const char *path, int flags, mode_t mode) +{ + return TEMP_FAILURE_RETRY (openat (l->fd, path, flags, mode)); +} + +static ssize_t +direct_readlinkat (struct ovl_layer *l, const char *path, char *buf, size_t bufsiz) +{ + return TEMP_FAILURE_RETRY (readlinkat (l->fd, path, buf, bufsiz)); +} + +static int +direct_load_data_source (struct ovl_layer *l, const char *opaque) +{ + l->path = realpath (opaque, NULL); + if (l->path == NULL) + return -1; + + l->fd = open (l->path, O_DIRECTORY); + if (l->fd < 0) + { + free (l->path); + l->path = NULL; + return l->fd; + } + + return 0; +} + +static int +direct_cleanup (struct ovl_layer *l) +{ + return 0; +} + +struct data_source direct_access_ds = + { + .load_data_source = direct_load_data_source, + .cleanup = direct_cleanup, + .file_exists = direct_file_exists, + .statat = direct_statat, + .fstat = direct_fstat, + .opendir = direct_opendir, + .readdir = direct_readdir, + .closedir = direct_closedir, + .openat = direct_openat, + .getxattr = direct_getxattr, + .listxattr = direct_listxattr, + .readlinkat = direct_readlinkat, + }; diff --git a/fuse-overlayfs.h b/fuse-overlayfs.h index 226f30f..3280f5c 100644 --- a/fuse-overlayfs.h +++ b/fuse-overlayfs.h @@ -109,6 +109,8 @@ struct ovl_layer /* a data_source defines the methods for accessing a lower layer. */ struct data_source { + int (*load_data_source)(struct ovl_layer *l, const char *opaque); + int (*cleanup)(struct ovl_layer *l); int (*file_exists)(struct ovl_layer *l, const char *pathname); int (*statat)(struct ovl_layer *l, const char *path, struct stat *st, int flags); int (*fstat)(struct ovl_layer *l, int fd, const char *path, struct stat *st); diff --git a/main.c b/main.c index b2e02ac..5821341 100644 --- a/main.c +++ b/main.c @@ -141,12 +141,6 @@ open_by_handle_at (int mount_fd, struct file_handle *handle, int flags) } #endif -static int -file_exists_at (int dirfd, const char *pathname) -{ - return faccessat (dirfd, pathname, F_OK, AT_SYMLINK_NOFOLLOW|AT_EACCESS); -} - #ifndef RENAME_EXCHANGE # define RENAME_EXCHANGE (1 << 1) # define RENAME_NOREPLACE (1 << 2) @@ -274,52 +268,6 @@ inode_to_node (struct ovl_data *lo, ino_t n) return lookup_inode (lo, n)->node; } -static int -strconcat3 (char *dest, size_t size, const char *s1, const char *s2, const char *s3) -{ - size_t t; - char *current = dest; - - size--; - - if (s1) - { - t = strlen (s1); - if (t > size) - t = size; - - memcpy (current, s1, t); - current += t; - - size -= t; - } - if (s2) - { - t = strlen (s2); - if (t > size) - t = size; - - memcpy (current, s2, t); - current += t; - - size -= t; - } - if (s3) - { - t = strlen (s3); - if (t > size) - t = size; - - memcpy (current, s3, t); - current += t; - - size -= t; - } - *current = '\0'; - - return current - dest; -} - static void check_can_mknod (struct ovl_data *lo) { @@ -1602,14 +1550,10 @@ read_dirs (struct ovl_data *lo, char *path, bool low, struct ovl_layer *layers) l->ovl_data = lo; + l->path = NULL; l->fd = -1; - l->path = realpath (it, NULL); - if (l->path == NULL) - return NULL; - - l->fd = open (l->path, O_DIRECTORY); - if (l->fd < 0) + if (l->ds->load_data_source (l, it) < 0) return NULL; l->low = low; @@ -2912,23 +2856,6 @@ ovl_rmdir (fuse_req_t req, fuse_ino_t parent, const char *name) do_rm (req, parent, name, true); } -static int -open_fd_or_get_path (struct ovl_layer *l, const char *path, char *out, int *fd, int flags) -{ - int ret; - - out[0] = '\0'; - - *fd = l->ds->openat (l, path, O_NONBLOCK|O_NOFOLLOW|flags, 0755); - if (*fd < 0 && (errno == ELOOP || errno == EISDIR)) - { - strconcat3 (out, PATH_MAX, l->path, "/", path); - return 0; - } - - return *fd; -} - static int direct_setxattr (struct ovl_layer *l, const char *path, const char *name, const char *buf, size_t size, int flags) { @@ -4789,117 +4716,6 @@ ovl_copy_file_range (fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fus } #endif -static int -direct_file_exists (struct ovl_layer *l, const char *pathname) -{ - return file_exists_at (l->fd, pathname); -} - -static int -direct_listxattr (struct ovl_layer *l, const char *path, char *buf, size_t size) -{ - cleanup_close int fd = -1; - char full_path[PATH_MAX]; - int ret; - - full_path[0] = '\0'; - ret = open_fd_or_get_path (l, path, full_path, &fd, O_RDONLY); - if (ret < 0) - return ret; - - if (fd >= 0) - return flistxattr (fd, buf, size); - - return llistxattr (full_path, buf, size); -} - -static int -direct_getxattr (struct ovl_layer *l, const char *path, const char *name, char *buf, size_t size) -{ - cleanup_close int fd = -1; - char full_path[PATH_MAX]; - int ret; - - full_path[0] = '\0'; - ret = open_fd_or_get_path (l, path, full_path, &fd, O_RDONLY); - if (ret < 0) - return ret; - - if (fd >= 0) - return fgetxattr (fd, name, buf, size); - - return lgetxattr (full_path, name, buf, size); -} - -static int -direct_fstat (struct ovl_layer *l, int fd, const char *path, struct stat *st) -{ - return fstat (fd, st); -} - -static int -direct_statat (struct ovl_layer *l, const char *path, struct stat *st, int flags) -{ - return TEMP_FAILURE_RETRY (fstatat (l->fd, path, st, flags)); -} - -static struct dirent * -direct_readdir (void *dirp) -{ - return readdir (dirp); -} - -static void * -direct_opendir (struct ovl_layer *l, const char *path) -{ - cleanup_close int cleanup_fd = -1; - DIR *dp = NULL; - - cleanup_fd = TEMP_FAILURE_RETRY (openat (l->fd, path, O_DIRECTORY)); - if (cleanup_fd < 0) - return NULL; - - dp = fdopendir (cleanup_fd); - if (dp == NULL) - return NULL; - - cleanup_fd = -1; - - return dp; -} - -static int -direct_closedir (void *dirp) -{ - return closedir (dirp); -} - -static int -direct_openat (struct ovl_layer *l, const char *path, int flags, mode_t mode) -{ - return TEMP_FAILURE_RETRY (openat (l->fd, path, flags, mode)); -} - -static ssize_t -direct_readlinkat (struct ovl_layer *l, const char *path, char *buf, size_t bufsiz) -{ - return TEMP_FAILURE_RETRY (readlinkat (l->fd, path, buf, bufsiz)); -} - -struct data_source direct_access_ds = - { - .file_exists = direct_file_exists, - .statat = direct_statat, - .fstat = direct_fstat, - .opendir = direct_opendir, - .readdir = direct_readdir, - .closedir = direct_closedir, - .openat = direct_openat, - .getxattr = direct_getxattr, - .listxattr = direct_listxattr, - .readlinkat = direct_readlinkat, - }; - static struct fuse_lowlevel_ops ovl_oper = { .statfs = ovl_statfs, @@ -5228,6 +5044,9 @@ err_out2: fuse_session_destroy (se); err_out1: + for (tmp_layer = lo.layers; tmp_layer; tmp_layer = tmp_layer->next) + tmp_layer->ds->cleanup (tmp_layer); + node_mark_all_free (lo.root); hash_free (lo.inodes); diff --git a/utils.c b/utils.c new file mode 100644 index 0000000..26853e3 --- /dev/null +++ b/utils.c @@ -0,0 +1,124 @@ +/* fuse-overlayfs: Overlay Filesystem in Userspace + + Copyright (C) 2019 Red Hat Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include "utils.h" + +int +file_exists_at (int dirfd, const char *pathname) +{ + return faccessat (dirfd, pathname, F_OK, AT_SYMLINK_NOFOLLOW|AT_EACCESS); + +} + +int +strconcat3 (char *dest, size_t size, const char *s1, const char *s2, const char *s3) +{ + size_t t; + char *current = dest; + + size--; + + if (s1) + { + t = strlen (s1); + if (t > size) + t = size; + + memcpy (current, s1, t); + current += t; + + size -= t; + } + if (s2) + { + t = strlen (s2); + if (t > size) + t = size; + + memcpy (current, s2, t); + current += t; + + size -= t; + } + if (s3) + { + t = strlen (s3); + if (t > size) + t = size; + + memcpy (current, s3, t); + current += t; + + size -= t; + } + *current = '\0'; + + return current - dest; +} + +void +cleanup_freep (void *p) +{ + void **pp = (void **) p; + free (*pp); +} + +void +cleanup_filep (FILE **f) +{ + FILE *file = *f; + if (file) + (void) fclose (file); +} + +void +cleanup_closep (void *p) +{ + int *pp = p; + if (*pp >= 0) + close (*pp); +} + +void +cleanup_dirp (DIR **p) +{ + DIR *dir = *p; + if (dir) + closedir (dir); +} + +int +open_fd_or_get_path (struct ovl_layer *l, const char *path, char *out, int *fd, int flags) +{ + int ret; + + out[0] = '\0'; + + *fd = l->ds->openat (l, path, O_NONBLOCK|O_NOFOLLOW|flags, 0755); + if (*fd < 0 && (errno == ELOOP || errno == EISDIR)) + { + strconcat3 (out, PATH_MAX, l->path, "/", path); + return 0; + } + + return *fd; +} diff --git a/utils.h b/utils.h index 3a383ef..a00daa3 100644 --- a/utils.h +++ b/utils.h @@ -18,36 +18,22 @@ #ifndef UTILS_H # define UTILS_H -void -cleanup_freep (void *p) -{ - void **pp = (void **) p; - free (*pp); -} +# include +# include +# include +# include +# include +# include "fuse-overlayfs.h" -void -cleanup_filep (FILE **f) -{ - FILE *file = *f; - if (file) - (void) fclose (file); -} +void cleanup_freep (void *p); +void cleanup_filep (FILE **f); +void cleanup_closep (void *p); +void cleanup_dirp (DIR **p); -void -cleanup_closep (void *p) -{ - int *pp = p; - if (*pp >= 0) - close (*pp); -} +int file_exists_at (int dirfd, const char *pathname); -void -cleanup_dirp (DIR **p) -{ - DIR *dir = *p; - if (dir) - closedir (dir); -} +int strconcat3 (char *dest, size_t size, const char *s1, const char *s2, const char *s3); +int open_fd_or_get_path (struct ovl_layer *l, const char *path, char *out, int *fd, int flags); # define cleanup_file __attribute__((cleanup (cleanup_filep))) # define cleanup_free __attribute__((cleanup (cleanup_freep)))