]> Dogcows Code - chaz/tar/blobdiff - src/incremen.c
(procdir): Use is_individual_file to check for
[chaz/tar] / src / incremen.c
index d354efa2bde79a725a4ee4292228847664116c42..bc8128f3c259e1d884400b199ee882c18f88359e 100644 (file)
@@ -119,10 +119,12 @@ make_directory (const char *name)
   size_t namelen = strlen (name);
   size_t size = offsetof (struct directory, name) + namelen + 1;
   struct directory *directory = xmalloc (size);
+  directory->contents = directory->icontents = NULL;
+  directory->orig = NULL;
+  directory->flags = false;
   strcpy (directory->name, name);
   if (ISSLASH (directory->name[namelen-1]))
     directory->name[namelen-1] = 0;
-  directory->flags = false;
   return directory;
 }
   
@@ -196,9 +198,10 @@ find_directory_meta (dev_t dev, ino_t ino)
   else
     {
       struct directory *dir = make_directory ("");
+      struct directory *ret;
       dir->device_number = dev;
       dir->inode_number = ino;
-      struct directory *ret = hash_lookup (directory_meta_table, dir);
+      ret = hash_lookup (directory_meta_table, dir);
       free (dir);
       return ret;
     }
@@ -322,7 +325,7 @@ procdir (char *name_buffer, struct stat *stat_data,
      omit it... */
   if (one_file_system_option && device != stat_data->st_dev
       /* ... except if it was explicitely given in the command line */
-      && !((np = name_scan (name_buffer, true)) && np->explicit))
+      && !is_individual_file (name_buffer))
     directory->children = NO_CHILDREN;
   else if (children == ALL_CHILDREN) 
     directory->children = ALL_CHILDREN;
@@ -340,11 +343,12 @@ dumpdir_locate (const char *dump, const char *name)
   if (dump)
     while (*dump)
       {
-       /* Ignore 'R' (rename) entries, since they break alphabetical ordering.
+       /* Ignore 'R' (rename) and 'X' (tempname) entries, since they break
+          alphabetical ordering. 
           They normally do not occur in dumpdirs from the snapshot files,
           but this function is also used by purge_directory, which operates
           on a dumpdir from the archive, hence the need for this test. */
-       if (*dump != 'R')
+       if (!strchr ("RX", *dump))
          {
            int rc = strcmp (dump + 1, name);
            if (rc == 0)
@@ -553,49 +557,6 @@ get_directory_contents (char *dir_name, dev_t device)
 }
 
 \f
-static bool
-try_pos (char *name, int pos, const char *dumpdir)
-{
-  int i;
-  static char namechars[] =
-    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
-  if (pos > 0)
-    for (i = 0; i < sizeof namechars; i++)
-      {
-       name[pos] = namechars[i];
-       if (!dumpdir_locate (dumpdir, name)
-           || try_pos (name, pos-1, dumpdir))
-         return true;
-      }
-  
-  return false;
-}
-  
-static bool
-create_temp_name (char *name, const char *dumpdir)
-{
-  size_t pos = strlen (name) - 6;
-  return try_pos (name + pos, 5, dumpdir);
-}
-
-char *
-make_tmp_dir_name (const char *name)
-{
-  char *dirname = dir_name (name);
-  char *tmp_name = NULL;
-  struct directory *dir = find_directory (dirname);
-      
-  tmp_name = new_name (dirname, "000000");
-  if (!create_temp_name (tmp_name, dir ? dir->contents : NULL))
-    {
-      free (tmp_name);
-      tmp_name = NULL;
-    }
-  free (dirname);
-  return tmp_name;
-}
-
 static void
 obstack_code_rename (struct obstack *stk, char *from, char *to)
 {
@@ -636,14 +597,17 @@ rename_handler (void *data, void *proc_data)
 
          /* Break the cycle by using a temporary name for one of its
             elements.
-            FIXME: Leave the choice of the name to the extractor. */
-         temp_name = make_tmp_dir_name (dir->name);
-         obstack_code_rename (stk, dir->name, temp_name);
+            First, create a temp name stub entry. */
+         temp_name = dir_name (dir->name);
+         obstack_1grow (stk, 'X');
+         obstack_grow (stk, temp_name, strlen (temp_name) + 1);
+
+         obstack_code_rename (stk, dir->name, "");
 
          for (p = dir; p != prev; p = p->orig)
            obstack_code_rename (stk, p->orig->name, p->name);
 
-         obstack_code_rename (stk, temp_name, prev->name);
+         obstack_code_rename (stk, "", prev->name);
        }
     }
   return true;
@@ -1170,62 +1134,175 @@ is_dumpdir (struct tar_stat_info *stat_info)
   return stat_info->is_dumpdir;
 }
 
+static bool
+dumpdir_ok (char *dumpdir)
+{
+  char *p;
+  int has_tempdir = 0;
+  int expect = 0;
+  
+  for (p = dumpdir; *p; p += strlen (p) + 1)
+    {
+      if (expect && *p != expect)
+       {
+         ERROR ((0, 0,
+                 _("Malformed dumpdir: expected '%c' but found %#3o"),
+                 expect, *p));
+         return false;
+       }
+      switch (*p)
+       {
+       case 'X':
+         if (has_tempdir)
+           {
+             ERROR ((0, 0,
+                     _("Malformed dumpdir: 'X' duplicated")));
+             return false;
+           }
+         else
+           has_tempdir = 1;
+         break;
+         
+       case 'R':
+         if (p[1] == 0)
+           {
+             if (!has_tempdir)
+               {
+                 ERROR ((0, 0,
+                         _("Malformed dumpdir: empty name in 'R'")));
+                 return false;
+               }
+             else
+               has_tempdir = 0;
+           }
+         expect = 'T';
+         break;
+           
+       case 'T':
+         if (expect != 'T')
+           {
+             ERROR ((0, 0,
+                     _("Malformed dumpdir: 'T' not preceeded by 'R'")));
+             return false;
+           }  
+         if (p[1] == 0 && !has_tempdir)
+           {
+             ERROR ((0, 0,
+                     _("Malformed dumpdir: empty name in 'T'")));
+             return false;
+           }
+         expect = 0;
+         break;
+         
+       case 'N':
+       case 'Y':
+       case 'D':
+         break;
+
+       default:
+         /* FIXME: bail out? */
+         break;
+       }
+    }
+
+  if (expect)
+    {
+      ERROR ((0, 0,
+             _("Malformed dumpdir: expected '%c' but found end of data"),
+             expect));
+      return false;
+    }
+
+  if (has_tempdir)
+    WARN ((0, 0, _("Malformed dumpdir: 'X' never used")));
+
+  return true;
+}
+      
 /* Examine the directories under directory_name and delete any
    files that were not there at the time of the back-up. */
-void
-purge_directory (char const *directory_name)
+static bool
+try_purge_directory (char const *directory_name)
 {
   char *current_dir;
   char *cur, *arc, *p;
-
+  char *temp_stub = NULL;
+  
   if (!is_dumpdir (&current_stat_info))
-    {
-      skip_member ();
-      return;
-    }
+    return false;
 
   current_dir = savedir (directory_name);
 
   if (!current_dir)
-    {
-      /* The directory doesn't exist now.  It'll be created.  In any
-        case, we don't have to delete any files out of it.  */
-
-      skip_member ();
-      return;
-    }
-
+    /* The directory doesn't exist now.  It'll be created.  In any
+       case, we don't have to delete any files out of it.  */
+    return false;
+
+  /* Verify if dump directory is sane */
+  if (!dumpdir_ok (current_stat_info.dumpdir))
+    return false;
+       
   /* Process renames */
   for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
     {
-      if (*arc == 'R')
+      if (*arc == 'X')
+       {
+#define TEMP_DIR_TEMPLATE "tar.XXXXXX"   
+         size_t len = strlen (arc + 1);
+         temp_stub = xrealloc (temp_stub, len + 1 + sizeof TEMP_DIR_TEMPLATE);
+         memcpy (temp_stub, arc + 1, len);
+         temp_stub[len] = '/';
+         memcpy (temp_stub + len + 1, TEMP_DIR_TEMPLATE,
+                 sizeof TEMP_DIR_TEMPLATE);
+         if (!mkdtemp (temp_stub))
+           {
+             ERROR ((0, errno,
+                     _("Cannot create temporary directory using template %s"),
+                     quote (temp_stub)));
+             free (temp_stub);
+             free (current_dir);
+             return false;
+           }
+       }
+      else if (*arc == 'R')
        {
          char *src, *dst;
          src = arc + 1;
          arc += strlen (arc) + 1;
          dst = arc + 1;
 
+         if (*src == 0)
+           src = temp_stub;
+         else if (*dst == 0)
+           dst = temp_stub;
+           
          if (!rename_directory (src, dst))
            {
+             free (temp_stub);
              free (current_dir);
              /* FIXME: Make sure purge_directory(dst) will return
                 immediately */
-             return;
+             return false;
            }
        }
     }
+
+  free (temp_stub);
   
   /* Process deletes */
   p = NULL;
   for (cur = current_dir; *cur; cur += strlen (cur) + 1)
     {
-      if (!dumpdir_locate (current_stat_info.dumpdir, cur))
-       {
-         struct stat st;
-         if (p)
-           free (p);
-         p = new_name (directory_name, cur);
+      const char *entry;
+      struct stat st;
+      if (p)
+       free (p);
+      p = new_name (directory_name, cur);
 
+      if (!(entry = dumpdir_locate (current_stat_info.dumpdir, cur))
+         || (*entry == 'D' && S_ISDIR (st.st_mode))
+         || (*entry == 'Y' && !S_ISDIR (st.st_mode)))
+       {
          if (deref_stat (false, p, &st))
            {
              if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed
@@ -1261,8 +1338,16 @@ purge_directory (char const *directory_name)
   free (p);
   
   free (current_dir);
+  return true;
 }
 
+void
+purge_directory (char const *directory_name)
+{
+  if (!try_purge_directory (directory_name))
+    skip_member ();
+}
+     
 void
 list_dumpdir (char *buffer, size_t size)
 {
@@ -1275,6 +1360,7 @@ list_dumpdir (char *buffer, size_t size)
        case 'D':
        case 'R':
        case 'T':
+       case 'X':
          fprintf (stdlis, "%c ", *buffer);
          buffer++;
          size--;
This page took 0.028328 seconds and 4 git commands to generate.