]> Dogcows Code - chaz/tar/blobdiff - src/tar.c
Fix --keep-old-files option.
[chaz/tar] / src / tar.c
index 223de2cdf531137d07c2ddbdbfe705f9af1fa764..21d9910712ed8aea12f2bef2ea4a984e019a6f74 100644 (file)
--- a/src/tar.c
+++ b/src/tar.c
@@ -43,7 +43,7 @@
 #include <closeout.h>
 #include <configmake.h>
 #include <exitfail.h>
-#include <getdate.h>
+#include <parse-datetime.h>
 #include <rmt.h>
 #include <rmt-command.h>
 #include <prepargs.h>
@@ -328,6 +328,7 @@ enum
   SHOW_DEFAULTS_OPTION,
   SHOW_OMITTED_DIRS_OPTION,
   SHOW_TRANSFORMED_NAMES_OPTION,
+  SKIP_OLD_FILES_OPTION,
   SPARSE_VERSION_OPTION,
   STRIP_COMPONENTS_OPTION,
   SUFFIX_OPTION,
@@ -452,7 +453,11 @@ static struct argp_option options[] = {
   {"remove-files", REMOVE_FILES_OPTION, 0, 0,
    N_("remove files after adding them to the archive"), GRID+1 },
   {"keep-old-files", 'k', 0, 0,
-   N_("don't replace existing files when extracting"), GRID+1 },
+   N_("don't replace existing files when extracting, "
+      "treat them as errors"), GRID+1 },
+  {"skip-old-files", SKIP_OLD_FILES_OPTION, 0, 0,
+   N_("don't replace existing files when extracting, silently skip over them"),
+   GRID+1 },
   {"keep-newer-files", KEEP_NEWER_FILES_OPTION, 0, 0,
    N_("don't replace existing files that are newer than their archive copies"), GRID+1 },
   {"overwrite", OVERWRITE_OPTION, 0, 0,
@@ -892,12 +897,12 @@ static char const * const backup_file_table[] = {
 };
 
 static void
-add_exclude_array (char const * const * fv)
+add_exclude_array (char const * const * fv, int options)
 {
   int i;
 
   for (i = 0; fv[i]; i++)
-    add_exclude (excluded, fv[i], 0);
+    add_exclude (excluded, fv[i], options);
 }
 
 \f
@@ -956,10 +961,13 @@ static void
 stat_on_signal (int signo)
 {
 #ifdef HAVE_SIGACTION
+# ifndef SA_RESTART
+#  define SA_RESTART 0
+# endif
   struct sigaction act;
   act.sa_handler = sigstat;
   sigemptyset (&act.sa_mask);
-  act.sa_flags = 0;
+  act.sa_flags = SA_RESTART;
   sigaction (signo, &act, NULL);
 #else
   signal (signo, sigstat);
@@ -1014,7 +1022,7 @@ get_date_or_file (struct tar_args *args, const char *option,
       || *str == '.')
     {
       struct stat st;
-      if (deref_stat (dereference_option, str, &st) != 0)
+      if (stat (str, &st) != 0)
        {
          stat_error (str);
          USAGE_ERROR ((0, 0, _("Date sample file not found")));
@@ -1023,7 +1031,7 @@ get_date_or_file (struct tar_args *args, const char *option,
     }
   else
     {
-      if (! get_date (ts, str, NULL))
+      if (! parse_datetime (ts, str, NULL))
        {
          WARN ((0, 0, _("Substituting %s for unknown date format %s"),
                 tartime (*ts, false), quote (str)));
@@ -1142,6 +1150,20 @@ add_file_id (const char *filename)
   file_id_list = p;
 }
 
+/* Default density numbers for [0-9][lmh] device specifications */
+
+#ifndef LOW_DENSITY_NUM
+# define LOW_DENSITY_NUM 0
+#endif
+
+#ifndef MID_DENSITY_NUM
+# define MID_DENSITY_NUM 8
+#endif
+
+#ifndef HIGH_DENSITY_NUM
+# define HIGH_DENSITY_NUM 16
+#endif
+
 static void
 update_argv (const char *filename, struct argp_state *state)
 {
@@ -1350,6 +1372,58 @@ expand_pax_option (struct tar_args *targs, const char *arg)
 }
 
 \f
+static uintmax_t
+parse_owner_group (char *arg, uintmax_t field_max, char const **name_option)
+{
+  strtol_error err;
+  uintmax_t u = UINTMAX_MAX;
+  char *end;
+  char const *name = 0;
+  char const *invalid_num = 0;
+  char *colon = strchr (arg, ':');
+
+  if (colon)
+    {
+      char const *num = colon + 1;
+      *colon = '\0';
+      if (*arg)
+       name = arg;
+      if (num && (! (xstrtoumax (num, &end, 10, &u, "") == LONGINT_OK
+                    && u <= field_max)))
+       invalid_num = num;
+    }
+  else
+    {
+      uintmax_t u1;
+      switch ('0' <= *arg && *arg <= '9'
+             ? xstrtoumax (arg, &end, 10, &u1, "")
+             : LONGINT_INVALID)
+       {
+       default:
+         name = arg;
+         break;
+
+       case LONGINT_OK:
+         if (u1 <= field_max)
+           {
+             u = u1;
+             break;
+           }
+         /* Fall through.  */
+       case LONGINT_OVERFLOW:
+         invalid_num = arg;
+         break;
+       }
+    }
+
+  if (invalid_num)
+    FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (invalid_num),
+                 _("Invalid owner or group ID")));
+  if (name)
+    *name_option = name;
+  return u;
+}
+
 #define TAR_SIZE_SUFFIXES "bBcGgkKMmPTtw"
 
 static error_t
@@ -1475,7 +1549,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
       /* Don't replace existing files.  */
       old_files_option = KEEP_OLD_FILES;
       break;
-
+      
     case 'K':
       starting_file_option = true;
       addname (arg, 0, true, NULL);
@@ -1605,6 +1679,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
       sparse_option = true;
       break;
 
+    case SKIP_OLD_FILES_OPTION:
+      old_files_option = SKIP_OLD_FILES;
+      break;
+
     case SPARSE_VERSION_OPTION:
       sparse_option = true;
       {
@@ -1755,7 +1833,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
       break;
 
     case EXCLUDE_BACKUPS_OPTION:
-      add_exclude_array (backup_file_table);
+      add_exclude_array (backup_file_table, EXCLUDE_WILDCARDS);
       break;
 
     case EXCLUDE_OPTION:
@@ -1790,7 +1868,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
       break;
 
     case EXCLUDE_VCS_OPTION:
-      add_exclude_array (vcs_file_table);
+      add_exclude_array (vcs_file_table, 0);
       break;
 
     case FORCE_LOCAL_OPTION:
@@ -1822,17 +1900,18 @@ parse_opt (int key, char *arg, struct argp_state *state)
       break;
 
     case GROUP_OPTION:
-      if (! (strlen (arg) < GNAME_FIELD_SIZE
-            && gname_to_gid (arg, &group_option)))
-       {
-         uintmax_t g;
-         if (xstrtoumax (arg, 0, 10, &g, "") == LONGINT_OK
-             && g == (gid_t) g)
-           group_option = g;
-         else
-           FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (arg),
-                         _("Invalid group")));
-       }
+      {
+       uintmax_t u = parse_owner_group (arg, TYPE_MAXIMUM (gid_t),
+                                        &group_name_option);
+       if (u == UINTMAX_MAX)
+         {
+           group_option = -1;
+           if (group_name_option)
+             gname_to_gid (group_name_option, &group_option);
+         }
+       else
+         group_option = u;
+      }
       break;
 
     case MODE_OPTION:
@@ -1908,17 +1987,18 @@ parse_opt (int key, char *arg, struct argp_state *state)
       break;
 
     case OWNER_OPTION:
-      if (! (strlen (arg) < UNAME_FIELD_SIZE
-            && uname_to_uid (arg, &owner_option)))
-       {
-         uintmax_t u;
-         if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK
-             && u == (uid_t) u)
-           owner_option = u;
-         else
-           FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (arg),
-                         _("Invalid owner")));
-       }
+      {
+       uintmax_t u = parse_owner_group (arg, TYPE_MAXIMUM (uid_t),
+                                        &owner_name_option);
+       if (u == UINTMAX_MAX)
+         {
+           owner_option = -1;
+           if (owner_name_option)
+             uname_to_uid (owner_name_option, &owner_option);
+         }
+       else
+         owner_option = u;
+      }
       break;
 
     case QUOTE_CHARS_OPTION:
@@ -2227,8 +2307,8 @@ decode_options (int argc, char **argv)
   tar_sparse_major = 1;
   tar_sparse_minor = 0;
 
-  owner_option = -1;
-  group_option = -1;
+  owner_option = -1; owner_name_option = NULL;
+  group_option = -1; group_name_option = NULL;
 
   check_device_option = true;
 
@@ -2451,6 +2531,18 @@ decode_options (int argc, char **argv)
   if (recursive_unlink_option)
     old_files_option = UNLINK_FIRST_OLD_FILES;
 
+  /* Flags for accessing files to be read from or copied into.  POSIX says
+     O_NONBLOCK has unspecified effect on most types of files, but in
+     practice it never harms and sometimes helps.  */
+  {
+    int base_open_flags =
+      (O_BINARY | O_CLOEXEC | O_NOCTTY | O_NONBLOCK
+       | (dereference_option ? 0 : O_NOFOLLOW)
+       | (atime_preserve_option == system_atime_preserve ? O_NOATIME : 0));
+    open_read_flags = O_RDONLY | base_open_flags;
+    open_searchdir_flags = O_SEARCH | O_DIRECTORY | base_open_flags;
+  }
+  fstatat_flags = dereference_option ? 0 : AT_SYMLINK_NOFOLLOW;
 
   if (subcommand_option == TEST_LABEL_SUBCOMMAND)
     {
@@ -2662,9 +2754,31 @@ tar_stat_init (struct tar_stat_info *st)
   memset (st, 0, sizeof (*st));
 }
 
+/* Close the stream or file descriptor associated with ST, and remove
+   all traces of it from ST.  Return true if successful, false (with a
+   diagnostic) otherwise.  */
+bool
+tar_stat_close (struct tar_stat_info *st)
+{
+  int status = (st->dirstream ? closedir (st->dirstream)
+               : 0 < st->fd ? close (st->fd)
+               : 0);
+  st->dirstream = 0;
+  st->fd = 0;
+
+  if (status == 0)
+    return true;
+  else
+    {
+      close_diag (st->orig_file_name);
+      return false;
+    }
+}
+
 void
 tar_stat_destroy (struct tar_stat_info *st)
 {
+  tar_stat_close (st);
   free (st->orig_file_name);
   free (st->file_name);
   free (st->link_name);
This page took 0.027205 seconds and 4 git commands to generate.