瀏覽代碼

(dumpdir_locate,obstack_code_rename,purge_directory): Re-implement renaming. Introduce
X control code.
(make_tmp_dir_name): Remove

Sergey Poznyakoff 19 年之前
父節點
當前提交
2d2e1d411e
共有 1 個文件被更改,包括 146 次插入66 次删除
  1. 146 66
      src/incremen.c

+ 146 - 66
src/incremen.c

@@ -343,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)
@@ -556,49 +557,6 @@ get_directory_contents (char *dir_name, dev_t device)
 }
 
 
-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)
 {
@@ -639,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;
@@ -1173,50 +1134,160 @@ 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;
@@ -1267,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)
 {
@@ -1281,6 +1360,7 @@ list_dumpdir (char *buffer, size_t size)
 	case 'D':
 	case 'R':
 	case 'T':
+	case 'X':
 	  fprintf (stdlis, "%c ", *buffer);
 	  buffer++;
 	  size--;