mirror of
https://github.com/containers/fuse-overlayfs.git
synced 2025-09-09 07:16:11 -04:00
Merge pull request #119 from giuseppe/c-plugins
fuse-overlayfs: add C plugins system
This commit is contained in:
commit
fa0cd999c8
@ -4,14 +4,16 @@ bin_PROGRAMS = fuse-overlayfs
|
||||
|
||||
ACLOCAL_AMFLAGS = -Im4
|
||||
|
||||
EXTRA_DIST = m4/gnulib-cache.m4 rpm/fuse-overlayfs.spec.template autogen.sh fuse-overlayfs.1.md utils.h NEWS tests/suid-test.c
|
||||
EXTRA_DIST = m4/gnulib-cache.m4 rpm/fuse-overlayfs.spec.template autogen.sh fuse-overlayfs.1.md utils.h NEWS tests/suid-test.c plugin.h plugin-manager.h
|
||||
|
||||
CLEANFILES = fuse-overlayfs.1
|
||||
|
||||
AM_CPPFLAGS = -DPKGLIBEXECDIR='"$(pkglibexecdir)"'
|
||||
|
||||
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 plugin-manager.c
|
||||
|
||||
WD := $(shell pwd)
|
||||
|
||||
|
@ -54,10 +54,11 @@ LDFLAGS=$old_LDFLAGS
|
||||
|
||||
AC_DEFINE_UNQUOTED([HAVE_FUSE_CACHE_READDIR], $cache_readdir, [Define if libfuse is available])
|
||||
|
||||
AC_SEARCH_LIBS([dlopen], [dl], [], [AC_MSG_ERROR([unable to find dlopen()])])
|
||||
|
||||
AC_FUNC_ERROR_AT_LINE
|
||||
AC_FUNC_MALLOC
|
||||
AC_CHECK_FUNCS([open_by_handle_at error memset strdup copy_file_range])
|
||||
AC_CHECK_FUNCS([open_by_handle_at error memset strdup copy_file_range statx])
|
||||
|
||||
AC_CONFIG_FILES([Makefile lib/Makefile])
|
||||
AC_OUTPUT
|
||||
|
210
direct.c
Normal file
210
direct.c
Normal file
@ -0,0 +1,210 @@
|
||||
/* fuse-overlayfs: Overlay Filesystem in Userspace
|
||||
|
||||
Copyright (C) 2018 Giuseppe Scrivano <giuseppe@scrivano.org>
|
||||
Copyright (C) 2018-2019 Red Hat Inc.
|
||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "fuse-overlayfs.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/xattr.h>
|
||||
|
||||
#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, unsigned int mask, struct stat *st)
|
||||
{
|
||||
#ifdef HAVE_STATX
|
||||
int ret;
|
||||
struct statx stx;
|
||||
|
||||
ret = statx (fd, "", AT_STATX_DONT_SYNC|AT_EMPTY_PATH, mask, &stx);
|
||||
|
||||
if (ret < 0 && errno == ENOSYS)
|
||||
goto fallback;
|
||||
if (ret == 0)
|
||||
statx_to_stat (&stx, st);
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
fallback:
|
||||
return fstat (fd, st);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
direct_statat (struct ovl_layer *l, const char *path, struct stat *st, int flags, unsigned int mask)
|
||||
{
|
||||
#ifdef HAVE_STATX
|
||||
int ret;
|
||||
struct statx stx;
|
||||
|
||||
ret = statx (l->fd, path, AT_STATX_DONT_SYNC|flags, mask, &stx);
|
||||
|
||||
if (ret < 0 && errno == ENOSYS)
|
||||
goto fallback;
|
||||
if (ret == 0)
|
||||
statx_to_stat (&stx, st);
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
fallback:
|
||||
return 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, const char *path, int n_layer)
|
||||
{
|
||||
l->path = realpath (path, NULL);
|
||||
if (l->path == NULL)
|
||||
{
|
||||
fprintf (stderr, "cannot resolve path %s\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
l->fd = open (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;
|
||||
}
|
||||
|
||||
static int
|
||||
direct_num_of_layers (const char *opaque, const char *path)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct data_source direct_access_ds =
|
||||
{
|
||||
.num_of_layers = direct_num_of_layers,
|
||||
.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,
|
||||
};
|
157
fuse-overlayfs.h
Normal file
157
fuse-overlayfs.h
Normal file
@ -0,0 +1,157 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef FUSE_OVERLAYFS_H
|
||||
# define FUSE_OVERLAYFS_H
|
||||
# define _GNU_SOURCE
|
||||
|
||||
# include <sys/stat.h>
|
||||
# include <plugin-manager.h>
|
||||
# include <stdbool.h>
|
||||
# include <sys/types.h>
|
||||
|
||||
typedef struct hash_table Hash_table;
|
||||
|
||||
struct ovl_ino
|
||||
{
|
||||
struct ovl_node *node;
|
||||
ino_t ino;
|
||||
dev_t dev;
|
||||
int lookups;
|
||||
mode_t mode;
|
||||
int nlinks;
|
||||
};
|
||||
|
||||
struct ovl_node
|
||||
{
|
||||
struct ovl_node *parent;
|
||||
Hash_table *children;
|
||||
struct ovl_layer *layer, *last_layer;
|
||||
ino_t tmp_ino;
|
||||
dev_t tmp_dev;
|
||||
char *path;
|
||||
char *name;
|
||||
int hidden_dirfd;
|
||||
int node_lookups;
|
||||
size_t name_hash;
|
||||
Hash_table *inodes;
|
||||
struct ovl_ino *ino;
|
||||
struct ovl_node *next_link;
|
||||
|
||||
unsigned int do_unlink : 1;
|
||||
unsigned int do_rmdir : 1;
|
||||
unsigned int hidden : 1;
|
||||
unsigned int whiteout : 1;
|
||||
unsigned int loaded : 1;
|
||||
unsigned int no_security_capability : 1;
|
||||
};
|
||||
|
||||
struct ovl_mapping
|
||||
{
|
||||
struct ovl_mapping *next;
|
||||
unsigned int host;
|
||||
unsigned int to;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
struct ovl_data
|
||||
{
|
||||
struct fuse_session *se;
|
||||
char *uid_str;
|
||||
char *gid_str;
|
||||
struct ovl_mapping *uid_mappings;
|
||||
struct ovl_mapping *gid_mappings;
|
||||
char *mountpoint;
|
||||
char *lowerdir;
|
||||
char *context;
|
||||
char *upperdir;
|
||||
char *workdir;
|
||||
char *redirect_dir;
|
||||
char *plugins;
|
||||
int workdir_fd;
|
||||
int debug;
|
||||
struct ovl_layer *layers;
|
||||
|
||||
Hash_table *inodes;
|
||||
|
||||
struct ovl_node *root;
|
||||
char *timeout_str;
|
||||
double timeout;
|
||||
int threaded;
|
||||
int fsync;
|
||||
int fast_ino_check;
|
||||
int writeback;
|
||||
int disable_xattrs;
|
||||
|
||||
/* current uid/gid*/
|
||||
uid_t uid;
|
||||
uid_t gid;
|
||||
|
||||
struct ovl_plugin_context *plugins_ctx;
|
||||
};
|
||||
|
||||
struct ovl_layer
|
||||
{
|
||||
struct ovl_layer *next;
|
||||
struct data_source *ds;
|
||||
struct ovl_data *ovl_data;
|
||||
char *path;
|
||||
int fd;
|
||||
bool low;
|
||||
|
||||
void *data_source_private_data;
|
||||
};
|
||||
|
||||
/* a data_source defines the methods for accessing a lower layer. */
|
||||
struct data_source
|
||||
{
|
||||
int (*num_of_layers) (const char *opaque, const char *path);
|
||||
int (*load_data_source)(struct ovl_layer *l, const char *opaque, const char *path, int n_layer);
|
||||
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, unsigned int mask);
|
||||
int (*fstat)(struct ovl_layer *l, int fd, const char *path, unsigned int mask, struct stat *st);
|
||||
void *(*opendir)(struct ovl_layer *l, const char *path);
|
||||
struct dirent *(*readdir)(void *dirp);
|
||||
int (*closedir)(void *dirp);
|
||||
int (*openat)(struct ovl_layer *l, const char *path, int flags, mode_t mode);
|
||||
int (*listxattr)(struct ovl_layer *l, const char *path, char *buf, size_t size);
|
||||
int (*getxattr)(struct ovl_layer *l, const char *path, const char *name, char *buf, size_t size);
|
||||
ssize_t (*readlinkat)(struct ovl_layer *l, const char *path, char *buf, size_t bufsiz);
|
||||
};
|
||||
|
||||
/* passtrough to the file system. */
|
||||
struct data_source direct_access_ds;
|
||||
|
||||
# ifndef HAVE_STATX
|
||||
# define STATX_TYPE 0x00000001U /* Want/got stx_mode & S_IFMT */
|
||||
# define STATX_MODE 0x00000002U /* Want/got stx_mode & ~S_IFMT */
|
||||
# define STATX_NLINK 0x00000004U /* Want/got stx_nlink */
|
||||
# define STATX_UID 0x00000008U /* Want/got stx_uid */
|
||||
# define STATX_GID 0x00000010U /* Want/got stx_gid */
|
||||
# define STATX_ATIME 0x00000020U /* Want/got stx_atime */
|
||||
# define STATX_MTIME 0x00000040U /* Want/got stx_mtime */
|
||||
# define STATX_CTIME 0x00000080U /* Want/got stx_ctime */
|
||||
# define STATX_INO 0x00000100U /* Want/got stx_ino */
|
||||
# define STATX_SIZE 0x00000200U /* Want/got stx_size */
|
||||
# define STATX_BLOCKS 0x00000400U /* Want/got stx_blocks */
|
||||
# define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */
|
||||
# define STATX_BTIME 0x00000800U /* Want/got stx_btime */
|
||||
# define STATX_ALL 0x00000fffU /* All currently supported flags */
|
||||
# endif
|
||||
|
||||
#endif
|
125
plugin-manager.c
Normal file
125
plugin-manager.c
Normal file
@ -0,0 +1,125 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <plugin.h>
|
||||
#include <stdlib.h>
|
||||
#include <error.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
struct ovl_plugin_context *
|
||||
load_plugins (const char *plugins)
|
||||
{
|
||||
char *saveptr = NULL, *it;
|
||||
cleanup_free char *buf = NULL;
|
||||
struct ovl_plugin_context *ctx;
|
||||
|
||||
ctx = calloc (1, sizeof (*ctx));
|
||||
if (ctx == NULL)
|
||||
error (EXIT_FAILURE, errno, "cannot allocate context");
|
||||
|
||||
buf = strdup (plugins);
|
||||
if (buf == NULL)
|
||||
error (EXIT_FAILURE, errno, "cannot allocate memory");
|
||||
|
||||
for (it = strtok_r (buf, ":", &saveptr); it; it = strtok_r (NULL, ":", &saveptr))
|
||||
plugin_load_one (ctx, it);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void
|
||||
plugin_load_one (struct ovl_plugin_context *context, const char *path)
|
||||
{
|
||||
plugin_name name;
|
||||
struct ovl_plugin *p;
|
||||
plugin_version version;
|
||||
void *handle = dlopen (path, RTLD_NOW|RTLD_LOCAL);
|
||||
if (! handle)
|
||||
error (EXIT_FAILURE, 0, "cannot load plugin %s: %s", path, dlerror());
|
||||
|
||||
p = calloc (1, sizeof (*p));
|
||||
if (p == NULL)
|
||||
error (EXIT_FAILURE, errno, "cannot load plugin %s", path);
|
||||
p->next = context->plugins;
|
||||
|
||||
version = dlsym (handle, "plugin_version");
|
||||
if (version == NULL)
|
||||
error (EXIT_FAILURE, 0, "cannot find symbol `plugin_version` in plugin %s", path);
|
||||
|
||||
if (version () != 1)
|
||||
error (EXIT_FAILURE, 0, "invalid plugin version for %s", path);
|
||||
|
||||
p->handle = handle;
|
||||
name = dlsym (handle, "plugin_name");
|
||||
if (name == NULL)
|
||||
error (EXIT_FAILURE, 0, "cannot find symbol `plugin_name` in plugin %s", path);
|
||||
|
||||
p->name = name ();
|
||||
|
||||
if (plugin_find (context, p->name))
|
||||
error (EXIT_FAILURE, 0, "plugin %s added twice", p->name);
|
||||
|
||||
p->load = dlsym (handle, "plugin_load");
|
||||
if (p->load == NULL)
|
||||
error (EXIT_FAILURE, 0, "cannot find symbol `plugin_load` in plugin %s", path);
|
||||
|
||||
p->release = dlsym (handle, "plugin_release");
|
||||
if (p->release == NULL)
|
||||
error (EXIT_FAILURE, 0, "cannot find symbol `plugin_release` in plugin %s", path);
|
||||
|
||||
context->plugins = p;
|
||||
}
|
||||
|
||||
struct ovl_plugin *
|
||||
plugin_find (struct ovl_plugin_context *context, const char *name)
|
||||
{
|
||||
struct ovl_plugin *it;
|
||||
|
||||
for (it = context->plugins; it; it = it->next)
|
||||
{
|
||||
if (strcmp (name, it->name) == 0)
|
||||
return it;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
plugin_free_all (struct ovl_plugin_context *context)
|
||||
{
|
||||
struct ovl_plugin *it, *next;
|
||||
|
||||
it = context->plugins;
|
||||
while (it)
|
||||
{
|
||||
next = it->next;
|
||||
|
||||
it->release ();
|
||||
|
||||
/* Skip dlclose (it->handle) as it causes plugins written in Go to crash. */
|
||||
|
||||
free (it);
|
||||
|
||||
it = next;
|
||||
}
|
||||
|
||||
free (context);
|
||||
|
||||
return 0;
|
||||
}
|
35
plugin-manager.h
Normal file
35
plugin-manager.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PLUGIN_MANAGER_H
|
||||
# define PLUGIN_MANAGER_H
|
||||
# include <config.h>
|
||||
|
||||
# include <dlfcn.h>
|
||||
|
||||
struct ovl_plugin_context
|
||||
{
|
||||
struct ovl_plugin *plugins;
|
||||
};
|
||||
|
||||
void plugin_load_one (struct ovl_plugin_context *context, const char *path);
|
||||
int plugin_free_all (struct ovl_plugin_context *context);
|
||||
struct ovl_plugin *plugin_find (struct ovl_plugin_context *context, const char *name);
|
||||
struct ovl_plugin_context *load_plugins (const char *plugins);
|
||||
|
||||
#endif
|
41
plugin.h
Normal file
41
plugin.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PLUGIN_H
|
||||
# define PLUGIN_H
|
||||
# include <config.h>
|
||||
|
||||
# include <utils.h>
|
||||
# include <fuse-overlayfs.h>
|
||||
|
||||
typedef struct data_source *(*plugin_load_data_source)(const char *opaque, const char *path);
|
||||
typedef int (*plugin_release)();
|
||||
typedef const char *(*plugin_name)();
|
||||
typedef int (*plugin_version)();
|
||||
|
||||
struct ovl_plugin
|
||||
{
|
||||
struct ovl_plugin *next;
|
||||
const char *name;
|
||||
void *handle;
|
||||
|
||||
plugin_load_data_source load;
|
||||
plugin_release release;
|
||||
};
|
||||
|
||||
#endif
|
@ -83,3 +83,18 @@ touch merged/usr 2>&1 | grep Read-only
|
||||
mkdir merged/abcd12345 2>&1 | grep Read-only
|
||||
ln merged/file-lower-layer merged/file-lower-layer-link 2>&1 | grep Read-only
|
||||
ln -s merged/file-lower-layer merged/a-symlink 2>&1 | grep Read-only
|
||||
|
||||
umount merged
|
||||
|
||||
# https://github.com/containers/fuse-overlayfs/issues/136
|
||||
rm -rf lower1 lower2 lower3 lower upper workdir merged
|
||||
mkdir lower1 lower2 lower3 upper workdir merged
|
||||
|
||||
mkdir -p lower1/dir1/dir2
|
||||
touch lower1/dir1/dir2/foo
|
||||
touch lower2/.wh.dir1
|
||||
mkdir -p lower3/dir1/dir2
|
||||
|
||||
fuse-overlayfs -o lowerdir=lower3:lower2:lower1,upperdir=upper,workdir=workdir merged
|
||||
|
||||
test \! -e merged/dir1/dir2/foo
|
||||
|
151
utils.c
Normal file
151
utils.c
Normal file
@ -0,0 +1,151 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "utils.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
int
|
||||
file_exists_at (int dirfd, const char *pathname)
|
||||
{
|
||||
return faccessat (dirfd, pathname, F_OK, AT_SYMLINK_NOFOLLOW|AT_EACCESS);
|
||||
}
|
||||
|
||||
#ifdef HAVE_STATX
|
||||
void
|
||||
copy_statx_to_stat_time (struct statx_timestamp *stx, struct timespec *st)
|
||||
{
|
||||
st->tv_sec = stx->tv_sec;
|
||||
st->tv_nsec = stx->tv_nsec;
|
||||
}
|
||||
|
||||
void
|
||||
statx_to_stat (struct statx *stx, struct stat *st)
|
||||
{
|
||||
st->st_dev = makedev (stx->stx_dev_major, stx->stx_dev_minor);
|
||||
st->st_ino = stx->stx_ino;
|
||||
st->st_mode = stx->stx_mode;
|
||||
st->st_nlink = stx->stx_nlink;
|
||||
st->st_uid = stx->stx_uid;
|
||||
st->st_gid = stx->stx_gid;
|
||||
st->st_rdev = makedev (stx->stx_rdev_major, stx->stx_rdev_minor);
|
||||
st->st_size = stx->stx_size;
|
||||
st->st_blksize = stx->stx_blksize;
|
||||
st->st_blocks = stx->stx_blocks;
|
||||
copy_statx_to_stat_time (&stx->stx_atime, &st->st_atim);
|
||||
copy_statx_to_stat_time (&stx->stx_ctime, &st->st_ctim);
|
||||
copy_statx_to_stat_time (&stx->stx_mtime, &st->st_mtim);
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
50
utils.h
50
utils.h
@ -18,36 +18,28 @@
|
||||
#ifndef UTILS_H
|
||||
# define UTILS_H
|
||||
|
||||
void
|
||||
cleanup_freep (void *p)
|
||||
{
|
||||
void **pp = (void **) p;
|
||||
free (*pp);
|
||||
}
|
||||
# define _GNU_SOURCE
|
||||
|
||||
void
|
||||
cleanup_filep (FILE **f)
|
||||
{
|
||||
FILE *file = *f;
|
||||
if (file)
|
||||
(void) fclose (file);
|
||||
}
|
||||
# include <config.h>
|
||||
|
||||
void
|
||||
cleanup_closep (void *p)
|
||||
{
|
||||
int *pp = p;
|
||||
if (*pp >= 0)
|
||||
close (*pp);
|
||||
}
|
||||
# include <unistd.h>
|
||||
# include <stdio.h>
|
||||
# include <sys/types.h>
|
||||
# include <dirent.h>
|
||||
# include <stdlib.h>
|
||||
# include <sys/types.h>
|
||||
# include <fcntl.h>
|
||||
# include "fuse-overlayfs.h"
|
||||
|
||||
void
|
||||
cleanup_dirp (DIR **p)
|
||||
{
|
||||
DIR *dir = *p;
|
||||
if (dir)
|
||||
closedir (dir);
|
||||
}
|
||||
void cleanup_freep (void *p);
|
||||
void cleanup_filep (FILE **f);
|
||||
void cleanup_closep (void *p);
|
||||
void cleanup_dirp (DIR **p);
|
||||
|
||||
int file_exists_at (int dirfd, const char *pathname);
|
||||
|
||||
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)))
|
||||
@ -57,4 +49,8 @@ cleanup_dirp (DIR **p)
|
||||
# define LIKELY(x) __builtin_expect((x),1)
|
||||
# define UNLIKELY(x) __builtin_expect((x),0)
|
||||
|
||||
# ifdef HAVE_STATX
|
||||
void statx_to_stat (struct statx *stx, struct stat *st);
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user