nautilus r14438 - in trunk: . libnautilus-private



Author: cneumair
Date: Sun Aug  3 12:50:51 2008
New Revision: 14438
URL: http://svn.gnome.org/viewvc/nautilus?rev=14438&view=rev

Log:
2008-08-03  Christian Neumair  <cneumair gnome org>

	* libnautilus-private/nautilus-file-operations.c (str_replace),
	(make_file_name_valid_for_dest_fs), (get_unique_target_file),
	(get_target_file_for_link), (get_target_file), (create_dest_dir),
	(copy_move_directory), (query_fs_type), (copy_move_file),
	(copy_files), (move_file_prepare), (move_files_prepare),
	(move_files), (move_job), (link_file), (link_job), (create_job):
	Support transfer of files with reserved characters to FAT. Auto-escape
	them to the unreserved underscore character. Fixes #448148.


Modified:
   trunk/ChangeLog
   trunk/libnautilus-private/nautilus-file-operations.c

Modified: trunk/libnautilus-private/nautilus-file-operations.c
==============================================================================
--- trunk/libnautilus-private/nautilus-file-operations.c	(original)
+++ trunk/libnautilus-private/nautilus-file-operations.c	Sun Aug  3 12:50:51 2008
@@ -197,6 +197,9 @@
 				 GCancellable *cancellable,
 				 gpointer user_data);
 
+static char * query_fs_type (GFile *file,
+			     GCancellable *cancellable);
+
 static char *
 format_time (int seconds)
 {
@@ -2857,10 +2860,50 @@
 	return max_length;
 }
 
+#define FAT_FORBIDDEN_CHARACTERS "/:;*?\"<>"
+
+static gboolean
+str_replace (char *str,
+	     const char *chars_to_replace,
+	     char replacement)
+{
+	gboolean success;
+	int i;
+
+	success = FALSE;
+	for (i = 0; str[i] != '\0'; i++) {
+		if (strchr (chars_to_replace, str[i])) {
+			success = TRUE;
+			str[i] = replacement;
+		}
+	}
+
+	return success;
+}
+
+static gboolean
+make_file_name_valid_for_dest_fs (char *filename,
+				 const char *dest_fs_type)
+{
+	if (dest_fs_type != NULL && filename != NULL) {
+		if (!strcmp (dest_fs_type, "fat")  ||
+		    !strcmp (dest_fs_type, "vfat") ||
+		    !strcmp (dest_fs_type, "msdos") ||
+		    !strcmp (dest_fs_type, "msdosfs")) {
+			gboolean ret;
+			ret = str_replace (filename, FAT_FORBIDDEN_CHARACTERS, '_');
+			return ret;
+		}
+	}
+
+	return FALSE;
+}
+
 static GFile *
 get_unique_target_file (GFile *src,
 			GFile *dest_dir,
 			gboolean same_fs,
+			const char *dest_fs_type,
 			int count)
 {
 	const char *editname, *end;
@@ -2880,6 +2923,7 @@
 		
 		if (editname != NULL) {
 			new_name = get_duplicate_name (editname, count, max_length);
+			make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
 			dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL);
 			g_free (new_name);
 		}
@@ -2892,6 +2936,7 @@
 
 		if (g_utf8_validate (basename, -1, NULL)) {
 			new_name = get_duplicate_name (basename, count, max_length);
+			make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
 			dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL);
 			g_free (new_name);
 		} 
@@ -2902,6 +2947,7 @@
 				count += atoi (end + 1);
 			}
 			new_name = g_strdup_printf ("%s.%d", basename, count);
+			make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
 			dest = g_file_get_child (dest_dir, new_name);
 			g_free (new_name);
 		}
@@ -2915,6 +2961,7 @@
 static GFile *
 get_target_file_for_link (GFile *src,
 			  GFile *dest_dir,
+			  const char *dest_fs_type,
 			  int count)
 {
 	const char *editname;
@@ -2934,6 +2981,7 @@
 		
 		if (editname != NULL) {
 			new_name = get_link_name (editname, count, max_length);
+			make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
 			dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL);
 			g_free (new_name);
 		}
@@ -2943,9 +2991,11 @@
 
 	if (dest == NULL) {
 		basename = g_file_get_basename (src);
+		make_file_name_valid_for_dest_fs (basename, dest_fs_type);
 
 		if (g_utf8_validate (basename, -1, NULL)) {
 			new_name = get_link_name (basename, count, max_length);
+			make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
 			dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL);
 			g_free (new_name);
 		} 
@@ -2956,6 +3006,7 @@
 			} else {
 				new_name = g_strdup_printf ("%s.lnk%d", basename, count);
 			}
+			make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
 			dest = g_file_get_child (dest_dir, new_name);
 			g_free (new_name);
 		}
@@ -2969,12 +3020,13 @@
 static GFile *
 get_target_file (GFile *src,
 		 GFile *dest_dir,
+		 const char *dest_fs_type,
 		 gboolean same_fs)
 {
 	char *basename;
 	GFile *dest;
 	GFileInfo *info;
-	const char *copyname;
+	char *copyname;
 
 	dest = NULL;
 	if (!same_fs) {
@@ -2983,10 +3035,12 @@
 					  0, NULL, NULL);
 		
 		if (info) {
-			copyname = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_COPY_NAME);
+			copyname = g_strdup (g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_COPY_NAME));
 
 			if (copyname) {
+				make_file_name_valid_for_dest_fs (copyname, dest_fs_type);
 				dest = g_file_get_child_for_display_name (dest_dir, copyname, NULL);
+				g_free (copyname);
 			}
 			
 			g_object_unref (info);
@@ -2995,6 +3049,7 @@
 
 	if (dest == NULL) {
 		basename = g_file_get_basename (src);
+		make_file_name_valid_for_dest_fs (basename, dest_fs_type);
 		dest = g_file_get_child (dest_dir, basename);
 		g_free (basename);
 	}
@@ -3052,6 +3107,7 @@
 			    GFile *dest_dir,
 			    gboolean same_fs,
 			    gboolean unique_names,
+			    char **dest_fs_type,
 			    SourceInfo *source_info,
 			    TransferInfo *transfer_info,
 			    GHashTable *debuting_files,
@@ -3059,25 +3115,61 @@
 			    gboolean overwrite,
 			    gboolean *skipped_file);
 
-static gboolean
+typedef enum {
+	CREATE_DEST_DIR_RETRY,
+	CREATE_DEST_DIR_FAILED,
+	CREATE_DEST_DIR_SUCCESS
+} CreateDestDirResult;
+
+static CreateDestDirResult
 create_dest_dir (CommonJob *job,
 		 GFile *src,
-		 GFile *dest)
+		 GFile **dest,
+		 gboolean same_fs,
+		 char **dest_fs_type)
 {
 	GError *error;
+	GFile *new_dest, *dest_dir;
 	char *primary, *secondary, *details;
 	int response;
+	gboolean handled_invalid_filename;
+
+	handled_invalid_filename = *dest_fs_type != NULL;
 
  retry:
 	/* First create the directory, then copy stuff to it before
 	   copying the attributes, because we need to be sure we can write to it */
 	
 	error = NULL;
-	if (!g_file_make_directory (dest, job->cancellable, &error)) {
+	if (!g_file_make_directory (*dest, job->cancellable, &error)) {
 		if (IS_IO_ERROR (error, CANCELLED)) {
 			g_error_free (error);
-			return FALSE;
+			return CREATE_DEST_DIR_FAILED;
+		} else if (IS_IO_ERROR (error, INVALID_FILENAME) &&
+			   !handled_invalid_filename) {
+			handled_invalid_filename = TRUE;
+
+			g_assert (*dest_fs_type == NULL);
+
+			dest_dir = g_file_get_parent (*dest);
+
+			if (dest_dir != NULL) {
+				*dest_fs_type = query_fs_type (dest_dir, job->cancellable);
+
+				new_dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
+				g_object_unref (dest_dir);
+
+				if (!g_file_equal (*dest, new_dest)) {
+					g_object_unref (*dest);
+					*dest = new_dest;
+					g_error_free (error);
+					return CREATE_DEST_DIR_RETRY;
+				} else {
+					g_object_unref (new_dest);
+				}
+			}
 		}
+
 		primary = f (_("Error while copying."));
 		details = NULL;
 		
@@ -3108,18 +3200,25 @@
 		} else {
 			g_assert_not_reached ();
 		}
-		return FALSE;
+		return CREATE_DEST_DIR_FAILED;
 	}
-	nautilus_file_changes_queue_file_added (dest);
-	return TRUE;
+	nautilus_file_changes_queue_file_added (*dest);
+	return CREATE_DEST_DIR_SUCCESS;
 }
 
-static void
+/* a return value of FALSE means retry, i.e.
+ * the destination has changed and the source
+ * is expected to re-try the preceeding
+ * g_file_move() or g_file_copy() call with
+ * the new destination.
+ */
+static gboolean
 copy_move_directory (CopyMoveJob *copy_job,
 		     GFile *src,
-		     GFile *dest,
+		     GFile **dest,
 		     gboolean same_fs,
 		     gboolean create_dest,
+		     char **parent_dest_fs_type,
 		     SourceInfo *source_info,
 		     TransferInfo *transfer_info,
 		     GHashTable *debuting_files,
@@ -3130,6 +3229,7 @@
 	GFile *src_file;
 	GFileEnumerator *enumerator;
 	char *primary, *secondary, *details;
+	char *dest_fs_type;
 	int response;
 	gboolean skip_error;
 	gboolean local_skipped_file;
@@ -3138,17 +3238,31 @@
 	job = (CommonJob *)copy_job;
 	
 	if (create_dest) {
-		if (!create_dest_dir (job, src, dest)) {
-			*skipped_file = TRUE;
-			return;
+		switch (create_dest_dir (job, src, dest, same_fs, parent_dest_fs_type)) {
+			case CREATE_DEST_DIR_RETRY:
+				/* next time copy_move_directory() is called,
+				 * create_dest will be FALSE if a directory already
+				 * exists under the new name (i.e. WOULD_RECURSE)
+				 */
+				return FALSE;
+
+			case CREATE_DEST_DIR_FAILED:
+				*skipped_file = TRUE;
+				return TRUE;
+
+			case CREATE_DEST_DIR_SUCCESS:
+			default:
+				break;
 		}
+
 		if (debuting_files) {
-			g_hash_table_replace (debuting_files, g_object_ref (dest), GINT_TO_POINTER (TRUE));
+			g_hash_table_replace (debuting_files, g_object_ref (*dest), GINT_TO_POINTER (TRUE));
 		}
 
 	}
 
 	local_skipped_file = FALSE;
+	dest_fs_type = NULL;
 	
 	skip_error = should_skip_readdir_error (job, src);
  retry:
@@ -3160,12 +3274,13 @@
 						&error);
 	if (enumerator) {
 		error = NULL;
-		
+
 		while (!job_aborted (job) &&
 		       (info = g_file_enumerator_next_file (enumerator, job->cancellable, skip_error?NULL:&error)) != NULL) {
 			src_file = g_file_get_child (src,
 						     g_file_info_get_name (info));
-			copy_move_file (copy_job, src_file, dest, same_fs, FALSE, source_info, transfer_info, NULL, NULL, FALSE, &local_skipped_file);
+			copy_move_file (copy_job, src_file, *dest, same_fs, FALSE, &dest_fs_type,
+					source_info, transfer_info, NULL, NULL, FALSE, &local_skipped_file);
 			g_object_unref (src_file);
 			g_object_unref (info);
 		}
@@ -3215,7 +3330,7 @@
 		report_copy_progress (copy_job, source_info, transfer_info);
 
 		if (debuting_files) {
-			g_hash_table_replace (debuting_files, g_object_ref (dest), GINT_TO_POINTER (create_dest));
+			g_hash_table_replace (debuting_files, g_object_ref (*dest), GINT_TO_POINTER (create_dest));
 		}
 	} else if (IS_IO_ERROR (error, CANCELLED)) {
 		g_error_free (error);
@@ -3259,7 +3374,7 @@
 
 	if (create_dest) {
 		/* Ignore errors here. Failure to copy metadata is not a hard error */
-		g_file_copy_attributes (src, dest,
+		g_file_copy_attributes (src, *dest,
 					G_FILE_COPY_NOFOLLOW_SYMLINKS,
 					job->cancellable, NULL);
 	}
@@ -3302,6 +3417,9 @@
 	if (local_skipped_file) {
 		*skipped_file = TRUE;
 	}
+
+	g_free (dest_fs_type);
+	return TRUE;
 }
 
 static gboolean
@@ -3480,6 +3598,34 @@
 	return FALSE;
 }
 
+static char *
+query_fs_type (GFile *file,
+	       GCancellable *cancellable)
+{
+	GFileInfo *fsinfo;
+	char *ret;
+
+	ret = NULL;
+
+	fsinfo = g_file_query_filesystem_info (file,
+					       G_FILE_ATTRIBUTE_FILESYSTEM_TYPE,
+					       cancellable,
+					       NULL);
+	if (fsinfo != NULL) {
+		ret = g_strdup (g_file_info_get_attribute_string (fsinfo, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE));
+		g_object_unref (fsinfo);
+	}
+
+	if (ret == NULL) {
+		/* ensure that we don't attempt to query
+		 * the FS type for each file in a given
+		 * directory, if it can't be queried. */
+		ret = g_strdup ("");
+	}
+
+	return ret;
+}
+
 /* Debuting files is non-NULL only for toplevel items */
 static void
 copy_move_file (CopyMoveJob *copy_job,
@@ -3487,6 +3633,7 @@
 		GFile *dest_dir,
 		gboolean same_fs,
 		gboolean unique_names,
+		char **dest_fs_type,
 		SourceInfo *source_info,
 		TransferInfo *transfer_info,
 		GHashTable *debuting_files,
@@ -3494,7 +3641,7 @@
 		gboolean overwrite,
 		gboolean *skipped_file)
 {
-	GFile *dest;
+	GFile *dest, *new_dest;
 	GError *error;
 	GFileCopyFlags flags;
 	char *primary, *secondary, *details;
@@ -3504,6 +3651,7 @@
 	CommonJob *job;
 	gboolean res;
 	int unique_name_nr;
+	gboolean handled_invalid_filename;
 
 	job = (CommonJob *)copy_job;
 	
@@ -3514,10 +3662,15 @@
 
 	unique_name_nr = 1;
 
+	/* another file in the same directory might have handled the invalid
+	 * filename condition for us
+	 */
+	handled_invalid_filename = *dest_fs_type != NULL;
+
 	if (unique_names) {
-		dest = get_unique_target_file (src, dest_dir, same_fs, unique_name_nr++);
+		dest = get_unique_target_file (src, dest_dir, same_fs, *dest_fs_type, unique_name_nr++);
 	} else {
-		dest = get_target_file (src, dest_dir, same_fs);
+		dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
 	}
 
 
@@ -3611,6 +3764,30 @@
 		return;
 	}
 
+	if (!handled_invalid_filename &&
+	    IS_IO_ERROR (error, INVALID_FILENAME)) {
+		handled_invalid_filename = TRUE;
+
+		g_assert (*dest_fs_type == NULL);
+		*dest_fs_type = query_fs_type (dest_dir, job->cancellable);
+
+		if (unique_names) {
+			new_dest = get_unique_target_file (src, dest_dir, same_fs, *dest_fs_type, unique_name_nr);
+		} else {
+			new_dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
+		}
+
+		if (!g_file_equal (dest, new_dest)) {
+			g_object_unref (dest);
+			dest = new_dest;
+
+			g_error_free (error);
+			goto retry;
+		} else {
+			g_object_unref (new_dest);
+		}
+	}
+
 	/* Conflict */
 	if (!overwrite &&
 	    IS_IO_ERROR (error, EXISTS)) {
@@ -3618,7 +3795,7 @@
 
 		if (unique_names) {
 			g_object_unref (dest);
-			dest = get_unique_target_file (src, dest_dir, same_fs, unique_name_nr++);
+			dest = get_unique_target_file (src, dest_dir, same_fs, *dest_fs_type, unique_name_nr++);
 			g_error_free (error);
 			goto retry;
 		}
@@ -3780,10 +3957,15 @@
 			same_fs = FALSE;
 		}
 		
-		copy_move_directory (copy_job, src, dest, same_fs,
-				     would_recurse,
-				     source_info, transfer_info,
-				     debuting_files, skipped_file);
+		if (!copy_move_directory (copy_job, src, &dest, same_fs,
+					  would_recurse, dest_fs_type,
+					  source_info, transfer_info,
+					  debuting_files, skipped_file)) {
+			/* destination changed, since it was an invalid file name */
+			g_assert (*dest_fs_type != NULL);
+			handled_invalid_filename = TRUE;
+			goto retry;
+		}
 
 		g_object_unref (dest);
 		return;
@@ -3843,6 +4025,9 @@
 	gboolean skipped_file;
 	gboolean unique_names;
 	GFile *dest;
+	char *dest_fs_type;
+
+	dest_fs_type = NULL;
 
 	common = &job->common;
 
@@ -3877,6 +4062,7 @@
 			skipped_file = FALSE;
 			copy_move_file (job, src, dest,
 					same_fs, unique_names,
+					&dest_fs_type,
 					source_info, transfer_info,
 					job->debuting_files,
 					point, FALSE, &skipped_file);
@@ -3884,6 +4070,8 @@
 		}
 		i++;
 	}
+
+	g_free (dest_fs_type);
 }
 
 static gboolean
@@ -4070,12 +4258,13 @@
 		   GFile *src,
 		   GFile *dest_dir,
 		   gboolean same_fs,
+		   char **dest_fs_type,
 		   GHashTable *debuting_files,
 		   GdkPoint *position,
 		   GList **fallback_files,
 		   int files_left)
 {
-	GFile *dest;
+	GFile *dest, *new_dest;
 	GError *error;
 	CommonJob *job;
 	gboolean overwrite;
@@ -4083,12 +4272,14 @@
 	int response;
 	GFileCopyFlags flags;
 	MoveFileCopyFallback *fallback;
+	gboolean handled_invalid_filename;
 
 	overwrite = FALSE;
+	handled_invalid_filename = *dest_fs_type != NULL;
 
 	job = (CommonJob *)move_job;
 	
-	dest = get_target_file (src, dest_dir, same_fs);
+	dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
 
 
 	/* Don't allow recursive move/copy into itself.  
@@ -4156,9 +4347,26 @@
 		return;
 	}
 
+	if (IS_IO_ERROR (error, INVALID_FILENAME) &&
+	    !handled_invalid_filename) {
+		handled_invalid_filename = TRUE;
+
+		g_assert (*dest_fs_type == NULL);
+		*dest_fs_type = query_fs_type (dest_dir, job->cancellable);
+
+		new_dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
+		if (!g_file_equal (dest, new_dest)) {
+			g_object_unref (dest);
+			dest = new_dest;
+			goto retry;
+		} else {
+			g_object_unref (new_dest);
+		}
+	}
+
 	/* Conflict */
-	if (!overwrite &&
-	    IS_IO_ERROR (error, EXISTS)) {
+	else if (!overwrite &&
+		 IS_IO_ERROR (error, EXISTS)) {
 		gboolean is_merge;
 		
 		g_error_free (error);
@@ -4290,6 +4498,7 @@
 static void
 move_files_prepare (CopyMoveJob *job,
 		    const char *dest_fs_id,
+		    char **dest_fs_type,
 		    GList **fallbacks)
 {
 	CommonJob *common;
@@ -4325,7 +4534,7 @@
 		}
 		
 		move_file_prepare (job, src, job->destination,
-				   same_fs,
+				   same_fs, dest_fs_type,
 				   job->debuting_files,
 				   point,
 				   fallbacks,
@@ -4343,6 +4552,7 @@
 move_files (CopyMoveJob *job,
 	    GList *fallbacks,
 	    const char *dest_fs_id,
+	    char **dest_fs_type,
 	    SourceInfo *source_info,
 	    TransferInfo *transfer_info)
 {
@@ -4354,8 +4564,7 @@
 	GdkPoint *point;
 	gboolean skipped_file;
 	MoveFileCopyFallback *fallback;
-
-	common = &job->common;
+common = &job->common;
 
 	report_copy_progress (job, source_info, transfer_info);
 	
@@ -4381,7 +4590,7 @@
 		   selected overwrite on all toplevel items */
 		skipped_file = FALSE;
 		copy_move_file (job, src, job->destination,
-				same_fs, FALSE, 
+				same_fs, FALSE, dest_fs_type,
 				source_info, transfer_info,
 				job->debuting_files,
 				point, fallback->overwrite, &skipped_file);
@@ -4422,6 +4631,7 @@
 	SourceInfo source_info;
 	TransferInfo transfer_info;
 	char *dest_fs_id;
+	char *dest_fs_type;
 	GList *fallback_files;
 
 	job = user_data;
@@ -4429,6 +4639,7 @@
 	common->io_job = io_job;
 
 	dest_fs_id = NULL;
+	dest_fs_type = NULL;
 
 	fallbacks = NULL;
 	
@@ -4443,7 +4654,7 @@
 	}
 
 	/* This moves all files that we can do without copy + delete */
-	move_files_prepare (job, dest_fs_id, &fallbacks);
+	move_files_prepare (job, dest_fs_id, &dest_fs_type, &fallbacks);
 	if (job_aborted (common)) {
 		goto aborted;
 	}
@@ -4474,13 +4685,14 @@
 	memset (&transfer_info, 0, sizeof (transfer_info));
 	move_files (job,
 		    fallbacks,
-		    dest_fs_id,
+		    dest_fs_id, &dest_fs_type,
 		    &source_info, &transfer_info);
 
  aborted:
 	eel_g_list_free_deep (fallbacks);
 
 	g_free (dest_fs_id);
+	g_free (dest_fs_type);
 	
 	g_io_scheduler_job_send_to_mainloop (io_job,
 					     move_job_done,
@@ -4545,11 +4757,12 @@
 static void
 link_file (CopyMoveJob *job,
 	   GFile *src, GFile *dest_dir,
+	   char **dest_fs_type,
 	   GHashTable *debuting_files,
 	   GdkPoint *position,
 	   int files_left)
 {
-	GFile *dest;
+	GFile *dest, *new_dest;
 	int count;
 	char *path;
 	gboolean not_local;
@@ -4557,12 +4770,14 @@
 	CommonJob *common;
 	char *primary, *secondary, *details;
 	int response;
+	gboolean handled_invalid_filename;
 
 	common = (CommonJob *)job;
 
 	count = 1;
+	handled_invalid_filename = *dest_fs_type != NULL;
 
-	dest = get_target_file_for_link (src, dest_dir, count);
+	dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count);
 
  retry:
 	error = NULL;
@@ -4592,10 +4807,30 @@
 	}
 	g_free (path);
 
+	if (error != NULL &&
+	    IS_IO_ERROR (error, INVALID_FILENAME) &&
+	    !handled_invalid_filename) {
+		handled_invalid_filename = TRUE;
+
+		g_assert (*dest_fs_type == NULL);
+		*dest_fs_type = query_fs_type (dest_dir, common->cancellable);
+
+		new_dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count);
+
+		if (!g_file_equal (dest, new_dest)) {
+			g_object_unref (dest);
+			dest = new_dest;
+			g_error_free (error);
+
+			goto retry;
+		} else {
+			g_object_unref (new_dest);
+		}
+	}
 	/* Conflict */
 	if (error != NULL && IS_IO_ERROR (error, EXISTS)) {
 		g_object_unref (dest);
-		dest = get_target_file_for_link (src, dest_dir, count++);
+		dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count++);
 		g_error_free (error);
 		goto retry;
 	}
@@ -4680,6 +4915,7 @@
 	GArray *copy_positions;
 	GFile *src;
 	GdkPoint *point;
+	char *dest_fs_type;
 	int total, left;
 	int i;
 	GList *l;
@@ -4690,6 +4926,8 @@
 
 	copy_files = NULL;
 	copy_positions = NULL;
+
+	dest_fs_type = NULL;
 	
 	nautilus_progress_info_start (job->common.progress);
 	
@@ -4719,7 +4957,7 @@
 
 		
 		link_file (job, src, job->destination,
-			   job->debuting_files,
+			   &dest_fs_type, job->debuting_files,
 			   point, left);
 		report_link_progress (job, total, --left);
 		i++;
@@ -4727,6 +4965,7 @@
 	}
 
  aborted:
+	g_free (dest_fs_type);
 	
 	g_io_scheduler_job_send_to_mainloop (io_job,
 					     link_job_done,
@@ -5121,7 +5360,8 @@
 	CommonJob *common;
 	int count;
 	GFile *dest;
-	char *filename, *filename2;
+	char *filename, *filename2, *new_filename;
+	char *dest_fs_type;
 	GError *error;
 	gboolean res;
 	gboolean filename_is_utf8;
@@ -5129,6 +5369,7 @@
 	int response;
 	char *data;
 	GFileOutputStream *out;
+	gboolean handled_invalid_filename;
 
 	job = user_data;
 	common = &job->common;
@@ -5136,6 +5377,9 @@
 
 	nautilus_progress_info_start (job->common.progress);
 
+	handled_invalid_filename = FALSE;
+
+	dest_fs_type = NULL;
 	filename = NULL;
 	dest = NULL;
 	
@@ -5168,6 +5412,7 @@
 		}
 	} 
 
+	make_file_name_valid_for_dest_fs (filename, dest_fs_type);
 	if (filename_is_utf8) {
 		dest = g_file_get_child_for_display_name (job->dest_dir, filename, NULL);
 	}
@@ -5230,10 +5475,43 @@
 			nautilus_file_changes_queue_schedule_position_remove (dest);
 		}
 	} else {
-		if (error != NULL && IS_IO_ERROR (error, EXISTS)) {
+		g_assert (error != NULL);
+
+		if (IS_IO_ERROR (error, INVALID_FILENAME) &&
+		    !handled_invalid_filename) {
+			handled_invalid_filename = TRUE;
+
+			g_assert (dest_fs_type == NULL);
+			dest_fs_type = query_fs_type (job->dest_dir, common->cancellable);
+
+			g_object_unref (dest);
+
+			if (count > 1) {
+				new_filename = g_strdup (filename);
+			} else {
+				new_filename = g_strdup_printf ("%s %d", filename, count);
+			}
+
+			if (make_file_name_valid_for_dest_fs (new_filename, dest_fs_type)) {
+				g_object_unref (dest);
+
+				if (filename_is_utf8) {
+					dest = g_file_get_child_for_display_name (job->dest_dir, new_filename, NULL);
+				}
+				if (dest == NULL) {
+					dest = g_file_get_child (job->dest_dir, new_filename);
+				}
+
+				g_free (new_filename);
+				g_error_free (error);
+				goto retry;
+			}
+			g_free (new_filename);
+		} else if (IS_IO_ERROR (error, EXISTS)) {
 			g_object_unref (dest);
 			dest = NULL;
 			filename2 = g_strdup_printf ("%s %d", filename, ++count);
+			make_file_name_valid_for_dest_fs (filename2, dest_fs_type);
 			if (filename_is_utf8) {
 				dest = g_file_get_child_for_display_name (job->dest_dir, filename2, NULL);
 			}
@@ -5245,7 +5523,7 @@
 			goto retry;
 		}
 		
-		else if (error != NULL && IS_IO_ERROR (error, CANCELLED)) {
+		else if (IS_IO_ERROR (error, CANCELLED)) {
 			g_error_free (error);
 		}
 		
@@ -5284,6 +5562,7 @@
 		g_object_unref (dest);
 	}
 	g_free (filename);
+	g_free (dest_fs_type);
 	g_io_scheduler_job_send_to_mainloop_async (io_job,
 						   create_job_done,
 						   job,



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