mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 15:06: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;
|
GVfsClass *class;
|
||||||
GVfs *vfs;
|
GVfs *vfs;
|
||||||
int errsv;
|
int errsv;
|
||||||
|
size_t basename_len;
|
||||||
|
GError *my_error = NULL;
|
||||||
|
|
||||||
if (glib_should_use_portal ())
|
if (glib_should_use_portal ())
|
||||||
return g_trash_portal_trash_file (file, error);
|
return g_trash_portal_trash_file (file, error);
|
||||||
@ -2224,40 +2226,91 @@ g_local_file_trash (GFile *file,
|
|||||||
g_free (trashdir);
|
g_free (trashdir);
|
||||||
|
|
||||||
basename = g_path_get_basename (local->filename);
|
basename = g_path_get_basename (local->filename);
|
||||||
|
basename_len = strlen (basename);
|
||||||
i = 1;
|
i = 1;
|
||||||
trashname = NULL;
|
trashname = NULL;
|
||||||
infofile = NULL;
|
infofile = NULL;
|
||||||
do {
|
while (TRUE)
|
||||||
g_free (trashname);
|
{
|
||||||
g_free (infofile);
|
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);
|
|
||||||
|
|
||||||
fd = g_open (infofile, O_CREAT | O_EXCL | O_CLOEXEC, 0666);
|
/* Make sure we can create a unique info file */
|
||||||
errsv = errno;
|
trashname = get_unique_filename (basename, i++);
|
||||||
} while (fd == -1 && errsv == EEXIST);
|
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 (basename);
|
||||||
g_free (infodir);
|
g_free (infodir);
|
||||||
|
|
||||||
if (fd == -1)
|
if (fd == -1 || my_error)
|
||||||
{
|
{
|
||||||
g_free (filesdir);
|
g_free (filesdir);
|
||||||
g_free (topdir);
|
g_free (topdir);
|
||||||
g_free (trashname);
|
g_free (trashname);
|
||||||
g_free (infofile);
|
g_free (infofile);
|
||||||
|
|
||||||
g_set_io_error (error,
|
if (my_error)
|
||||||
_("Unable to create trashing info file for %s: %s"),
|
g_propagate_error (error, my_error);
|
||||||
file, errsv);
|
else
|
||||||
|
{
|
||||||
|
g_set_io_error (error,
|
||||||
|
_("Unable to create trashing info file for %s: %s"),
|
||||||
|
file, errsv);
|
||||||
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) g_close (fd, NULL);
|
|
||||||
|
|
||||||
/* Write the full content of the info file before trashing to make
|
/* Write the full content of the info file before trashing to make
|
||||||
* sure someone doesn't read an empty file. See #749314
|
* sure someone doesn't read an empty file. See #749314
|
||||||
*/
|
*/
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
#include <gio/gunixmounts.h>
|
#include <gio/gunixmounts.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
/* Test that g_file_trash() returns G_IO_ERROR_NOT_SUPPORTED for files on system mounts. */
|
/* Test that g_file_trash() returns G_IO_ERROR_NOT_SUPPORTED for files on system mounts. */
|
||||||
static void
|
static void
|
||||||
@ -188,6 +189,79 @@ test_trash_symlinks (void)
|
|||||||
g_free (target);
|
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
|
int
|
||||||
main (int argc, char *argv[])
|
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/not-supported", test_trash_not_supported);
|
||||||
g_test_add_func ("/trash/symlinks", test_trash_symlinks);
|
g_test_add_func ("/trash/symlinks", test_trash_symlinks);
|
||||||
|
g_test_add_func ("/trash/long-filename", test_trash_long_filename);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user