From cf17de5a8a71ae6c51371af35cb7568240540055 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 15 Feb 2019 12:28:25 +0100 Subject: [PATCH 01/14] main: fix a fd leak Signed-off-by: Giuseppe Scrivano --- main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index 67c540e..9834b46 100644 --- a/main.c +++ b/main.c @@ -1010,6 +1010,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; + closedir (dp); return NULL; } } @@ -1799,7 +1800,10 @@ create_node_directory (struct ovl_data *lo, struct ovl_node *src) ret = TEMP_FAILURE_RETRY (fstat (sfd, &st)); if (ret < 0) - return ret; + { + close (sfd); + return ret; + } times[0] = st.st_atim; times[1] = st.st_mtim; From 090f9e11c2325ae21ae8e75a28ee8b09e8c6b796 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 15 Feb 2019 17:20:03 +0100 Subject: [PATCH 02/14] main: do the unlink only after we created the temporary file in case of failures when we open the temporary file, we don't do any modification to the file system. Signed-off-by: Giuseppe Scrivano --- main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/main.c b/main.c index 9834b46..832945d 100644 --- a/main.c +++ b/main.c @@ -2331,13 +2331,6 @@ ovl_do_open (fuse_req_t req, fuse_ino_t parent, const char *name, int flags, mod if (p == NULL) return -1; - if (delete_whiteout (lo, -1, p, name) < 0) - return -1; - - sprintf (path, "%s/%s", p->path, name); - if (unlinkat (get_upper_layer (lo)->fd, path, 0) < 0 && errno != ENOENT) - return -1; - sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ()); fd = TEMP_FAILURE_RETRY (openat (lo->workdir_fd, wd_tmp_file_name, flags, mode & ~ctx->umask)); @@ -2350,6 +2343,13 @@ ovl_do_open (fuse_req_t req, fuse_ino_t parent, const char *name, int flags, mod return -1; } + sprintf (path, "%s/%s", p->path, name); + if (unlinkat (get_upper_layer (lo)->fd, path, 0) < 0 && errno != ENOENT) + return -1; + + if (delete_whiteout (lo, -1, p, name) < 0) + return -1; + if (renameat (lo->workdir_fd, wd_tmp_file_name, get_upper_layer (lo)->fd, path) < 0) { unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); From 37d91db36e1dc0576231979c6a9f05be82375787 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 15 Feb 2019 13:13:35 +0100 Subject: [PATCH 03/14] fuse-overlayfs: start using GCC autocleanup let's start using __attribute__((cleanup)), it helps to simplify a lot of code, and hopefully avoid some bugs. Signed-off-by: Giuseppe Scrivano --- Makefile.am | 2 +- main.c | 243 +++++++++++++++++----------------------------------- utils.h | 57 ++++++++++++ 3 files changed, 138 insertions(+), 164 deletions(-) create mode 100644 utils.h diff --git a/Makefile.am b/Makefile.am index 521072e..3ec97aa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,7 @@ bin_PROGRAMS = fuse-overlayfs ACLOCAL_AMFLAGS = -Im4 -EXTRA_DIST = m4/gnulib-cache.m4 rpm/fuse-overlayfs.spec.template autogen.sh fuse-overlayfs.1.md +EXTRA_DIST = m4/gnulib-cache.m4 rpm/fuse-overlayfs.spec.template autogen.sh fuse-overlayfs.1.md utils.h CLEANFILES = fuse-overlayfs.1 diff --git a/main.c b/main.c index 832945d..85ce9d2 100644 --- a/main.c +++ b/main.c @@ -55,6 +55,8 @@ #include #include +#include + #ifndef RENAME_EXCHANGE # define RENAME_EXCHANGE (1 << 1) # define RENAME_NOREPLACE (1 << 2) @@ -377,7 +379,7 @@ static int create_whiteout (struct ovl_data *lo, struct ovl_node *parent, const char *name, bool skip_mknod) { char whiteout_path[PATH_MAX + 10]; - int fd = -1; + cleanup_close int fd = -1; static bool can_mknod = true; if (!disable_ovl_whiteout && !skip_mknod && can_mknod) @@ -401,7 +403,6 @@ create_whiteout (struct ovl_data *lo, struct ovl_node *parent, const char *name, if (fd < 0 && errno != EEXIST) return -1; - close (fd); return 0; } @@ -458,7 +459,7 @@ static int hide_node (struct ovl_data *lo, struct ovl_node *node, bool unlink_src) { char dest[PATH_MAX]; - char *newpath; + cleanup_free char *newpath = NULL; asprintf (&newpath, "%lu", get_next_wd_counter ()); if (newpath == NULL) @@ -480,10 +481,7 @@ hide_node (struct ovl_data *lo, struct ovl_node *node, bool unlink_src) newpath, RENAME_WHITEOUT) < 0) { if (renameat (node_dirfd (node), node->path, lo->workdir_fd, newpath) < 0) - { - free (newpath); - return -1; - } + return -1; if (node->parent) { if (create_whiteout (lo, node->parent, node->name, false) < 0) @@ -496,23 +494,19 @@ hide_node (struct ovl_data *lo, struct ovl_node *node, bool unlink_src) if (node_dirp (node)) { if (mkdirat (lo->workdir_fd, newpath, 0700) < 0) - { - free (newpath); - return -1; - } + return -1; } else { if (linkat (node_dirfd (node), node->path, lo->workdir_fd, newpath, 0) < 0) - { - free (newpath); - return -1; - } + return -1; } } node->hidden_dirfd = lo->workdir_fd; free (node->path); node->path = newpath; + newpath = NULL; /* Do not auto cleanup. */ + node->hidden = 1; node->parent = NULL; @@ -771,7 +765,7 @@ make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_ for (it = layer; it; it = it->next) { ssize_t s; - int fd = TEMP_FAILURE_RETRY (openat (it->fd, path, O_RDONLY|O_NONBLOCK|O_NOFOLLOW|O_PATH)); + cleanup_close int fd = TEMP_FAILURE_RETRY (openat (it->fd, path, O_RDONLY|O_NONBLOCK|O_NOFOLLOW|O_PATH)); if (fd < 0) continue; @@ -779,7 +773,6 @@ make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_ ret->ino = st.st_ino; close (fd); - fd = TEMP_FAILURE_RETRY (openat (it->fd, path, O_RDONLY|O_NONBLOCK|O_NOFOLLOW)); if (fd < 0) continue; @@ -793,7 +786,7 @@ make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_ if (s < sizeof (buf) - sizeof(int) * 2) { - int originfd; + cleanup_close int originfd = -1; /* overlay in the kernel stores a file handle in the .origin xattr. @@ -810,8 +803,6 @@ make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_ if (fstat (originfd, &st) == 0) { ret->ino = st.st_ino; - close (originfd); - close (fd); break; } } @@ -823,8 +814,6 @@ make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_ if (s > 0) path[s] = '\0'; - close (fd); - if (parent && parent->last_layer == it) break; } @@ -885,7 +874,6 @@ get_whiteout_name (const char *name, struct stat *st) static struct ovl_node * load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char *path, char *name) { - DIR *dp; struct dirent *dent; struct stat st, tmp_st; struct ovl_layer *it, *upper_layer = get_upper_layer (lo); @@ -899,17 +887,19 @@ 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 = TEMP_FAILURE_RETRY (openat (it->fd, path, O_DIRECTORY)); - if (fd < 0) + 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; - dp = fdopendir (fd); + dp = fdopendir (cleanup_fd); if (dp == NULL) - { - close (fd); - continue; - } + continue; + cleanup_fd = -1; /* It is not owned by dp. */ + + fd = dirfd (dp); for (;;) { int ret; @@ -923,12 +913,7 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char if (dent == NULL) { if (errno) - { - int saved_errno = errno; - closedir (dp); - errno = saved_errno; - return NULL; - } + return NULL; break; } @@ -939,10 +924,7 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char continue; if (TEMP_FAILURE_RETRY (fstatat (fd, dent->d_name, &st, AT_SYMLINK_NOFOLLOW)) < 0) - { - closedir (dp); return NULL; - } child = hash_lookup (n->children, &key); if (child) @@ -964,10 +946,8 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char sprintf (node_path, ".wh.%s", dent->d_name); ret = TEMP_FAILURE_RETRY (fstatat (fd, node_path, &tmp_st, AT_SYMLINK_NOFOLLOW)); if (ret < 0 && errno != ENOENT) - { - closedir (dp); - return NULL; - } + return NULL; + sprintf (node_path, "%s/%s", n->path, dent->d_name); if (ret == 0) @@ -976,7 +956,6 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char if (child == NULL) { errno = ENOMEM; - closedir (dp); return NULL; } } @@ -989,7 +968,6 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char if (child == NULL) { errno = ENOMEM; - closedir (dp); return NULL; } } @@ -1001,7 +979,6 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char if (child == NULL) { errno = ENOMEM; - closedir (dp); return NULL; } } @@ -1010,11 +987,9 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char if (insert_node (n, child, false) == NULL) { errno = ENOMEM; - closedir (dp); return NULL; } } - closedir (dp); if (n->last_layer == it) break; @@ -1038,8 +1013,9 @@ free_layers (struct ovl_layer *layers) static struct ovl_layer * read_dirs (char *path, bool low, struct ovl_layer *layers) { - char *buf = NULL, *saveptr = NULL, *it; + char *saveptr = NULL, *it; struct ovl_layer *last; + cleanup_free char *buf = NULL; if (path == NULL) return NULL; @@ -1052,7 +1028,7 @@ read_dirs (char *path, bool low, struct ovl_layer *layers) while (last && last->next) last = last->next; - for (it = strtok_r (path, ":", &saveptr); it; it = strtok_r (NULL, ":", &saveptr)) + for (it = strtok_r (buf, ":", &saveptr); it; it = strtok_r (NULL, ":", &saveptr)) { char full_path[PATH_MAX + 1]; struct ovl_layer *l = NULL; @@ -1102,7 +1078,6 @@ read_dirs (char *path, bool low, struct ovl_layer *layers) layers = l; } } - free (buf); return layers; } @@ -1372,11 +1347,11 @@ create_missing_whiteouts (struct ovl_data *lo, struct ovl_node *node, const char for (l = get_lower_layers (lo); l; l = l->next) { - DIR *dp; - int fd; + cleanup_dir DIR *dp = NULL; + cleanup_close int cleanup_fd = -1; - fd = TEMP_FAILURE_RETRY (openat (l->fd, from, O_DIRECTORY)); - if (fd < 0) + cleanup_fd = TEMP_FAILURE_RETRY (openat (l->fd, from, O_DIRECTORY)); + if (cleanup_fd < 0) { if (errno == ENOENT) continue; @@ -1386,15 +1361,15 @@ create_missing_whiteouts (struct ovl_data *lo, struct ovl_node *node, const char return -1; } - dp = fdopendir (fd); + dp = fdopendir (cleanup_fd); if (dp == NULL) - { - close (fd); - return -1; - } + return -1; else { struct dirent *dent; + int fd = cleanup_fd; + + cleanup_fd = -1; /* Now owned by dp. */ for (;;) { @@ -1406,12 +1381,7 @@ create_missing_whiteouts (struct ovl_data *lo, struct ovl_node *node, const char if (dent == NULL) { if (errno) - { - int saved_errno = errno; - closedir (dp); - errno = saved_errno; - return -1; - } + return -1; break; } @@ -1428,38 +1398,22 @@ create_missing_whiteouts (struct ovl_data *lo, struct ovl_node *node, const char { if (node_dirp (n)) { - char *c; + cleanup_free char *c = NULL; n = load_dir (lo, n, n->layer, n->path, n->name); if (n == NULL) - { - closedir (dp); - return -1; - } + return -1; if (asprintf (&c, "%s/%s", from, n->name) < 0) - { - closedir (dp); - return -1; - } + return -1; if (create_missing_whiteouts (lo, n, c) < 0) - { - free (c); - closedir (dp); - return -1; - } - free (c); + return -1; } continue; } if (create_whiteout (lo, node, dent->d_name, false) < 0) - { - closedir (dp); - return -1; - } + return -1; } - - closedir (dp); } } return 0; @@ -1471,7 +1425,8 @@ ovl_do_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, { struct ovl_dirp *d = ovl_dirp (fi); size_t remaining = size; - char *p, *buffer = calloc (size, 1); + char *p; + cleanup_free char *buffer = calloc (size, 1); if (buffer == NULL) { @@ -1494,7 +1449,7 @@ ovl_do_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, if (ret < 0) { fuse_reply_err (req, errno); - goto exit; + return; } if (offset == 0) @@ -1532,8 +1487,6 @@ ovl_do_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, remaining -= entsize; } fuse_reply_buf (req, buffer, size - remaining); - exit: - free (buffer); } static void @@ -1573,8 +1526,8 @@ ovl_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size) ssize_t len; struct ovl_node *node; struct ovl_data *lo = ovl_data (req); - char *buf = NULL; - int fd; + cleanup_free char *buf = NULL; + cleanup_close int fd = -1; if (ovl_debug (req)) fprintf (stderr, "ovl_listxattr(ino=%" PRIu64 ", size=%zu)\n", ino, size); @@ -1599,7 +1552,6 @@ ovl_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size) fd = TEMP_FAILURE_RETRY (openat (node_dirfd (node), node->path, O_RDONLY|O_NONBLOCK)); if (fd < 0) { - free (buf); fuse_reply_err (req, errno); return; } @@ -1611,9 +1563,6 @@ ovl_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size) fuse_reply_xattr (req, len); else if (len <= size) fuse_reply_buf (req, buf, len); - - free (buf); - close (fd); } static void @@ -1622,8 +1571,8 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) ssize_t len; struct ovl_node *node; struct ovl_data *lo = ovl_data (req); - char *buf = NULL; - int fd; + cleanup_free char *buf = NULL; + cleanup_close int fd = -1; if (ovl_debug (req)) fprintf (stderr, "ovl_getxattr(ino=%" PRIu64 ", name=%s, size=%zu)\n", ino, name, size); @@ -1648,7 +1597,6 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) fd = TEMP_FAILURE_RETRY (openat (node_dirfd (node), node->path, O_RDONLY|O_NONBLOCK)); if (fd < 0) { - free (buf); fuse_reply_err (req, errno); return; } @@ -1660,9 +1608,6 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) fuse_reply_xattr (req, len); else if (len <= size) fuse_reply_buf (req, buf, len); - - free (buf); - close (fd); } static void @@ -1714,8 +1659,8 @@ create_directory (struct ovl_data *lo, int dirfd, const char *name, const struct struct ovl_node *parent, int xattr_sfd, uid_t uid, gid_t gid, mode_t mode) { int ret; - int dfd = -1; - char *buf = NULL; + cleanup_close int dfd = -1; + cleanup_free char *buf = NULL; char wd_tmp_file_name[32]; sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ()); @@ -1769,11 +1714,6 @@ create_directory (struct ovl_data *lo, int dirfd, const char *name, const struct ret = renameat (lo->workdir_fd, wd_tmp_file_name, dirfd, name); } out: - if (dfd >= 0) - close (dfd); - if (buf) - free (buf); - if (ret < 0) unlinkat (lo->workdir_fd, wd_tmp_file_name, AT_REMOVEDIR); @@ -1785,7 +1725,7 @@ create_node_directory (struct ovl_data *lo, struct ovl_node *src) { int ret; struct stat st; - int sfd = -1; + cleanup_close int sfd = -1; struct timespec times[2]; if (src == NULL) @@ -1800,18 +1740,13 @@ create_node_directory (struct ovl_data *lo, struct ovl_node *src) ret = TEMP_FAILURE_RETRY (fstat (sfd, &st)); if (ret < 0) - { - close (sfd); - return ret; - } + return ret; times[0] = st.st_atim; times[1] = st.st_mtim; ret = create_directory (lo, get_upper_layer (lo)->fd, src->path, times, src->parent, sfd, st.st_uid, st.st_gid, st.st_mode); - close (sfd); - if (ret == 0) { src->layer = get_upper_layer (lo); @@ -1828,10 +1763,11 @@ copyup (struct ovl_data *lo, struct ovl_node *node) { int saved_errno; int ret = -1; - int dfd = -1, sfd = -1; + cleanup_close int dfd = -1; + cleanup_close int sfd = -1; struct stat st; const size_t buf_size = 1 << 20; - char *buf = NULL; + cleanup_free char *buf = NULL; struct timespec times[2]; char wd_tmp_file_name[32]; @@ -1937,11 +1873,6 @@ copyup (struct ovl_data *lo, struct ovl_node *node) exit: saved_errno = errno; - free (buf); - if (sfd >= 0) - close (sfd); - if (dfd >= 0) - close (dfd); if (ret < 0) unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); errno = saved_errno; @@ -2025,26 +1956,22 @@ update_paths (struct ovl_node *node) static int empty_dir (struct ovl_data *lo, struct ovl_node *node) { - DIR *dp; - int fd; + cleanup_dir DIR *dp = NULL; + cleanup_close int cleanup_fd = -1; struct dirent *dent; - fd = TEMP_FAILURE_RETRY (openat (get_upper_layer (lo)->fd, node->path, O_DIRECTORY)); - if (fd < 0) + cleanup_fd = TEMP_FAILURE_RETRY (openat (get_upper_layer (lo)->fd, node->path, O_DIRECTORY)); + if (cleanup_fd < 0) return -1; - if (set_fd_opaque (fd) < 0) - { - close (fd); - return -1; - } + if (set_fd_opaque (cleanup_fd) < 0) + return -1; - dp = fdopendir (fd); + dp = fdopendir (cleanup_fd); if (dp == NULL) - { - close (fd); - return -1; - } + return -1; + + cleanup_fd = -1; /* It is not owned by dp. */ for (;;) { @@ -2053,12 +1980,7 @@ empty_dir (struct ovl_data *lo, struct ovl_node *node) if (dent == NULL) { if (errno) - { - int saved_errno = errno; - closedir (dp); - errno = saved_errno; - return -1; - } + return -1; break; } @@ -2070,8 +1992,6 @@ empty_dir (struct ovl_data *lo, struct ovl_node *node) unlinkat (dirfd (dp), dent->d_name, AT_REMOVEDIR); } - closedir (dp); - return 0; } @@ -2194,7 +2114,7 @@ ovl_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name, { struct ovl_data *lo = ovl_data (req); struct ovl_node *node; - int fd; + cleanup_close int fd = -1; if (ovl_debug (req)) fprintf (stderr, "ovl_setxattr(ino=%" PRIu64 "s, name=%s, value=%s, size=%zu, flags=%d)\n", ino, name, @@ -2233,7 +2153,6 @@ ovl_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name, close (fd); return; } - close (fd); fuse_reply_err (req, 0); } @@ -2242,7 +2161,7 @@ ovl_removexattr (fuse_req_t req, fuse_ino_t ino, const char *name) { struct ovl_node *node; struct ovl_data *lo = ovl_data (req); - int fd; + cleanup_close int fd = -1; if (ovl_debug (req)) fprintf (stderr, "ovl_removexattr(ino=%" PRIu64 "s, name=%s)\n", ino, name); @@ -2275,7 +2194,6 @@ ovl_removexattr (fuse_req_t req, fuse_ino_t ino, const char *name) return; } - close (fd); fuse_reply_err (req, 0); } @@ -2286,7 +2204,7 @@ ovl_do_open (fuse_req_t req, fuse_ino_t parent, const char *name, int flags, mod struct ovl_node *n; bool readonly = (flags & (O_APPEND | O_RDWR | O_WRONLY | O_CREAT | O_TRUNC)) == 0; char path[PATH_MAX + 10]; - int fd; + cleanup_close int fd = -1; const struct fuse_ctx *ctx = fuse_req_ctx (req); flags |= O_NOFOLLOW; @@ -2310,6 +2228,7 @@ ovl_do_open (fuse_req_t req, fuse_ino_t parent, const char *name, int flags, mod if (!n) { + int ret; struct ovl_node *p; const struct fuse_ctx *ctx = fuse_req_ctx (req); char wd_tmp_file_name[32]; @@ -2370,14 +2289,14 @@ ovl_do_open (fuse_req_t req, fuse_ino_t parent, const char *name, int flags, mod close (fd); return -1; } - return fd; + ret = fd; + fd = -1; /* We use a temporary variable so we don't close it at cleanup. */ + return ret; } /* readonly, we can use both lowerdir and upperdir. */ if (readonly) - { - return TEMP_FAILURE_RETRY (openat (node_dirfd (n), n->path, flags, mode)); - } + return TEMP_FAILURE_RETRY (openat (node_dirfd (n), n->path, flags, mode)); else { n = get_node_up (lo, n); @@ -2456,7 +2375,7 @@ static void ovl_create (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi) { - int fd; + cleanup_close int fd = -1; struct fuse_entry_param e; struct ovl_data *lo = ovl_data (req); struct ovl_node *node; @@ -2477,11 +2396,11 @@ ovl_create (fuse_req_t req, fuse_ino_t parent, const char *name, node = do_lookup_file (lo, parent, name); if (node == NULL || do_getattr (req, &e, node) < 0) { - close (fd); fuse_reply_err (req, errno); return; } fi->fh = fd; + fd = -1; /* Do not clean it up. */ node->lookups++; fuse_reply_create (req, &e, fi); @@ -2490,7 +2409,7 @@ ovl_create (fuse_req_t req, fuse_ino_t parent, const char *name, static void ovl_open (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - int fd; + cleanup_close int fd = -1; if (ovl_debug (req)) fprintf (stderr, "ovl_open(ino=%" PRIu64 "s)\n", ino); @@ -2502,6 +2421,7 @@ ovl_open (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) return; } fi->fh = fd; + fd = -1; /* Do not clean it up. */ fuse_reply_open (req, fi); } @@ -2726,11 +2646,11 @@ ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newn } else { - int dfd = TEMP_FAILURE_RETRY (openat (node_dirfd (newparentnode), path, O_WRONLY|O_NONBLOCK)); + cleanup_close int dfd = TEMP_FAILURE_RETRY (openat (node_dirfd (newparentnode), path, O_WRONLY|O_NONBLOCK)); if (dfd >= 0) { bool set = false; - int sfd = TEMP_FAILURE_RETRY (openat (node_dirfd (node), node->path, O_RDONLY|O_NONBLOCK)); + cleanup_close int sfd = TEMP_FAILURE_RETRY (openat (node_dirfd (node), node->path, O_RDONLY|O_NONBLOCK)); if (sfd >= 0) { char origin_path[PATH_MAX + 10]; @@ -2743,13 +2663,10 @@ ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newn s = fgetxattr (sfd, ORIGIN_XATTR, origin_path, sizeof (origin_path)); if (s > 0) set = fsetxattr (dfd, ORIGIN_XATTR, origin_path, s, 0) == 0; - - close (sfd); } if (! set) fsetxattr (dfd, ORIGIN_XATTR, node->path, strlen (node->path), 0); - close (dfd); } } diff --git a/utils.h b/utils.h new file mode 100644 index 0000000..ce11cd9 --- /dev/null +++ b/utils.h @@ -0,0 +1,57 @@ +/* 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 UTILS_H +# define UTILS_H + +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); +} + +# define cleanup_file __attribute__((cleanup (cleanup_filep))) +# define cleanup_free __attribute__((cleanup (cleanup_freep))) +# define cleanup_close __attribute__((cleanup (cleanup_closep))) +# define cleanup_dir __attribute__((cleanup (cleanup_dirp))) + +#endif From 3ff2c01cbb672fd0da94be327a0c141f02177baf Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 15 Feb 2019 22:31:56 +0100 Subject: [PATCH 04/14] main: add missing debug messages Signed-off-by: Giuseppe Scrivano --- main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/main.c b/main.c index 85ce9d2..4210fcd 100644 --- a/main.c +++ b/main.c @@ -1277,6 +1277,9 @@ ovl_opendir (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) struct ovl_node *it; struct ovl_dirp *d = calloc (1, sizeof (struct ovl_dirp)); + if (ovl_debug (req)) + fprintf (stderr, "ovl_opendir(ino=%" PRIu64 ")\n", ino); + if (d == NULL) { errno = ENOENT; @@ -1493,6 +1496,8 @@ static void ovl_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, struct fuse_file_info *fi) { + if (ovl_debug (req)) + fprintf (stderr, "ovl_readdir(ino=%" PRIu64 ", size=%zu, offset=%llo)\n", ino, size, offset); ovl_do_readdir (req, ino, size, offset, fi, 0); } @@ -1500,6 +1505,8 @@ static void ovl_readdirplus (fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, struct fuse_file_info *fi) { + if (ovl_debug (req)) + fprintf (stderr, "ovl_readdirplus(ino=%" PRIu64 ", size=%zu, offset=%llo)\n", ino, size, offset); ovl_do_readdir (req, ino, size, offset, fi, 1); } @@ -1509,6 +1516,9 @@ ovl_releasedir (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) size_t s; struct ovl_dirp *d = ovl_dirp (fi); + if (ovl_debug (req)) + fprintf (stderr, "ovl_releasedir(ino=%" PRIu64 ")\n", ino); + for (s = 2; s < d->tbl_size; s++) { struct ovl_node *n = d->tbl[s]; From 43b6b2ecf9245a27c5b27c5530a60e917a05fccc Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Sat, 16 Feb 2019 10:00:20 +0100 Subject: [PATCH 05/14] fuse-overlayfs: add check to readdir for the node parent ensure the node was not moved and that its parent is the same as the directory we are reading. Signed-off-by: Giuseppe Scrivano --- main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index 4210fcd..716e51f 100644 --- a/main.c +++ b/main.c @@ -1257,6 +1257,7 @@ ovl_lookup (fuse_req_t req, fuse_ino_t parent, const char *name) struct ovl_dirp { struct ovl_data *lo; + struct ovl_node *parent; struct ovl_node **tbl; size_t tbl_size; size_t offset; @@ -1304,6 +1305,7 @@ ovl_opendir (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) goto out_errno; d->offset = 0; + d->parent = node; d->tbl_size = hash_get_n_entries (node->children) + 2; d->tbl = malloc (sizeof (struct ovl_node *) * d->tbl_size); if (d->tbl == NULL) @@ -1460,7 +1462,11 @@ ovl_do_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, else if (offset == 1) name = ".."; else - name = node->name; + { + if (node->parent != d->parent) + continue; + name = node->name; + } if (!plus) entsize = fuse_add_direntry (req, p, remaining, name, &st, offset + 1); From 346067ab87ef59760cf1d126f750814fd73db52a Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Sat, 16 Feb 2019 21:22:28 +0100 Subject: [PATCH 06/14] fuse-overlayfs: accept option "dev" Signed-off-by: Giuseppe Scrivano --- main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.c b/main.c index 716e51f..d1adcce 100644 --- a/main.c +++ b/main.c @@ -3516,6 +3516,8 @@ fuse_opt_proc (void *data, const char *arg, int key, struct fuse_args *outargs) return 1; if (strcmp (arg, "suid") == 0) return 1; + if (strcmp (arg, "dev") == 0) + return 1; if (key == FUSE_OPT_KEY_NONOPT) { From f64f65287817fecd0c5d41cd74f6c8b7bd64ffb2 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 15 Feb 2019 22:22:14 +0100 Subject: [PATCH 07/14] fuse-overlayfs: drop usage of static arrays for paths now that we are using autocleanup macros, there are no excuses for using static arrays. Signed-off-by: Giuseppe Scrivano --- main.c | 284 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 218 insertions(+), 66 deletions(-) diff --git a/main.c b/main.c index d1adcce..c70bbb8 100644 --- a/main.c +++ b/main.c @@ -378,15 +378,17 @@ is_directory_opaque (int dirfd, const char *path) static int create_whiteout (struct ovl_data *lo, struct ovl_node *parent, const char *name, bool skip_mknod) { - char whiteout_path[PATH_MAX + 10]; - cleanup_close int fd = -1; static bool can_mknod = true; + cleanup_close int fd = -1; if (!disable_ovl_whiteout && !skip_mknod && can_mknod) { + cleanup_free char *whiteout_path = NULL; int ret; - sprintf (whiteout_path, "%s/%s", parent->path, name); + ret = asprintf (&whiteout_path, "%s/%s", parent->path, name); + if (ret < 0) + return ret; ret = mknodat (get_upper_layer (lo)->fd, whiteout_path, S_IFCHR|0700, makedev (0, 0)); if (ret == 0) return 0; @@ -397,12 +399,18 @@ create_whiteout (struct ovl_data *lo, struct ovl_node *parent, const char *name, /* if it fails with EPERM then do not attempt mknod again. */ can_mknod = false; } + else + { + cleanup_free char *whiteout_path = NULL; + int ret; - sprintf (whiteout_path, "%s/.wh.%s", parent->path, name); - fd = TEMP_FAILURE_RETRY (openat (get_upper_layer (lo)->fd, whiteout_path, O_CREAT|O_WRONLY|O_NONBLOCK, 0700)); - if (fd < 0 && errno != EEXIST) - return -1; - + ret = asprintf (&whiteout_path, "%s/.wh.%s", parent->path, name); + if (ret < 0) + return ret; + fd = TEMP_FAILURE_RETRY (openat (get_upper_layer (lo)->fd, whiteout_path, O_CREAT|O_WRONLY|O_NONBLOCK, 0700)); + if (fd < 0 && errno != EEXIST) + return -1; + } return 0; } @@ -410,7 +418,6 @@ static int delete_whiteout (struct ovl_data *lo, int dirfd, struct ovl_node *parent, const char *name) { struct stat st; - char whiteout_path[PATH_MAX + 10]; if (dirfd >= 0) { @@ -425,7 +432,12 @@ delete_whiteout (struct ovl_data *lo, int dirfd, struct ovl_node *parent, const } else { - sprintf (whiteout_path, "%s/%s", parent->path, name); + cleanup_free char *whiteout_path = NULL; + int ret; + + ret = asprintf (&whiteout_path, "%s/%s", parent->path, name); + if (ret < 0) + return ret; if (TEMP_FAILURE_RETRY (fstatat (get_upper_layer (lo)->fd, whiteout_path, &st, AT_SYMLINK_NOFOLLOW)) == 0 && (st.st_mode & S_IFMT) == S_IFCHR @@ -441,13 +453,25 @@ delete_whiteout (struct ovl_data *lo, int dirfd, struct ovl_node *parent, const if (dirfd >= 0) { - sprintf (whiteout_path, ".wh.%s", name); + cleanup_free char *whiteout_path = NULL; + int ret; + + ret = asprintf (&whiteout_path, ".wh.%s", name); + if (ret < 0) + return ret; + if (unlinkat (dirfd, whiteout_path, 0) < 0 && errno != ENOENT) return -1; } else { - sprintf (whiteout_path, "%s/.wh.%s", parent->path, name); + cleanup_free char *whiteout_path = NULL; + int ret; + + ret = asprintf (&whiteout_path, "%s/.wh.%s", parent->path, name); + if (ret < 0) + return ret; + if (unlinkat (get_upper_layer (lo)->fd, whiteout_path, 0) < 0 && errno != ENOENT) return -1; } @@ -458,15 +482,12 @@ delete_whiteout (struct ovl_data *lo, int dirfd, struct ovl_node *parent, const static int hide_node (struct ovl_data *lo, struct ovl_node *node, bool unlink_src) { - char dest[PATH_MAX]; cleanup_free char *newpath = NULL; + int ret; - asprintf (&newpath, "%lu", get_next_wd_counter ()); - if (newpath == NULL) - { - unlink (dest); - return -1; - } + ret = asprintf (&newpath, "%lu", get_next_wd_counter ()); + if (ret < 0) + return ret; assert (node->layer == get_upper_layer (lo)); @@ -906,7 +927,8 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char struct ovl_node key; const char *wh; struct ovl_node *child = NULL; - char node_path[PATH_MAX + 1]; + cleanup_free char *node_path = NULL; + cleanup_free char *whiteout_path = NULL; errno = 0; dent = readdir (dp); @@ -943,12 +965,17 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char } } - sprintf (node_path, ".wh.%s", dent->d_name); - ret = TEMP_FAILURE_RETRY (fstatat (fd, node_path, &tmp_st, AT_SYMLINK_NOFOLLOW)); + ret = asprintf (&whiteout_path, ".wh.%s", dent->d_name); + if (ret < 0) + return NULL; + + ret = TEMP_FAILURE_RETRY (fstatat (fd, whiteout_path, &tmp_st, AT_SYMLINK_NOFOLLOW)); if (ret < 0 && errno != ENOENT) return NULL; - sprintf (node_path, "%s/%s", n->path, dent->d_name); + ret = asprintf (&node_path, "%s/%s", n->path, dent->d_name); + if (ret < 0) + return NULL; if (ret == 0) { @@ -1030,10 +1057,11 @@ read_dirs (char *path, bool low, struct ovl_layer *layers) for (it = strtok_r (buf, ":", &saveptr); it; it = strtok_r (NULL, ":", &saveptr)) { - char full_path[PATH_MAX + 1]; + cleanup_free char *full_path = NULL; struct ovl_layer *l = NULL; - if (realpath (it, full_path) < 0) + full_path = realpath (it, NULL); + if (full_path == NULL) return NULL; l = malloc (sizeof (*l)); @@ -1106,17 +1134,20 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name) if (node == NULL) { int ret; - char path[PATH_MAX]; - char whpath[PATH_MAX]; struct ovl_layer *it; struct stat st, tmp_st; struct ovl_layer *upper_layer = get_upper_layer (lo); for (it = lo->layers; it; it = it->next) { + cleanup_free char *path = NULL; + cleanup_free char *whpath = NULL; const char *wh_name; - sprintf (path, "%s/%s", pnode->path, name); + ret = asprintf (&path, "%s/%s", pnode->path, name); + if (ret < 0) + return NULL; + ret = TEMP_FAILURE_RETRY (fstatat (it->fd, path, &st, AT_SYMLINK_NOFOLLOW)); if (ret < 0) { @@ -1124,7 +1155,10 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name) if (errno == ENOENT) { - sprintf (whpath, "%s/.wh.%s", pnode->path, name); + ret = asprintf (&whpath, "%s/.wh.%s", pnode->path, name); + if (ret < 0) + return NULL; + ret = TEMP_FAILURE_RETRY (fstatat (it->fd, whpath, &tmp_st, AT_SYMLINK_NOFOLLOW)); if (ret < 0 && errno != ENOENT) return NULL; @@ -1166,7 +1200,13 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name) } } - sprintf (whpath, "%s/.wh.%s", pnode->path, name); + if (whpath == NULL) + { + ret = asprintf (&whpath, "%s/.wh.%s", pnode->path, name); + if (ret < 0) + return NULL; + } + ret = TEMP_FAILURE_RETRY (fstatat (it->fd, whpath, &tmp_st, AT_SYMLINK_NOFOLLOW)); if (ret < 0 && errno != ENOENT) return NULL; @@ -1431,8 +1471,9 @@ ovl_do_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, struct ovl_dirp *d = ovl_dirp (fi); size_t remaining = size; char *p; - cleanup_free char *buffer = calloc (size, 1); + cleanup_free char *buffer = NULL; + buffer = calloc (size, 1); if (buffer == NULL) { fuse_reply_err (req, ENOMEM); @@ -1762,7 +1803,6 @@ create_node_directory (struct ovl_data *lo, struct ovl_node *src) times[1] = st.st_mtim; ret = create_directory (lo, get_upper_layer (lo)->fd, src->path, times, src->parent, sfd, st.st_uid, st.st_gid, st.st_mode); - if (ret == 0) { src->layer = get_upper_layer (lo); @@ -1810,10 +1850,25 @@ copyup (struct ovl_data *lo, struct ovl_node *node) if ((st.st_mode & S_IFMT) == S_IFLNK) { - char p[PATH_MAX + 1]; - ret = readlinkat (node_dirfd (node), node->path, p, sizeof (p) - 1); - if (ret < 0) - goto exit; + size_t current_size = PATH_MAX + 1; + cleanup_free char *p = malloc (current_size); + + while (1) + { + char *new; + + ret = readlinkat (node_dirfd (node), node->path, p, current_size - 1); + if (ret < 0) + goto exit; + if (ret < current_size - 1) + break; + + current_size = current_size * 2; + new = realloc (p, current_size); + if (new == NULL) + goto exit; + p = new; + } p[ret] = '\0'; ret = symlinkat (p, get_upper_layer (lo)->fd, node->path); if (ret < 0) @@ -1876,8 +1931,11 @@ copyup (struct ovl_data *lo, struct ovl_node *node) if (node->parent) { - char whpath[PATH_MAX + 10]; - sprintf (whpath, "%s/.wh.%s", node->parent->path, node->name); + cleanup_free char *whpath = NULL; + + ret = asprintf (&whpath, "%s/.wh.%s", node->parent->path, node->name); + if (ret < 0) + goto exit; if (unlinkat (get_upper_layer (lo)->fd, whpath, 0) < 0 && errno != ENOENT) goto exit; } @@ -2219,7 +2277,7 @@ ovl_do_open (fuse_req_t req, fuse_ino_t parent, const char *name, int flags, mod struct ovl_data *lo = ovl_data (req); struct ovl_node *n; bool readonly = (flags & (O_APPEND | O_RDWR | O_WRONLY | O_CREAT | O_TRUNC)) == 0; - char path[PATH_MAX + 10]; + cleanup_free char *path = NULL; cleanup_close int fd = -1; const struct fuse_ctx *ctx = fuse_req_ctx (req); @@ -2278,7 +2336,12 @@ ovl_do_open (fuse_req_t req, fuse_ino_t parent, const char *name, int flags, mod return -1; } - sprintf (path, "%s/%s", p->path, name); + ret = asprintf (&path, "%s/%s", p->path, name); + if (ret < 0) + { + unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); + return ret; + } if (unlinkat (get_upper_layer (lo)->fd, path, 0) < 0 && errno != ENOENT) return -1; @@ -2596,7 +2659,7 @@ ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newn { struct ovl_data *lo = ovl_data (req); struct ovl_node *node, *newparentnode, *destnode; - char path[PATH_MAX + 10]; + cleanup_free char *path = NULL; int ret; struct fuse_entry_param e; char wd_tmp_file_name[32]; @@ -2647,7 +2710,12 @@ ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newn sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ()); - sprintf (path, "%s/%s", newparentnode->path, newname); + ret = asprintf (&path, "%s/%s", newparentnode->path, newname); + if (ret < 0) + { + fuse_reply_err (req, errno); + return; + } if (linkat (node_dirfd (newparentnode), node->path, lo->workdir_fd, wd_tmp_file_name, 0) < 0) { @@ -2669,14 +2737,58 @@ ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newn cleanup_close int sfd = TEMP_FAILURE_RETRY (openat (node_dirfd (node), node->path, O_RDONLY|O_NONBLOCK)); if (sfd >= 0) { - char origin_path[PATH_MAX + 10]; - size_t s; + size_t current_size = PATH_MAX + 1; + cleanup_free char *origin_path = NULL; + ssize_t s; - s = fgetxattr (sfd, PRIVILEGED_ORIGIN_XATTR, origin_path, sizeof (origin_path)); + origin_path = malloc (current_size); + if (origin_path == NULL) + { + fuse_reply_err (req, errno); + return; + } + + while (1) + { + char *tmp; + + s = fgetxattr (sfd, PRIVILEGED_ORIGIN_XATTR, origin_path, current_size); + if (s < 0) + break; + if (s < current_size) + break; + + current_size *= 2; + tmp = realloc (origin_path, current_size); + if (tmp == NULL) + { + fuse_reply_err (req, errno); + return; + } + origin_path = tmp; + } if (s > 0) fsetxattr (dfd, PRIVILEGED_ORIGIN_XATTR, origin_path, s, 0); - s = fgetxattr (sfd, ORIGIN_XATTR, origin_path, sizeof (origin_path)); + while (1) + { + char *tmp; + + s = fgetxattr (sfd, ORIGIN_XATTR, origin_path, current_size); + if (s < 0) + break; + if (s < current_size) + break; + + current_size *= 2; + tmp = realloc (origin_path, current_size); + if (tmp == NULL) + { + fuse_reply_err (req, errno); + return; + } + origin_path = tmp; + } if (s > 0) set = fsetxattr (dfd, ORIGIN_XATTR, origin_path, s, 0) == 0; } @@ -2721,7 +2833,7 @@ ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *na { struct ovl_data *lo = ovl_data (req); struct ovl_node *pnode, *node; - char path[PATH_MAX + 10]; + cleanup_free char *path = NULL; int ret; struct fuse_entry_param e; const struct fuse_ctx *ctx = fuse_req_ctx (req); @@ -2775,7 +2887,13 @@ ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *na return; } - sprintf (path, "%s/%s", pnode->path, name); + 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) { @@ -3192,10 +3310,11 @@ ovl_statfs (fuse_req_t req, fuse_ino_t ino) static void ovl_readlink (fuse_req_t req, fuse_ino_t ino) { - struct ovl_node *node; struct ovl_data *lo = ovl_data (req); + cleanup_free char *buf = NULL; + struct ovl_node *node; + size_t current_size; int ret = 0; - char buf[PATH_MAX + 1]; if (ovl_debug (req)) fprintf (stderr, "ovl_readlink(ino=%" PRIu64 "s)\n", ino); @@ -3207,16 +3326,35 @@ ovl_readlink (fuse_req_t req, fuse_ino_t ino) return; } - ret = readlinkat (node_dirfd (node), node->path, buf, sizeof (buf)); - if (ret == -1) + current_size = PATH_MAX + 1; + buf = malloc (current_size); + if (buf == NULL) { - fuse_reply_err (req, errno); + fuse_reply_err (req, ENOENT); return; } - if (ret == sizeof (buf)) + + while (1) { - fuse_reply_err (req, ENAMETOOLONG); - return; + char *tmp; + + ret = readlinkat (node_dirfd (node), node->path, buf, current_size - 1); + if (ret == -1) + { + fuse_reply_err (req, errno); + return; + } + if (ret < current_size - 1) + break; + + current_size *= 2; + tmp = realloc (buf, current_size); + if (tmp == NULL) + { + fuse_reply_err (req, errno); + return; + } + buf = tmp; } buf[ret] = '\0'; @@ -3266,7 +3404,7 @@ ovl_mknod (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev struct ovl_data *lo = ovl_data (req); struct ovl_node *pnode; int ret = 0; - char path[PATH_MAX + 10]; + cleanup_free char *path = NULL; struct fuse_entry_param e; const struct fuse_ctx *ctx = fuse_req_ctx (req); char wd_tmp_file_name[32]; @@ -3305,17 +3443,24 @@ ovl_mknod (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev if (fchownat (lo->workdir_fd, wd_tmp_file_name, get_uid (lo, ctx->uid), get_gid (lo, ctx->gid), 0) < 0) { - unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); fuse_reply_err (req, errno); + unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); + return; + } + + ret = asprintf (&path, "%s/%s", pnode->path, name); + if (ret < 0) + { + fuse_reply_err (req, errno); + unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); return; } - sprintf (path, "%s/%s", pnode->path, name); ret = renameat (lo->workdir_fd, wd_tmp_file_name, get_upper_layer (lo)->fd, path); if (ret < 0) { - unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); fuse_reply_err (req, errno); + unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); return; } @@ -3362,7 +3507,7 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) struct ovl_data *lo = ovl_data (req); struct ovl_node *pnode; int ret = 0; - char path[PATH_MAX + 10]; + char *path; struct fuse_entry_param e; const struct fuse_ctx *ctx = fuse_req_ctx (req); @@ -3390,7 +3535,12 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) fuse_reply_err (req, errno); return; } - sprintf (path, "%s/%s", pnode->path, name); + ret = asprintf (&path, "%s/%s", pnode->path, name); + if (ret < 0) + { + fuse_reply_err (req, errno); + return; + } ret = create_directory (lo, get_upper_layer (lo)->fd, path, NULL, pnode, -1, get_uid (lo, ctx->uid), get_gid (lo, ctx->gid), mode & ~ctx->umask); @@ -3620,9 +3770,10 @@ main (int argc, char *argv[]) error (EXIT_FAILURE, 0, "upperdir not specified"); else { - char full_path[PATH_MAX + 1]; + cleanup_free char *full_path = NULL; - if (realpath (lo.upperdir, full_path) < 0) + full_path = realpath (lo.upperdir, NULL); + if (full_path == NULL) error (EXIT_FAILURE, errno, "cannot retrieve path for %s", lo.upperdir); lo.upperdir = strdup (full_path); @@ -3659,9 +3810,10 @@ main (int argc, char *argv[]) error (EXIT_FAILURE, 0, "workdir not specified"); else { - char path[PATH_MAX + 1]; + cleanup_free char *path = NULL; - if (realpath (lo.workdir, path) < 0) + path = realpath (lo.workdir, NULL); + if (path == NULL) goto err_out1; mkdir (path, 0700); strcat (path, "/work"); From 71be2a838fa7752ea081f943250b386910505b13 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Sun, 17 Feb 2019 10:22:34 +0100 Subject: [PATCH 08/14] .travis.yml: add tests for installing rpm packages on fuse-overlayfs Signed-off-by: Giuseppe Scrivano --- .travis.yml | 4 ++++ tests/fedora-installs.sh | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100755 tests/fedora-installs.sh diff --git a/.travis.yml b/.travis.yml index e4c0730..fe5a5a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ +services: + - docker language: c sudo: required dist: trusty @@ -16,6 +18,7 @@ addons: - g++ - python3-setuptools before_install: + - docker pull fedora & - sudo mkdir -p /lower /upper /mnt - (cd /; sudo git clone https://github.com/amir73il/unionmount-testsuite.git) - (git clone git://github.com/ninja-build/ninja.git && cd ninja && python3.5 ./bootstrap.py && sudo cp ninja /usr/bin) @@ -28,3 +31,4 @@ script: - sudo make -j install; sudo cp fuse-overlayfs /sbin - (cd /unionmount-testsuite; sudo ./run --ov --fuse=fuse-overlayfs --xdev) - (cd /unionmount-testsuite; FUSE_OVERLAYFS_DISABLE_OVL_WHITEOUT=1 sudo -E ./run --ov --fuse=fuse-overlayfs --xdev) + - sudo tests/fedora-installs.sh diff --git a/tests/fedora-installs.sh b/tests/fedora-installs.sh new file mode 100755 index 0000000..fcc58d4 --- /dev/null +++ b/tests/fedora-installs.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +mkdir lower upper workdir merged + +fuse-overlayfs -o lowerdir=lower,upperdir=upper,workdir=workdir,suid,dev merged + +docker run --rm -ti -v merged:/merged fedora dnf --installroot /merged --releasever 29 install -y glibc-common + +umount merged + +# Make sure workdir is empty, and move the upper layer down +rm -rf workdir lower +mv upper lower +mkdir upper workdir + +fuse-overlayfs -o lowerdir=lower,upperdir=upper,workdir=workdir,suid,dev merged + +# Install some big packages +docker run --rm -ti -v merged:/merged fedora dnf --installroot /merged --releasever 29 install -y emacs texlive + +umount merged From f1b1e52a153d554ea52360fab308ff82aeb0c3d2 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Sun, 17 Feb 2019 11:39:30 +0100 Subject: [PATCH 09/14] fuse-overlayfs: refactor some xattrs common code Signed-off-by: Giuseppe Scrivano --- main.c | 131 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 60 deletions(-) diff --git a/main.c b/main.c index c70bbb8..3dc0204 100644 --- a/main.c +++ b/main.c @@ -720,6 +720,45 @@ make_whiteout_node (const char *path, const char *name) return ret; } +static ssize_t +safe_read_xattr (char **ret, int sfd, const char *name, size_t initial_size) +{ + cleanup_free char *buffer = NULL; + size_t current_size; + ssize_t s; + + current_size = initial_size; + buffer = malloc (current_size + 1); + if (buffer == NULL) + return -1; + + while (1) + { + char *tmp; + + s = fgetxattr (sfd, name, buffer, current_size); + if (s < 0) + break; + if (s < current_size) + break; + + current_size *= 2; + tmp = realloc (buffer, current_size + 1); + if (tmp == NULL) + return -1; + + buffer = tmp; + } + + buffer[s] == '\0'; + + /* Change owner. */ + *ret = buffer; + buffer = NULL; + + return s; +} + static struct ovl_node * make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_t ino, bool dir_p, struct ovl_node *parent) { @@ -780,12 +819,23 @@ make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_ { struct stat st; struct ovl_layer *it; - char path[PATH_MAX]; + cleanup_free char *path = NULL; + + path = strdup (ret->path); + if (path == NULL) + { + free (ret->path); + free (ret->name); + free (ret); + errno = ENOMEM; + return NULL; + } - strcpy (path, ret->path); for (it = layer; it; it = it->next) { ssize_t s; + cleanup_free char *val = NULL; + cleanup_free char *origin = NULL; cleanup_close int fd = TEMP_FAILURE_RETRY (openat (it->fd, path, O_RDONLY|O_NONBLOCK|O_NOFOLLOW|O_PATH)); if (fd < 0) continue; @@ -797,11 +847,11 @@ make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_ fd = TEMP_FAILURE_RETRY (openat (it->fd, path, O_RDONLY|O_NONBLOCK|O_NOFOLLOW)); if (fd < 0) continue; - s = fgetxattr (fd, PRIVILEGED_ORIGIN_XATTR, path, sizeof (path) - 1); + s = safe_read_xattr (&val, fd, PRIVILEGED_ORIGIN_XATTR, PATH_MAX); if (s > 0) { char buf[512]; - struct ovl_fh *ofh = (struct ovl_fh *) path; + struct ovl_fh *ofh = (struct ovl_fh *) val; size_t s = ofh->len - sizeof (*ofh); struct file_handle *fh = (struct file_handle *) buf; @@ -831,9 +881,13 @@ make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_ } /* If an origin is specified, use it for the next layer lookup. */ - s = fgetxattr (fd, ORIGIN_XATTR, path, sizeof (path) - 1); + s = safe_read_xattr (&origin, fd, ORIGIN_XATTR, PATH_MAX); if (s > 0) - path[s] = '\0'; + { + free (path); + path = origin; + origin = NULL; + } if (parent && parent->last_layer == it) break; @@ -1687,18 +1741,18 @@ copy_xattr (int sfd, int dfd, char *buf, size_t buf_size) { size_t xattr_len; - xattr_len = flistxattr (sfd, buf, buf_size / 2); + xattr_len = flistxattr (sfd, buf, buf_size); if (xattr_len > 0) { char *it; - char *xattr_buf = buf + buf_size / 2; for (it = buf; it - buf < xattr_len; it += strlen (it) + 1) { - ssize_t s = fgetxattr (sfd, it, xattr_buf, buf_size / 2); + cleanup_free char *v = NULL; + ssize_t s = safe_read_xattr (&v, sfd, it, 256); if (s < 0) return -1; - if (fsetxattr (dfd, it, xattr_buf, s, 0) < 0) + if (fsetxattr (dfd, it, v, s, 0) < 0) { if (errno == EINVAL) continue; @@ -2737,64 +2791,21 @@ ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newn cleanup_close int sfd = TEMP_FAILURE_RETRY (openat (node_dirfd (node), node->path, O_RDONLY|O_NONBLOCK)); if (sfd >= 0) { - size_t current_size = PATH_MAX + 1; cleanup_free char *origin_path = NULL; ssize_t s; - origin_path = malloc (current_size); - if (origin_path == NULL) - { - fuse_reply_err (req, errno); - return; - } - - while (1) - { - char *tmp; - - s = fgetxattr (sfd, PRIVILEGED_ORIGIN_XATTR, origin_path, current_size); - if (s < 0) - break; - if (s < current_size) - break; - - current_size *= 2; - tmp = realloc (origin_path, current_size); - if (tmp == NULL) - { - fuse_reply_err (req, errno); - return; - } - origin_path = tmp; - } + s = safe_read_xattr (&origin_path, sfd, PRIVILEGED_ORIGIN_XATTR, PATH_MAX + 1); if (s > 0) fsetxattr (dfd, PRIVILEGED_ORIGIN_XATTR, origin_path, s, 0); - - while (1) + else { - char *tmp; - - s = fgetxattr (sfd, ORIGIN_XATTR, origin_path, current_size); - if (s < 0) - break; - if (s < current_size) - break; - - current_size *= 2; - tmp = realloc (origin_path, current_size); - if (tmp == NULL) - { - fuse_reply_err (req, errno); - return; - } - origin_path = tmp; + s = safe_read_xattr (&origin_path, sfd, ORIGIN_XATTR, PATH_MAX + 1); + if (s > 0) + fsetxattr (dfd, PRIVILEGED_ORIGIN_XATTR, origin_path, s, 0); + else + fsetxattr (dfd, ORIGIN_XATTR, node->path, strlen (node->path), 0); } - if (s > 0) - set = fsetxattr (dfd, ORIGIN_XATTR, origin_path, s, 0) == 0; } - - if (! set) - fsetxattr (dfd, ORIGIN_XATTR, node->path, strlen (node->path), 0); } } From 67fa787735a09525686e2dfbbaefdd0bd0b2b61b Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Sun, 17 Feb 2019 20:10:48 +0100 Subject: [PATCH 10/14] fuse-overlayfs: use cleanup function for initializing node Signed-off-by: Giuseppe Scrivano --- main.c | 103 ++++++++++++++++++++++++++------------------------------- 1 file changed, 47 insertions(+), 56 deletions(-) diff --git a/main.c b/main.c index 3dc0204..462dfa6 100644 --- a/main.c +++ b/main.c @@ -692,32 +692,45 @@ node_compare (const void *n1, const void *n2) return strcmp (node1->name, node2->name) == 0 ? true : false; } +static void +cleanup_node_initp (struct ovl_node **p) +{ + struct ovl_node *n = *p; + if (n == NULL) + return; + if (n->children) + hash_free (n->children); + free (n->name); + free (n->path); + free (n); +} + +#define cleanup_node_init __attribute__((cleanup (cleanup_node_initp))) + static struct ovl_node * make_whiteout_node (const char *path, const char *name) { - struct ovl_node *ret = calloc (1, sizeof (*ret)); + struct ovl_node *ret_xchg; + cleanup_node_init struct ovl_node *ret = NULL; + + ret = calloc (1, sizeof (*ret)); if (ret == NULL) - { - errno = ENOMEM; - return NULL; - } + return NULL; + ret->name = strdup (name); if (ret->name == NULL) - { - free (ret); - errno = ENOMEM; return NULL; - } + ret->path = strdup (path); if (ret->path == NULL) - { - free (ret->name); - free (ret); - errno = ENOMEM; - return NULL; - } + return NULL; + ret->whiteout = 1; - return ret; + + ret_xchg = ret; + ret = NULL; + + return ret_xchg; } static ssize_t @@ -762,43 +775,27 @@ safe_read_xattr (char **ret, int sfd, const char *name, size_t initial_size) static struct ovl_node * make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_t ino, bool dir_p, struct ovl_node *parent) { - struct ovl_node *ret = malloc (sizeof (*ret)); - if (ret == NULL) - { - errno = ENOMEM; - return NULL; - } + struct ovl_node *ret_xchg; + cleanup_node_init struct ovl_node *ret = NULL; + + ret = calloc (1, sizeof (*ret)); + if (ret == NULL) + return NULL; - ret->last_layer = NULL; ret->parent = parent; - ret->lookups = 0; - ret->do_unlink = 0; - ret->hidden = 0; - ret->do_rmdir = 0; - ret->whiteout = 0; ret->layer = layer; ret->ino = ino; - ret->present_lowerdir = 0; ret->hidden_dirfd = -1; ret->name = strdup (name); if (ret->name == NULL) - { - free (ret); - errno = ENOMEM; - return NULL; - } + return NULL; if (has_prefix (path, "./") && path[2]) path += 2; ret->path = strdup (path); if (ret->path == NULL) - { - free (ret->name); - free (ret); - errno = ENOMEM; - return NULL; - } + return NULL; if (!dir_p) ret->children = NULL; @@ -806,13 +803,7 @@ make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_ { ret->children = hash_initialize (10, NULL, node_hasher, node_compare, node_free); if (ret->children == NULL) - { - free (ret->path); - free (ret->name); - free (ret); - errno = ENOMEM; - return NULL; - } + return NULL; } if (ret->ino == 0) @@ -823,13 +814,7 @@ make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_ path = strdup (ret->path); if (path == NULL) - { - free (ret->path); - free (ret->name); - free (ret); - errno = ENOMEM; - return NULL; - } + return NULL; for (it = layer; it; it = it->next) { @@ -894,7 +879,10 @@ make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_ } } - return ret; + ret_xchg = ret; + ret = NULL; + + return ret_xchg; } static struct ovl_node * @@ -957,7 +945,10 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char { n = make_ovl_node (path, layer, name, 0, true, NULL); if (n == NULL) - return NULL; + { + errno = ENOMEM; + return NULL; + } } for (it = lo->layers; it; it = it->next) From 7f21f8fcf94772aa38311ffd7a06b761a4950c8f Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Sun, 17 Feb 2019 20:54:50 +0100 Subject: [PATCH 11/14] fuse-overlayfs: add cleanup for layers Signed-off-by: Giuseppe Scrivano --- main.c | 56 +++++++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/main.c b/main.c index 462dfa6..ca99227 100644 --- a/main.c +++ b/main.c @@ -1082,6 +1082,15 @@ free_layers (struct ovl_layer *layers) free (layers); } +static void +cleanup_layerp (struct ovl_layer **p) +{ + struct ovl_layer *l = *p; + free_layers (l); +} + +#define cleanup_layer __attribute__((cleanup (cleanup_layerp))) + static struct ovl_layer * read_dirs (char *path, bool low, struct ovl_layer *layers) { @@ -1102,36 +1111,20 @@ read_dirs (char *path, bool low, struct ovl_layer *layers) for (it = strtok_r (buf, ":", &saveptr); it; it = strtok_r (NULL, ":", &saveptr)) { - cleanup_free char *full_path = NULL; - struct ovl_layer *l = NULL; + cleanup_layer struct ovl_layer *l = NULL; - full_path = realpath (it, NULL); - if (full_path == NULL) - return NULL; - - l = malloc (sizeof (*l)); + l = calloc (1, sizeof (*l)); if (l == NULL) - { - free_layers (layers); - return NULL; - } + return NULL; + l->fd = -1; - l->path = strdup (full_path); + l->path = realpath (it, NULL); if (l->path == NULL) - { - free (l); - free_layers (layers); - return NULL; - } + return NULL; l->fd = open (l->path, O_DIRECTORY); if (l->fd < 0) - { - free (l->path); - free (l); - free_layers (layers); - return NULL; - } + return NULL; l->low = low; if (low) @@ -1150,6 +1143,7 @@ read_dirs (char *path, bool low, struct ovl_layer *layers) l->next = layers; layers = l; } + l = NULL; } return layers; } @@ -3734,6 +3728,8 @@ main (int argc, char *argv[]) .mountpoint = NULL, }; int ret = -1; + cleanup_layer struct ovl_layer *layers = NULL; + struct ovl_layer *tmp_layer = NULL; struct fuse_args args = FUSE_ARGS_INIT (argc, newargv); if (getenv ("FUSE_OVERLAYFS_DISABLE_OVL_WHITEOUT")) @@ -3795,13 +3791,16 @@ main (int argc, char *argv[]) lo.uid_mappings = lo.uid_str ? read_mappings (lo.uid_str) : NULL; lo.gid_mappings = lo.gid_str ? read_mappings (lo.gid_str) : NULL; - lo.layers = read_dirs (lo.lowerdir, true, NULL); - if (lo.layers == NULL) - error (EXIT_FAILURE, errno, "cannot read lower dirs"); + layers = read_dirs (lo.lowerdir, true, NULL); + if (layers == NULL) + { + error (EXIT_FAILURE, errno, "cannot read lower dirs"); + } - lo.layers = read_dirs (lo.upperdir, false, lo.layers); - if (lo.layers == NULL) + tmp_layer = read_dirs (lo.upperdir, false, layers); + if (tmp_layer == NULL) error (EXIT_FAILURE, errno, "cannot read upper dir"); + lo.layers = layers = tmp_layer; lo.root = load_dir (&lo, NULL, get_upper_layer (&lo), ".", ""); if (lo.root == NULL) @@ -3865,7 +3864,6 @@ err_out1: close (lo.workdir_fd); - free_layers (lo.layers); fuse_opt_free_args (&args); return ret ? 1 : 0; From de3727adb2093220bafe7fe43424d8bf51e3c885 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Mon, 18 Feb 2019 20:05:33 +0100 Subject: [PATCH 12/14] travis: exit immediately if something fails Signed-off-by: Giuseppe Scrivano --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index fe5a5a8..1a91801 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,10 +25,10 @@ before_install: - (git clone https://github.com/mesonbuild/meson.git; cd meson; sudo python3.5 ./setup.py install) - (wget https://github.com/libfuse/libfuse/releases/download/fuse-3.2.4/fuse-3.2.4.tar.xz; tar xf fuse-3.2.4.tar.xz; cd fuse-3.2.4; mkdir build; cd build; meson .. --prefix /usr && ninja && sudo ninja install) script: - - ./autogen.sh - - ./configure - - make -j $(nproc) - - sudo make -j install; sudo cp fuse-overlayfs /sbin - - (cd /unionmount-testsuite; sudo ./run --ov --fuse=fuse-overlayfs --xdev) - - (cd /unionmount-testsuite; FUSE_OVERLAYFS_DISABLE_OVL_WHITEOUT=1 sudo -E ./run --ov --fuse=fuse-overlayfs --xdev) + - ./autogen.sh || travis_terminate 1; + - ./configure || travis_terminate 1; + - make -j $(nproc) || travis_terminate 1; + - sudo make -j install; sudo cp fuse-overlayfs /sbin || travis_terminate 1; + - (cd /unionmount-testsuite; sudo ./run --ov --fuse=fuse-overlayfs --xdev) || travis_terminate 1; + - (cd /unionmount-testsuite; FUSE_OVERLAYFS_DISABLE_OVL_WHITEOUT=1 sudo -E ./run --ov --fuse=fuse-overlayfs --xdev) || travis_terminate 1; - sudo tests/fedora-installs.sh From 130e0000e5c1a474a1fbb9f8d2cd8507e22c5296 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Mon, 18 Feb 2019 20:03:38 +0100 Subject: [PATCH 13/14] fuse-overlayfs: accept nosuid,nodev,exec,noexec Signed-off-by: Giuseppe Scrivano --- main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/main.c b/main.c index ca99227..ba51326 100644 --- a/main.c +++ b/main.c @@ -3664,6 +3664,14 @@ fuse_opt_proc (void *data, const char *arg, int key, struct fuse_args *outargs) return 1; if (strcmp (arg, "dev") == 0) return 1; + if (strcmp (arg, "nosuid") == 0) + return 1; + if (strcmp (arg, "nodev") == 0) + return 1; + if (strcmp (arg, "exec") == 0) + return 1; + if (strcmp (arg, "noexec") == 0) + return 1; if (key == FUSE_OPT_KEY_NONOPT) { From 1533c9f5962513f5ef90c28fddae6b01c5c3dbda Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Mon, 18 Feb 2019 16:28:40 +0100 Subject: [PATCH 14/14] fuse-overlayfs: skip whiteout if not present in lower layers Signed-off-by: Giuseppe Scrivano --- main.c | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/main.c b/main.c index ba51326..d25adf4 100644 --- a/main.c +++ b/main.c @@ -376,15 +376,41 @@ is_directory_opaque (int dirfd, const char *path) } static int -create_whiteout (struct ovl_data *lo, struct ovl_node *parent, const char *name, bool skip_mknod) +create_whiteout (struct ovl_data *lo, struct ovl_node *parent, const char *name, bool skip_mknod, bool force_create) { static bool can_mknod = true; cleanup_close int fd = -1; + int ret; + + if (! force_create) + { + cleanup_free char *path = NULL; + struct ovl_layer *l; + bool found = false; + + ret = asprintf (&path, "%s/%s", parent->path, name); + if (ret < 0) + return ret; + + for (l = get_lower_layers (lo); l; l = l->next) + { + struct stat st; + + ret = TEMP_FAILURE_RETRY (fstatat (l->fd, path, &st, AT_SYMLINK_NOFOLLOW)); + if (ret < 0 && errno == ENOENT) + continue; + + found = true; + break; + } + /* Not present in the lower layers, do not do anything. */ + if (!found) + return 0; + } if (!disable_ovl_whiteout && !skip_mknod && can_mknod) { cleanup_free char *whiteout_path = NULL; - int ret; ret = asprintf (&whiteout_path, "%s/%s", parent->path, name); if (ret < 0) @@ -505,7 +531,7 @@ hide_node (struct ovl_data *lo, struct ovl_node *node, bool unlink_src) return -1; if (node->parent) { - if (create_whiteout (lo, node->parent, node->name, false) < 0) + if (create_whiteout (lo, node->parent, node->name, false, false) < 0) return -1; } } @@ -1495,7 +1521,7 @@ create_missing_whiteouts (struct ovl_data *lo, struct ovl_node *node, const char continue; } - if (create_whiteout (lo, node, dent->d_name, false) < 0) + if (create_whiteout (lo, node, dent->d_name, false, true) < 0) return -1; } } @@ -3215,7 +3241,7 @@ ovl_rename_direct (fuse_req_t req, fuse_ino_t parent, const char *name, whiteout file until the renameat2 is completed. */ if (node_dirp (node)) { - ret = create_whiteout (lo, destpnode, newname, true); + ret = create_whiteout (lo, destpnode, newname, true, true); if (ret < 0) goto error; unlinkat (destfd, newname, 0); @@ -3231,7 +3257,7 @@ ovl_rename_direct (fuse_req_t req, fuse_ino_t parent, const char *name, if (ret < 0) goto error; - ret = create_whiteout (lo, pnode, name, false); + ret = create_whiteout (lo, pnode, name, false, true); if (ret < 0) goto error; } @@ -3379,7 +3405,7 @@ hide_all (struct ovl_data *lo, struct ovl_node *node) int ret; it = nodes[i]; - ret = create_whiteout (lo, node, it->name, false); + ret = create_whiteout (lo, node, it->name, false, true); node_free (it); if (ret < 0)