]> Dogcows Code - chaz/tar/blobdiff - src/tar.c
Improve listed incremental dumps.
[chaz/tar] / src / tar.c
index 41a53ec5a4f62b53458c081b7d326dbd764d57fc..8d23a4faa656f270dee2a3b70838003a035e81ad 100644 (file)
--- a/src/tar.c
+++ b/src/tar.c
@@ -1,7 +1,7 @@
 /* A tar (tape archiver) program.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000,
-   2001, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   2001, 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
 
    Written by John Gilmore, starting 1985-08-25.
 
@@ -50,6 +50,7 @@
 #include <version-etc.h>
 #include <xstrtol.h>
 #include <stdopen.h>
+#include <priv-set.h>
 
 /* Local declarations.  */
 
@@ -249,8 +250,11 @@ enum
   ANCHORED_OPTION = CHAR_MAX + 1,
   ATIME_PRESERVE_OPTION,
   BACKUP_OPTION,
+  CHECK_DEVICE_OPTION,
   CHECKPOINT_OPTION,
+  CHECKPOINT_ACTION_OPTION,
   DELAY_DIRECTORY_RESTORE_OPTION,
+  HARD_DEREFERENCE_OPTION,
   DELETE_OPTION,
   EXCLUDE_CACHES_OPTION,
   EXCLUDE_CACHES_UNDER_OPTION,
@@ -268,14 +272,19 @@ enum
   IGNORE_FAILED_READ_OPTION,
   INDEX_FILE_OPTION,
   KEEP_NEWER_FILES_OPTION,
+  LEVEL_OPTION,
   LZMA_OPTION,
+  LZOP_OPTION,
   MODE_OPTION,
   MTIME_OPTION,
   NEWER_MTIME_OPTION,
   NO_ANCHORED_OPTION,
+  NO_AUTO_COMPRESS_OPTION,
+  NO_CHECK_DEVICE_OPTION,
   NO_DELAY_DIRECTORY_RESTORE_OPTION,
   NO_IGNORE_CASE_OPTION,
   NO_IGNORE_COMMAND_ERROR_OPTION,
+  NO_NULL_OPTION,
   NO_OVERWRITE_DIR_OPTION,
   NO_QUOTE_CHARS_OPTION,
   NO_RECURSION_OPTION,
@@ -317,10 +326,10 @@ enum
   TRANSFORM_OPTION,
   UNQUOTE_OPTION,
   USAGE_OPTION,
-  USE_COMPRESS_PROGRAM_OPTION,
   UTC_OPTION,
   VERSION_OPTION,
   VOLNO_FILE_OPTION,
+  WARNING_OPTION, 
   WILDCARDS_MATCH_SLASH_OPTION,
   WILDCARDS_OPTION
 };
@@ -346,7 +355,7 @@ The version control may be set with --backup or VERSION_CONTROL, values are:\n\n
 
 /* NOTE:
 
-   Available option letters are DEIJQY and eqy. Consider the following
+   Available option letters are DEQY and eqy. Consider the following
    assignments:
 
    [For Solaris tar compatibility =/= Is it important at all?]
@@ -354,7 +363,6 @@ The version control may be set with --backup or VERSION_CONTROL, values are:\n\n
    E  use extended headers (--format=posix)
 
    [q  alias for --occurrence=1 =/= this would better be used for quiet?]
-   [I  same as T =/= will harm star compatibility]
 
    y  per-file gzip compression
    Y  per-block gzip compression */
@@ -399,6 +407,8 @@ static struct argp_option options[] = {
    N_("handle old GNU-format incremental backup"), GRID+1 },
   {"listed-incremental", 'g', N_("FILE"), 0,
    N_("handle new GNU-format incremental backup"), GRID+1 },
+  {"level", LEVEL_OPTION, N_("NUMBER"), 0,
+   N_("dump level for created listed-incremental archive"), GRID+1 },
   {"ignore-failed-read", IGNORE_FAILED_READ_OPTION, 0, 0,
    N_("do not exit with nonzero on unreadable files"), GRID+1 },
   {"occurrence", OCCURRENCE_OPTION, N_("NUMBER"), OPTION_ARG_OPTIONAL,
@@ -409,6 +419,12 @@ static struct argp_option options[] = {
       " NUMBER defaults to 1"), GRID+1 },
   {"seek", 'n', NULL, 0,
    N_("archive is seekable"), GRID+1 },
+  {"no-check-device", NO_CHECK_DEVICE_OPTION, NULL, 0,
+   N_("do not check device numbers when creating incremental archives"),
+   GRID+1 },
+  {"check-device", CHECK_DEVICE_OPTION, NULL, 0,
+   N_("check device numbers when creating incremental archives (default)"),
+   GRID+1 },
 #undef GRID
 
 #define GRID 30
@@ -470,9 +486,9 @@ static struct argp_option options[] = {
   {"touch", 'm', 0, 0,
    N_("don't extract file modified time"), GRID+1 },
   {"same-owner", SAME_OWNER_OPTION, 0, 0,
-   N_("try extracting files with the same ownership"), GRID+1 },
+   N_("try extracting files with the same ownership as exists in the archive (default for superuser)"), GRID+1 },
   {"no-same-owner", NO_SAME_OWNER_OPTION, 0, 0,
-   N_("extract files as yourself"), GRID+1 },
+   N_("extract files as yourself (default for ordinary users)"), GRID+1 },
   {"numeric-owner", NUMERIC_OWNER_OPTION, 0, 0,
    N_("always use numbers for user/group names"), GRID+1 },
   {"preserve-permissions", 'p', 0, 0,
@@ -582,6 +598,9 @@ static struct argp_option options[] = {
    N_("Compression options:"), GRID },
   {"auto-compress", 'a', 0, 0,
    N_("use archive suffix to determine the compression program"), GRID+1 },
+  {"no-auto-compress", NO_AUTO_COMPRESS_OPTION, 0, 0,
+   N_("do not use archive suffix to determine the compression program"),
+   GRID+1 },
   {"bzip2", 'j', 0, 0,
    N_("filter the archive through bzip2"), GRID+1 },
   {"gzip", 'z', 0, 0,
@@ -593,7 +612,11 @@ static struct argp_option options[] = {
   {"uncompress", 0, 0, OPTION_ALIAS, NULL, GRID+1 },
   {"lzma", LZMA_OPTION, 0, 0,
    N_("filter the archive through lzma"), GRID+1 },
-  {"use-compress-program", USE_COMPRESS_PROGRAM_OPTION, N_("PROG"), 0,
+  {"lzop", LZOP_OPTION, 0, 0,
+   N_("filter the archive through lzop"), GRID+8 },
+  {"xz", 'J', 0, 0,
+   N_("filter the archive through xz"), GRID+8 },
+  {"use-compress-program", 'I', N_("PROG"), 0,
    N_("filter through PROG (must accept -d)"), GRID+1 },
 #undef GRID
   
@@ -609,6 +632,8 @@ static struct argp_option options[] = {
    N_("get names to extract or create from FILE"), GRID+1 },
   {"null", NULL_OPTION, 0, 0,
    N_("-T reads null-terminated names, disable -C"), GRID+1 },
+  {"no-null", NO_NULL_OPTION, 0, 0,
+   N_("disable the effect of the previous --null option"), GRID+1 },
   {"unquote", UNQUOTE_OPTION, 0, 0,
    N_("unquote filenames read with -T (default)"), GRID+1 },
   {"no-unquote", NO_UNQUOTE_OPTION, 0, 0,
@@ -644,6 +669,8 @@ static struct argp_option options[] = {
    N_("don't strip leading `/'s from file names"), GRID+1 },
   {"dereference", 'h', 0, 0,
    N_("follow symlinks; archive and dump the files they point to"), GRID+1 },
+  {"hard-dereference", HARD_DEREFERENCE_OPTION, 0, 0,
+   N_("follow hard links; archive and dump the files they refer to"), GRID+1 },
   {"starting-file", 'K', N_("MEMBER-NAME"), 0,
    N_("begin at member MEMBER-NAME in the archive"), GRID+1 },
   {"newer", 'N', N_("DATE-OR-FILE"), 0,
@@ -665,6 +692,7 @@ static struct argp_option options[] = {
    GRID+1 },
   {"transform", TRANSFORM_OPTION, N_("EXPRESSION"), 0,
    N_("use sed replace EXPRESSION to transform file names"), GRID+1 },
+  {"xform", 0, 0, OPTION_ALIAS, NULL, GRID+1 },
 #undef GRID
 
 #define GRID 120
@@ -695,9 +723,14 @@ static struct argp_option options[] = {
 
   {"verbose", 'v', 0, 0,
    N_("verbosely list files processed"), GRID+1 },
-  {"checkpoint", CHECKPOINT_OPTION, N_("[.]NUMBER"), OPTION_ARG_OPTIONAL,
+  {"warning", WARNING_OPTION, N_("KEYWORD"), 0,
+   N_("warning control"), GRID+1 },
+  {"checkpoint", CHECKPOINT_OPTION, N_("NUMBER"), OPTION_ARG_OPTIONAL,
    N_("display progress messages every NUMBERth record (default 10)"),
    GRID+1 },
+  {"checkpoint-action", CHECKPOINT_ACTION_OPTION, N_("ACTION"), 0,
+   N_("execute ACTION on each checkpoint"),
+   GRID+1 },
   {"check-links", 'l', 0, 0,
    N_("print a message if not all links are dumped"), GRID+1 },
   {"totals", TOTALS_OPTION, N_("SIGNAL"), OPTION_ARG_OPTIONAL,
@@ -834,6 +867,16 @@ exclude_vcs_files ()
     "=RELEASE-ID",
     "=meta-update",
     "=update",
+    /* Bazaar */
+    ".bzr",
+    ".bzrignore",
+    ".bzrtags",
+    /* Mercurial */
+    ".hg",
+    ".hgignore",
+    ".hgtags",
+    /* darcs */
+    "_darcs",
     NULL
   };
 
@@ -1014,6 +1057,9 @@ report_textual_dates (struct tar_args *args)
 \f
 static volatile int _argp_hang;
 
+/* Either NL or NUL, as decided by the --null option.  */
+static char filename_terminator;
+
 enum read_file_list_state  /* Result of reading file name from the list file */
   {
     file_list_success,     /* OK, name read successfully */
@@ -1022,16 +1068,16 @@ enum read_file_list_state  /* Result of reading file name from the list file */
     file_list_skip         /* Empty (zero-length) entry encountered, skip it */
   };
 
-/* Read from FP a sequence of characters up to FILENAME_TERMINATOR and put them
+/* Read from FP a sequence of characters up to TERM and put them
    into STK.
  */
 static enum read_file_list_state
-read_name_from_file (FILE *fp, struct obstack *stk)
+read_name_from_file (FILE *fp, struct obstack *stk, int term)
 {
   int c;
   size_t counter = 0;
 
-  for (c = getc (fp); c != EOF && c != filename_terminator; c = getc (fp))
+  for (c = getc (fp); c != EOF && c != term; c = getc (fp))
     {
       if (c == 0)
        {
@@ -1112,7 +1158,8 @@ update_argv (const char *filename, struct argp_state *state)
   size_t new_argc;
   bool is_stdin = false;
   enum read_file_list_state read_state;
-
+  int term = filename_terminator;
+  
   if (!strcmp (filename, "-"))
     {
       is_stdin = true;
@@ -1126,7 +1173,8 @@ update_argv (const char *filename, struct argp_state *state)
        open_fatal (filename);
     }
 
-  while ((read_state = read_name_from_file (fp, &argv_stk)) != file_list_end)
+  while ((read_state = read_name_from_file (fp, &argv_stk, term))
+        != file_list_end)
     {
       switch (read_state)
        {
@@ -1141,8 +1189,9 @@ update_argv (const char *filename, struct argp_state *state)
          {
            size_t size;
 
-           WARN ((0, 0, N_("%s: file name read contains nul character"),
-                  quotearg_colon (filename)));
+           WARNOPT (WARN_FILENAME_WITH_NULS,
+                    (0, 0, N_("%s: file name read contains nul character"),
+                     quotearg_colon (filename)));
 
            /* Prepare new stack contents */
            size = obstack_object_size (&argv_stk);
@@ -1155,7 +1204,7 @@ update_argv (const char *filename, struct argp_state *state)
            obstack_1grow (&argv_stk, 0);
            count = 1;
            /* Read rest of files using new filename terminator */
-           filename_terminator = 0;
+           term = 0;
            break;
          }
 
@@ -1172,7 +1221,7 @@ update_argv (const char *filename, struct argp_state *state)
 
   start = obstack_finish (&argv_stk);
 
-  if (filename_terminator == 0)
+  if (term == 0)
     for (p = start; *p; p += strlen (p) + 1)
       if (p[0] == '-')
        count++;
@@ -1188,7 +1237,7 @@ update_argv (const char *filename, struct argp_state *state)
 
   for (i = state->next, p = start; *p; p += strlen (p) + 1, i++)
     {
-      if (filename_terminator == 0 && p[0] == '-')
+      if (term == 0 && p[0] == '-')
        state->argv[i++] = "--add-file";
       state->argv[i] = p;
     }
@@ -1237,6 +1286,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case 'a':
       args->compress_autodetect = true;
       break;
+
+    case NO_AUTO_COMPRESS_OPTION:
+      args->compress_autodetect = false;
+      break;
       
     case 'b':
       {
@@ -1308,6 +1361,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
       dereference_option = true;
       break;
 
+    case HARD_DEREFERENCE_OPTION:
+      hard_dereference_option = true;
+      break;
+      
     case 'i':
       /* Ignore zero blocks (eofs).  This can't be the default,
         because Unix tar writes two blocks of zeros, then pads out
@@ -1316,16 +1373,14 @@ parse_opt (int key, char *arg, struct argp_state *state)
       ignore_zeros_option = true;
       break;
 
-    case 'I':
-      USAGE_ERROR ((0, 0,
-                   _("Warning: the -I option is not supported;"
-                     " perhaps you meant -j or -T?")));
-      break;
-
     case 'j':
       set_use_compress_program_option ("bzip2");
       break;
 
+    case 'J':
+      set_use_compress_program_option ("xz");
+      break;
+      
     case 'k':
       /* Don't replace existing files.  */
       old_files_option = KEEP_OLD_FILES;
@@ -1333,7 +1388,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
 
     case 'K':
       starting_file_option = true;
-      addname (arg, 0);
+      addname (arg, 0, NULL);
       break;
 
     case ONE_FILE_SYSTEM_OPTION:
@@ -1357,10 +1412,23 @@ parse_opt (int key, char *arg, struct argp_state *state)
       }
       break;
 
+    case LEVEL_OPTION:
+      {
+       char *p;
+       incremental_level = strtoul (arg, &p, 10);
+       if (*p)
+         USAGE_ERROR ((0, 0, _("Invalid incremental level value")));
+      }
+      break;
+      
     case LZMA_OPTION:
       set_use_compress_program_option ("lzma");
       break;
       
+    case LZOP_OPTION:
+      set_use_compress_program_option ("lzop");
+      break;
+      
     case 'm':
       touch_option = true;
       break;
@@ -1482,6 +1550,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
 
     case 'v':
       verbose_option++;
+      warning_option |= WARN_VERBOSE_WARNINGS;
       break;
 
     case 'V':
@@ -1534,6 +1603,14 @@ parse_opt (int key, char *arg, struct argp_state *state)
                        " on this platform")));
       break;
 
+    case CHECK_DEVICE_OPTION:
+      check_device_option = true;
+      break;
+      
+    case NO_CHECK_DEVICE_OPTION:
+      check_device_option = false;
+      break;
+      
     case CHECKPOINT_OPTION:
       if (arg)
        {
@@ -1541,7 +1618,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
 
          if (*arg == '.')
            {
-             checkpoint_style = checkpoint_dot;
+             checkpoint_compile_action (".");
              arg++;
            }
          checkpoint_option = strtoul (arg, &p, 0);
@@ -1550,9 +1627,13 @@ parse_opt (int key, char *arg, struct argp_state *state)
                          _("--checkpoint value is not an integer")));
        }
       else
-       checkpoint_option = 10;
+       checkpoint_option = DEFAULT_CHECKPOINT;
       break;
 
+    case CHECKPOINT_ACTION_OPTION:
+      checkpoint_compile_action (arg);
+      break;
+      
     case BACKUP_OPTION:
       backup_option = true;
       if (arg)
@@ -1690,6 +1771,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
       filename_terminator = '\0';
       break;
 
+    case NO_NULL_OPTION:
+      filename_terminator = '\n';
+      break;
+
     case NUMERIC_OWNER_OPTION:
       numeric_owner_option = true;
       break;
@@ -1752,6 +1837,8 @@ parse_opt (int key, char *arg, struct argp_state *state)
       /* FIXME: What it is good for? */
       same_permissions_option = true;
       same_order_option = true;
+      WARN ((0, 0, _("The --preserve option is deprecated, "
+                    "use --preserve-permissions --preserve-order instead")));
       break;
 
     case RECORD_SIZE_OPTION:
@@ -1835,7 +1922,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
       set_transform_expr (arg);
       break;
 
-    case USE_COMPRESS_PROGRAM_OPTION:
+    case 'I':
       set_use_compress_program_option (arg);
       break;
 
@@ -1879,6 +1966,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
       unquote_option = false;
       break;
 
+    case WARNING_OPTION:
+      set_warning_option (arg);
+      break;
+      
     case '0':
     case '1':
     case '2':
@@ -2038,6 +2129,10 @@ decode_options (int argc, char **argv)
   owner_option = -1;
   group_option = -1;
 
+  check_device_option = true;
+
+  incremental_level = -1;
+  
   /* Convert old-style tar call by exploding option element and rearranging
      options accordingly.  */
 
@@ -2202,7 +2297,10 @@ decode_options (int argc, char **argv)
       && NEWER_OPTION_INITIALIZED (newer_mtime_option))
     USAGE_ERROR ((0, 0,
                  _("Cannot combine --listed-incremental with --newer")));
-
+  if (incremental_level != -1 && !listed_incremental_option)
+    WARN ((0, 0,
+          _("--level is meaningless without --listed-incremental")));
+  
   if (volume_label_option)
     {
       if (archive_format == GNU_FORMAT || archive_format == OLDGNU_FORMAT)
@@ -2274,6 +2372,13 @@ decode_options (int argc, char **argv)
   else if (utc_option)
     verbose_option = 2;
 
+  if (tape_length_option && tape_length_option < record_size)
+    USAGE_ERROR ((0, 0, _("Volume length cannot be less than record size")));
+
+  if (same_order_option && listed_incremental_option)
+    USAGE_ERROR ((0, 0, _("--preserve-order is not compatible with "
+                         "--listed-incremental")));
+  
   /* Forbid using -c with no input files whatsoever.  Check that `-f -',
      explicit or implied, is used correctly.  */
 
@@ -2339,6 +2444,8 @@ decode_options (int argc, char **argv)
        backup_option = false;
     }
 
+  checkpoint_finish_compile ();
+  
   if (verbose_option)
     report_textual_dates (&args);
 }
@@ -2374,11 +2481,14 @@ main (int argc, char **argv)
 
   obstack_init (&argv_stk);
 
-#ifdef SIGCHLD
+  /* Ensure default behavior for some signals */
+  signal (SIGPIPE, SIG_DFL);
   /* System V fork+wait does not work if SIGCHLD is ignored.  */
   signal (SIGCHLD, SIG_DFL);
-#endif
 
+  /* Try to disable the ability to unlink a directory.  */
+  priv_set_remove_linkdir ();
+  
   /* Decode options.  */
 
   decode_options (argc, argv);
@@ -2445,7 +2555,7 @@ main (int argc, char **argv)
   name_term ();
 
   if (exit_status == TAREXIT_FAILURE)
-    error (0, 0, _("Error exit delayed from previous errors"));
+    error (0, 0, _("Exiting with failure status due to previous errors"));
 
   if (stdlis == stdout)
     close_stdout ();
This page took 0.037613 seconds and 4 git commands to generate.