need some review
- From: Alexander Larsson <alexl redhat com>
- To: gnome-vfs-list gnome org
- Subject: need some review
- Date: Wed, 18 Dec 2002 07:30:41 -0500 (EST)
I just checked in the attached patch. It fixes a bad data-loss bug
related to moving files over one of their parent directories.
(http://bugzilla.gnome.org/show_bug.cgi?id=99346)
The patch should be safe in itself, but I would like if someone verified
that I didn't miss any way to get data loss.
--
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Alexander Larsson Red Hat, Inc
alexl redhat com alla lysator liu se
He's a hate-fuelled Amish senator haunted by memories of 'Nam. She's a
pregnant antique-collecting Hell's Angel with an incredible destiny. They
fight crime!
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gnome-vfs/ChangeLog,v
retrieving revision 1.1441
diff -u -p -r1.1441 ChangeLog
--- ChangeLog 17 Dec 2002 08:50:59 -0000 1.1441
+++ ChangeLog 18 Dec 2002 12:19:57 -0000
@@ -1,3 +1,24 @@
+2002-12-18 Alexander Larsson <alexl redhat com>
+
+ * libgnomevfs/gnome-vfs-private-utils.h:
+ * libgnomevfs/gnome-vfs-utils.c:
+ (_gnome_vfs_uri_resolve_all_symlinks_uri),
+ (_gnome_vfs_uri_resolve_all_symlinks),
+ (_gnome_vfs_uri_is_in_subdir):
+ New functions. Not exported since we're in a freeze, but might
+ be nice to export later.
+
+ * libgnomevfs/gnome-vfs-xfer.c:
+ (move_source_is_in_target),
+ (handle_name_conflicts):
+ Handle the case when moving a file over a directory it is contained in.
+ (Bug #99346)
+
+ * test/Makefile.am:
+ * test/test-resolv.c: (main):
+ * test/test-subdir.c: (main):
+ Some test code.
+
2002-12-17 Alexander Larsson <alexl redhat com>
* configure.in:
Index: libgnomevfs/gnome-vfs-private-utils.h
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-private-utils.h,v
retrieving revision 1.12
diff -u -p -r1.12 gnome-vfs-private-utils.h
--- libgnomevfs/gnome-vfs-private-utils.h 3 Aug 2001 00:39:58 -0000 1.12
+++ libgnomevfs/gnome-vfs-private-utils.h 18 Dec 2002 12:19:57 -0000
@@ -72,6 +72,14 @@ gboolean gnome_vfs_istr_has_prefix (cons
gboolean gnome_vfs_istr_has_suffix (const char *haystack,
const char *needle);
+GnomeVFSResult _gnome_vfs_uri_resolve_all_symlinks_uri (GnomeVFSURI *uri,
+ GnomeVFSURI **result_uri);
+GnomeVFSResult _gnome_vfs_uri_resolve_all_symlinks (const char *text_uri,
+ char **resolved_text_uri);
+
+gboolean _gnome_vfs_uri_is_in_subdir (GnomeVFSURI *uri, GnomeVFSURI *dir);
+
+
G_END_DECLS
#endif /* _GNOME_VFS_PRIVATE_UTILS_H */
Index: libgnomevfs/gnome-vfs-utils.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-utils.c,v
retrieving revision 1.57
diff -u -p -r1.57 gnome-vfs-utils.c
--- libgnomevfs/gnome-vfs-utils.c 20 Sep 2002 02:52:48 -0000 1.57
+++ libgnomevfs/gnome-vfs-utils.c 18 Dec 2002 12:19:58 -0000
@@ -61,6 +61,8 @@
#define READ_CHUNK_SIZE 8192
+#define MAX_SYMLINKS_FOLLOWED 32
+
gchar*
gnome_vfs_format_file_size_for_display (GnomeVFSFileSize bytes)
@@ -1891,3 +1893,166 @@ gnome_vfs_make_uri_full_from_relative (c
return result;
}
+GnomeVFSResult
+_gnome_vfs_uri_resolve_all_symlinks_uri (GnomeVFSURI *uri,
+ GnomeVFSURI **result_uri)
+{
+ GnomeVFSURI *new_uri, *resolved_uri;
+ GnomeVFSFileInfo *info;
+ GnomeVFSResult res;
+ char *p;
+ int n_followed_symlinks;
+
+ /* Ref the original uri so we don't lose it */
+ uri = gnome_vfs_uri_ref (uri);
+
+ *result_uri = NULL;
+
+ info = gnome_vfs_file_info_new ();
+
+ p = uri->text;
+ n_followed_symlinks = 0;
+ while (*p != 0) {
+ while (*p == GNOME_VFS_URI_PATH_CHR)
+ p++;
+ while (*p != 0 && *p != GNOME_VFS_URI_PATH_CHR)
+ p++;
+
+ new_uri = gnome_vfs_uri_dup (uri);
+ g_free (new_uri->text);
+ new_uri->text = g_strndup (uri->text, p - uri->text);
+
+ gnome_vfs_file_info_clear (info);
+ res = gnome_vfs_get_file_info_uri (new_uri, info, GNOME_VFS_FILE_INFO_DEFAULT);
+ if (res != GNOME_VFS_OK) {
+ gnome_vfs_uri_unref (new_uri);
+ goto out;
+ }
+ if (info->type == GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK &&
+ info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SYMLINK_NAME) {
+ n_followed_symlinks++;
+ if (n_followed_symlinks > MAX_SYMLINKS_FOLLOWED) {
+ res = GNOME_VFS_ERROR_TOO_MANY_LINKS;
+ gnome_vfs_uri_unref (new_uri);
+ goto out;
+ }
+ resolved_uri = gnome_vfs_uri_resolve_relative (new_uri,
+ info->symlink_name);
+ if (*p != 0) {
+ gnome_vfs_uri_unref (uri);
+ uri = gnome_vfs_uri_append_path (resolved_uri, p);
+ gnome_vfs_uri_unref (resolved_uri);
+ } else {
+ gnome_vfs_uri_unref (uri);
+ uri = resolved_uri;
+ }
+
+ p = uri->text;
+ }
+ gnome_vfs_uri_unref (new_uri);
+ }
+
+ res = GNOME_VFS_OK;
+ *result_uri = gnome_vfs_uri_dup (uri);
+ out:
+ gnome_vfs_file_info_unref (info);
+ gnome_vfs_uri_unref (uri);
+ return res;
+}
+
+GnomeVFSResult
+_gnome_vfs_uri_resolve_all_symlinks (const char *text_uri,
+ char **resolved_text_uri)
+{
+ GnomeVFSURI *uri, *resolved_uri;
+ GnomeVFSResult res;
+
+ *resolved_text_uri = NULL;
+
+ uri = gnome_vfs_uri_new (text_uri);
+ if (uri == NULL || uri->text == NULL) {
+ return GNOME_VFS_ERROR_NOT_SUPPORTED;
+ }
+
+ res = _gnome_vfs_uri_resolve_all_symlinks_uri (uri, &resolved_uri);
+
+ if (res == GNOME_VFS_OK) {
+ *resolved_text_uri = gnome_vfs_uri_to_string (resolved_uri, GNOME_VFS_URI_HIDE_NONE);
+ gnome_vfs_uri_unref (resolved_uri);
+ }
+ return res;
+}
+
+gboolean
+_gnome_vfs_uri_is_in_subdir (GnomeVFSURI *uri, GnomeVFSURI *dir)
+{
+ GnomeVFSFileInfo *dirinfo, *info;
+ GnomeVFSURI *resolved_dir, *parent, *tmp;
+ GnomeVFSResult res;
+ gboolean is_in_dir;
+
+ resolved_dir = NULL;
+ parent = NULL;
+
+ is_in_dir = FALSE;
+
+ dirinfo = gnome_vfs_file_info_new ();
+ info = gnome_vfs_file_info_new ();
+
+ res = gnome_vfs_get_file_info_uri (dir, dirinfo, GNOME_VFS_FILE_INFO_DEFAULT);
+ if (res != GNOME_VFS_OK || dirinfo->type != GNOME_VFS_FILE_TYPE_DIRECTORY) {
+ goto out;
+ }
+
+ res = _gnome_vfs_uri_resolve_all_symlinks_uri (dir, &resolved_dir);
+ if (res != GNOME_VFS_OK) {
+ goto out;
+ }
+
+ res = _gnome_vfs_uri_resolve_all_symlinks_uri (uri, &tmp);
+ if (res != GNOME_VFS_OK) {
+ goto out;
+ }
+
+ parent = gnome_vfs_uri_get_parent (tmp);
+ gnome_vfs_uri_unref (tmp);
+
+ while (parent != NULL) {
+ res = gnome_vfs_get_file_info_uri (parent, info, GNOME_VFS_FILE_INFO_DEFAULT);
+ if (res != GNOME_VFS_OK) {
+ break;
+ }
+
+ if (dirinfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_DEVICE &&
+ dirinfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_INODE &&
+ info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_DEVICE &&
+ info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_INODE) {
+ if (dirinfo->device == info->device &&
+ dirinfo->inode == info->inode) {
+ is_in_dir = TRUE;
+ break;
+ }
+ } else {
+ if (gnome_vfs_uri_equal (dir, parent)) {
+ is_in_dir = TRUE;
+ break;
+ }
+ }
+
+ tmp = gnome_vfs_uri_get_parent (parent);
+ gnome_vfs_uri_unref (parent);
+ parent = tmp;
+ }
+
+ out:
+ if (resolved_dir != NULL) {
+ gnome_vfs_uri_unref (resolved_dir);
+ }
+ if (parent != NULL) {
+ gnome_vfs_uri_unref (parent);
+ }
+ gnome_vfs_file_info_unref (info);
+ return is_in_dir;
+}
+
+
Index: libgnomevfs/gnome-vfs-xfer.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-xfer.c,v
retrieving revision 1.101
diff -u -p -r1.101 gnome-vfs-xfer.c
--- libgnomevfs/gnome-vfs-xfer.c 29 Oct 2002 10:37:22 -0000 1.101
+++ libgnomevfs/gnome-vfs-xfer.c 18 Dec 2002 12:19:58 -0000
@@ -40,6 +40,7 @@
#include "gnome-vfs-directory.h"
#include "gnome-vfs-ops.h"
#include "gnome-vfs-utils.h"
+#include "gnome-vfs-private-utils.h"
#include <glib/gstrfuncs.h>
#include <glib/gmessages.h>
#include <string.h>
@@ -794,6 +795,34 @@ directory_add_items_and_size (GnomeVFSUR
}
+/* Checks to see if any part of the source pathname of a move
+ * is inside the target. If it is we can't remove the target
+ * and then move the source to it since we would then remove
+ * the source before we moved it.
+ */
+static gboolean
+move_source_is_in_target (GnomeVFSURI *source, GnomeVFSURI *target)
+{
+ GnomeVFSURI *parent, *tmp;
+ gboolean res;
+
+ parent = gnome_vfs_uri_ref (source);
+
+ res = FALSE;
+ while (parent != NULL) {
+ if (_gnome_vfs_uri_is_in_subdir (parent, target)) {
+ res = TRUE;
+ break;
+ }
+ tmp = gnome_vfs_uri_get_parent (parent);
+ gnome_vfs_uri_unref (parent);
+ parent = tmp;
+ }
+ gnome_vfs_uri_unref (parent);
+
+ return res;
+}
+
/* Compares the list of files about to be created by a transfer with
* any possible existing files with conflicting names in the target directory.
* Handles conflicts, optionaly removing the conflicting file/directory
@@ -868,8 +897,13 @@ handle_name_conflicts (GList **source_ur
gnome_vfs_get_file_info_uri (uri, info, GNOME_VFS_FILE_INFO_DEFAULT);
progress_set_source_target_uris (progress, uri, NULL);
if (info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
- remove_directory (uri, TRUE, progress,
- xfer_options, error_mode, &skip);
+ if (move_source_is_in_target (source_uri, uri)) {
+ /* Would like a better error here */
+ result = GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY;
+ } else {
+ remove_directory (uri, TRUE, progress,
+ xfer_options, error_mode, &skip);
+ }
} else {
remove_file (uri, progress,
xfer_options, error_mode, &skip);
Index: test/Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-vfs/test/Makefile.am,v
retrieving revision 1.54
diff -u -p -r1.54 Makefile.am
--- test/Makefile.am 5 Nov 2002 11:31:26 -0000 1.54
+++ test/Makefile.am 18 Dec 2002 12:19:58 -0000
@@ -25,8 +25,10 @@ noinst_PROGRAMS = \
test-mime-info \
test-monitor \
test-performance \
+ test-resolv \
test-seek \
test-shell \
+ test-subdir \
test-symlinks \
test-ssl \
test-sync \
@@ -63,6 +65,12 @@ test_async_LDADD = $(libraries)
test_performance_SOURCES = test-performance.c
test_performance_LDADD = $(libraries)
+
+test_resolv_SOURCES = test-resolv.c
+test_resolv_LDADD = $(libraries)
+
+test_subdir_SOURCES = test-subdir.c
+test_subdir_LDADD = $(libraries)
test_async_directory_SOURCES = test-async-directory.c
test_async_directory_LDADD = $(libraries)
Index: test/test-resolv.c
===================================================================
RCS file: test/test-resolv.c
diff -N test/test-resolv.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ test/test-resolv.c 18 Dec 2002 12:19:58 -0000
@@ -0,0 +1,70 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* test-info.c - Test program for the `resolve_all_symlinks()' functionality of the
+ GNOME Virtual File System.
+
+ Copyright (C) 2002 Free Software Foundation
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Alexander Larsson <alexl redhat com> */
+
+
+#include <config.h>
+
+#include <glib/gmessages.h>
+#include <libgnomevfs/gnome-vfs-init.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
+#include <libgnomevfs/gnome-vfs-private-utils.h>
+#include <stdio.h>
+#include <time.h>
+
+int
+main (int argc,
+ char **argv)
+{
+ GnomeVFSResult result;
+ gchar *uri;
+ int i=1;
+
+ if (argc < 2) {
+ fprintf (stderr, "Usage: %s <uri> [<uri>...]\n", argv[0]);
+ return 1;
+ }
+
+ if (!gnome_vfs_init ()) {
+ fprintf (stderr, "%s: Cannot initialize the GNOME Virtual File System.\n",
+ argv[0]);
+ return 1;
+ }
+
+ while (i < argc) {
+ char *resolved;
+
+ uri = argv[i];
+
+ result = _gnome_vfs_uri_resolve_all_symlinks (uri, &resolved);
+ if (result != GNOME_VFS_OK) {
+ fprintf (stderr, "%s: %s: %s\n",
+ argv[0], uri, gnome_vfs_result_to_string (result));
+ } else {
+ g_print("URI \"%s\" resolves to \"%s\".\n", uri, resolved);
+ }
+
+ i++;
+ }
+
+ return 0;
+}
Index: test/test-subdir.c
===================================================================
RCS file: test/test-subdir.c
diff -N test/test-subdir.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ test/test-subdir.c 18 Dec 2002 12:19:58 -0000
@@ -0,0 +1,61 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* test-info.c - Test program for the `is_in_subdir()' functionality of the
+ GNOME Virtual File System.
+
+ Copyright (C) 2002 Free Software Foundation
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Alexander Larsson <alexl redhat com> */
+
+
+#include <config.h>
+
+#include <glib/gmessages.h>
+#include <libgnomevfs/gnome-vfs-init.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
+#include <libgnomevfs/gnome-vfs-private-utils.h>
+#include <stdio.h>
+#include <time.h>
+
+
+int
+main (int argc,
+ char **argv)
+{
+ GnomeVFSURI *uri1, *uri2;
+
+ if (argc != 3) {
+ fprintf (stderr, "Usage: %s <uri1> <uri2>\n", argv[0]);
+ return 1;
+ }
+
+ if (!gnome_vfs_init ()) {
+ fprintf (stderr, "%s: Cannot initialize the GNOME Virtual File System.\n",
+ argv[0]);
+ return 1;
+ }
+
+
+ uri1 = gnome_vfs_uri_new (argv[1]);
+ uri2 = gnome_vfs_uri_new (argv[2]);
+
+ g_print ("is_in_subdir (uri: %s, dir: %s) == %d\n",
+ argv[1], argv[2],
+ _gnome_vfs_uri_is_in_subdir (uri1, uri2));
+
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]