fuse-overlayfs: split ovl_rename in two functions

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
Giuseppe Scrivano 2018-07-15 14:30:26 +02:00
parent 234a1baaf9
commit b3f454183f
No known key found for this signature in database
GPG Key ID: E4730F97F60286ED

408
main.c
View File

@ -2560,9 +2560,9 @@ ovl_flock (fuse_req_t req, fuse_ino_t ino,
}
static void
ovl_rename (fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_ino_t newparent, const char *newname,
unsigned int flags)
ovl_rename_exchange (fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_ino_t newparent, const char *newname,
unsigned int flags)
{
struct ovl_node *pnode, *node, *destnode, *destpnode;
struct ovl_data *lo = ovl_data (req);
@ -2570,10 +2570,8 @@ ovl_rename (fuse_req_t req, fuse_ino_t parent, const char *name,
int saved_errno;
int srcfd = -1;
int destfd = -1;
struct ovl_node key, *rm = NULL;
if (ovl_debug (req))
fprintf (stderr, "ovl_rename(ino=%" PRIu64 "s, name=%s , ino=%" PRIu64 "s, name=%s)\n", parent, name, newparent, newname);
struct ovl_node *rm1, *rm2;
char *tmp;
node = do_lookup_file (lo, parent, name);
if (node == NULL)
@ -2626,170 +2624,52 @@ ovl_rename (fuse_req_t req, fuse_ino_t parent, const char *name,
if (node == NULL)
goto error;
if (flags & RENAME_EXCHANGE)
if (destnode == NULL)
{
if (destnode == NULL)
{
errno = ENOENT;
goto error;
}
if (node_dirp (node) && destnode->present_lowerdir)
{
fuse_reply_err (req, EXDEV);
return;
}
destnode = get_node_up (lo, destnode);
if (destnode == NULL)
goto error;
errno = ENOENT;
goto error;
}
else
if (node_dirp (node) && destnode->present_lowerdir)
{
key.name = (char *) newname;
if (flags & RENAME_NOREPLACE)
{
rm = hash_lookup (destpnode->children, &key);
if (rm && !rm->whiteout)
{
errno = EEXIST;
goto error;
}
}
if (destnode != NULL && !destnode->whiteout && node_dirp (destnode))
{
size_t whiteouts = 0;
destnode = load_dir (lo, destnode, destnode->layer, destnode->path, destnode->name);
if (destnode == NULL)
goto error;
if (count_dir_entries (destnode, &whiteouts) > 0)
{
errno = ENOTEMPTY;
goto error;
}
if (whiteouts && empty_dir (lo, destnode) < 0)
goto error;
if (create_missing_whiteouts (lo, node, destnode->path) < 0)
{
fuse_reply_err (req, errno);
return;
}
}
rm = hash_lookup (destpnode->children, &key);
if (rm)
{
if (!rm->whiteout && rm->ino == node->ino)
goto error;
if (node_dirp (node) && rm->present_lowerdir)
{
if (create_missing_whiteouts (lo, node, rm->path) < 0)
goto error;
}
hash_delete (destpnode->children, rm);
if (rm->lookups > 0)
node_free (rm);
else
{
node_free (rm);
rm = NULL;
}
if (rm)
{
/* If the node is still accessible then be sure we
can write to it. Fix it to be done when a write is
really done, not now. */
rm = get_node_up (lo, rm);
if (rm == NULL)
{
fuse_reply_err (req, errno);
return;
}
if (hide_node (lo, rm, false) < 0)
goto error;
}
}
fuse_reply_err (req, EXDEV);
return;
}
destnode = get_node_up (lo, destnode);
if (destnode == NULL)
goto error;
if (flags & RENAME_EXCHANGE)
ret = syscall (SYS_renameat2, srcfd, name, destfd, newname, flags);
if (ret < 0)
goto error;
rm1 = hash_delete (destpnode->children, destnode);
rm2 = hash_delete (pnode->children, node);
tmp = node->path;
node->path = destnode->path;
destnode->path = tmp;
tmp = node->name;
node->name = destnode->name;
destnode->name = tmp;
node = insert_node (destpnode, node, true);
if (node == NULL)
{
struct ovl_node *rm1, *rm2;
char *tmp;
ret = syscall (SYS_renameat2, srcfd, name, destfd, newname, flags);
if (ret < 0)
goto error;
rm1 = hash_delete (destpnode->children, destnode);
rm2 = hash_delete (pnode->children, node);
tmp = node->path;
node->path = destnode->path;
destnode->path = tmp;
tmp = node->name;
node->name = destnode->name;
destnode->name = tmp;
node = insert_node (destpnode, node, true);
if (node == NULL)
{
node_free (rm1);
node_free (rm2);
goto error;
}
destnode = insert_node (pnode, destnode, true);
if (destnode == NULL)
{
node_free (rm1);
node_free (rm2);
goto error;
}
if ((update_paths (node) < 0) || (update_paths (destnode) < 0))
goto error;
node_free (rm1);
node_free (rm2);
goto error;
}
else
destnode = insert_node (pnode, destnode, true);
if (destnode == NULL)
{
unlinkat (destfd, newname, 0);
/* 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);
if (ret < 0)
{
ret = syscall (SYS_renameat2, srcfd, name, destfd, newname, flags);
if (ret < 0)
goto error;
ret = create_whiteout (lo, pnode, name);
if (ret < 0)
goto error;
}
hash_delete (pnode->children, node);
free (node->name);
node->name = strdup (newname);
if (node->name == NULL)
{
ret = -1;
goto error;
}
node = insert_node (destpnode, node, true);
if (node == NULL)
goto error;
if (update_paths (node) < 0)
goto error;
node_free (rm1);
node_free (rm2);
goto error;
}
if ((update_paths (node) < 0) || (update_paths (destnode) < 0))
goto error;
if (delete_whiteout (lo, destfd, NULL, newname) < 0)
goto error;
@ -2811,6 +2691,210 @@ ovl_rename (fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_reply_err (req, ret == 0 ? 0 : errno);
}
static void
ovl_rename_direct (fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_ino_t newparent, const char *newname,
unsigned int flags)
{
struct ovl_node *pnode, *node, *destnode, *destpnode;
struct ovl_data *lo = ovl_data (req);
int ret;
int saved_errno;
int srcfd = -1;
int destfd = -1;
struct ovl_node key, *rm = NULL;
node = do_lookup_file (lo, parent, name);
if (node == NULL)
{
fuse_reply_err (req, ENOENT);
return;
}
if (node_dirp (node))
{
node = load_dir (lo, node, node->layer, node->path, node->name);
if (node == NULL)
{
fuse_reply_err (req, errno);
return;
}
if (node->layer != get_upper_layer (lo) || node->present_lowerdir)
{
fuse_reply_err (req, EXDEV);
return;
}
}
pnode = node->parent;
destpnode = do_lookup_file (lo, newparent, NULL);
destnode = NULL;
pnode = get_node_up (lo, pnode);
if (pnode == NULL)
goto error;
ret = TEMP_FAILURE_RETRY (openat (node_dirfd (pnode), pnode->path, O_DIRECTORY));
if (ret < 0)
goto error;
srcfd = ret;
destpnode = get_node_up (lo, destpnode);
if (destpnode == NULL)
goto error;
ret = TEMP_FAILURE_RETRY (openat (node_dirfd (destpnode), destpnode->path, O_DIRECTORY));
if (ret < 0)
goto error;
destfd = ret;
destnode = do_lookup_file (lo, newparent, newname);
node = get_node_up (lo, node);
if (node == NULL)
goto error;
key.name = (char *) newname;
if (flags & RENAME_NOREPLACE)
{
rm = hash_lookup (destpnode->children, &key);
if (rm && !rm->whiteout)
{
errno = EEXIST;
goto error;
}
}
if (destnode != NULL && !destnode->whiteout && node_dirp (destnode))
{
size_t whiteouts = 0;
destnode = load_dir (lo, destnode, destnode->layer, destnode->path, destnode->name);
if (destnode == NULL)
goto error;
if (count_dir_entries (destnode, &whiteouts) > 0)
{
errno = ENOTEMPTY;
goto error;
}
if (whiteouts && empty_dir (lo, destnode) < 0)
goto error;
if (create_missing_whiteouts (lo, node, destnode->path) < 0)
{
fuse_reply_err (req, errno);
return;
}
}
rm = hash_lookup (destpnode->children, &key);
if (rm)
{
if (!rm->whiteout && rm->ino == node->ino)
goto error;
if (node_dirp (node) && rm->present_lowerdir)
{
if (create_missing_whiteouts (lo, node, rm->path) < 0)
goto error;
}
hash_delete (destpnode->children, rm);
if (rm->lookups > 0)
node_free (rm);
else
{
node_free (rm);
rm = NULL;
}
if (rm)
{
/* If the node is still accessible then be sure we
can write to it. Fix it to be done when a write is
really done, not now. */
rm = get_node_up (lo, rm);
if (rm == NULL)
{
fuse_reply_err (req, errno);
return;
}
if (hide_node (lo, rm, false) < 0)
goto error;
}
}
unlinkat (destfd, newname, 0);
/* 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);
if (ret < 0)
{
ret = syscall (SYS_renameat2, srcfd, name, destfd, newname, flags);
if (ret < 0)
goto error;
ret = create_whiteout (lo, pnode, name);
if (ret < 0)
goto error;
}
hash_delete (pnode->children, node);
free (node->name);
node->name = strdup (newname);
if (node->name == NULL)
{
ret = -1;
goto error;
}
node = insert_node (destpnode, node, true);
if (node == NULL)
goto error;
if (update_paths (node) < 0)
goto error;
if (delete_whiteout (lo, destfd, NULL, newname) < 0)
goto error;
ret = 0;
goto cleanup;
error:
ret = -1;
cleanup:
saved_errno = errno;
if (srcfd >= 0)
close (srcfd);
if (destfd >= 0)
close (destfd);
errno = saved_errno;
fuse_reply_err (req, ret == 0 ? 0 : errno);
}
static void
ovl_rename (fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_ino_t newparent, const char *newname,
unsigned int flags)
{
if (ovl_debug (req))
fprintf (stderr, "ovl_rename(ino=%" PRIu64 "s, name=%s , ino=%" PRIu64 "s, name=%s)\n", parent, name, newparent, newname);
if (flags & RENAME_EXCHANGE)
ovl_rename_exchange (req, parent, name, newparent, newname, flags);
else
ovl_rename_direct (req, parent, name, newparent, newname, flags);
}
static void
ovl_statfs (fuse_req_t req, fuse_ino_t ino)
{