need some review



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]