mirror of
https://github.com/containers/fuse-overlayfs.git
synced 2025-09-09 07:16:11 -04:00
Merge pull request #214 from giuseppe/mkdir-fix
mkdir: if the destination exists atomically swap them
This commit is contained in:
commit
8b4062db5c
9
NEWS
9
NEWS
@ -1,3 +1,12 @@
|
||||
* fuse-overlayfs-1.1.0
|
||||
|
||||
- use openat(2) when available.
|
||||
- accept "ro" as mount option.
|
||||
- fix set mtime for a symlink.
|
||||
- fix some issues reported by static analysis.
|
||||
- fix potential infinite loop on a short read.
|
||||
- fix creating a directory if the destination already exists in the upper layer.
|
||||
|
||||
* fuse-overlayfs-1.0.0
|
||||
|
||||
- fix portability issue to 32 bits archs.
|
||||
|
@ -1,5 +1,5 @@
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([fuse-overlayfs], [1.0.0], [giuseppe@scrivano.org])
|
||||
AC_INIT([fuse-overlayfs], [1.1.0], [giuseppe@scrivano.org])
|
||||
AC_CONFIG_SRCDIR([main.c])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
|
150
main.c
150
main.c
@ -823,7 +823,7 @@ drop_node_from_ino (Hash_table *inodes, struct ovl_node *node)
|
||||
}
|
||||
|
||||
static int
|
||||
direct_renameat2 (struct ovl_layer *l, int olddirfd, const char *oldpath,
|
||||
direct_renameat2 (int olddirfd, const char *oldpath,
|
||||
int newdirfd, const char *newpath, unsigned int flags)
|
||||
{
|
||||
return syscall (SYS_renameat2, olddirfd, oldpath, newdirfd, newpath, flags);
|
||||
@ -2393,6 +2393,67 @@ copy_xattr (int sfd, int dfd, char *buf, size_t buf_size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
empty_dirfd (int fd)
|
||||
{
|
||||
cleanup_dir DIR *dp = NULL;
|
||||
struct dirent *dent;
|
||||
|
||||
dp = fdopendir (fd);
|
||||
if (dp == NULL)
|
||||
{
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int ret;
|
||||
|
||||
errno = 0;
|
||||
dent = readdir (dp);
|
||||
if (dent == NULL)
|
||||
{
|
||||
if (errno)
|
||||
return -1;
|
||||
|
||||
break;
|
||||
}
|
||||
if (strcmp (dent->d_name, ".") == 0)
|
||||
continue;
|
||||
if (strcmp (dent->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
ret = unlinkat (dirfd (dp), dent->d_name, 0);
|
||||
if (ret < 0 && errno == EISDIR)
|
||||
{
|
||||
ret = unlinkat (dirfd (dp), dent->d_name, AT_REMOVEDIR);
|
||||
if (ret < 0 && errno == ENOTEMPTY)
|
||||
{
|
||||
int dfd;
|
||||
|
||||
dfd = safe_openat (dirfd (dp), dent->d_name, O_DIRECTORY, 0);
|
||||
if (dfd < 0)
|
||||
return -1;
|
||||
|
||||
ret = empty_dirfd (dfd);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
ret = unlinkat (dirfd (dp), dent->d_name, AT_REMOVEDIR);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_node_directory (struct ovl_data *lo, struct ovl_node *src);
|
||||
|
||||
static int
|
||||
@ -2482,6 +2543,24 @@ create_directory (struct ovl_data *lo, int dirfd, const char *name, const struct
|
||||
ret = renameat (lo->workdir_fd, wd_tmp_file_name, dirfd, name);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (errno == EEXIST)
|
||||
{
|
||||
int dfd = -1;
|
||||
|
||||
ret = direct_renameat2 (lo->workdir_fd, wd_tmp_file_name, dirfd, name, RENAME_EXCHANGE);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
dfd = TEMP_FAILURE_RETRY (safe_openat (lo->workdir_fd, wd_tmp_file_name, O_DIRECTORY, 0));
|
||||
if (dfd < 0)
|
||||
return -1;
|
||||
|
||||
ret = empty_dirfd (dfd);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
return unlinkat (lo->workdir_fd, wd_tmp_file_name, AT_REMOVEDIR);
|
||||
}
|
||||
if (errno == ENOTDIR)
|
||||
unlinkat (dirfd, name, 0);
|
||||
if (errno == ENOENT && parent)
|
||||
@ -2816,67 +2895,6 @@ update_paths (struct ovl_node *node)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
empty_dirfd (int fd)
|
||||
{
|
||||
cleanup_dir DIR *dp = NULL;
|
||||
struct dirent *dent;
|
||||
|
||||
dp = fdopendir (fd);
|
||||
if (dp == NULL)
|
||||
{
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int ret;
|
||||
|
||||
errno = 0;
|
||||
dent = readdir (dp);
|
||||
if (dent == NULL)
|
||||
{
|
||||
if (errno)
|
||||
return -1;
|
||||
|
||||
break;
|
||||
}
|
||||
if (strcmp (dent->d_name, ".") == 0)
|
||||
continue;
|
||||
if (strcmp (dent->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
ret = unlinkat (dirfd (dp), dent->d_name, 0);
|
||||
if (ret < 0 && errno == EISDIR)
|
||||
{
|
||||
ret = unlinkat (dirfd (dp), dent->d_name, AT_REMOVEDIR);
|
||||
if (ret < 0 && errno == ENOTEMPTY)
|
||||
{
|
||||
int dfd;
|
||||
|
||||
dfd = safe_openat (dirfd (dp), dent->d_name, O_DIRECTORY, 0);
|
||||
if (dfd < 0)
|
||||
return -1;
|
||||
|
||||
ret = empty_dirfd (dfd);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
ret = unlinkat (dirfd (dp), dent->d_name, AT_REMOVEDIR);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
empty_dir (struct ovl_layer *l, const char *path)
|
||||
{
|
||||
@ -4006,7 +4024,7 @@ ovl_rename_exchange (fuse_req_t req, fuse_ino_t parent, const char *name,
|
||||
goto error;
|
||||
|
||||
|
||||
ret = direct_renameat2 (node->layer, srcfd, name, destfd, newname, flags);
|
||||
ret = direct_renameat2 (srcfd, name, destfd, newname, flags);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
@ -4179,7 +4197,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 = direct_renameat2 (get_upper_layer (lo), srcfd, name, destfd, newname, flags|RENAME_EXCHANGE);
|
||||
ret = direct_renameat2 (srcfd, name, destfd, newname, flags|RENAME_EXCHANGE);
|
||||
if (ret == 0)
|
||||
goto done;
|
||||
|
||||
@ -4199,11 +4217,11 @@ 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 = direct_renameat2 (get_upper_layer (lo), srcfd, name, destfd,
|
||||
ret = direct_renameat2 (srcfd, name, destfd,
|
||||
newname, flags|RENAME_WHITEOUT);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = direct_renameat2 (get_upper_layer (lo), srcfd, name, destfd,
|
||||
ret = direct_renameat2 (srcfd, name, destfd,
|
||||
newname, flags);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
Loading…
x
Reference in New Issue
Block a user