Skip to content

Instantly share code, notes, and snippets.

@giuseppe
Last active September 14, 2019 16:20
Show Gist options
  • Save giuseppe/a669ed7248de557a9b5fd272ffe2a4f4 to your computer and use it in GitHub Desktop.
Save giuseppe/a669ed7248de557a9b5fd272ffe2a4f4 to your computer and use it in GitHub Desktop.
fuse-overlayfs shared storage
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/xattr.h>
#include <dirent.h>
#include <error.h>
#include <string.h>
#include <errno.h>
void
convert (int dfd)
{
DIR *d;
struct dirent *de;
int fd;
char p[64];
char b[64];
d = fdopendir (dfd);
if (d == NULL)
{
close (dfd);
error (EXIT_FAILURE, errno, "cannot open directory");
}
for (de = readdir (d); de; de = readdir (d))
{
struct stat st;
mode_t newmode;
if (strcmp (de->d_name, ".") == 0 ||
strcmp (de->d_name, "..") == 0)
continue;
printf ("convert %s\n", de->d_name);
if (fstatat (dirfd (d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
error (EXIT_FAILURE, errno, "stat");
sprintf (b, "%o:%d:%d", st.st_mode & 0777, st.st_uid, st.st_gid);
newmode = (st.st_mode & ~0777) | 0755;
switch (st.st_mode & S_IFMT)
{
case S_IFDIR:
fd = openat (dirfd (d), de->d_name, O_DIRECTORY);
if (fd < 0)
error (EXIT_FAILURE, errno, "open directory %s", de->d_name);
if (fsetxattr (fd, "user.original-permissions", b, strlen (b) + 1, XATTR_CREATE) < 0 && errno != EEXIST)
error (EXIT_FAILURE, errno, "cannot set xattr for dir %s", de->d_name);
if (fchmod (fd, newmode) < 0)
error (EXIT_FAILURE, errno, "cannot set fchmod %s", de->d_name);
convert (fd);
break;
default:
fd = openat (dirfd (d), de->d_name, O_PATH|O_NOFOLLOW);
if (fd < 0)
error (EXIT_FAILURE, errno, "open %s", de->d_name);
sprintf (p, "/proc/self/fd/%d", fd);
if (setxattr (p, "user.original-permissions", b, strlen (b) + 1, XATTR_CREATE) < 0 && errno != EEXIST && errno != EPERM)
error (EXIT_FAILURE, errno, "cannot set xattr %s", de->d_name);
if (chmod (p, newmode) < 0 && errno != ENOTSUP)
error (EXIT_FAILURE, errno, "cannot chmod %s", de->d_name);
close (fd);
break;
}
}
closedir (d);
}
int main (int argc, char **argv)
{
int fd;
if (argc < 1)
error (EXIT_FAILURE, 0, "specify a path");
fd = open (argv[1], O_DIRECTORY|O_NOFOLLOW);
if (fd < 0)
error (EXIT_FAILURE, 0, "open %s", argv[1]);
convert (fd);
return 0;
}
# All files must be copied under the fuse-overlayfs root source directory
all: test-plugin.so convert
test-plugin.so:
gcc -fPIC -I $(pwd) -shared -o test-plugin.so test-plugin.c utils.c
convert:
gcc convert.c -o convert
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/xattr.h>
#include "fuse-overlayfs.h"
#include "utils.h"
static int
test_file_exists (struct ovl_layer *l, const char *pathname)
{
return file_exists_at (l->fd, pathname);
}
static int
test_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
test_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
test_fstat (struct ovl_layer *l, int fd, const char *path, unsigned int mask, struct stat *st)
{
char b[32];
int r;
mode_t mode;
uid_t uid;
gid_t gid;
r = fstat (fd, st);
if (r < 0)
return r;
r = fgetxattr (fd, "user.original-permissions", b, sizeof (b) - 1);
if (r < 0 && errno == ENODATA)
return 0;
if (r < 0)
return r;
b[r] = '\0';
sscanf (b, "%o:%d:%d", &mode, &uid, &gid);
st->st_mode = (st->st_mode & ~0777) | mode;
st->st_uid = uid;
st->st_gid = gid;
return 0;
}
static int
test_statat (struct ovl_layer *l, const char *path, struct stat *st, int flags, unsigned int mask)
{
char p[PATH_MAX];
char b[32];
mode_t mode;
int r;
uid_t uid;
gid_t gid;
r = TEMP_FAILURE_RETRY (fstatat (l->fd, path, st, flags));
if (r < 0)
return r;
sprintf (p, "%s/%s", l->path, path);
r = getxattr (p, "user.original-permissions", b, sizeof (b) - 1);
if (r < 0 && (errno == ENODATA || errno == ENOENT))
return 0;
if (r < 0)
return r;
b[r] = '\0';
sscanf (b, "%o:%d:%d", &mode, &uid, &gid);
st->st_mode = (st->st_mode & ~0777) | mode;
st->st_uid = uid;
st->st_gid = gid;
return 0;
}
static struct dirent *
test_readdir (void *dirp)
{
return readdir (dirp);
}
static void *
test_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
test_closedir (void *dirp)
{
return closedir (dirp);
}
static int
test_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
test_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
test_load_data_source (struct ovl_layer *l, const char *opaque, const char *path)
{
l->path = realpath (path, 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
test_cleanup (struct ovl_layer *l)
{
return 0;
}
struct data_source test_ds =
{
.load_data_source = test_load_data_source,
.cleanup = test_cleanup,
.file_exists = test_file_exists,
.statat = test_statat,
.fstat = test_fstat,
.opendir = test_opendir,
.readdir = test_readdir,
.closedir = test_closedir,
.openat = test_openat,
.getxattr = test_getxattr,
.listxattr = test_listxattr,
.readlinkat = test_readlinkat,
};
int
plugin_version ()
{
return 1;
}
const char *
plugin_name ()
{
return "test";
}
struct data_source *plugin_load (struct ovl_layer *layer, const char *opaque, const char *path)
{
return &test_ds;
}
int
plugin_release (struct ovl_layer *l)
{
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment