http://bugzilla.gnome.org/show_bug.cgi?id=364843 Keep the generated names for "reallylongfilename (copy).txt" from overflowing the maximum allowed length for path names. Patch by Dave Camp . Index: libnautilus-private/nautilus-file-operations.c ================================================================================ --- libnautilus-private/nautilus-file-operations.c +++ libnautilus-private/nautilus-file-operations.c @@ -1163,19 +1163,58 @@ } } + +static char * +shorten_string (const char *base, int reduce_by) +{ + int len; + char *ret; + const char *p; + + len = strlen (base); + len -= reduce_by; + + if (len <= 0) { + return NULL; + } + + ret = g_malloc (len + 1); + + p = base; + while (len) { + char *next; + next = g_utf8_next_char (p); + if (next - p > len || *next == '\0') { + break; + } + + len -= next - p; + p = next; + } + + if (p - base == 0) { + g_free (ret); + return NULL; + } else { + memcpy (ret, base, p - base); + ret[p-base] = '\0'; + return ret; + } +} + /* Note that we have these two separate functions with separate format * strings for ease of localization. */ static char * -get_link_name (char *name, int count) +get_link_name (char *name, int count, int max_length) { char *result; char *unescaped_name; char *unescaped_tmp_name; char *unescaped_result; char *new_file; - + int unescaped_result_size; const char *format; g_assert (name != NULL); @@ -1210,6 +1249,17 @@ break; } unescaped_result = g_strdup_printf (format, unescaped_name); + if (max_length > 0 && (unescaped_result_size = strlen (unescaped_result)) > max_length) { + char *new_name; + + new_name = shorten_string (unescaped_name, unescaped_result_size - max_length); + if (new_name) { + g_free (unescaped_result); + unescaped_result = g_strdup_printf (format, new_name); + g_assert (strlen (unescaped_result) <= max_length); + g_free (new_name); + } + } } else { /* Handle special cases for the first few numbers of each ten. @@ -1238,6 +1288,17 @@ break; } unescaped_result = g_strdup_printf (format, count, unescaped_name); + if (max_length > 0 && (unescaped_result_size = strlen (unescaped_result)) > max_length) { + char *new_name; + + new_name = shorten_string (unescaped_name, unescaped_result_size - max_length); + if (new_name) { + g_free (unescaped_result); + unescaped_result = g_strdup_printf (format, count, new_name); + g_assert (strlen (unescaped_result) <= max_length); + g_free (new_name); + } + } } new_file = g_filename_from_utf8 (unescaped_result, -1, NULL, NULL, NULL); result = gnome_vfs_escape_path_string (new_file); @@ -1434,11 +1495,11 @@ } static char * -make_next_duplicate_name (const char *base, const char *suffix, int count) +make_next_duplicate_name (const char *base, const char *suffix, int count, int max_length) { const char *format; char *result; - + int name_size; if (count < 1) { g_warning ("bad count %d in get_duplicate_name", count); @@ -1463,6 +1524,18 @@ } result = g_strdup_printf (format, base, suffix); + + if (max_length > 0 && (name_size = strlen (result)) > max_length) { + char *new_base; + + new_base = shorten_string (base, name_size - max_length); + if (new_base) { + g_free (result); + result = g_strdup_printf (format, new_base, suffix); + g_assert (strlen (result) <= max_length); + g_free (new_base); + } + } } else { /* Handle special cases for the first few numbers of each ten. @@ -1506,13 +1579,25 @@ } result = g_strdup_printf (format, base, count, suffix); + if (max_length > 0 && (name_size = strlen (result)) > max_length) { + char *new_base; + + new_base = shorten_string (base, name_size - max_length); + if (new_base) { + g_free (result); + result = g_strdup_printf (format, new_base, count, suffix); + g_assert (strlen (result) <= max_length); + g_free (new_base); + + } + } } return result; } static char * -get_duplicate_name (const char *name, int count_increment) +get_duplicate_name (const char *name, int count_increment, int max_length) { char *result; char *name_base; @@ -1520,7 +1605,7 @@ int count; parse_previous_duplicate_name (name, &name_base, &suffix, &count); - result = make_next_duplicate_name (name_base, suffix, count + count_increment); + result = make_next_duplicate_name (name_base, suffix, count + count_increment, max_length); g_free (name_base); @@ -1528,7 +1613,7 @@ } static char * -get_next_duplicate_name (char *name, int count_increment) +get_next_duplicate_name (char *name, int count_increment, int max_length) { char *unescaped_name; char *unescaped_tmp_name; @@ -1554,7 +1639,7 @@ g_free (unescaped_tmp_name); - unescaped_result = get_duplicate_name (unescaped_name, count_increment); + unescaped_result = get_duplicate_name (unescaped_name, count_increment, max_length); g_free (unescaped_name); new_file = g_filename_from_utf8 (unescaped_result, -1, NULL, NULL, NULL); @@ -1565,21 +1650,74 @@ } static int +get_max_name_length (const char *text_uri) +{ + int max_length; + GnomeVFSURI *uri; + char *dir; + long max_path; + long max_name; + + max_length = -1; + + uri = gnome_vfs_uri_new (text_uri); + if (!uri) { + return max_length; + } + + if (strcmp (gnome_vfs_uri_get_scheme (uri), "file") != 0) { + gnome_vfs_uri_unref (uri); + return max_length; + } + + dir = gnome_vfs_uri_extract_dirname (uri); + + max_path = pathconf (dir, _PC_PATH_MAX); + max_name = pathconf (dir, _PC_NAME_MAX); + + if (max_name == -1 && max_path == -1) { + max_length = -1; + } else if (max_name == -1 && max_path != -1) { + max_length = max_path - (strlen (dir) + 1); + } else if (max_name != -1 && max_path == -1) { + max_length = max_name; + } else { + int leftover; + + leftover = max_path - (strlen (dir) + 1); + + max_length = MIN (leftover, max_name); + } + + g_free (dir); + + gnome_vfs_uri_unref (uri); + + return max_length; +} + +static int handle_transfer_duplicate (GnomeVFSXferProgressInfo *progress_info, TransferInfo *transfer_info) { + int max_length; + + max_length = get_max_name_length (progress_info->target_name); + switch (transfer_info->kind) { case TRANSFER_LINK: progress_info->duplicate_name = get_link_name (progress_info->duplicate_name, - progress_info->duplicate_count); + progress_info->duplicate_count, + max_length); break; case TRANSFER_COPY: case TRANSFER_MOVE_TO_TRASH: progress_info->duplicate_name = get_next_duplicate_name (progress_info->duplicate_name, - progress_info->duplicate_count); + progress_info->duplicate_count, + max_length); break; default: break; @@ -2722,47 +2860,47 @@ setlocale (LC_MESSAGES, "C"); /* test the next duplicate name generator */ - EEL_CHECK_STRING_RESULT (get_duplicate_name (" (copy)", 1), " (another copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo", 1), "foo (copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name (".bashrc", 1), ".bashrc (copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name (".foo.txt", 1), ".foo (copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo", 1), "foo foo (copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo.txt", 1), "foo (copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo.txt", 1), "foo foo (copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo.txt txt", 1), "foo foo (copy).txt txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo...txt", 1), "foo (copy)...txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo...", 1), "foo (copy)..."); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo. (copy)", 1), "foo. (another copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (copy)", 1), "foo (another copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (copy).txt", 1), "foo (another copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (another copy)", 1), "foo (3rd copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (another copy).txt", 1), "foo (3rd copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (another copy).txt", 1), "foo foo (3rd copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (13th copy)", 1), "foo (14th copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (13th copy).txt", 1), "foo (14th copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (21st copy)", 1), "foo (22nd copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (21st copy).txt", 1), "foo (22nd copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (22nd copy)", 1), "foo (23rd copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (22nd copy).txt", 1), "foo (23rd copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (23rd copy)", 1), "foo (24th copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (23rd copy).txt", 1), "foo (24th copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (24th copy)", 1), "foo (25th copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (24th copy).txt", 1), "foo (25th copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (24th copy)", 1), "foo foo (25th copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (24th copy).txt", 1), "foo foo (25th copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (100000000000000th copy).txt", 1), "foo foo (copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (10th copy)", 1), "foo (11th copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (10th copy).txt", 1), "foo (11th copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (11th copy)", 1), "foo (12th copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (11th copy).txt", 1), "foo (12th copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (12th copy)", 1), "foo (13th copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (12th copy).txt", 1), "foo (13th copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (110th copy)", 1), "foo (111th copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (110th copy).txt", 1), "foo (111th copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (122nd copy)", 1), "foo (123rd copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (122nd copy).txt", 1), "foo (123rd copy).txt"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (123rd copy)", 1), "foo (124th copy)"); - EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (123rd copy).txt", 1), "foo (124th copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name (" (copy)", 1, -1), " (another copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo", 1, -1), "foo (copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name (".bashrc", 1, -1), ".bashrc (copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name (".foo.txt", 1, -1), ".foo (copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo", 1, -1), "foo foo (copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo.txt", 1, -1), "foo (copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo.txt", 1, -1), "foo foo (copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo.txt txt", 1, -1), "foo foo (copy).txt txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo...txt", 1, -1), "foo (copy)...txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo...", 1, -1), "foo (copy)..."); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo. (copy)", 1, -1), "foo. (another copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (copy)", 1, -1), "foo (another copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (copy).txt", 1, -1), "foo (another copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (another copy)", 1, -1), "foo (3rd copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (another copy).txt", 1, -1), "foo (3rd copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (another copy).txt", 1, -1), "foo foo (3rd copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (13th copy)", 1, -1), "foo (14th copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (13th copy).txt", 1, -1), "foo (14th copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (21st copy)", 1, -1), "foo (22nd copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (21st copy).txt", 1, -1), "foo (22nd copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (22nd copy)", 1, -1), "foo (23rd copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (22nd copy).txt", 1, -1), "foo (23rd copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (23rd copy)", 1, -1), "foo (24th copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (23rd copy).txt", 1, -1), "foo (24th copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (24th copy)", 1, -1), "foo (25th copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (24th copy).txt", 1, -1), "foo (25th copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (24th copy)", 1, -1), "foo foo (25th copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (24th copy).txt", 1, -1), "foo foo (25th copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (100000000000000th copy).txt", 1, -1), "foo foo (copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (10th copy)", 1, -1), "foo (11th copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (10th copy).txt", 1, -1), "foo (11th copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (11th copy)", 1, -1), "foo (12th copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (11th copy).txt", 1, -1), "foo (12th copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (12th copy)", 1, -1), "foo (13th copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (12th copy).txt", 1, -1), "foo (13th copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (110th copy)", 1, -1), "foo (111th copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (110th copy).txt", 1, -1), "foo (111th copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (122nd copy)", 1, -1), "foo (123rd copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (122nd copy).txt", 1, -1), "foo (123rd copy).txt"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (123rd copy)", 1, -1), "foo (124th copy)"); + EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (123rd copy).txt", 1, -1), "foo (124th copy).txt"); setlocale (LC_MESSAGES, ""); }