mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 06:56:14 +01:00
Merge branch 'trashing-long-file-name' into 'main'
GLocalFile: support trashing long file name See merge request GNOME/glib!3697
This commit is contained in:
commit
07fa7b261c
@ -1997,6 +1997,8 @@ g_local_file_trash (GFile *file,
|
||||
GVfsClass *class;
|
||||
GVfs *vfs;
|
||||
int errsv;
|
||||
size_t basename_len;
|
||||
GError *my_error = NULL;
|
||||
|
||||
if (glib_should_use_portal ())
|
||||
return g_trash_portal_trash_file (file, error);
|
||||
@ -2224,40 +2226,91 @@ g_local_file_trash (GFile *file,
|
||||
g_free (trashdir);
|
||||
|
||||
basename = g_path_get_basename (local->filename);
|
||||
basename_len = strlen (basename);
|
||||
i = 1;
|
||||
trashname = NULL;
|
||||
infofile = NULL;
|
||||
do {
|
||||
g_free (trashname);
|
||||
g_free (infofile);
|
||||
|
||||
trashname = get_unique_filename (basename, i++);
|
||||
infoname = g_strconcat (trashname, ".trashinfo", NULL);
|
||||
infofile = g_build_filename (infodir, infoname, NULL);
|
||||
g_free (infoname);
|
||||
while (TRUE)
|
||||
{
|
||||
g_free (trashname);
|
||||
g_free (infofile);
|
||||
|
||||
fd = g_open (infofile, O_CREAT | O_EXCL | O_CLOEXEC, 0666);
|
||||
errsv = errno;
|
||||
} while (fd == -1 && errsv == EEXIST);
|
||||
/* Make sure we can create a unique info file */
|
||||
trashname = get_unique_filename (basename, i++);
|
||||
infoname = g_strconcat (trashname, ".trashinfo", NULL);
|
||||
infofile = g_build_filename (infodir, infoname, NULL);
|
||||
g_free (infoname);
|
||||
|
||||
fd = g_open (infofile, O_CREAT | O_EXCL | O_CLOEXEC, 0666);
|
||||
errsv = errno;
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
if (errsv == EEXIST)
|
||||
continue;
|
||||
else if (errsv == ENAMETOOLONG)
|
||||
{
|
||||
if (basename_len <= strlen (".trashinfo"))
|
||||
break; /* fail with ENAMETOOLONG */
|
||||
basename_len -= strlen (".trashinfo");
|
||||
basename[basename_len] = '\0';
|
||||
i = 1;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break; /* fail with other error */
|
||||
}
|
||||
|
||||
(void) g_close (fd, NULL);
|
||||
|
||||
/* Make sure we can write the info file */
|
||||
if (!g_file_set_contents_full (infofile, NULL, 0,
|
||||
G_FILE_SET_CONTENTS_CONSISTENT | G_FILE_SET_CONTENTS_ONLY_EXISTING,
|
||||
0600, &my_error))
|
||||
{
|
||||
g_unlink (infofile);
|
||||
if (g_error_matches (my_error,
|
||||
G_FILE_ERROR,
|
||||
G_FILE_ERROR_NAMETOOLONG))
|
||||
{
|
||||
if (basename_len <= strlen (".XXXXXX"))
|
||||
break; /* fail with ENAMETOOLONG */
|
||||
basename_len -= strlen (".XXXXXX");
|
||||
basename[basename_len] = '\0';
|
||||
i = 1;
|
||||
g_clear_error (&my_error);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break; /* fail with other error */
|
||||
}
|
||||
|
||||
/* file created */
|
||||
break;
|
||||
}
|
||||
|
||||
g_free (basename);
|
||||
g_free (infodir);
|
||||
|
||||
if (fd == -1)
|
||||
if (fd == -1 || my_error)
|
||||
{
|
||||
g_free (filesdir);
|
||||
g_free (topdir);
|
||||
g_free (trashname);
|
||||
g_free (infofile);
|
||||
|
||||
g_set_io_error (error,
|
||||
_("Unable to create trashing info file for %s: %s"),
|
||||
file, errsv);
|
||||
if (my_error)
|
||||
g_propagate_error (error, my_error);
|
||||
else
|
||||
{
|
||||
g_set_io_error (error,
|
||||
_("Unable to create trashing info file for %s: %s"),
|
||||
file, errsv);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
(void) g_close (fd, NULL);
|
||||
|
||||
/* Write the full content of the info file before trashing to make
|
||||
* sure someone doesn't read an empty file. See #749314
|
||||
*/
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <glib/gstdio.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gunixmounts.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* Test that g_file_trash() returns G_IO_ERROR_NOT_SUPPORTED for files on system mounts. */
|
||||
static void
|
||||
@ -188,6 +189,79 @@ test_trash_symlinks (void)
|
||||
g_free (target);
|
||||
}
|
||||
|
||||
/* Test that long filename are handled correctly */
|
||||
static void
|
||||
test_trash_long_filename (void)
|
||||
{
|
||||
const gchar *long_filename = "test_trash_long_filename_aaaaaaaaaaaaaaaaaaaaaaaaa" \
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
|
||||
"aaaaa"; /* 255 bytes */
|
||||
gchar *filepath;
|
||||
int fd;
|
||||
GFile *file;
|
||||
GError *error = NULL;
|
||||
|
||||
/* The test assumes that test file is located on ext fs. */
|
||||
filepath = g_build_filename (g_get_home_dir (), long_filename, NULL);
|
||||
fd = g_open (filepath, O_CREAT | O_RDONLY, 0666);
|
||||
if (fd == -1)
|
||||
{
|
||||
g_test_skip ("Failed to create test file");
|
||||
g_free (filepath);
|
||||
return;
|
||||
}
|
||||
(void) g_close (fd, NULL);
|
||||
file = g_file_new_for_path (filepath);
|
||||
g_file_trash (file, NULL, &error);
|
||||
g_unlink (filepath);
|
||||
g_assert_no_error (error);
|
||||
|
||||
/* Delete trashed version of test file */
|
||||
{
|
||||
GFileEnumerator *enumerator;
|
||||
GFile *trash;
|
||||
|
||||
trash = g_file_new_for_uri ("trash:///");
|
||||
enumerator = g_file_enumerate_children (trash,
|
||||
G_FILE_ATTRIBUTE_STANDARD_NAME ","
|
||||
G_FILE_ATTRIBUTE_TRASH_ORIG_PATH,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
NULL, NULL);
|
||||
|
||||
if (enumerator)
|
||||
{
|
||||
GFileInfo *info;
|
||||
|
||||
while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL)
|
||||
{
|
||||
const char *origpath = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH);
|
||||
|
||||
if (strcmp (filepath, origpath) == 0)
|
||||
{
|
||||
GFile *item = g_file_get_child (trash, g_file_info_get_name (info));
|
||||
g_file_delete (item, NULL, NULL);
|
||||
g_object_unref (item);
|
||||
g_object_unref (info);
|
||||
break;
|
||||
}
|
||||
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
g_file_enumerator_close (enumerator, NULL, NULL);
|
||||
g_object_unref (enumerator);
|
||||
}
|
||||
g_object_unref (trash);
|
||||
}
|
||||
|
||||
g_free (filepath);
|
||||
g_object_unref (file);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@ -195,6 +269,7 @@ main (int argc, char *argv[])
|
||||
|
||||
g_test_add_func ("/trash/not-supported", test_trash_not_supported);
|
||||
g_test_add_func ("/trash/symlinks", test_trash_symlinks);
|
||||
g_test_add_func ("/trash/long-filename", test_trash_long_filename);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user