]> Dogcows Code - chaz/tar/commitdiff
tar: --owner and --group names and numbers
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 13 Aug 2011 17:19:07 +0000 (10:19 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 13 Aug 2011 17:20:40 +0000 (10:20 -0700)
The --owner and --group options now accept operands of the form
NAME:NUM, so that you can specify both symbolic name and numeric
ID for owner and group.  Also, in these options, NAME no longer
needs to be present in the current host's user and group
databases; this implements Debian enhancement request 136231
<http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=136231> reported
by Mark W. Eichin, communicated by Thayne Harbaugh to bug-tar in
<http://lists.gnu.org/archive/html/bug-tar/2011-08/msg00001.html>.
* NEWS, doc/tar.texi (Option Summary, override): Document enhancement.
* src/common.h (group_name_option, owner_name_option): New decls.
* src/create.c (start_header): Don't assume owner and group names
are in current host database.
* src/tar.c (parse_owner_group): New function, for parsing NAME:NUM.
(parse_opt): Use it.
(decode_options): Initialize owner_name_option, group_name_option.
* tests/owner.at: New file, to test this enhancement.
* tests/Makefile.am (TESTSUITE_AT): Add it.
* tests/testsuite.at: Include it.

NEWS
doc/tar.texi
src/common.h
src/create.c
src/tar.c
tests/Makefile.am
tests/owner.at [new file with mode: 0644]
tests/testsuite.at

diff --git a/NEWS b/NEWS
index 12c1dd6308ff42f6508dbc6ddd0295ed01d5540d..06955f4f8e2d3f270320f0772f1813c6405e2b4e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,18 @@
-GNU tar NEWS - User visible changes. 2011-03-12
+GNU tar NEWS - User visible changes. 2011-08-13
 Please send GNU tar bug reports to <bug-tar@gnu.org>
 
 \f
+version ?.? - ?, 201?-??-??
+
+* New features
+
+** --owner and --group names and numbers
+
+The --owner and --group options now accept operands of the form
+NAME:NUM, so that you can specify both symbolic name and numeric ID
+for owner and group.  In these options, NAME no longer needs to be
+present in the current host's user and group databases.
+
 version 1.26 - Sergey Poznyakoff, 2011-03-12
 
 * Bugfixes
index 357c8c1c41f7e9b47030b15ee3a13cd8b2ba51ac..48e8c3cc002a57f0f5a5e9893f7b578088febc75 100644 (file)
@@ -2713,9 +2713,9 @@ tutorial}).
 @item --group=@var{group}
 
 Files added to the @command{tar} archive will have a group @acronym{ID} of @var{group},
-rather than the group from the source file.  @var{group} is first decoded
-as a group symbolic name, but if this interpretation fails, it has to be
-a decimal numeric group @acronym{ID}.  @xref{override}.
+rather than the group from the source file.  @var{group} can specify a
+symbolic name, or a numeric @acronym{ID}, or both as
+@var{name}:@var{id}.  @xref{override}.
 
 Also see the comments for the @option{--owner=@var{user}} option.
 
@@ -3082,8 +3082,8 @@ from an archive.  @xref{Overwrite Old Files}.
 
 Specifies that @command{tar} should use @var{user} as the owner of members
 when creating archives, instead of the user associated with the source
-file.  @var{user} is first decoded as a user symbolic name, but if
-this interpretation fails, it has to be a decimal numeric user @acronym{ID}.
+file.  @var{user} can specify a symbolic name, or a numeric
+@acronym{ID}, or both as @var{name}:@var{id}.
 @xref{override}.
 
 This option does not affect extraction from archives.
@@ -4947,8 +4947,22 @@ tar: Option --mtime: Treating date `yesterday' as 2006-06-20
 
 Specifies that @command{tar} should use @var{user} as the owner of members
 when creating archives, instead of the user associated with the source
-file.  The argument @var{user} can be either an existing user symbolic
-name, or a decimal numeric user @acronym{ID}.
+file.
+
+If @var{user} contains a colon, it is taken to be of the form
+@var{name}:@var{id} where a nonempty @var{name} specifies the user
+name and a nonempty @var{id} specifies the decimal numeric user
+@acronym{ID}.  If @var{user} does not contain a colon, it is taken to
+be a user number if it is one or more decimal digits; otherwise it is
+taken to be a user name.
+
+If a name is given but no number, the number is inferred from the
+current host's user database if possible, and the file's user number
+is used otherwise.  If a number is given but no name, the name is
+inferred from the number if possible, and an empty name is used
+otherwise.  If both name and number are given, the user database is
+not consulted, and the name and number need not be valid on the
+current host.
 
 There is no value indicating a missing number, and @samp{0} usually means
 @code{root}.  Some people like to force @samp{0} as the value to offer in
@@ -4971,8 +4985,9 @@ $ @kbd{tar -c -f archive.tar --owner=root .}
 @opindex group
 
 Files added to the @command{tar} archive will have a group @acronym{ID} of @var{group},
-rather than the group from the source file.  The argument @var{group}
-can be either an existing group symbolic name, or a decimal numeric group @acronym{ID}.
+rather than the group from the source file.  As with @option{--owner},
+the argument @var{group} can be an existing group symbolic name, or a
+decimal numeric group @acronym{ID}, or @var{name}:@var{id}.
 @end table
 
 @node Ignore Failed Read
index 0b9bd7a1273b5c76218863ffabbfa52097a42d12..8c81cad0393cbea477c6fa9610f0f3b7eb696520 100644 (file)
@@ -158,7 +158,8 @@ enum exclusion_tag_type
   };
 
 /* Specified value to be put into tar file in place of stat () results, or
-   just -1 if such an override should not take place.  */
+   just null and -1 if such an override should not take place.  */
+GLOBAL char const *group_name_option;
 GLOBAL gid_t group_option;
 
 GLOBAL bool ignore_failed_read_option;
@@ -230,7 +231,8 @@ GLOBAL bool numeric_owner_option;
 GLOBAL bool one_file_system_option;
 
 /* Specified value to be put into tar file in place of stat () results, or
-   just -1 if such an override should not take place.  */
+   just null and -1 if such an override should not take place.  */
+GLOBAL char const *owner_name_option;
 GLOBAL uid_t owner_option;
 
 GLOBAL bool recursive_unlink_option;
index 43b5a4c23ab1140f38180d02e2b140c9886bd031..9839e1fdc81a2d0e5a4a08e978c96f3540fa6566 100644 (file)
@@ -920,8 +920,15 @@ start_header (struct tar_stat_info *st)
     }
   else
     {
-      uid_to_uname (st->stat.st_uid, &st->uname);
-      gid_to_gname (st->stat.st_gid, &st->gname);
+      if (owner_name_option)
+       st->uname = xstrdup (owner_name_option);
+      else
+       uid_to_uname (st->stat.st_uid, &st->uname);
+
+      if (group_name_option)
+       st->gname = xstrdup (group_name_option);
+      else
+       gid_to_gname (st->stat.st_gid, &st->gname);
 
       if (archive_format == POSIX_FORMAT
          && (strlen (st->uname) > UNAME_FIELD_SIZE
index 95781624a4594c38a586f2f63b9b37fdf05954dc..6d370441b96e5932198aeb4a6b6dbbe5ac371e29 100644 (file)
--- a/src/tar.c
+++ b/src/tar.c
@@ -1364,6 +1364,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
@@ -1836,17 +1888,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:
@@ -1922,17 +1975,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:
@@ -2241,8 +2295,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;
 
index d9c9aae5f631a8955266ef55db6cf071f2f82bd4..7acc9d6dd4e02c9b1793d5709067b514b178d482 100644 (file)
@@ -128,6 +128,7 @@ TESTSUITE_AT = \
  old.at\
  options.at\
  options02.at\
+ owner.at\
  pipe.at\
  recurse.at\
  rename01.at\
diff --git a/tests/owner.at b/tests/owner.at
new file mode 100644 (file)
index 0000000..799bd43
--- /dev/null
@@ -0,0 +1,45 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+
+# Test suite for GNU tar.
+# Copyright 2011 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 Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# Check the --owner and --group options.
+
+AT_SETUP([--owner and --group])
+AT_KEYWORDS([owner])
+
+AT_TAR_CHECK([
+export TZ=UTC0
+
+genfile --file a
+
+tar --owner="Joe the Plumber:1234" \
+    --group="Plumber's Union:5678" \
+    --mtime='@0' \
+    -cf arc a
+
+tar -tvf arc
+tar --numeric-owner -tvf arc
+],
+[0],
+[-rw-r--r-- Joe the Plumber/Plumber's Union 0 1970-01-01 00:00 a
+-rw-r--r-- 1234/5678         0 1970-01-01 00:00 a
+],
+[],[],[],[gnu])
+
+AT_CLEANUP
index 9f262ec8c714ecb4acbf042a233637c482855a89..35f8c2f707a2ab2dea7c092539ffa56fef3f24d1 100644 (file)
@@ -222,6 +222,7 @@ m4_include([multiv07.at])
 m4_include([multiv08.at])
 
 m4_include([old.at])
+m4_include([owner.at])
 
 m4_include([recurse.at])
 
This page took 0.044219 seconds and 4 git commands to generate.