]> Dogcows Code - chaz/tar/blobdiff - src/incremen.c
(directory.new): New member
[chaz/tar] / src / incremen.c
index ec8a86dfe4dc3c1f38fd6be2051aa76ffd482c0b..366fb36c486b5b6ae96c189f17020f3a33bc1bce 100644 (file)
@@ -1,7 +1,7 @@
 /* GNU dump extensions to tar.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004, 2005 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
@@ -34,9 +34,10 @@ struct directory
     struct timespec mtime;      /* Modification time */
     dev_t device_number;       /* device number for directory */
     ino_t inode_number;                /* inode number for directory */
-    enum children children;
-    bool nfs;
-    bool found;
+    enum children children;     /* what to save under this directory */
+    bool nfs;                   /* is the directory mounted on nfs? */
+    bool found;                 /* was the directory found on fs? */
+    bool new;                   /* is it new? */
     char name[1];              /* file name of directory */
   };
 
@@ -67,6 +68,19 @@ compare_directories (void const *entry1, void const *entry2)
   return strcmp (directory1->name, directory2->name) == 0;
 }
 
+static struct directory *
+make_directory (const char *name)
+{
+  size_t namelen = strlen (name);
+  size_t size = offsetof (struct directory, name) + namelen + 1;
+  struct directory *directory = xmalloc (size);
+  strcpy (directory->name, name);
+  if (ISSLASH (directory->name[namelen-1]))
+    directory->name[namelen-1] = 0;
+  directory->new = false;
+  return directory;
+}
+  
 /* Create and link a new directory entry for directory NAME, having a
    device number DEV and an inode number INO, with NFS indicating
    whether it is an NFS device and FOUND indicating whether we have
@@ -75,8 +89,7 @@ static struct directory *
 note_directory (char const *name, struct timespec mtime,
                dev_t dev, ino_t ino, bool nfs, bool found)
 {
-  size_t size = offsetof (struct directory, name) + strlen (name) + 1;
-  struct directory *directory = xmalloc (size);
+  struct directory *directory = make_directory (name);
 
   directory->mtime = mtime;
   directory->device_number = dev;
@@ -84,7 +97,6 @@ note_directory (char const *name, struct timespec mtime,
   directory->children = CHANGED_CHILDREN;
   directory->nfs = nfs;
   directory->found = found;
-  strcpy (directory->name, name);
 
   if (! ((directory_table
          || (directory_table = hash_initialize (0, 0, hash_directory,
@@ -103,10 +115,10 @@ find_directory (char *name)
     return 0;
   else
     {
-      size_t size = offsetof (struct directory, name) + strlen (name) + 1;
-      struct directory *dir = alloca (size);
-      strcpy (dir->name, name);
-      return hash_lookup (directory_table, dir);
+      struct directory *dir = make_directory (name);
+      struct directory *ret = hash_lookup (directory_table, dir);
+      free (dir);
+      return ret;
     }
 }
 
@@ -115,15 +127,9 @@ update_parent_directory (const char *name)
 {
   struct directory *directory;
   char *p, *name_buffer;
-  
+
   p = dir_name (name);
-  name_buffer = xmalloc (strlen (p) + 2);
-  strcpy (name_buffer, p);
-  if (! ISSLASH (p[strlen (p) - 1]))
-    strcat (name_buffer, "/");
-  
-  directory = find_directory (name_buffer);
-  free (name_buffer);
+  directory = find_directory (p);
   if (directory)
     {
       struct stat st;
@@ -142,15 +148,16 @@ compare_dirents (const void *first, const void *second)
                 (*(char *const *) second) + 1);
 }
 
-enum children 
+enum children
 procdir (char *name_buffer, struct stat *stat_data,
         dev_t device,
         enum children children,
         bool verbose)
-{ 
+{
   struct directory *directory;
   bool nfs = NFS_FILE_STAT (*stat_data);
-  
+  struct name *np;
+
   if ((directory = find_directory (name_buffer)) != NULL)
     {
       /* With NFS, the same file can have two different devices
@@ -159,7 +166,7 @@ procdir (char *name_buffer, struct stat *stat_data,
         To avoid spurious incremental redumping of
         directories, consider all NFS devices as equal,
         relying on the i-node to establish differences.  */
-      
+
       if (! (((directory->nfs & nfs)
              || directory->device_number == stat_data->st_dev)
             && directory->inode_number == stat_data->st_ino))
@@ -172,7 +179,7 @@ procdir (char *name_buffer, struct stat *stat_data,
          directory->device_number = stat_data->st_dev;
          directory->inode_number = stat_data->st_ino;
        }
-      else if (listed_incremental_option)
+      else if (listed_incremental_option && !directory->new)
        /* Newer modification time can mean that new files were
           created in the directory or some of the existing files
           were renamed. */
@@ -201,13 +208,18 @@ procdir (char *name_buffer, struct stat *stat_data,
                 && OLDER_STAT_TIME (*stat_data, c))))
        ? ALL_CHILDREN
        : CHANGED_CHILDREN;
+      directory->new = true;
     }
-  
-  if (one_file_system_option && device != stat_data->st_dev)
+
+  /* If the directory is on another device and --one-file-system was given,
+     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))
     directory->children = NO_CHILDREN;
   else if (children == ALL_CHILDREN)
     directory->children = ALL_CHILDREN;
-  
+
   return directory->children;
 }
 
@@ -242,7 +254,7 @@ scan_directory (struct obstack *stk, char *dir_name, dev_t device)
     }
   else
     children = procdir (name_buffer, &stat_data, device, NO_CHILDREN, false);
-  
+
   if (dirp && children != NO_CHILDREN)
     for (entry = dirp;
         (entrylen = strlen (entry)) != 0;
@@ -288,13 +300,12 @@ scan_directory (struct obstack *stk, char *dir_name, dev_t device)
              }
 #endif
 
+           else if (children == CHANGED_CHILDREN
+                    && OLDER_STAT_TIME (stat_data, m)
+                    && (!after_date_option || OLDER_STAT_TIME (stat_data, c)))
+             obstack_1grow (stk, 'N');
            else
-             if (children == CHANGED_CHILDREN
-                 && OLDER_STAT_TIME (stat_data, m)
-                 && (!after_date_option || OLDER_STAT_TIME (stat_data, c)))
-               obstack_1grow (stk, 'N');
-             else
-               obstack_1grow (stk, 'Y');
+             obstack_1grow (stk, 'Y');
          }
 
        obstack_grow (stk, entry, entrylen + 1);
@@ -372,7 +383,7 @@ dumpdir_size (const char *p)
       totsize += size;
       p += size;
     }
-  return totsize + 1;  
+  return totsize + 1;
 }
 
 \f
@@ -394,7 +405,7 @@ static FILE *listed_incremental_stream;
    correctly and that tar will use the most conservative backup method among
    possible alternatives (i.e. prefer ALL_CHILDREN over CHANGED_CHILDREN,
    etc.) This ensures that the snapshots are updated to the recent version
-   without any loss of data. */ 
+   without any loss of data. */
 void
 read_directory_file (void)
 {
@@ -431,7 +442,7 @@ read_directory_file (void)
       uintmax_t u;
       time_t t = u;
       int incremental_version;
-      
+
       if (strncmp (buf, PACKAGE_NAME, sizeof PACKAGE_NAME - 1) == 0)
        {
          ebuf = buf + sizeof PACKAGE_NAME - 1;
@@ -440,7 +451,7 @@ read_directory_file (void)
          for (; *ebuf != '-'; ebuf++)
            if (!*ebuf)
              ERROR((1, 0, _("Bad incremental file format")));
-         
+
          incremental_version = (errno = 0, strtoumax (ebuf+1, &ebuf, 10));
          if (getline (&buf, &bufsize, fp) <= 0)
            {
@@ -456,7 +467,7 @@ read_directory_file (void)
       if (incremental_version > TAR_INCREMENTAL_VERSION)
        ERROR((1, 0, _("Unsupported incremental format version: %d"),
               incremental_version));
-      
+
       t = u = (errno = 0, strtoumax (buf, &ebuf, 10));
       if (buf == ebuf || (u == 0 && errno == EINVAL))
        ERROR ((0, 0, "%s:%ld: %s",
@@ -471,7 +482,7 @@ read_directory_file (void)
       else if (incremental_version == 1)
        {
          newer_mtime_option.tv_sec = t;
-         
+
          t = u = (errno = 0, strtoumax (buf, &ebuf, 10));
          if (buf == ebuf || (u == 0 && errno == EINVAL))
            ERROR ((0, 0, "%s:%ld: %s",
@@ -513,19 +524,19 @@ read_directory_file (void)
                ERROR ((0, 0, "%s:%ld: %s",
                        quotearg_colon (listed_incremental_option), lineno,
                        _("Invalid modification time (seconds)")));
-             else if (mtime.tv_sec != u) 
+             else if (mtime.tv_sec != u)
                ERROR ((0, 0, "%s:%ld: %s",
                        quotearg_colon (listed_incremental_option), lineno,
                        _("Modification time (seconds) out of range")));
              strp = ebuf;
-         
+
              errno = 0;
              mtime.tv_nsec = u = strtoumax (strp, &ebuf, 10);
              if (!isspace (*ebuf))
                ERROR ((0, 0, "%s:%ld: %s",
                        quotearg_colon (listed_incremental_option), lineno,
                        _("Invalid modification time (nanoseconds)")));
-             else if (mtime.tv_nsec != u) 
+             else if (mtime.tv_nsec != u)
                ERROR ((0, 0, "%s:%ld: %s",
                        quotearg_colon (listed_incremental_option), lineno,
                        _("Modification time (nanoseconds) out of range")));
@@ -533,14 +544,14 @@ read_directory_file (void)
            }
          else
            memset (&mtime, 0, sizeof mtime);
-         
+
          errno = 0;
          dev = u = strtoumax (strp, &ebuf, 10);
          if (!isspace (*ebuf))
            ERROR ((0, 0, "%s:%ld: %s",
                    quotearg_colon (listed_incremental_option), lineno,
                    _("Invalid device number")));
-         else if (dev != u) 
+         else if (dev != u)
            ERROR ((0, 0, "%s:%ld: %s",
                    quotearg_colon (listed_incremental_option), lineno,
                    _("Device number out of range")));
@@ -560,7 +571,7 @@ read_directory_file (void)
 
          strp++;
          unquote_string (strp);
-         note_directory (strp, mtime, dev, ino, nfs, 0);
+         note_directory (strp, mtime, dev, ino, nfs, false);
        }
     }
 
@@ -583,7 +594,7 @@ write_directory_file_entry (void *entry, void *data)
       int e;
       char buf[UINTMAX_STRSIZE_BOUND];
       char *str = quote_copy_string (directory->name);
-      
+
       if (directory->nfs)
        fprintf (fp, "+");
       fprintf (fp, "%s ", umaxtostr (directory->mtime.tv_sec, buf));
@@ -591,7 +602,7 @@ write_directory_file_entry (void *entry, void *data)
       fprintf (fp, "%s ", umaxtostr (directory->device_number, buf));
       fprintf (fp, "%s ", umaxtostr (directory->inode_number, buf));
       fprintf (fp, "%s\n", str ? str : directory->name);
-              
+
       e = errno;
       if (str)
        free (str);
@@ -616,7 +627,7 @@ write_directory_file (void)
 
   fprintf (fp, "%s-%s-%d\n", PACKAGE_NAME, PACKAGE_VERSION,
           TAR_INCREMENTAL_VERSION);
-  
+
   fprintf (fp, "%lu %lu\n",
           (unsigned long int) start_time.tv_sec,
           (unsigned long int) start_time.tv_nsec);
@@ -631,24 +642,22 @@ write_directory_file (void)
 \f
 /* Restoration of incremental dumps.  */
 
-void
-get_gnu_dumpdir ()
+static void
+get_gnu_dumpdir (struct tar_stat_info *stat_info)
 {
   size_t size;
   size_t copied;
   union block *data_block;
   char *to;
   char *archive_dir;
-  
-  size = current_stat_info.stat.st_size;
-  if (size != current_stat_info.stat.st_size)
-    xalloc_die ();
+
+  size = stat_info->stat.st_size;
 
   archive_dir = xmalloc (size);
   to = archive_dir;
 
   set_next_block_after (current_header);
-  mv_begin (&current_stat_info);
+  mv_begin (stat_info);
 
   for (; size > 0; size -= copied)
     {
@@ -666,12 +675,22 @@ get_gnu_dumpdir ()
     }
 
   mv_end ();
-  
-  current_stat_info.stat.st_size = 0; /* For skip_member() and friends
-                                        to work correctly */
-  current_stat_info.dumpdir = archive_dir;
+
+  stat_info->dumpdir = archive_dir;
+  stat_info->skipped = true; /* For skip_member() and friends
+                               to work correctly */
 }
 
+/* Return T if STAT_INFO represents a dumpdir archive member.
+   Note: can invalidate current_header. It happens if flush_archive()
+   gets called within get_gnu_dumpdir() */
+bool
+is_dumpdir (struct tar_stat_info *stat_info)
+{
+  if (stat_info->is_dumpdir && !stat_info->dumpdir)
+    get_gnu_dumpdir (stat_info);
+  return stat_info->is_dumpdir;
+}
 
 /* Examine the directories under directory_name and delete any
    files that were not there at the time of the back-up. */
@@ -681,12 +700,12 @@ purge_directory (char const *directory_name)
   char *current_dir;
   char *cur, *arc;
 
-  if (!current_stat_info.dumpdir)
+  if (!is_dumpdir (&current_stat_info))
     {
       skip_member ();
       return;
     }
-  
+
   current_dir = savedir (directory_name);
 
   if (!current_dir)
@@ -758,13 +777,13 @@ list_dumpdir (char *buffer, size_t size)
          buffer++;
          size--;
          break;
-         
+
        case 0:
          fputc ('\n', stdlis);
          buffer++;
          size--;
          break;
-         
+
        default:
          fputc (*buffer, stdlis);
          buffer++;
This page took 0.03311 seconds and 4 git commands to generate.