Use the new gs_dirfd_iterator api in symlink_tree

tingping/wmclass
Alexander Larsson 2015-01-12 16:05:12 +01:00
parent 206bf95fa3
commit b8c29f18ae
1 changed files with 54 additions and 76 deletions

View File

@ -100,84 +100,77 @@ overlay_symlink_tree_dir (int source_parent_fd,
{
gboolean ret = FALSE;
int res;
int source_dfd = -1;
int destination_dfd = -1;
DIR *srcd = NULL;
gs_dirfd_iterator_cleanup GSDirFdIterator source_iter;
gs_fd_close int destination_dfd = -1;
struct dirent *dent;
if (source_name == NULL)
source_dfd = source_parent_fd; /* We take ownership of the passed fd and close it */
else
if (!gs_dirfd_iterator_init_at (source_parent_fd, source_name, FALSE, &source_iter, error))
goto out;
do
res = mkdirat (destination_parent_fd, destination_name, 0777);
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (res == -1)
{
if (!gs_file_open_dir_fd_at (source_parent_fd, source_name,
&source_dfd,
cancellable, error))
goto out;
}
if (destination_name == NULL)
destination_dfd = destination_parent_fd; /* We take ownership of the passed fd and close it */
else
{
do
res = mkdirat (destination_parent_fd, destination_name, 0777);
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (res == -1)
{
if (errno != EEXIST)
{
gs_set_error_from_errno (error, errno);
goto out;
}
}
if (!gs_file_open_dir_fd_at (destination_parent_fd, destination_name,
&destination_dfd,
cancellable, error))
goto out;
}
srcd = fdopendir (source_dfd);
if (!srcd)
{
gs_set_error_from_errno (error, errno);
goto out;
}
while ((dent = readdir (srcd)) != NULL)
{
const char *name = dent->d_name;
struct stat child_stbuf;
if (strcmp (name, ".") == 0 ||
strcmp (name, "..") == 0)
continue;
if (fstatat (source_dfd, name, &child_stbuf,
AT_SYMLINK_NOFOLLOW) != 0)
if (errno != EEXIST)
{
gs_set_error_from_errno (error, errno);
goto out;
}
}
if (S_ISDIR (child_stbuf.st_mode))
if (!gs_file_open_dir_fd_at (destination_parent_fd, destination_name,
&destination_dfd,
cancellable, error))
goto out;
while (TRUE)
{
gboolean is_dir = FALSE;
if (!gs_dirfd_iterator_next_dent (&source_iter, &dent, cancellable, error))
goto out;
if (dent == NULL)
break;
if (dent->d_type == DT_DIR)
is_dir = TRUE;
else if (dent->d_type == DT_UNKNOWN)
{
gs_free gchar *target = g_build_filename ("..", source_symlink_prefix, name, NULL);
if (!overlay_symlink_tree_dir (source_dfd, name, target, destination_dfd, name,
struct stat stbuf;
if (fstatat (source_iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
{
int errsv = errno;
if (errsv == ENOENT)
continue;
else
{
gs_set_error_from_errno (error, errsv);
goto out;
}
}
is_dir = S_ISDIR (stbuf.st_mode);
}
if (is_dir)
{
gs_free gchar *target = g_build_filename ("..", source_symlink_prefix, dent->d_name, NULL);
if (!overlay_symlink_tree_dir (source_iter.fd, dent->d_name, target, destination_dfd, dent->d_name,
cancellable, error))
goto out;
}
else
{
gs_free gchar *target = g_build_filename (source_symlink_prefix, name, NULL);
gs_free gchar *target = g_build_filename (source_symlink_prefix, dent->d_name, NULL);
if (unlinkat (destination_dfd, name, 0) != 0 && errno != ENOENT)
if (unlinkat (destination_dfd, dent->d_name, 0) != 0 && errno != ENOENT)
{
gs_set_error_from_errno (error, errno);
goto out;
}
if (symlinkat (target, destination_dfd, name) != 0)
if (symlinkat (target, destination_dfd, dent->d_name) != 0)
{
gs_set_error_from_errno (error, errno);
goto out;
@ -187,12 +180,6 @@ overlay_symlink_tree_dir (int source_parent_fd,
ret = TRUE;
out:
if (srcd != NULL)
closedir (srcd); /* This closes source_dfd */
else if (source_dfd != -1)
close (source_dfd);
if (destination_dfd != -1)
close (destination_dfd);
return ret;
}
@ -205,23 +192,14 @@ xdg_app_overlay_symlink_tree (GFile *source,
GError **error)
{
gboolean ret = FALSE;
int source_dfd = -1;
int destination_dfd = -1;
if (!gs_file_open_dir_fd (source, &source_dfd, cancellable, error))
if (!gs_file_ensure_directory (destination, TRUE, cancellable, error))
goto out;
if (!gs_file_ensure_directory (destination, TRUE, cancellable, error) ||
!gs_file_open_dir_fd (destination, &destination_dfd, cancellable, error))
{
close (source_dfd);
goto out;
}
/* The fds are closed by this call */
if (!overlay_symlink_tree_dir (source_dfd, NULL,
if (!overlay_symlink_tree_dir (AT_FDCWD, gs_file_get_path_cached (source),
symlink_prefix,
destination_dfd, NULL,
AT_FDCWD, gs_file_get_path_cached (destination),
cancellable, error))
goto out;