diff lib/protocols.c @ 852:5e3005923374

2006-11-16 Brian Masney <masneyb@gftp.org> * 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)
author masneyb
date Fri, 17 Nov 2006 02:24:14 +0000
parents 83d39217749c
children 30eaf54a63f7
line wrap: on
line diff
--- 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);