Преглед изворни кода

(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)
   if (dump)
     while (*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,
 	   They normally do not occur in dumpdirs from the snapshot files,
 	   but this function is also used by purge_directory, which operates
 	   but this function is also used by purge_directory, which operates
 	   on a dumpdir from the archive, hence the need for this test. */
 	   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);
 	    int rc = strcmp (dump + 1, name);
 	    if (rc == 0)
 	    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
 static void
 obstack_code_rename (struct obstack *stk, char *from, char *to)
 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
 	  /* Break the cycle by using a temporary name for one of its
 	     elements.
 	     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)
 	  for (p = dir; p != prev; p = p->orig)
 	    obstack_code_rename (stk, p->orig->name, p->name);
 	    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;
   return true;
@@ -1173,50 +1134,160 @@ is_dumpdir (struct tar_stat_info *stat_info)
   return stat_info->is_dumpdir;
   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
 /* Examine the directories under directory_name and delete any
    files that were not there at the time of the back-up. */
    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 *current_dir;
   char *cur, *arc, *p;
   char *cur, *arc, *p;
-
+  char *temp_stub = NULL;
+  
   if (!is_dumpdir (&current_stat_info))
   if (!is_dumpdir (&current_stat_info))
-    {
-      skip_member ();
-      return;
-    }
+    return false;
 
 
   current_dir = savedir (directory_name);
   current_dir = savedir (directory_name);
 
 
   if (!current_dir)
   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 */
   /* Process renames */
   for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
   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;
 	  char *src, *dst;
 	  src = arc + 1;
 	  src = arc + 1;
 	  arc += strlen (arc) + 1;
 	  arc += strlen (arc) + 1;
 	  dst = arc + 1;
 	  dst = arc + 1;
 
 
+	  if (*src == 0)
+	    src = temp_stub;
+	  else if (*dst == 0)
+	    dst = temp_stub;
+	    
 	  if (!rename_directory (src, dst))
 	  if (!rename_directory (src, dst))
 	    {
 	    {
+	      free (temp_stub);
 	      free (current_dir);
 	      free (current_dir);
 	      /* FIXME: Make sure purge_directory(dst) will return
 	      /* FIXME: Make sure purge_directory(dst) will return
 		 immediately */
 		 immediately */
-	      return;
+	      return false;
 	    }
 	    }
 	}
 	}
     }
     }
+
+  free (temp_stub);
   
   
   /* Process deletes */
   /* Process deletes */
   p = NULL;
   p = NULL;
@@ -1267,8 +1338,16 @@ purge_directory (char const *directory_name)
   free (p);
   free (p);
   
   
   free (current_dir);
   free (current_dir);
+  return true;
 }
 }
 
 
+void
+purge_directory (char const *directory_name)
+{
+  if (!try_purge_directory (directory_name))
+    skip_member ();
+}
+     
 void
 void
 list_dumpdir (char *buffer, size_t size)
 list_dumpdir (char *buffer, size_t size)
 {
 {
@@ -1281,6 +1360,7 @@ list_dumpdir (char *buffer, size_t size)
 	case 'D':
 	case 'D':
 	case 'R':
 	case 'R':
 	case 'T':
 	case 'T':
+	case 'X':
 	  fprintf (stdlis, "%c ", *buffer);
 	  fprintf (stdlis, "%c ", *buffer);
 	  buffer++;
 	  buffer++;
 	  size--;
 	  size--;