]> Dogcows Code - chaz/tar/blobdiff - src/tar.c
Include full-write.h.
[chaz/tar] / src / tar.c
index dfbeca8eb70f90a9e49b510537f4c2cad4060d9b..0095701d68ca9ec836590b0c9369d37b722ec7a9 100644 (file)
--- a/src/tar.c
+++ b/src/tar.c
@@ -1,5 +1,5 @@
 /* A tar (tape archiver) program.
-   Copyright 1988, 92,93,94,95,96,97, 1999 Free Software Foundation, Inc.
+   Copyright 1988,92,93,94,95,96,97,99,2000,2001 Free Software Foundation, Inc.
    Written by John Gilmore, starting 1985-08-25.
 
    This program is free software; you can redistribute it and/or modify it
@@ -18,6 +18,7 @@
 
 #include "system.h"
 
+#include <fnmatch.h>
 #include <getopt.h>
 
 #include <signal.h>
 # define SIGCHLD SIGCLD
 #endif
 
-#include <time.h>
-#ifndef time
-time_t time ();
-#endif
-
 /* The following causes "common.h" to produce definitions of all the global
    variables, rather than just "extern" declarations of them.  GNU tar does
    depend on the system loader to preset all GLOBAL variables to neutral (or
@@ -37,7 +33,10 @@ time_t time ();
 #define GLOBAL
 #include "common.h"
 
-#include "xstrtol.h"
+#include <localedir.h>
+#include <prepargs.h>
+#include <quotearg.h>
+#include <xstrtol.h>
 
 time_t get_date ();
 
@@ -51,17 +50,14 @@ time_t get_date ();
 # define DEFAULT_BLOCKING 20
 #endif
 
-static void usage PARAMS ((int));
+static void usage PARAMS ((int)) __attribute__ ((noreturn));
 \f
 /* Miscellaneous.  */
 
-/*----------------------------------------------.
-| Doesn't return if stdin already requested.    |
-`----------------------------------------------*/
-
 /* Name of option using stdin.  */
 static const char *stdin_used_by;
 
+/* Doesn't return if stdin already requested.  */
 void
 request_stdin (const char *option)
 {
@@ -72,10 +68,7 @@ request_stdin (const char *option)
   stdin_used_by = option;
 }
 
-/*--------------------------------------------------------.
-| Returns true if and only if the user typed 'y' or 'Y'.  |
-`--------------------------------------------------------*/
-
+/* Returns true if and only if the user typed 'y' or 'Y'.  */
 int
 confirm (const char *message_action, const char *message_name)
 {
@@ -85,18 +78,19 @@ confirm (const char *message_action, const char *message_name)
   if (!confirm_file)
     {
       if (archive == 0 || stdin_used_by)
-       confirm_file = fopen (TTY_NAME, "r");
+       {
+         confirm_file = fopen (TTY_NAME, "r");
+         if (! confirm_file)
+           open_fatal (TTY_NAME);
+       }
       else
        {
          request_stdin ("-w");
          confirm_file = stdin;
        }
-
-      if (!confirm_file)
-       FATAL_ERROR ((0, 0, _("Cannot read confirmation from user")));
     }
 
-  fprintf (stdlis, "%s %s?", message_action, message_name);
+  fprintf (stdlis, "%s %s?", message_action, quote (message_name));
   fflush (stdlis);
 
   {
@@ -134,8 +128,8 @@ enum
   GROUP_OPTION,
   MODE_OPTION,
   NEWER_MTIME_OPTION,
-  NO_RECURSE_OPTION,
   NULL_OPTION,
+  OVERWRITE_OPTION,
   OWNER_OPTION,
   POSIX_OPTION,
   PRESERVE_OPTION,
@@ -164,7 +158,7 @@ static int show_help;
 /* If nonzero, print the version on standard output and exit.  */
 static int show_version;
 
-struct option long_options[] =
+static struct option long_options[] =
 {
   {"absolute-names", no_argument, 0, 'P'},
   {"absolute-paths", no_argument, 0, OBSOLETE_ABSOLUTE_NAMES},
@@ -176,7 +170,7 @@ struct option long_options[] =
   {"block-number", no_argument, 0, 'R'},
   {"block-size", required_argument, 0, OBSOLETE_BLOCKING_FACTOR},
   {"blocking-factor", required_argument, 0, 'b'},
-  {"bzip2", no_argument, 0, 'I'},
+  {"bzip2", no_argument, 0, 'j'},
   {"catenate", no_argument, 0, 'A'},
   {"checkpoint", no_argument, &checkpoint_option, 1},
   {"compare", no_argument, 0, 'd'},
@@ -217,12 +211,13 @@ struct option long_options[] =
   {"newer", required_argument, 0, 'N'},
   {"newer-mtime", required_argument, 0, NEWER_MTIME_OPTION},
   {"null", no_argument, 0, NULL_OPTION},
-  {"no-recursion", no_argument, 0, NO_RECURSE_OPTION},
+  {"no-recursion", no_argument, &recursion_option, 0},
   {"no-same-owner", no_argument, &same_owner_option, -1},
   {"no-same-permissions", no_argument, &same_permissions_option, -1},
   {"numeric-owner", no_argument, &numeric_owner_option, 1},
   {"old-archive", no_argument, 0, 'o'},
   {"one-file-system", no_argument, 0, 'l'},
+  {"overwrite", no_argument, 0, OVERWRITE_OPTION},
   {"owner", required_argument, 0, OWNER_OPTION},
   {"portability", no_argument, 0, 'o'},
   {"posix", no_argument, 0, POSIX_OPTION},
@@ -262,10 +257,7 @@ struct option long_options[] =
   {0, 0, 0, 0}
 };
 
-/*---------------------------------------------.
-| Print a usage message and exit with STATUS.  |
-`---------------------------------------------*/
-
+/* Print a usage message and exit with STATUS.  */
 static void
 usage (int status)
 {
@@ -308,7 +300,8 @@ Main operation mode:\n\
 Operation modifiers:\n\
   -W, --verify               attempt to verify the archive after writing it\n\
       --remove-files         remove files after adding them to the archive\n\
-  -k, --keep-old-files       don't overwrite existing files when extracting\n\
+  -k, --keep-old-files       don't replace existing files when extracting\n\
+      --overwrite            overwrite existing files when extracting\n\
   -U, --unlink-first         remove each file prior to extracting over it\n\
       --recursive-unlink     empty hierarchies prior to extracting directory\n\
   -S, --sparse               handle sparse files efficiently\n\
@@ -364,7 +357,7 @@ Archive format selection:\n\
               PATTERN                at list/extract time, a globbing PATTERN\n\
   -o, --old-archive, --portability   write a V7 format archive\n\
       --posix                        write a POSIX format archive\n\
-  -I, --bzip2                        filter the archive through bzip2\n\
+  -j, --bzip2                        filter the archive through bzip2\n\
   -z, --gzip, --ungzip               filter the archive through gzip\n\
   -Z, --compress, --uncompress       filter the archive through compress\n\
       --use-compress-program=PROG    filter through PROG (must accept -d)\n"),
@@ -428,17 +421,20 @@ or a device.  *This* `tar' defaults to `-f%s -b%d'.\n"),
   exit (status);
 }
 
-/*----------------------------.
-| Parse the options for tar.  |
-`----------------------------*/
+/* Parse the options for tar.  */
 
-/* Available option letters are DEHJQY and aejnqy.  Some are reserved:
+/* Available option letters are DEHIJQY and aenqy.  Some are reserved:
 
+   e  exit immediately with a nonzero exit status if unexpected errors occur
+   E  use extended headers (draft POSIX headers, that is)
+   I  same as T (for compatibility with Solaris tar)
+   n  the archive is quickly seekable, so don't worry about random seeks
+   q  stop after extracting the first occurrence of the named file
    y  per-file gzip compression
    Y  per-block gzip compression */
 
 #define OPTION_STRING \
-  "-01234567ABC:F:GIK:L:MN:OPRST:UV:WX:Zb:cdf:g:hiklmoprstuvwxz"
+  "-01234567ABC:F:GK:L:MN:OPRST:UV:WX:Zb:cdf:g:hijklmoprstuvwxz"
 
 static void
 set_subcommand_option (enum subcommand subcommand)
@@ -473,7 +469,7 @@ add_filtered_exclude (struct exclude *dummy, char const *pattern)
 }
 
 static void
-decode_options (int argc, char *const *argv)
+decode_options (int argc, char **argv)
 {
   int optchar;                 /* option letter */
   int input_files;             /* number of input files */
@@ -489,6 +485,7 @@ decode_options (int argc, char *const *argv)
   excluded_with_slash = new_exclude ();
   excluded_without_slash = new_exclude ();
   newer_mtime_option = TYPE_MINIMUM (time_t);
+  recursion_option = FNM_LEADING_DIR;
 
   owner_option = -1;
   group_option = -1;
@@ -554,6 +551,8 @@ decode_options (int argc, char *const *argv)
 
   input_files = 0;
 
+  prepend_default_options (getenv ("TAR_OPTIONS"), &argc, &argv);
+
   while (optchar = getopt_long (argc, argv, OPTION_STRING, long_options, 0),
         optchar != -1)
     switch (optchar)
@@ -591,7 +590,8 @@ decode_options (int argc, char *const *argv)
                 && u == (blocking_factor = u)
                 && 0 < blocking_factor
                 && u == (record_size = u * BLOCKSIZE) / BLOCKSIZE))
-           USAGE_ERROR ((0, 0, _("Invalid blocking factor")));
+           USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+                         _("Invalid blocking factor")));
        }
        break;
 
@@ -670,14 +670,13 @@ decode_options (int argc, char *const *argv)
        ignore_zeros_option = 1;
        break;
 
-      case 'I':
+      case 'j':
        set_use_compress_program_option ("bzip2");
        break;
 
       case 'k':
-       /* Don't overwrite existing files.  */
-
-       keep_old_files_option = 1;
+       /* Don't replace existing files.  */
+       old_files_option = KEEP_OLD_FILES;
        break;
 
       case 'K':
@@ -696,7 +695,8 @@ decode_options (int argc, char *const *argv)
        {
          uintmax_t u;
          if (xstrtoumax (optarg, 0, 10, &u, "") != LONGINT_OK)
-           USAGE_ERROR ((0, 0, _("Invalid tape length")));
+           USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+                         _("Invalid tape length")));
          tape_length_option = 1024 * (tarlong) u;
          multi_volume_option = 1;
        }
@@ -723,13 +723,28 @@ decode_options (int argc, char *const *argv)
        /* Fall through.  */
 
       case NEWER_MTIME_OPTION:
-       if (newer_mtime_option != TYPE_MINIMUM (time_t))
+       if (newer_mtime_option != TYPE_MINIMUM (time_t))
          USAGE_ERROR ((0, 0, _("More than one threshold date")));
 
-       newer_mtime_option = get_date (optarg, 0);
-       if (newer_mtime_option == (time_t) -1)
-         WARN ((0, 0, _("Substituting %s for unknown date format `%s'"),
-                tartime (newer_mtime_option), optarg));
+       if (FILESYSTEM_PREFIX_LEN (optarg) != 0
+           || ISSLASH (*optarg)
+           || *optarg == '.')
+         {
+           struct stat st;
+           if (deref_stat (dereference_option, optarg, &st) != 0)
+             {
+               stat_error (optarg);
+               USAGE_ERROR ((0, 0, _("Date file not found")));
+             }
+           newer_mtime_option = st.st_mtime;
+         }
+       else
+         {
+           newer_mtime_option = get_date (optarg, 0);
+           if (newer_mtime_option == (time_t) -1)
+             WARN ((0, 0, _("Substituting %s for unknown date format %s"),
+                    tartime (newer_mtime_option), quote (optarg)));
+         }
 
        break;
 #endif /* not MSDOS */
@@ -800,7 +815,7 @@ decode_options (int argc, char *const *argv)
        break;
 
       case 'U':
-       unlink_first_option = 1;
+       old_files_option = UNLINK_FIRST_OLD_FILES;
        break;
 
       case 'v':
@@ -825,7 +840,10 @@ decode_options (int argc, char *const *argv)
 
       case 'X':
        if (add_exclude_file (add_filtered_exclude, 0, optarg, '\n') != 0)
-         FATAL_ERROR ((0, errno, "%s", optarg));
+         {
+           int e = errno;
+           FATAL_ERROR ((0, e, "%s", quotearg_colon (optarg)));
+         }
        break;
 
       case 'z':
@@ -863,7 +881,8 @@ decode_options (int argc, char *const *argv)
                && g == (gid_t) g)
              group_option = g;
            else
-             FATAL_ERROR ((0, 0, _("Invalid group given on option")));
+             FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+                           _("%s: Invalid group")));
          }
        break;
 
@@ -874,17 +893,17 @@ decode_options (int argc, char *const *argv)
        if (mode_option == MODE_INVALID)
          FATAL_ERROR ((0, 0, _("Invalid mode given on option")));
        if (mode_option == MODE_MEMORY_EXHAUSTED)
-         FATAL_ERROR ((0, 0, _("Memory exhausted")));
-       break;
-
-      case NO_RECURSE_OPTION:
-       no_recurse_option = 1;
+         xalloc_die ();
        break;
 
       case NULL_OPTION:
        filename_terminator = '\0';
        break;
 
+      case OVERWRITE_OPTION:
+       old_files_option = OVERWRITE_OLD_FILES;
+       break;
+
       case OWNER_OPTION:
        if (! (strlen (optarg) < UNAME_FIELD_SIZE
               && uname_to_uid (optarg, &owner_option)))
@@ -894,7 +913,8 @@ decode_options (int argc, char *const *argv)
                && u == (uid_t) u)
              owner_option = u;
            else
-             FATAL_ERROR ((0, 0, _("Invalid owner given on option")));
+             FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+                           _("Invalid owner")));
          }
        break;
 
@@ -922,7 +942,8 @@ decode_options (int argc, char *const *argv)
          uintmax_t u;
          if (! (xstrtoumax (optarg, 0, 10, &u, "") == LONGINT_OK
                 && u == (size_t) u))
-           USAGE_ERROR ((0, 0, _("Invalid record size")));
+           USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+                         _("Invalid record size")));
          record_size = u;
          if (record_size % BLOCKSIZE != 0)
            USAGE_ERROR ((0, 0, _("Record size must be a multiple of %d."),
@@ -1039,7 +1060,7 @@ decode_options (int argc, char *const *argv)
   if (show_version)
     {
       printf ("tar (GNU %s) %s\n%s\n%s\n%s\n", PACKAGE, VERSION,
-             "Copyright 1999 Free Software Foundation, Inc.",
+             "Copyright 2001 Free Software Foundation, Inc.",
              _("\
 This program comes with NO WARRANTY, to the extent permitted by law.\n\
 You may redistribute it under the terms of the GNU General Public License;\n\
@@ -1093,9 +1114,27 @@ see the file named COPYING for details."),
     USAGE_ERROR ((0, 0,
                  _("Cannot combine --listed-incremental with --newer")));
 
+  if (volume_label_option)
+    {
+      size_t volume_label_max_len =
+       (sizeof current_header->header.name
+        - 1 /* for trailing '\0' */
+        - (multi_volume_option
+           ? (sizeof " Volume "
+              - 1 /* for null at end of " Volume " */
+              + INT_STRLEN_BOUND (int) /* for volume number */
+              - 1 /* for sign, as 0 <= volno */)
+           : 0));
+      if (volume_label_max_len < strlen (volume_label_option))
+       USAGE_ERROR ((0, 0,
+                     _("%s: Volume label is too long (limit is %lu bytes)"),
+                     quotearg_colon (volume_label_option),
+                     (unsigned long) volume_label_max_len));
+    }
+
   /* If ready to unlink hierarchies, so we are for simpler files.  */
   if (recursive_unlink_option)
-    unlink_first_option = 1;
+    old_files_option = UNLINK_FIRST_OLD_FILES;
 
   /* Forbid using -c with no input files whatsoever.  Check that `-f -',
      explicit or implied, is used correctly.  */
@@ -1145,12 +1184,9 @@ see the file named COPYING for details."),
 \f
 /* Tar proper.  */
 
-/*-----------------------.
-| Main routine for tar.         |
-`-----------------------*/
-
+/* Main routine for tar.  */
 int
-main (int argc, char *const *argv)
+main (int argc, char **argv)
 {
 #if HAVE_CLOCK_GETTIME
   if (clock_gettime (CLOCK_REALTIME, &start_timespec) != 0)
@@ -1163,6 +1199,7 @@ main (int argc, char *const *argv)
 
   exit_status = TAREXIT_SUCCESS;
   filename_terminator = '\n';
+  set_quoting_style (0, escape_quoting_style);
 
   /* Pre-allocate a few structures.  */
 
@@ -1215,6 +1252,7 @@ main (int argc, char *const *argv)
     case EXTRACT_SUBCOMMAND:
       extr_init ();
       read_and (extract_archive);
+      extract_finish ();
       break;
 
     case LIST_SUBCOMMAND:
This page took 0.031152 seconds and 4 git commands to generate.