diff --git a/fuse-overlayfs.h b/fuse-overlayfs.h
new file mode 100644
index 0000000..226f30f
--- /dev/null
+++ b/fuse-overlayfs.h
@@ -0,0 +1,127 @@
+/* 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 .
+*/
+#ifndef FUSE_OVERLAYFS_H
+# define FUSE_OVERLAYFS_H
+
+# include
+# include
+
+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;
+ 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_layer
+{
+ struct ovl_layer *next;
+ struct data_source *ds;
+ struct ovl_data *ovl_data;
+ char *path;
+ int fd;
+ bool low;
+};
+
+/* a data_source defines the methods for accessing a lower layer. */
+struct data_source
+{
+ 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);
+ 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;
+
+#endif
diff --git a/main.c b/main.c
index 0a207c1..b2e02ac 100644
--- a/main.c
+++ b/main.c
@@ -24,6 +24,8 @@
#include
+#include "fuse-overlayfs.h"
+
#include
#include
#include
@@ -182,89 +184,6 @@ static bool disable_ovl_whiteout;
static uid_t overflow_uid;
static gid_t overflow_gid;
-struct ovl_layer
-{
- struct ovl_layer *next;
- char *path;
- int fd;
- bool low;
-};
-
-struct ovl_mapping
-{
- struct ovl_mapping *next;
- unsigned int host;
- unsigned int to;
- unsigned int len;
-};
-
-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_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;
- 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;
-};
-
static double
get_timeout (struct ovl_data *lo)
{
@@ -582,32 +501,6 @@ node_dirfd (struct ovl_node *n)
return n->layer->fd;
}
-static void
-get_node_path (struct ovl_data *lo, struct ovl_node *n, char *path)
-{
- if (n->hidden)
- strconcat3 (path, PATH_MAX, lo->workdir, "/", n->path);
- else
- strconcat3 (path, PATH_MAX, n->layer->path, "/", n->path);
-}
-
-static int
-open_fd_or_get_path (struct ovl_data *lo, struct ovl_node *n, char *path, int *fd, int mode)
-{
- int ret;
-
- path[0] = '\0';
-
- *fd = TEMP_FAILURE_RETRY (openat (node_dirfd (n), n->path, O_NONBLOCK|O_NOFOLLOW|mode));
- if (*fd < 0 && (errno == ELOOP || errno == EISDIR))
- {
- get_node_path (lo, n, path);
- return 0;
- }
-
- return *fd;
-}
-
static bool
has_prefix (const char *str, const char *pref)
{
@@ -645,33 +538,24 @@ set_fd_opaque (int fd)
}
static int
-is_directory_opaque (int dirfd, const char *path)
+is_directory_opaque (struct ovl_layer *l, const char *path)
{
- int fd;
char b[16];
ssize_t s;
- int saved_errno;
- fd = TEMP_FAILURE_RETRY (openat (dirfd, path, O_NONBLOCK));
- if (fd < 0)
- return -1;
-
- s = fgetxattr (fd, PRIVILEGED_OPAQUE_XATTR, b, sizeof (b));
+ s = l->ds->getxattr (l, path, PRIVILEGED_OPAQUE_XATTR, b, sizeof (b));
if (s < 0 && errno == ENODATA)
- s = fgetxattr (fd, OPAQUE_XATTR, b, sizeof (b));
-
- saved_errno = errno;
- close (fd);
+ s = l->ds->getxattr (l, path, OPAQUE_XATTR, b, sizeof (b));
if (s < 0)
{
- if (saved_errno == ENOTSUP || saved_errno == ENODATA)
+ if (errno == ENOTSUP || errno == ENODATA)
{
char whiteout_opq_path[PATH_MAX];
strconcat3 (whiteout_opq_path, PATH_MAX, path, "/" OPAQUE_WHITEOUT, NULL);
- if (file_exists_at (dirfd, whiteout_opq_path) == 0)
+ if (l->ds->file_exists (l, whiteout_opq_path) == 0)
return 1;
return (errno == ENOENT) ? 0 : -1;
@@ -699,7 +583,7 @@ create_whiteout (struct ovl_data *lo, struct ovl_node *parent, const char *name,
for (l = get_lower_layers (lo); l; l = l->next)
{
- ret = file_exists_at (l->fd, path);
+ ret = l->ds->file_exists (l, path);
if (ret < 0 && errno == ENOENT)
continue;
@@ -730,7 +614,8 @@ create_whiteout (struct ovl_data *lo, struct ovl_node *parent, const char *name,
strconcat3 (whiteout_wh_path, PATH_MAX, parent->path, "/.wh.", name);
- fd = TEMP_FAILURE_RETRY (openat (get_upper_layer (lo)->fd, whiteout_wh_path, O_CREAT|O_WRONLY|O_NONBLOCK, 0700));
+
+ fd = get_upper_layer (lo)->ds->openat (get_upper_layer (lo), whiteout_wh_path, O_CREAT|O_WRONLY|O_NONBLOCK, 0700);
if (fd < 0 && errno != EEXIST)
return -1;
@@ -761,7 +646,7 @@ delete_whiteout (struct ovl_data *lo, int dirfd, struct ovl_node *parent, const
strconcat3 (whiteout_path, PATH_MAX, parent->path, "/", name);
- if (TEMP_FAILURE_RETRY (fstatat (get_upper_layer (lo)->fd, whiteout_path, &st, AT_SYMLINK_NOFOLLOW)) == 0
+ if (get_upper_layer (lo)->ds->statat (get_upper_layer (lo), whiteout_path, &st, AT_SYMLINK_NOFOLLOW) == 0
&& (st.st_mode & S_IFMT) == S_IFCHR
&& major (st.st_rdev) == 0
&& minor (st.st_rdev) == 0)
@@ -833,16 +718,20 @@ static int
rpl_stat (fuse_req_t req, struct ovl_node *node, int fd, const char *path, struct stat *st_in, struct stat *st)
{
int ret = 0;
+ struct ovl_layer *l = node->layer;
struct ovl_data *data = ovl_data (req);
if (st_in)
memcpy (st, st_in, sizeof (* st));
else if (fd >= 0)
- ret = fstat (fd, st);
+ ret = l->ds->fstat (l, fd, path, st);
else if (path != NULL)
ret = stat (path, st);
- else
+ else if (node->hidden)
ret = fstatat (node_dirfd (node), node->path, st, AT_SYMLINK_NOFOLLOW);
+ else
+ ret = l->ds->statat (l, node->path, st, AT_SYMLINK_NOFOLLOW);
+
if (ret < 0)
return ret;
@@ -973,6 +862,13 @@ drop_node_from_ino (Hash_table *inodes, struct ovl_node *node)
}
}
+static int
+direct_renameat2 (struct ovl_layer *l, int olddirfd, const char *oldpath,
+ int newdirfd, const char *newpath, unsigned int flags)
+{
+ return syscall (SYS_renameat2, olddirfd, oldpath, newdirfd, newpath, flags);
+}
+
static int
hide_node (struct ovl_data *lo, struct ovl_node *node, bool unlink_src)
{
@@ -1350,10 +1246,13 @@ make_ovl_node (struct ovl_data *lo, const char *path, struct ovl_layer *layer, c
bool stat_only = false;
cleanup_free char *val = NULL;
cleanup_free char *origin = NULL;
- cleanup_close int fd = TEMP_FAILURE_RETRY (openat (it->fd, npath, O_RDONLY|O_NONBLOCK|O_NOFOLLOW));
+ cleanup_close int fd = -1;
+
+ fd = it->ds->openat (it, npath, O_RDONLY|O_NONBLOCK|O_NOFOLLOW, 0755);
+
if (fd < 0)
{
- if (errno != EPERM && fstatat (it->fd, npath, &st, AT_SYMLINK_NOFOLLOW) == 0)
+ if (errno != EPERM && it->ds->statat (it, npath, &st, AT_SYMLINK_NOFOLLOW) == 0)
{
ret->tmp_ino = st.st_ino;
ret->tmp_dev = st.st_dev;
@@ -1364,7 +1263,7 @@ make_ovl_node (struct ovl_data *lo, const char *path, struct ovl_layer *layer, c
}
/* It is an open FD, stat the file and read the origin xattrs. */
- if (fstat (fd, &st) == 0)
+ if (it->ds->fstat (it, fd, npath, &st) == 0)
{
ret->tmp_ino = st.st_ino;
ret->tmp_dev = st.st_dev;
@@ -1399,7 +1298,7 @@ make_ovl_node (struct ovl_data *lo, const char *path, struct ovl_layer *layer, c
originfd = open_by_handle_at (AT_FDCWD, fh, O_RDONLY);
if (originfd >= 0)
{
- if (fstat (originfd, &st) == 0)
+ if (it->ds->fstat (it, originfd, npath, &st) == 0)
{
ret->tmp_ino = st.st_ino;
ret->tmp_dev = st.st_dev;
@@ -1510,19 +1409,12 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char
for (it = lo->layers; it; it = it->next)
{
- int fd;
- cleanup_dir DIR *dp = NULL;
- cleanup_close int cleanup_fd = TEMP_FAILURE_RETRY (openat (it->fd, path, O_DIRECTORY));
- if (cleanup_fd < 0)
- continue;
+ DIR *dp = NULL;
- dp = fdopendir (cleanup_fd);
+ dp = it->ds->opendir (it, path);
if (dp == NULL)
continue;
- cleanup_fd = -1; /* It is now owned by dp. */
-
- fd = dirfd (dp);
for (;;)
{
int ret;
@@ -1532,11 +1424,14 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char
char whiteout_path[PATH_MAX];
errno = 0;
- dent = readdir (dp);
+ dent = it->ds->readdir (dp);
if (dent == NULL)
{
if (errno)
- return NULL;
+ {
+ it->ds->closedir (dp);
+ return NULL;
+ }
break;
}
@@ -1567,9 +1462,12 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char
strconcat3 (node_path, PATH_MAX, n->path, "/", dent->d_name);
- ret = file_exists_at (fd, whiteout_path);
+ ret = it->ds->file_exists (it, whiteout_path);
if (ret < 0 && errno != ENOENT)
- return NULL;
+ {
+ it->ds->closedir (dp);
+ return NULL;
+ }
if (ret == 0)
{
@@ -1577,6 +1475,7 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char
if (child == NULL)
{
errno = ENOMEM;
+ it->ds->closedir (dp);
return NULL;
}
}
@@ -1593,8 +1492,12 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char
a whiteout file. */
struct stat st;
- if (TEMP_FAILURE_RETRY (fstatat (fd, dent->d_name, &st, AT_SYMLINK_NOFOLLOW)) < 0)
- return NULL;
+ ret = it->ds->statat (it, node_path, &st, AT_SYMLINK_NOFOLLOW);
+ if (ret < 0)
+ {
+ it->ds->closedir (dp);
+ return NULL;
+ }
dirp = st.st_mode & S_IFDIR;
wh = get_whiteout_name (dent->d_name, &st);
@@ -1606,6 +1509,7 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char
if (child == NULL)
{
errno = ENOMEM;
+ it->ds->closedir (dp);
return NULL;
}
}
@@ -1615,6 +1519,7 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char
if (child == NULL)
{
errno = ENOMEM;
+ it->ds->closedir (dp);
return NULL;
}
child->last_layer = it;
@@ -1624,6 +1529,7 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char
if (insert_node (n, child, false) == NULL)
{
errno = ENOMEM;
+ it->ds->closedir (dp);
return NULL;
}
}
@@ -1667,7 +1573,7 @@ cleanup_layerp (struct ovl_layer **p)
#define cleanup_layer __attribute__((cleanup (cleanup_layerp)))
static struct ovl_layer *
-read_dirs (char *path, bool low, struct ovl_layer *layers)
+read_dirs (struct ovl_data *lo, char *path, bool low, struct ovl_layer *layers)
{
char *saveptr = NULL, *it;
struct ovl_layer *last;
@@ -1691,6 +1597,11 @@ read_dirs (char *path, bool low, struct ovl_layer *layers)
l = calloc (1, sizeof (*l));
if (l == NULL)
return NULL;
+
+ l->ds = &direct_access_ds;
+
+ l->ovl_data = lo;
+
l->fd = -1;
l->path = realpath (it, NULL);
@@ -1760,7 +1671,7 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name)
strconcat3 (path, PATH_MAX, pnode->path, "/", name);
- ret = TEMP_FAILURE_RETRY (fstatat (it->fd, path, &st, AT_SYMLINK_NOFOLLOW));
+ ret = it->ds->statat (it, path, &st, AT_SYMLINK_NOFOLLOW);
if (ret < 0)
{
int saved_errno = errno;
@@ -1772,7 +1683,7 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name)
strconcat3 (whpath, PATH_MAX, pnode->path, "/.wh.", name);
- ret = file_exists_at (it->fd, whpath);
+ ret = it->ds->file_exists (it, whpath);
if (ret < 0 && errno != ENOENT && errno != ENOTDIR)
return NULL;
if (ret == 0)
@@ -1801,7 +1712,7 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name)
}
strconcat3 (whpath, PATH_MAX, pnode->path, "/.wh.", name);
- ret = file_exists_at (it->fd, whpath);
+ ret = it->ds->file_exists (it, whpath);
if (ret < 0 && errno != ENOENT)
return NULL;
if (ret == 0)
@@ -1822,7 +1733,7 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name)
if (st.st_mode & S_IFDIR)
{
- ret = is_directory_opaque (it->fd, path);
+ ret = is_directory_opaque (it, path);
if (ret < 0)
{
node_free (node);
@@ -2007,7 +1918,7 @@ create_missing_whiteouts (struct ovl_data *lo, struct ovl_node *node, const char
cleanup_dir DIR *dp = NULL;
cleanup_close int cleanup_fd = -1;
- cleanup_fd = TEMP_FAILURE_RETRY (openat (l->fd, from, O_DIRECTORY));
+ cleanup_fd = l->ds->openat (l, from, O_DIRECTORY, 0755);
if (cleanup_fd < 0)
{
if (errno == ENOENT)
@@ -2225,8 +2136,6 @@ ovl_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size)
struct ovl_node *node;
struct ovl_data *lo = ovl_data (req);
cleanup_free char *buf = NULL;
- cleanup_close int fd = -1;
- char path[PATH_MAX];
int ret;
if (UNLIKELY (ovl_debug (req)))
@@ -2255,24 +2164,23 @@ ovl_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size)
}
}
- path[0] = '\0';
- ret = open_fd_or_get_path (lo, node, path, &fd, O_RDONLY);
+ if (! node->hidden)
+ ret = node->layer->ds->listxattr (node->layer, node->path, buf, size);
+ else
+ {
+ char path[PATH_MAX];
+ strconcat3 (path, PATH_MAX, lo->workdir, "/", node->path);
+ ret = listxattr (path, buf, size);
+ }
if (ret < 0)
{
fuse_reply_err (req, errno);
return;
}
- l = release_big_lock ();
+ len = ret;
- if (fd >= 0)
- len = flistxattr (fd, buf, size);
- else
- len = llistxattr (path, buf, size);
-
- if (len < 0)
- fuse_reply_err (req, errno);
- else if (size == 0)
+ if (size == 0)
fuse_reply_xattr (req, len);
else if (len <= size)
fuse_reply_buf (req, buf, len);
@@ -2286,8 +2194,6 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
struct ovl_node *node;
struct ovl_data *lo = ovl_data (req);
cleanup_free char *buf = NULL;
- cleanup_close int fd = -1;
- char path[PATH_MAX];
bool is_security_capability = false;
int ret;
@@ -2326,29 +2232,29 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
}
}
- path[0] = '\0';
- ret = open_fd_or_get_path (lo, node, path, &fd, O_RDONLY);
+ if (! node->hidden)
+ ret = node->layer->ds->getxattr (node->layer, node->path, name, buf, size);
+ else
+ {
+ char path[PATH_MAX];
+ strconcat3 (path, PATH_MAX, lo->workdir, "/", node->path);
+ ret = getxattr (path, name, buf, size);
+ }
+
+ if (get_timeout (lo) > 0 && is_security_capability && ret < 0 && errno == ENODATA)
+ node->no_security_capability = 1;
+
if (ret < 0)
{
fuse_reply_err (req, errno);
return;
}
- l = release_big_lock ();
+ len = ret;
- if (fd >= 0)
- len = fgetxattr (fd, name, buf, size);
- else
- len = lgetxattr (path, name, buf, size);
-
- if (get_timeout (lo) > 0 && is_security_capability && len < 0 && errno == ENODATA)
- node->no_security_capability = 1;
-
- if (len < 0)
- fuse_reply_err (req, errno);
- else if (size == 0)
+ if (size == 0)
fuse_reply_xattr (req, len);
- else if (len <= size)
+ else
fuse_reply_buf (req, buf, len);
}
@@ -2510,7 +2416,7 @@ create_node_directory (struct ovl_data *lo, struct ovl_node *src)
if (src->layer == get_upper_layer (lo))
return 0;
- ret = sfd = TEMP_FAILURE_RETRY (openat (node_dirfd (src), src->path, O_RDONLY|O_NONBLOCK));
+ ret = sfd = src->layer->ds->openat (src->layer, src->path, O_RDONLY|O_NONBLOCK, 0755);
if (ret < 0)
return ret;
@@ -2580,7 +2486,7 @@ copyup (struct ovl_data *lo, struct ovl_node *node)
sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ());
- ret = TEMP_FAILURE_RETRY (fstatat (node_dirfd (node), node->path, &st, AT_SYMLINK_NOFOLLOW));
+ ret = node->layer->ds->statat (node->layer, node->path, &st, AT_SYMLINK_NOFOLLOW);
if (ret < 0)
return ret;
@@ -2608,7 +2514,7 @@ copyup (struct ovl_data *lo, struct ovl_node *node)
{
char *new;
- ret = readlinkat (node_dirfd (node), node->path, p, current_size - 1);
+ ret = node->layer->ds->readlinkat (node->layer, node->path, p, current_size - 1);
if (ret < 0)
goto exit;
if (ret < current_size - 1)
@@ -2627,7 +2533,7 @@ copyup (struct ovl_data *lo, struct ovl_node *node)
goto success;
}
- ret = sfd = TEMP_FAILURE_RETRY (openat (node_dirfd (node), node->path, O_RDONLY|O_NONBLOCK));
+ ret = sfd = node->layer->ds->openat (node->layer, node->path, O_RDONLY|O_NONBLOCK, 0755);
if (sfd < 0)
goto exit;
@@ -2867,14 +2773,14 @@ empty_dirfd (int fd)
}
static int
-empty_dir (struct ovl_data *lo, struct ovl_node *node)
+empty_dir (struct ovl_layer *l, const char *path)
{
cleanup_dir DIR *dp = NULL;
cleanup_close int cleanup_fd = -1;
struct dirent *dent;
int ret;
- cleanup_fd = TEMP_FAILURE_RETRY (openat (get_upper_layer (lo)->fd, node->path, O_DIRECTORY));
+ cleanup_fd = TEMP_FAILURE_RETRY (openat (l->fd, path, O_DIRECTORY));
if (cleanup_fd < 0)
return -1;
@@ -2933,7 +2839,7 @@ do_rm (fuse_req_t req, fuse_ino_t parent, const char *name, bool dirp)
{
if (whiteouts > 0)
{
- if (empty_dir (lo, node) < 0)
+ if (empty_dir (get_upper_layer (lo), node->path) < 0)
{
fuse_reply_err (req, errno);
return;
@@ -3006,6 +2912,41 @@ 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)
+{
+ 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_WRONLY);
+ if (ret < 0)
+ return ret;
+
+ if (fd >= 0)
+ return fsetxattr (fd, name, buf, size, flags);
+
+ return setxattr (full_path, name, buf, size, flags);
+}
+
static void
ovl_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name,
const char *value, size_t size, int flags)
@@ -3013,9 +2954,7 @@ ovl_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name,
cleanup_lock int l = enter_big_lock ();
struct ovl_data *lo = ovl_data (req);
bool is_security_capability = false;
- cleanup_close int fd = -1;
struct ovl_node *node;
- char path[PATH_MAX];
int ret;
if (UNLIKELY (ovl_debug (req)))
@@ -3050,38 +2989,48 @@ ovl_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name,
return;
}
- path[0] = '\0';
- ret = open_fd_or_get_path (lo, node, path, &fd, O_WRONLY);
- if (ret < 0)
- {
- fuse_reply_err (req, errno);
- return;
- }
-
- l = release_big_lock ();
-
- if (fd >= 0)
- ret = fsetxattr (fd, name, value, size, flags);
+ if (! node->hidden)
+ ret = direct_setxattr (node->layer, node->path, name, value, size, flags);
else
- ret = setxattr (path, name, value, size, flags);
-
+ {
+ char path[PATH_MAX];
+ strconcat3 (path, PATH_MAX, lo->workdir, "/", node->path);
+ ret = setxattr (path, name, value, size, flags);
+ }
if (ret < 0)
{
fuse_reply_err (req, errno);
return;
}
+
node->no_security_capability = 1;
fuse_reply_err (req, 0);
}
+static int
+direct_removexattr (struct ovl_layer *l, const char *path, const char *name)
+{
+ 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_WRONLY);
+ if (ret < 0)
+ return ret;
+
+ if (fd >= 0)
+ return fremovexattr (fd, name);
+
+ return lremovexattr (full_path, name);
+}
+
static void
ovl_removexattr (fuse_req_t req, fuse_ino_t ino, const char *name)
{
cleanup_lock int l = enter_big_lock ();
struct ovl_node *node;
struct ovl_data *lo = ovl_data (req);
- cleanup_close int fd = -1;
- char path[PATH_MAX];
int ret;
if (UNLIKELY (ovl_debug (req)))
@@ -3101,20 +3050,14 @@ ovl_removexattr (fuse_req_t req, fuse_ino_t ino, const char *name)
return;
}
- path[0] = '\0';
- ret = open_fd_or_get_path (lo, node, path, &fd, O_WRONLY);
- if (ret < 0)
- {
- fuse_reply_err (req, errno);
- return;
- }
-
- l = release_big_lock ();
-
- if (fd >= 0)
- ret = fremovexattr (fd, name);
+ if (! node->hidden)
+ ret = direct_removexattr (node->layer, node->path, name);
else
- ret = lremovexattr (path, name);
+ {
+ char path[PATH_MAX];
+ strconcat3 (path, PATH_MAX, lo->workdir, "/", node->path);
+ ret = removexattr (path, name);
+ }
if (ret < 0)
{
@@ -3126,8 +3069,9 @@ ovl_removexattr (fuse_req_t req, fuse_ino_t ino, const char *name)
}
static int
-create_file (struct ovl_data *lo, int dirfd, const char *path, uid_t uid, gid_t gid, int flags, mode_t mode)
+direct_create_file (struct ovl_layer *l, int dirfd, const char *path, uid_t uid, gid_t gid, int flags, mode_t mode)
{
+ struct ovl_data *lo = l->ovl_data;
cleanup_close int fd = -1;
char wd_tmp_file_name[32];
int ret;
@@ -3253,7 +3197,7 @@ ovl_do_open (fuse_req_t req, fuse_ino_t parent, const char *name, int flags, mod
uid = get_uid (lo, ctx->uid);
gid = get_gid (lo, ctx->gid);
- fd = create_file (lo, get_upper_layer (lo)->fd, path, uid, gid, flags, mode & ~ctx->umask);
+ fd = direct_create_file (get_upper_layer (lo), get_upper_layer (lo)->fd, path, uid, gid, flags, mode & ~ctx->umask);
if (fd < 0)
return fd;
@@ -3263,7 +3207,7 @@ ovl_do_open (fuse_req_t req, fuse_ino_t parent, const char *name, int flags, mod
if (st == NULL)
st = &st_tmp;
- if (fstat (fd, st) < 0)
+ if (get_upper_layer (lo)->ds->fstat (get_upper_layer (lo), fd, path, st) < 0)
return -1;
n = make_ovl_node (lo, path, get_upper_layer (lo), name, st->st_ino, st->st_dev, false, p, lo->fast_ino_check);
@@ -3291,12 +3235,15 @@ ovl_do_open (fuse_req_t req, fuse_ino_t parent, const char *name, int flags, mod
/* readonly, we can use both lowerdir and upperdir. */
if (readonly)
{
+ struct ovl_layer *l = n->layer;
if (retnode)
*retnode = n;
- return TEMP_FAILURE_RETRY (openat (node_dirfd (n), n->path, flags, mode));
+ return l->ds->openat (l, n->path, flags, mode);
}
else
{
+ struct ovl_layer *l;
+
n = get_node_up (lo, n);
if (n == NULL)
return -1;
@@ -3304,7 +3251,9 @@ ovl_do_open (fuse_req_t req, fuse_ino_t parent, const char *name, int flags, mod
if (retnode)
*retnode = n;
- return TEMP_FAILURE_RETRY (openat (node_dirfd (n), n->path, flags, mode));
+ l = n->layer;
+
+ return l->ds->openat (l, n->path, flags, mode);
}
}
@@ -3518,6 +3467,13 @@ ovl_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, stru
/* Ignore request. */
}
+ uid = -1;
+ gid = -1;
+ if (to_set & FUSE_SET_ATTR_UID)
+ uid = get_uid (lo, attr->st_uid);
+ if (to_set & FUSE_SET_ATTR_GID)
+ gid = get_gid (lo, attr->st_gid);
+
if (fi != NULL)
fd = fi->fh; // use existing fd if fuse_file_info is available
else
@@ -3632,13 +3588,6 @@ ovl_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, stru
}
}
- uid = -1;
- gid = -1;
- if (to_set & FUSE_SET_ATTR_UID)
- uid = get_uid (lo, attr->st_uid);
- if (to_set & FUSE_SET_ATTR_GID)
- gid = get_gid (lo, attr->st_gid);
-
if (uid != -1 || gid != -1)
{
if (fd >= 0)
@@ -3661,6 +3610,12 @@ ovl_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, stru
fuse_reply_attr (req, &e.attr, get_timeout (lo));
}
+static int
+direct_linkat (struct ovl_layer *l, const char *oldpath, const char *newpath, int flags)
+{
+ return linkat (l->fd, oldpath, l->fd, newpath, 0);
+}
+
static void
ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname)
{
@@ -3725,13 +3680,8 @@ ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newn
return;
}
- if (linkat (node_dirfd (node), node->path, lo->workdir_fd, wd_tmp_file_name, 0) < 0)
- {
- fuse_reply_err (req, errno);
- return;
- }
-
- if (renameat (lo->workdir_fd, wd_tmp_file_name, node_dirfd (newparentnode), path) < 0)
+ ret = direct_linkat (get_upper_layer (lo), node->path, path, 0);
+ if (ret < 0)
{
fuse_reply_err (req, errno);
return;
@@ -3769,20 +3719,52 @@ ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newn
fuse_reply_entry (req, &e);
}
+static int
+direct_symlinkat (struct ovl_layer *l, const char *target, const char *linkpath, uid_t uid, gid_t gid)
+{
+ struct ovl_data *lo = l->ovl_data;
+ char wd_tmp_file_name[32];
+ int ret;
+
+ sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ());
+
+ unlinkat (lo->workdir_fd, wd_tmp_file_name, 0);
+ ret = symlinkat (linkpath, lo->workdir_fd, wd_tmp_file_name);
+ if (ret < 0)
+ return ret;
+
+ if (uid != lo->uid || gid != lo->gid)
+ {
+ ret = fchownat (lo->workdir_fd, wd_tmp_file_name, uid, gid, AT_SYMLINK_NOFOLLOW);
+ if (ret < 0)
+ {
+ unlinkat (lo->workdir_fd, wd_tmp_file_name, 0);
+ return ret;
+ }
+ }
+
+ ret = renameat (lo->workdir_fd, wd_tmp_file_name, get_upper_layer (lo)->fd, target);
+ if (ret < 0)
+ {
+ unlinkat (lo->workdir_fd, wd_tmp_file_name, 0);
+ return ret;
+ }
+
+ return 0;
+}
+
static void
ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *name)
{
cleanup_lock int l = enter_big_lock ();
struct ovl_data *lo = ovl_data (req);
struct ovl_node *pnode, *node;
- cleanup_free char *path = NULL;
int ret;
struct fuse_entry_param e;
const struct fuse_ctx *ctx = fuse_req_ctx (req);
char wd_tmp_file_name[32];
bool need_delete_whiteout = true;
- uid_t uid;
- gid_t gid;
+ cleanup_free char *path = NULL;
if (UNLIKELY (ovl_debug (req)))
fprintf (stderr, "ovl_symlink(link=%s, ino=%" PRIu64 "s, name=%s)\n", link, parent, name);
@@ -3811,26 +3793,18 @@ ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *na
if (pnode->loaded && node == NULL)
need_delete_whiteout = false;
- sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ());
-
- unlinkat (lo->workdir_fd, wd_tmp_file_name, 0);
- ret = symlinkat (link, lo->workdir_fd, wd_tmp_file_name);
+ ret = asprintf (&path, "%s/%s", pnode->path, name);
if (ret < 0)
{
- fuse_reply_err (req, errno);
+ fuse_reply_err (req, ENOMEM);
return;
}
- uid = get_uid (lo, ctx->uid);
- gid = get_uid (lo, ctx->gid);
- if (uid != lo->uid || gid != lo->gid)
+ ret = direct_symlinkat (get_upper_layer (lo), path, link, get_uid (lo, ctx->uid), get_gid (lo, ctx->gid));
+ if (ret < 0)
{
- if (fchownat (lo->workdir_fd, wd_tmp_file_name, get_uid (lo, ctx->uid), get_gid (lo, ctx->gid), AT_SYMLINK_NOFOLLOW) < 0)
- {
- unlinkat (lo->workdir_fd, wd_tmp_file_name, 0);
- fuse_reply_err (req, errno);
- return;
- }
+ fuse_reply_err (req, ENOMEM);
+ return;
}
if (need_delete_whiteout && delete_whiteout (lo, -1, pnode, name) < 0)
@@ -3840,20 +3814,6 @@ ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *na
return;
}
- ret = asprintf (&path, "%s/%s", pnode->path, name);
- if (ret < 0)
- {
- fuse_reply_err (req, errno);
- return;
- }
-
- ret = renameat (lo->workdir_fd, wd_tmp_file_name, get_upper_layer (lo)->fd, path);
- if (ret < 0)
- {
- fuse_reply_err (req, errno);
- return;
- }
-
node = make_ovl_node (lo, path, get_upper_layer (lo), name, 0, 0, false, pnode, lo->fast_ino_check);
if (node == NULL)
{
@@ -3964,7 +3924,7 @@ ovl_rename_exchange (fuse_req_t req, fuse_ino_t parent, const char *name,
goto error;
- ret = syscall (SYS_renameat2, srcfd, name, destfd, newname, flags);
+ ret = direct_renameat2 (node->layer, srcfd, name, destfd, newname, flags);
if (ret < 0)
goto error;
@@ -4101,7 +4061,7 @@ ovl_rename_direct (fuse_req_t req, fuse_ino_t parent, const char *name,
errno = ENOTEMPTY;
goto error;
}
- if (destnode_whiteouts && empty_dir (lo, destnode) < 0)
+ if (destnode_whiteouts && empty_dir (get_upper_layer (lo), destnode->path) < 0)
goto error;
}
@@ -4137,7 +4097,7 @@ ovl_rename_direct (fuse_req_t req, fuse_ino_t parent, const char *name,
so that with one operation we get both the rename and the whiteout created. */
if (destnode_is_whiteout)
{
- ret = syscall (SYS_renameat2, srcfd, name, destfd, newname, flags|RENAME_EXCHANGE);
+ ret = direct_renameat2 (get_upper_layer (lo), srcfd, name, destfd, newname, flags|RENAME_EXCHANGE);
if (ret == 0)
goto done;
@@ -4157,11 +4117,12 @@ ovl_rename_direct (fuse_req_t req, fuse_ino_t parent, const char *name,
/* Try to create the whiteout atomically, if it fails do the
rename+mknod separately. */
- ret = syscall (SYS_renameat2, srcfd, name, destfd,
- newname, flags|RENAME_WHITEOUT);
+ ret = direct_renameat2 (get_upper_layer (lo), srcfd, name, destfd,
+ newname, flags|RENAME_WHITEOUT);
if (ret < 0)
{
- ret = syscall (SYS_renameat2, srcfd, name, destfd, newname, flags);
+ ret = direct_renameat2 (get_upper_layer (lo), srcfd, name, destfd,
+ newname, flags);
if (ret < 0)
goto error;
@@ -4275,7 +4236,7 @@ ovl_readlink (fuse_req_t req, fuse_ino_t ino)
{
char *tmp;
- ret = readlinkat (node_dirfd (node), node->path, buf, current_size - 1);
+ ret = node->layer->ds->readlinkat (node->layer, node->path, buf, current_size - 1);
if (ret == -1)
{
fuse_reply_err (req, errno);
@@ -4561,6 +4522,22 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
fuse_reply_entry (req, &e);
}
+static int
+direct_fsync (struct ovl_layer *l, int fd, const char *path, int datasync)
+{
+ cleanup_close int cfd = -1;
+
+ if (fd < 0)
+ {
+ cfd = openat (l->fd, path, O_NOFOLLOW|O_DIRECTORY);
+ if (cfd < 0)
+ return cfd;
+ fd = cfd;
+ }
+
+ return datasync ? fdatasync (fd) : fsync (fd);
+}
+
static void
do_fsync (fuse_req_t req, fuse_ino_t ino, int datasync, int fd)
{
@@ -4569,7 +4546,6 @@ do_fsync (fuse_req_t req, fuse_ino_t ino, int datasync, int fd)
struct ovl_node *node;
struct ovl_data *lo = ovl_data (req);
cleanup_lock int l = 0;
- cleanup_close int cfd = -1;
char path[PATH_MAX];
if (!lo->fsync)
@@ -4588,27 +4564,15 @@ do_fsync (fuse_req_t req, fuse_ino_t ino, int datasync, int fd)
if (fd < 0)
strcpy (path, node->path);
- l = release_big_lock ();
-
if (! do_fsync)
{
fuse_reply_err (req, 0);
return;
}
- if (fd < 0)
- {
- cfd = openat (get_upper_layer (lo)->fd, path, O_NOFOLLOW|O_DIRECTORY);
- if (cfd < 0)
- {
- fuse_reply_err (req, errno == ENOENT ? 0 : errno);
- return;
- }
- fd = cfd;
- }
-
if (do_fsync)
- ret = datasync ? fdatasync (fd) : fsync (fd);
+ ret = direct_fsync (node->layer, fd, path, datasync);
+
fuse_reply_err (req, ret == 0 ? 0 : errno);
}
@@ -4632,6 +4596,12 @@ ovl_fsyncdir (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_inf
return do_fsync (req, ino, datasync, -1);
}
+static int
+direct_ioctl (struct ovl_layer *l, int fd, int cmd, unsigned long *r)
+{
+ return ioctl (fd, cmd, &r);
+}
+
static void
ovl_ioctl (fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg,
struct fuse_file_info *fi, unsigned int flags,
@@ -4688,7 +4658,7 @@ ovl_ioctl (fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg,
if (fd < 0)
{
- fd = cleaned_fd = TEMP_FAILURE_RETRY (openat (node_dirfd (node), node->path, O_RDONLY|O_NONBLOCK));
+ fd = cleaned_fd = node->layer->ds->openat (node->layer, node->path, O_RDONLY|O_NONBLOCK, 0755);
if (fd < 0)
{
fuse_reply_err (req, errno);
@@ -4698,12 +4668,18 @@ ovl_ioctl (fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg,
l = release_big_lock ();
- if (ioctl (fd, cmd, &r) < 0)
+ if (direct_ioctl (node->layer, fd, cmd, &r) < 0)
fuse_reply_err (req, errno);
else
fuse_reply_ioctl (req, 0, &r, out_bufsz ? sizeof (r) : 0);
}
+static int
+direct_fallocate (struct ovl_layer *l, int fd, int mode, off_t offset, off_t len)
+{
+ return fallocate (fd, mode, offset, len);
+}
+
static void
ovl_fallocate (fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi)
{
@@ -4731,7 +4707,7 @@ ovl_fallocate (fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t len
return;
}
- fd = TEMP_FAILURE_RETRY (openat (node_dirfd (node), node->path, O_NONBLOCK|O_NOFOLLOW|O_WRONLY));
+ fd = node->layer->ds->openat (node->layer, node->path, O_NONBLOCK|O_NOFOLLOW|O_WRONLY, 0755);
if (fd < 0)
{
fuse_reply_err (req, errno);
@@ -4740,11 +4716,20 @@ ovl_fallocate (fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t len
l = release_big_lock ();
- ret = fallocate (fd, mode, offset, length);
+ ret = direct_fallocate (node->layer, fd, mode, offset, length);
fuse_reply_err (req, ret < 0 ? errno : 0);
}
#ifdef HAVE_COPY_FILE_RANGE
+
+static ssize_t
+direct_copy_file_range (struct ovl_layer *l, int fd_in, off_t *off_in,
+ int fd_out, off_t *off_out,
+ size_t len, unsigned int flags)
+{
+ return copy_file_range (fd_in, off_in, fd_out, off_out, len, flags);
+}
+
static void
ovl_copy_file_range (fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fuse_file_info *fi_in, fuse_ino_t ino_out, off_t off_out, struct fuse_file_info *fi_out, size_t len, int flags)
{
@@ -4780,7 +4765,7 @@ ovl_copy_file_range (fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fus
return;
}
- fd = TEMP_FAILURE_RETRY (openat (node_dirfd (node), node->path, O_NONBLOCK|O_NOFOLLOW|O_RDONLY));
+ fd = node->layer->ds->openat (node->layer, node->path, O_NONBLOCK|O_NOFOLLOW|O_RDONLY, 0755);
if (fd < 0)
{
fuse_reply_err (req, errno);
@@ -4796,7 +4781,7 @@ ovl_copy_file_range (fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fus
l = release_big_lock ();
- ret = copy_file_range (fd, &off_in, fd_dest, &off_out, len, flags);
+ ret = direct_copy_file_range (node->layer, fd, &off_in, fd_dest, &off_out, len, flags);
if (ret < 0)
fuse_reply_err (req, errno);
else
@@ -4804,6 +4789,117 @@ 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,
@@ -5051,7 +5147,7 @@ main (int argc, char *argv[])
error (EXIT_FAILURE, errno, "cannot convert %s", lo.timeout_str);
}
- layers = read_dirs (lo.lowerdir, true, NULL);
+ layers = read_dirs (&lo, lo.lowerdir, true, NULL);
if (layers == NULL)
{
error (EXIT_FAILURE, errno, "cannot read lower dirs");
@@ -5059,7 +5155,7 @@ main (int argc, char *argv[])
if (lo.upperdir != NULL)
{
- tmp_layer = read_dirs (lo.upperdir, false, layers);
+ tmp_layer = read_dirs (&lo, lo.upperdir, false, layers);
if (tmp_layer == NULL)
error (EXIT_FAILURE, errno, "cannot read upper dir");
layers = tmp_layer;