[PATCH] 312707: moving a file or folder onto itself destroys it



Steps to reproduce:
1. mkdir -p parent1/folder
2. ln -s parent1 parent2
3. nautilus parent1 parent2
4. drag 'folder' across
5. confirm replace

Actual results:
'folder' deleted

The attached patch is not quite a correct fix -- when move+replacing identical but separate hardlinks it fails to remove the source.

http://bugzilla.gnome.org/show_bug.cgi?id=312707#c2

't.
? gnome-vfs-xfer.loT
Index: gnome-vfs-xfer.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-xfer.c,v
retrieving revision 1.125
diff -p -U9 -r1.125 gnome-vfs-xfer.c
--- gnome-vfs-xfer.c	8 Jul 2005 08:53:18 -0000	1.125
+++ gnome-vfs-xfer.c	5 Aug 2005 23:33:11 -0000
@@ -998,81 +998,100 @@ handle_name_conflicts (GList **source_ur
 	if (conflict_count == 0) {
 		/* No conflicts, we are done. */
 		return GNOME_VFS_OK;
 	}
 
 	/* Pass in the conflict count so that we can decide to present the Replace All
 	 * for multiple conflicts.
 	 */
 	progress->progress_info->duplicate_count = conflict_count;
-	
+
+	source_info = gnome_vfs_file_info_new ();
 	target_info = gnome_vfs_file_info_new ();
 	
 	/* Go through the list of names again, present overwrite alerts for each. */
 	for (target_item = *target_uri_list, source_item = *source_uri_list; 
 	     target_item != NULL;) {
 		gboolean replace;
 		gboolean skip;
-		gboolean is_move_to_self;
+		gboolean is_move;
+		gboolean to_self;
 		GnomeVFSURI *uri, *source_uri;
 		gboolean must_copy;
+		gboolean have_source_info = FALSE;
+		gboolean have_target_info = FALSE;
 
 		must_copy = FALSE;
 		skip = FALSE;
 		source_uri = (GnomeVFSURI *)source_item->data;
 		uri = (GnomeVFSURI *)target_item->data;
-		is_move_to_self = (xfer_options & GNOME_VFS_XFER_REMOVESOURCE) != 0
-			&& gnome_vfs_uri_equal (source_uri, uri);
-		if (!is_move_to_self &&
-		    gnome_vfs_get_file_info_uri (uri, target_info, GNOME_VFS_FILE_INFO_DEFAULT) == GNOME_VFS_OK) {
+		is_move = (xfer_options & GNOME_VFS_XFER_REMOVESOURCE) != 0;
+		to_self = gnome_vfs_uri_equal (source_uri, uri);
+
+		/* FIXME gnome_vfs_file_info_matches is a subtly wrong check
+		 * for to_self; if source and target are identical hardlinks,
+		 * source won't be deleted on move. A correct solution could
+		 * be e.g. a hypothetical physical_uri_equal (realpath on
+		 * file:), or renaming (or Trashing) the target and seeing if
+		 * the source disappeared...
+		 */
+		if (!(is_move && to_self)) {
+			have_target_info = (GNOME_VFS_OK == gnome_vfs_get_file_info_uri (uri, target_info, GNOME_VFS_FILE_INFO_DEFAULT));
+			if (have_target_info) {
+				have_source_info = (GNOME_VFS_OK == gnome_vfs_get_file_info_uri (source_uri, source_info, GNOME_VFS_FILE_INFO_DEFAULT));
+				if (have_source_info) {
+					to_self = gnome_vfs_file_info_matches (source_info, target_info);
+				}
+			}
+		}
+
+		if (!(is_move && to_self) && have_target_info) {
 			progress_set_source_target_uris (progress, source_uri, uri);
 			
 			/* no error getting info -- file exists, ask what to do */
 			replace = handle_overwrite (&result, progress, error_mode,
 						    overwrite_mode, &replace, &skip);
 			
 			/* FIXME bugzilla.eazel.com 1207:
 			 * move items to Trash here
 			 */
 			
 			/* get rid of the conflicting file */
 			if (replace) {
 				progress_set_source_target_uris (progress, uri, NULL);
 				if (target_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
 					if (move_source_is_in_target (source_uri, uri)) {
 						/* Would like a better error here */
 						result = GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY;
 					} else {
-						source_info = gnome_vfs_file_info_new ();
 						if (!link &&
-						    gnome_vfs_get_file_info_uri (source_uri, source_info, GNOME_VFS_FILE_INFO_DEFAULT) == GNOME_VFS_OK &&
+						    (have_source_info || GNOME_VFS_OK == gnome_vfs_get_file_info_uri (source_uri, source_info, GNOME_VFS_FILE_INFO_DEFAULT)) &&
 						    source_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
 							if (move || (xfer_options & GNOME_VFS_XFER_RECURSIVE)) {
 								result = handle_merged_directory_name_conflicts (xfer_options, error_mode,
 														 progress, source_uri, uri);
 							}
 							must_copy = TRUE;
 						} else {
 							result = remove_directory (uri, TRUE, progress, 
 										   xfer_options, error_mode, &skip);
 						}
-						gnome_vfs_file_info_unref (source_info);
 					}
 				} else {
 					result = remove_file (uri, progress,
 							      xfer_options, error_mode, &skip);
 				}
 			}
-			
-			gnome_vfs_file_info_clear (target_info);
 		}
 
-		
+		gnome_vfs_file_info_clear (source_info);
+		gnome_vfs_file_info_clear (target_info);
+
 		if (result != GNOME_VFS_OK) {
 			break;
 		}
 
 		if (skip) {
 			/* skipping a file, remove it's name from the source and target name
 			 * lists.
 			 */
 			source_item_to_remove = source_item;
@@ -1103,18 +1122,20 @@ handle_name_conflicts (GList **source_ur
 			*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);
 			
 			continue;
 		}
 
 		target_item = target_item->next; 
 		source_item = source_item->next;
 	}
+			    
+	gnome_vfs_file_info_unref (source_info);
 	gnome_vfs_file_info_unref (target_info);
 	
 	return result;
 }
 
 /* Create new directory. If GNOME_VFS_XFER_USE_UNIQUE_NAMES is set, 
  * return with an error if a name conflict occurs, else
  * handle the overwrite.
  * On success, opens the new directory
@@ -2348,18 +2369,19 @@ gnome_vfs_xfer_uri_internal (const GList
 		handle_error (&result, progress, &error_mode, &skip);
 		gnome_vfs_uri_unref (target_dir_uri);
 		return result;
 	}
 
 	move = (xfer_options & GNOME_VFS_XFER_REMOVESOURCE) != 0;
 	link = (xfer_options & GNOME_VFS_XFER_LINK_ITEMS) != 0;
 
 	if (move && link) {
+		gnome_vfs_uri_unref (target_dir_uri);
 		return GNOME_VFS_ERROR_BAD_PARAMETERS;
 	}
 
 	/* Create an owning list of source and destination uris.
 	 * We want to be able to remove items that we decide to skip during
 	 * name conflict check.
 	 */
 	source_uri_list = gnome_vfs_uri_list_copy ((GList *)source_uris);
 	target_uri_list = gnome_vfs_uri_list_copy ((GList *)target_uris);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]