Re: [PATCH] 312707: moving a file or folder onto itself destroys it
- From: Alexander Larsson <alexl redhat com>
- To: Tuukka Tolvanen <tuukka tolvanen gmail com>
- Cc: gnome-vfs-list gnome org
- Subject: Re: [PATCH] 312707: moving a file or folder onto itself destroys it
- Date: Thu, 25 Aug 2005 17:29:56 +0200
On Thu, 2005-08-25 at 12:38 +0200, Alexander Larsson wrote:
> On Sat, 2005-08-06 at 21:51 +0300, Tuukka Tolvanen wrote:
> > Tuukka Tolvanen wrote:
> >
> > > The attached patch is not quite a correct fix -- when move+replacing
> > > identical but separate hardlinks it fails to remove the source.
> >
> > bah. I threw another candidate on bugzilla that fixes /that/ issue:
> > - check for directory entry name match, then
> > - check for directory entry namespace match (same parent fileinfo)
> >
> > http://bugzilla.gnome.org/show_bug.cgi?id=312707#c3
>
> Hmmm. bugzilla down atm...
>
> > ...but then realized it's not the right solution either -- on e.g. ftp,
> > we don't get any decent identifying information in file_info so the
> > same-parent-folder test would be susceptible to false positives.
> >
> > Besides, the same filesystem could be reachable via multiple methods at
> > the same time anyhow, which renders fs entry identity comparisons pretty
> > academic. Temp-renaming targets that are in the way, instead of
> > deleting, seems to be the only way to really cover all the cases, that I
> > can think of. Does that sound right?
>
> I dislike both the initial fix and doing temp renaming. They introduce
> even more stats and other i/o into an already slow gnome_vfs_xfer. Also,
> such solutions sounds inherently racy.
>
> The kernel allows a move (rename) from parent2/folder to parent1/folder.
> It just returns success and does nothing. I wonder why a gnome-vfs-xfer
> removes the file. Shouldn't it just end up being a gnome_vfs_move (since
> the files are on the same filesystem), which shouldn't remove the file?
Damn, I tried this out (see attached not-very-tested patch), but it
didn't work out. The problem is that we on name conflicts of directory
moves, if you pick "replace" it actually switches into a merge, which is
done by changing from a move operation to a recursive copy + remove.
:(
Not sure what a good solution is here.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Alexander Larsson Red Hat, Inc
alexl redhat com alla lysator liu se
He's a world-famous overambitious firefighter on his last day in the job.
She's a virginal tempestuous wrestler with an MBA from Harvard. They fight
crime!
Index: libgnomevfs/gnome-vfs-xfer.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-xfer.c,v
retrieving revision 1.125
diff -u -p -r1.125 gnome-vfs-xfer.c
--- libgnomevfs/gnome-vfs-xfer.c 8 Jul 2005 08:53:18 -0000 1.125
+++ libgnomevfs/gnome-vfs-xfer.c 25 Aug 2005 15:26:39 -0000
@@ -2325,7 +2325,7 @@ gnome_vfs_xfer_uri_internal (const GList
GList *source_uri_list, *target_uri_list;
GList *source_uri, *target_uri;
GList *source_uri_list_copied;
- GList *merge_source_uri_list, *merge_target_uri_list;
+ GList *move_source_uri_list, *move_target_uri_list;
GnomeVFSURI *target_dir_uri;
gboolean move, link;
GnomeVFSFileSize free_bytes;
@@ -2363,28 +2363,37 @@ gnome_vfs_xfer_uri_internal (const GList
*/
source_uri_list = gnome_vfs_uri_list_copy ((GList *)source_uris);
target_uri_list = gnome_vfs_uri_list_copy ((GList *)target_uris);
- merge_source_uri_list = NULL;
- merge_target_uri_list = NULL;
+ move_source_uri_list = NULL;
+ move_target_uri_list = NULL;
- if ((xfer_options & GNOME_VFS_XFER_USE_UNIQUE_NAMES) == 0) {
+ if (move &&
+ (xfer_options & GNOME_VFS_XFER_USE_UNIQUE_NAMES) == 0) {
/* see if moved files are on the same file system so that we decide to do
* a simple move or have to do a copy/remove
*/
- for (source_uri = source_uri_list, target_uri = target_uri_list;
- source_uri != NULL;
- source_uri = source_uri->next, target_uri = target_uri->next) {
+ source_uri = source_uri_list;
+ target_uri = target_uri_list;
+ while (source_uri != NULL) {
+ GList *source_item_to_remove;
+ GList *target_item_to_remove;
gboolean same_fs;
g_assert (target_dir_uri != NULL);
result = gnome_vfs_check_same_fs_uris ((GnomeVFSURI *)source_uri->data,
- target_dir_uri, &same_fs);
+ target_dir_uri, &same_fs);
- if (result != GNOME_VFS_OK) {
- break;
+ source_item_to_remove = source_uri;
+ target_item_to_remove = target_uri;
+ source_uri = source_uri->next;
+ target_uri = target_uri->next;
+
+ if (result == GNOME_VFS_OK && same_fs) {
+ move_source_uri_list = g_list_prepend (move_source_uri_list, (GnomeVFSURI *)source_item_to_remove->data);
+ move_target_uri_list = g_list_prepend (move_target_uri_list, (GnomeVFSURI *)target_item_to_remove->data);
+ source_uri_list = g_list_remove_link (source_uri_list, source_item_to_remove);
+ target_uri_list = g_list_remove_link (target_uri_list, target_item_to_remove);
}
-
- move &= same_fs;
}
}
@@ -2393,9 +2402,18 @@ gnome_vfs_xfer_uri_internal (const GList
target_dir_uri = NULL;
}
+ call_progress (progress, GNOME_VFS_XFER_PHASE_COLLECTING);
+ if (move_source_uri_list != NULL) {
+ result = count_items_and_size (move_source_uri_list, xfer_options, progress, TRUE, link);
+ if (result != GNOME_VFS_ERROR_INTERRUPTED) {
+ /* Ignore anything but interruptions here -- we will deal with the errors
+ * during the actual copy
+ */
+ result = GNOME_VFS_OK;
+ }
+ }
if (result == GNOME_VFS_OK) {
- call_progress (progress, GNOME_VFS_XFER_PHASE_COLLECTING);
- result = count_items_and_size (source_uri_list, xfer_options, progress, move, link);
+ result = count_items_and_size (source_uri_list, xfer_options, progress, FALSE, link);
if (result != GNOME_VFS_ERROR_INTERRUPTED) {
/* Ignore anything but interruptions here -- we will deal with the errors
* during the actual copy
@@ -2408,11 +2426,13 @@ gnome_vfs_xfer_uri_internal (const GList
/* Calculate free space on destination. If an error is returned, we have a non-local
* file system, so we just forge ahead and hope for the best
*/
- target_dir_uri = gnome_vfs_uri_get_parent ((GnomeVFSURI *)target_uri_list->data);
+
+ target_uri = (target_uri_list != NULL) ? target_uri_list : move_target_uri_list;
+ target_dir_uri = gnome_vfs_uri_get_parent ((GnomeVFSURI *)target_uri->data);
result = gnome_vfs_get_volume_free_space (target_dir_uri, &free_bytes);
if (result == GNOME_VFS_OK) {
- if (!move && !link && progress->progress_info->bytes_total > free_bytes) {
+ if (!link && progress->progress_info->bytes_total > free_bytes) {
result = GNOME_VFS_ERROR_NO_SPACE;
progress_set_source_target_uris (progress, NULL, target_dir_uri);
handle_error (&result, progress, &error_mode, &skip);
@@ -2428,11 +2448,12 @@ gnome_vfs_xfer_uri_internal (const GList
}
if (result != GNOME_VFS_OK) {
- return result;
+ goto error;
}
if ((xfer_options & GNOME_VFS_XFER_USE_UNIQUE_NAMES) == 0) {
-
+ GList *merge_source_uri_list, *merge_target_uri_list;
+
/* Save the preflight numbers, handle_name_conflicts would overwrite them */
bytes_total = progress->progress_info->bytes_total;
files_total = progress->progress_info->files_total;
@@ -2443,18 +2464,31 @@ gnome_vfs_xfer_uri_internal (const GList
progress->progress_info->bytes_total = 0;
progress->progress_info->files_total = 0;
- result = handle_name_conflicts (&source_uri_list, &target_uri_list,
- xfer_options, &error_mode, &overwrite_mode,
- progress,
- move,
- link,
- &merge_source_uri_list,
- &merge_target_uri_list);
+ merge_source_uri_list = NULL;
+ merge_target_uri_list = NULL;
+
+ if (move_source_uri_list != NULL) {
+ result = handle_name_conflicts (&move_source_uri_list, &move_target_uri_list,
+ xfer_options, &error_mode, &overwrite_mode,
+ progress,
+ TRUE,
+ link,
+ &merge_source_uri_list,
+ &merge_target_uri_list);
+ }
+ if (result == GNOME_VFS_OK) {
+ result = handle_name_conflicts (&source_uri_list, &target_uri_list,
+ xfer_options, &error_mode, &overwrite_mode,
+ progress,
+ FALSE,
+ link,
+ NULL, NULL);
+ }
progress->progress_info->bytes_total = 0;
progress->progress_info->files_total = 0;
- if (result == GNOME_VFS_OK && move && merge_source_uri_list != NULL) {
+ if (result == GNOME_VFS_OK && merge_source_uri_list != NULL) {
/* Some moves was converted to copy,
remove previously added non-recursive sizes,
and add recursive sizes */
@@ -2488,7 +2522,7 @@ gnome_vfs_xfer_uri_internal (const GList
result = gnome_vfs_get_volume_free_space (target_dir_uri, &free_bytes);
if (result == GNOME_VFS_OK) {
- if (progress->progress_info->bytes_total > free_bytes) {
+ if (progress->progress_info->bytes_total + bytes_total > free_bytes) {
result = GNOME_VFS_ERROR_NO_SPACE;
progress_set_source_target_uris (progress, NULL, target_dir_uri);
}
@@ -2502,6 +2536,10 @@ gnome_vfs_xfer_uri_internal (const GList
target_dir_uri = NULL;
}
}
+
+ /* Now make the merge items normal copy ops */
+ source_uri_list = g_list_concat (source_uri_list, merge_source_uri_list);
+ target_uri_list = g_list_concat (target_uri_list, merge_target_uri_list);
}
/* Add previous size (non-copy size in the case of a move) */
@@ -2523,42 +2561,40 @@ gnome_vfs_xfer_uri_internal (const GList
} else {
call_progress (progress, GNOME_VFS_XFER_PHASE_READYTOGO);
- if (move) {
- g_assert (!link);
- result = move_items (source_uri_list, target_uri_list,
- xfer_options, &error_mode, &overwrite_mode,
- progress);
- if (result == GNOME_VFS_OK && merge_source_uri_list != NULL) {
- result = copy_items (merge_source_uri_list, merge_target_uri_list,
+ if (!link) {
+ if (move_source_uri_list != NULL) {
+ result = move_items (move_source_uri_list, move_target_uri_list,
+ xfer_options, &error_mode, &overwrite_mode,
+ progress);
+ }
+ if (result == GNOME_VFS_OK && source_uri_list != NULL) {
+ result = copy_items (source_uri_list, target_uri_list,
xfer_options, &error_mode, overwrite_mode,
progress, &source_uri_list_copied);
}
- } else if (link) {
+ if (result == GNOME_VFS_OK &&
+ xfer_options & GNOME_VFS_XFER_REMOVESOURCE) {
+ call_progress (progress, GNOME_VFS_XFER_PHASE_CLEANUP);
+ result = gnome_vfs_xfer_delete_items_common (source_uri_list_copied,
+ error_mode, xfer_options, progress);
+ }
+
+ } else {
result = link_items (source_uri_list, target_uri_list,
xfer_options, &error_mode, &overwrite_mode,
progress);
- } else {
- result = copy_items (source_uri_list, target_uri_list,
- xfer_options, &error_mode, overwrite_mode,
- progress, &source_uri_list_copied);
}
- if (result == GNOME_VFS_OK) {
- if (xfer_options & GNOME_VFS_XFER_REMOVESOURCE
- && !link) {
- call_progress (progress, GNOME_VFS_XFER_PHASE_CLEANUP);
- result = gnome_vfs_xfer_delete_items_common (
- source_uri_list_copied,
- error_mode, xfer_options, progress);
- }
- }
}
}
+
+ error:
+
gnome_vfs_uri_list_free (source_uri_list);
gnome_vfs_uri_list_free (target_uri_list);
- gnome_vfs_uri_list_free (merge_source_uri_list);
- gnome_vfs_uri_list_free (merge_target_uri_list);
+ gnome_vfs_uri_list_free (move_source_uri_list);
+ gnome_vfs_uri_list_free (move_target_uri_list);
gnome_vfs_uri_list_free (source_uri_list_copied);
return result;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]