# HG changeset patch # User masneyb # Date 1163730254 0 # Node ID 5e300592337430299bad9e26bc62c7186f9b3526 # Parent 83d39217749cf9bf6a3b52274a96eb59a82e3252 2006-11-16 Brian Masney * lib/gftp.h lib/protocols.c lib/local.c - added support for detecting recursive symbolic links. This currently only works when uploading files. It will only work when downloading files if the inode and device are properly populated. I need to check but it may be possible to get this information from the SSH and FSP protocols. (closes #172499) diff -r 83d39217749c -r 5e3005923374 ChangeLog --- a/ChangeLog Fri Nov 17 01:38:51 2006 +0000 +++ b/ChangeLog Fri Nov 17 02:24:14 2006 +0000 @@ -1,4 +1,13 @@ 2006-11-16 Brian Masney + * lib/gftp.h lib/protocols.c lib/local.c - added support for detecting + recursive symbolic links. This currently only works when uploading + files. It will only work when downloading files if the inode and device + are properly populated. I need to check but it may be possible to get + this information from the SSH and FSP protocols. (closes #172499) + + * lib/local.c lib/misc.c - moved uint_hash_compare() and + uint_hash_function() from local.c to misc.c + * lib/protocols.c - backed out last change where hidden files aren't transferred in the subdirectories if the show_hidden_files option is disabled. @@ -3715,7 +3724,7 @@ * cvsclean - added this script - * *.[ch] - added $Id: ChangeLog,v 1.500 2006/11/17 01:38:50 masneyb Exp $ tags + * *.[ch] - added $Id: ChangeLog,v 1.501 2006/11/17 02:24:03 masneyb Exp $ tags * debian/* - updated files from Debian maintainer diff -r 83d39217749c -r 5e3005923374 lib/gftp.h --- a/lib/gftp.h Fri Nov 17 01:38:51 2006 +0000 +++ b/lib/gftp.h Fri Nov 17 02:24:14 2006 +0000 @@ -244,6 +244,11 @@ off_t size, /* Size of the file */ startsize; /* Size to start the transfer at */ mode_t st_mode; /* File attributes */ + + dev_t st_dev; /* The device and associated inode. These */ + ino_t st_ino; /* two fields are used for detecting loops */ + /* with symbolic links. */ + unsigned int selected : 1, /* Is this file selected? */ was_sel : 1, /* Was this file selected before */ shown : 1, /* Is this file shown? */ @@ -753,6 +758,11 @@ guint string_hash_function ( gconstpointer key ); +gint uint_hash_compare ( gconstpointer path1, + gconstpointer path2 ); + +guint uint_hash_function ( gconstpointer key ); + void free_file_list ( GList * filelist ); gftp_file * copy_fdata ( gftp_file * fle ); diff -r 83d39217749c -r 5e3005923374 lib/local.c --- a/lib/local.c Fri Nov 17 01:38:51 2006 +0000 +++ b/lib/local.c Fri Nov 17 02:24:14 2006 +0000 @@ -382,6 +382,8 @@ g_hash_table_insert (lpd->grouphash, GUINT_TO_POINTER (st.st_gid), group); } + fle->st_dev = fst.st_dev; + fle->st_ino = fst.st_ino; fle->st_mode = fst.st_mode; fle->datetime = st.st_mtime; @@ -696,20 +698,6 @@ } -static gint -hash_compare (gconstpointer path1, gconstpointer path2) -{ - return (GPOINTER_TO_UINT (path1) == GPOINTER_TO_UINT (path2)); -} - - -static guint -hash_function (gconstpointer key) -{ - return (GPOINTER_TO_UINT (key)); -} - - void local_register_module (void) { @@ -765,8 +753,8 @@ lpd = g_malloc0 (sizeof (*lpd)); request->protocol_data = lpd; - lpd->userhash = g_hash_table_new (hash_function, hash_compare); - lpd->grouphash = g_hash_table_new (hash_function, hash_compare); + lpd->userhash = g_hash_table_new (uint_hash_function, uint_hash_compare); + lpd->grouphash = g_hash_table_new (uint_hash_function, uint_hash_compare); if (request->hostname != NULL) g_free (request->hostname); diff -r 83d39217749c -r 5e3005923374 lib/misc.c --- a/lib/misc.c Fri Nov 17 01:38:51 2006 +0000 +++ b/lib/misc.c Fri Nov 17 02:24:14 2006 +0000 @@ -430,6 +430,20 @@ } +gint +uint_hash_compare (gconstpointer path1, gconstpointer path2) +{ + return (GPOINTER_TO_UINT (path1) == GPOINTER_TO_UINT (path2)); +} + + +guint +uint_hash_function (gconstpointer key) +{ + return (GPOINTER_TO_UINT (key)); +} + + void free_file_list (GList * filelist) { diff -r 83d39217749c -r 5e3005923374 lib/protocols.c --- a/lib/protocols.c Fri Nov 17 01:38:51 2006 +0000 +++ b/lib/protocols.c Fri Nov 17 02:24:14 2006 +0000 @@ -2077,12 +2077,66 @@ } +static int +_lookup_curfle_in_device_hash (gftp_request * request, gftp_file * curfle, + GHashTable * device_hash) +{ + GHashTable * inode_hash; + + if (curfle->st_dev == 0 || curfle->st_ino == 0) + return (0); + + if ((inode_hash = g_hash_table_lookup (device_hash, + GUINT_TO_POINTER ((guint) curfle->st_dev))) != NULL) + { + if (g_hash_table_lookup (inode_hash, + GUINT_TO_POINTER ((guint) curfle->st_ino))) + { + request->logging_function (gftp_logging_error, request, + _("Found recursive symbolic link %s\n"), + curfle->file); + return (1); + } + + g_hash_table_insert (inode_hash, GUINT_TO_POINTER ((guint) curfle->st_ino), + GUINT_TO_POINTER (1)); + return (0); + } + else + { + inode_hash = g_hash_table_new (uint_hash_function, uint_hash_compare); + g_hash_table_insert (inode_hash, GUINT_TO_POINTER ((guint) curfle->st_ino), + GUINT_TO_POINTER (1)); + g_hash_table_insert (device_hash, GUINT_TO_POINTER ((guint) curfle->st_dev), + inode_hash); + return (0); + } + +} + + +static void +_free_inode_hash (gpointer key, gpointer value, gpointer user_data) +{ + g_hash_table_destroy (value); +} + + +static void +_free_device_hash (GHashTable * device_hash) +{ + g_hash_table_foreach (device_hash, _free_inode_hash, NULL); + g_hash_table_destroy (device_hash); +} + + int gftp_get_all_subdirs (gftp_transfer * transfer, void (*update_func) (gftp_transfer * transfer)) { GList * templist, * lastlist; char *oldfromdir, *oldtodir; + GHashTable * device_hash; gftp_file * curfle; off_t linksize; mode_t st_mode; @@ -2101,11 +2155,16 @@ return (ret); oldfromdir = oldtodir = NULL; + device_hash = g_hash_table_new (uint_hash_function, uint_hash_compare); for (templist = transfer->files; templist != NULL; templist = templist->next) { curfle = templist->data; + if (_lookup_curfle_in_device_hash (transfer->fromreq, curfle, + device_hash)) + continue; + if (S_ISLNK (curfle->st_mode) && !S_ISDIR (curfle->st_mode)) { st_mode = 0; @@ -2141,6 +2200,7 @@ { _cleanup_get_all_subdirs (transfer, oldfromdir, oldtodir, update_func); + _free_device_hash (device_hash); return (ret); } @@ -2156,6 +2216,7 @@ { _cleanup_get_all_subdirs (transfer, oldfromdir, oldtodir, update_func); + _free_device_hash (device_hash); return (ret); } } @@ -2175,6 +2236,7 @@ { _cleanup_get_all_subdirs (transfer, oldfromdir, oldtodir, update_func); + _free_device_hash (device_hash); return (ret); } @@ -2188,6 +2250,8 @@ update_func (transfer); } + _free_device_hash (device_hash); + if (oldfromdir != NULL) { ret = gftp_set_directory (transfer->fromreq, oldfromdir);