Browse Source

(struct exclude_tag): rename to exclusion_tag
(check_exclusion_tags): New function
(cachedir_file_p): New function (from check_cache_directory)
(dump_dir0,dump_file0): Use check_exclusion_tags

Sergey Poznyakoff 18 years ago
parent
commit
b9588c4722
1 changed files with 121 additions and 94 deletions
  1. 121 94
      src/create.c

+ 121 - 94
src/create.c

@@ -1,7 +1,7 @@
 /* Create a tar archive.
 
    Copyright (C) 1985, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
    Written by John Gilmore, on 1985-08-25.
 
@@ -34,36 +34,53 @@ struct link
     char name[1];
   };
 
-struct exclude_tag
+struct exclusion_tag
 {
   const char *name;
   size_t length;
-  struct exclude_tag *next;
+  enum exclusion_tag_type type;
+  bool (*predicate) (const char *name);
+  struct exclusion_tag *next;
 };
 
-static struct exclude_tag *exclude_tags;
+static struct exclusion_tag *exclusion_tags;
 
 void
-add_exclude_tag (const char *name)
+add_exclusion_tag (const char *name, enum exclusion_tag_type type,
+		   bool (*predicate) (const char *name))
 {
-  struct exclude_tag *tag = xmalloc (sizeof tag[0]);
-  tag->next = exclude_tags;
+  struct exclusion_tag *tag = xmalloc (sizeof tag[0]);
+  tag->next = exclusion_tags;
   tag->name = name;
+  tag->type = type;
+  tag->predicate = predicate;
   tag->length = strlen (name);
-  exclude_tags = tag;
+  exclusion_tags = tag;
 }
 
-static bool
-check_exclude_tags (char *dirname)
+static void
+exclusion_tag_warning (const char *dirname, const char *tagname,
+		       const char *message)
+{
+  if (verbose_option)
+    WARN ((0, 0,
+	   _("%s: contains a cache directory tag %s; %s"),
+	   quotearg_colon (dirname),
+	   quotearg_n (1, tagname),
+	   message));
+}
+
+static enum exclusion_tag_type 
+check_exclusion_tags (char *dirname, const char **tag_file_name)
 {
   static char *tagname;
   static size_t tagsize;
-  struct exclude_tag *tag;
+  struct exclusion_tag *tag;
   size_t dlen = strlen (dirname);
   char *nptr = NULL;
   char *ret = NULL;
   
-  for (tag = exclude_tags; tag; tag = tag->next)
+  for (tag = exclusion_tags; tag; tag = tag->next)
     {
       size_t size = dlen + tag->length + 1;
       if (size > tagsize)
@@ -78,18 +95,45 @@ check_exclude_tags (char *dirname)
 	  nptr = tagname + dlen;
 	}
       strcpy (nptr, tag->name);
-      if (access (tagname, F_OK) == 0)
+      if (access (tagname, F_OK) == 0
+	  && (!tag->predicate || tag->predicate (tagname)))
 	{
-	  if (verbose_option)
-	    WARN ((0, 0,
-		   _("%s: contains a cache directory tag %s; not dumped"),
-		   quotearg_colon (dirname),
-		   quotearg_n (1, tag->name)));
-	  return true;
+	  if (tag_file_name)
+	    *tag_file_name = tag->name;
+	  return tag->type;
 	}
     }
 
-  return false;
+  return exclusion_tag_none;
+}
+
+/* Exclusion predicate to test if the named file (usually "CACHEDIR.TAG")
+   contains a valid header, as described at:
+	http://www.brynosaurus.com/cachedir
+   Applications can write this file into directories they create
+   for use as caches containing purely regenerable, non-precious data,
+   allowing us to avoid archiving them if --exclude-caches is specified. */
+
+#define CACHEDIR_SIGNATURE "Signature: 8a477f597d28d172789f06886806bc55"
+#define CACHEDIR_SIGNATURE_SIZE (sizeof CACHEDIR_SIGNATURE - 1)
+
+bool
+cachedir_file_p (const char *name)
+{
+  bool tag_present = false;
+  int fd = open (name, O_RDONLY);
+  if (fd >= 0)
+    {
+      static char tagbuf[CACHEDIR_SIGNATURE_SIZE];
+
+      if (read (fd, tagbuf, CACHEDIR_SIGNATURE_SIZE)
+	  == CACHEDIR_SIGNATURE_SIZE
+	  && memcmp (tagbuf, CACHEDIR_SIGNATURE, CACHEDIR_SIGNATURE_SIZE) == 0)
+	tag_present = true;
+
+      close (fd);
+    }
+  return tag_present;
 }
 
 
@@ -1043,53 +1087,13 @@ dump_regular_file (int fd, struct tar_stat_info *st)
 }
 
 
-/* Look in directory DIRNAME for a cache directory tag file
-   with the magic name "CACHEDIR.TAG" and a standard header,
-   as described at:
-	http://www.brynosaurus.com/cachedir
-   Applications can write this file into directories they create
-   for use as caches containing purely regenerable, non-precious data,
-   allowing us to avoid archiving them if --exclude-caches is specified. */
-
-#define CACHEDIR_SIGNATURE "Signature: 8a477f597d28d172789f06886806bc55"
-#define CACHEDIR_SIGNATURE_SIZE (sizeof CACHEDIR_SIGNATURE - 1)
-
-static bool
-check_cache_directory (char *dirname)
-{
-  static char tagname[] = "CACHEDIR.TAG";
-  char *tagpath;
-  int fd;
-  bool tag_present = false;
-
-  tagpath = xmalloc (strlen (dirname) + strlen (tagname) + 1);
-  strcpy (tagpath, dirname);
-  strcat (tagpath, tagname);
-
-  fd = open (tagpath, O_RDONLY);
-  if (fd >= 0)
-    {
-      static char tagbuf[CACHEDIR_SIGNATURE_SIZE];
-
-      if (read (fd, tagbuf, CACHEDIR_SIGNATURE_SIZE)
-	  == CACHEDIR_SIGNATURE_SIZE
-	  && memcmp (tagbuf, CACHEDIR_SIGNATURE, CACHEDIR_SIGNATURE_SIZE) == 0)
-	tag_present = true;
-
-      close (fd);
-    }
-
-  free (tagpath);
-
-  return tag_present;
-}
-
 static void
 dump_dir0 (char *directory,
 	   struct tar_stat_info *st, int top_level, dev_t parent_device)
 {
   dev_t our_device = st->stat.st_dev;
-
+  const char *tag_file_name;
+  
   if (!is_avoided_name (st->orig_file_name))
     {
       union block *blk = NULL;
@@ -1171,34 +1175,61 @@ dump_dir0 (char *directory,
 	WARN ((0, 0,
 	       _("%s: file is on a different filesystem; not dumped"),
 	       quotearg_colon (st->orig_file_name)));
-      return;
     }
-  
-  {
-    char const *entry;
-    size_t entry_len;
-    char *name_buf = xstrdup (st->orig_file_name);
-    size_t name_size = strlen (name_buf);
-    size_t name_len = name_size;
+  else
+    {
+      char *name_buf;
+      size_t name_size;
+      
+      switch (check_exclusion_tags (st->orig_file_name, &tag_file_name))
+	{
+	case exclusion_tag_none:
+	case exclusion_tag_all:
+	  {
+	    char const *entry;
+	    size_t entry_len;
+	    size_t name_len;
 
-    /* Now output all the files in the directory.  */
-    /* FIXME: Should speed this up by cd-ing into the dir.  */
+	    name_buf = xstrdup (st->orig_file_name);
+	    name_size = name_len = strlen (name_buf);
 
-    for (entry = directory; (entry_len = strlen (entry)) != 0;
-	 entry += entry_len + 1)
-      {
-	if (name_size < name_len + entry_len)
-	  {
-	    name_size = name_len + entry_len;
-	    name_buf = xrealloc (name_buf, name_size + 1);
+	    /* Now output all the files in the directory.  */
+	    /* FIXME: Should speed this up by cd-ing into the dir.  */
+
+	    for (entry = directory; (entry_len = strlen (entry)) != 0;
+		 entry += entry_len + 1)
+	      {
+		if (name_size < name_len + entry_len)
+		  {
+		    name_size = name_len + entry_len;
+		    name_buf = xrealloc (name_buf, name_size + 1);
+		  }
+		strcpy (name_buf + name_len, entry);
+		if (!excluded_name (name_buf))
+		  dump_file (name_buf, 0, our_device);
+	      }
+	    
+	    free (name_buf);
 	  }
-	strcpy (name_buf + name_len, entry);
-	if (!excluded_name (name_buf))
+	  break;
+
+	case exclusion_tag_contents:
+	  exclusion_tag_warning (st->orig_file_name, tag_file_name,
+				 _("contents not dumped"));
+	  name_size = strlen (st->orig_file_name) + strlen (tag_file_name) + 1;
+	  name_buf = xmalloc (name_size);
+	  strcpy (name_buf, st->orig_file_name);
+	  strcat (name_buf, tag_file_name);
 	  dump_file (name_buf, 0, our_device);
-      }
-
-    free (name_buf);
-  }
+	  free (name_buf);
+	  break;
+      
+	case exclusion_tag_under:
+	  exclusion_tag_warning (st->orig_file_name, tag_file_name,
+				 _("contents not dumped"));
+	  break;
+	}
+    }
 }
 
 /* Ensure exactly one trailing slash.  */
@@ -1544,22 +1575,18 @@ dump_file0 (struct tar_stat_info *st, const char *p,
 
       if (is_dir)
 	{
+	  const char *tag_file_name;
 	  ensure_slash (&st->orig_file_name);
 	  ensure_slash (&st->file_name);
 
-	  if (exclude_caches_option
-	      && check_cache_directory (st->orig_file_name))
+	  if (check_exclusion_tags (st->orig_file_name, &tag_file_name)
+	      == exclusion_tag_all)
 	    {
-	      if (verbose_option)
-		WARN ((0, 0,
-		       _("%s: contains a cache directory tag; not dumped"),
-		       quotearg_colon (st->orig_file_name)));
+	      exclusion_tag_warning (st->orig_file_name, tag_file_name,
+				     _("directory not dumped"));
 	      return;
 	    }
 	  
-	  if (check_exclude_tags (st->orig_file_name))
-	    return;
-
 	  ok = dump_dir (fd, st, top_level, parent_device);
 
 	  /* dump_dir consumes FD if successful.  */