New options: --owner-map and --group-map.
* NEWS: Update. * doc/tar.1: Document --owner-map and --group-map * doc/tar.texi: Likewise. * src/map.c: New file. * src/Makefile.am: Add map.c * src/common.h (owner_map_read, owner_map_translate) (group_map_read, group_map_translate): New protos. * src/create.c (start_header): Use owner_map_translate and group_map_translate to optionally translate user/group names/ids. * src/tar.c: New options --owner-map and --group-map. * tests/map.at: New file. * tests/Makefile.am: Add map.at * tests/testsuite.at: Include map.at.
This commit is contained in:
20
NEWS
20
NEWS
@@ -1,4 +1,4 @@
|
||||
GNU tar NEWS - User visible changes. 2015-08-03
|
||||
GNU tar NEWS - User visible changes. 2015-11-02
|
||||
Please send GNU tar bug reports to <bug-tar@gnu.org>
|
||||
|
||||
|
||||
@@ -22,6 +22,24 @@ This option affects all --files-from options that occur after it in
|
||||
the command line. Its effect is reverted by the
|
||||
--no-verbatim-files-from option.
|
||||
|
||||
* New options: --owner-map=FILE and --group-map=FILE
|
||||
|
||||
These two options provide fine-grained control over what user/group
|
||||
names (or IDs) should be mapped when adding files to archive.
|
||||
|
||||
For both options, FILE is a plain text file with user or group
|
||||
mappings. Empty lines are ignored. Comments are introduced with
|
||||
# sign (unless quoted) and extend to the end of the corresponding
|
||||
line. Each non-empty line defines translation for a single UID (GID).
|
||||
It must consist of two fields, delimited by any amount of whitespace:
|
||||
|
||||
OLDNAME NEWNAME[:NEWID]
|
||||
|
||||
OLDNAME is either a valid user (group) name or a ID prefixed with +. Unless
|
||||
NEWID is supplied, NEWNAME must also be either a valid name or a
|
||||
+ID. Otherwise, both NEWNAME and NEWID need not be listed in the
|
||||
system user database.
|
||||
|
||||
* --null option reads file names verbatim
|
||||
|
||||
The --null option implies --verbatim-files-from. I.e. each line
|
||||
|
||||
60
doc/tar.1
60
doc/tar.1
@@ -13,7 +13,7 @@
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU General Public License
|
||||
.\" along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
.TH TAR 1 "August 24, 2015" "TAR" "GNU TAR Manual"
|
||||
.TH TAR 1 "November 2, 2015" "TAR" "GNU TAR Manual"
|
||||
.SH NAME
|
||||
tar \- an archiving utility
|
||||
.SH SYNOPSIS
|
||||
@@ -467,8 +467,33 @@ Delay setting modification times and permissions of extracted
|
||||
directories until the end of extraction. Use this option when
|
||||
extracting from an archive which has unusual member ordering.
|
||||
.TP
|
||||
\fB\-\-group\fR=\fINAME\fR
|
||||
Force \fINAME\fR as group for added files.
|
||||
\fB\-\-group\fR=\fINAME\fR[:\fIGID\fR]
|
||||
Force \fINAME\fR as group for added files. If \fIGID\fR is not
|
||||
supplied, \fINAME\fR can be either a user name or numeric GID. In
|
||||
this case the missing part (GID or name) will be inferred from the
|
||||
current host's group database.
|
||||
|
||||
When used with \fB\-\-group\-map\fR=\fIFILE\fR, affects only those
|
||||
files whose owner group is not listed in \fIFILE\fR.
|
||||
.TP
|
||||
\fB\-\-group\-map\fR=\fIFILE\fR
|
||||
Read group translation map from \fIFILE\fR. Empty lines are ignored.
|
||||
Comments are introduced with \fB#\fR sign and extend to the end of line.
|
||||
Each non-empty line in \fIFILE\fR defines translation for a single
|
||||
group. It must consist of two fields, delimited by any amount of whitespace:
|
||||
|
||||
.EX
|
||||
\fIOLDGRP\fR \fINEWGRP\fR[\fB:\fINEWGID\fR]
|
||||
.EE
|
||||
|
||||
\fIOLDGRP\fR is either a valid group name or a GID prefixed with
|
||||
\fB+\fR. Unless \fINEWGID\fR is supplied, \fINEWGRP\fR must also be
|
||||
either a valid group name or a \fB+\fIGID\fR. Otherwise, both
|
||||
\fINEWGRP\fR and \fINEWGID\fR need not be listed in the system group
|
||||
database.
|
||||
|
||||
As a result, each input file with owner group \fIOLDGRP\fR will be
|
||||
stored in archive with owner group \fINEWGRP\fR and GID \fINEWGID\fR.
|
||||
.TP
|
||||
\fB\-\-mode\fR=\fICHANGES\fR
|
||||
Force symbolic mode \fICHANGES\fR for added files.
|
||||
@@ -494,8 +519,33 @@ Apply the user's umask when extracting permissions from the archive
|
||||
\fB\-\-numeric\-owner\fR
|
||||
Always use numbers for user/group names.
|
||||
.TP
|
||||
\fB\-\-owner\fR=\fINAME\fR
|
||||
Force \fINAME\fR as owner for added files.
|
||||
\fB\-\-owner\fR=\fINAME\fR[:\fIUID\fR]
|
||||
Force \fINAME\fR as owner for added files. If \fIUID\fR is not
|
||||
supplied, \fINAME\fR can be either a user name or numeric UID. In
|
||||
this case the missing part (UID or name) will be inferred from the
|
||||
current host's user database.
|
||||
|
||||
When used with \fB\-\-owner\-map\fR=\fIFILE\fR, affects only those
|
||||
files whose owner is not listed in \fIFILE\fR.
|
||||
.TP
|
||||
\fB\-\-owner\-map\fR=\fIFILE\fR
|
||||
Read owner translation map from \fIFILE\fR. Empty lines are ignored.
|
||||
Comments are introduced with \fB#\fR sign and extend to the end of line.
|
||||
Each non-empty line in \fIFILE\fR defines translation for a single
|
||||
UID. It must consist of two fields, delimited by any amount of whitespace:
|
||||
|
||||
.EX
|
||||
\fIOLDUSR\fR \fINEWUSR\fR[\fB:\fINEWUID\fR]
|
||||
.EE
|
||||
|
||||
\fIOLDUSR\fR is either a valid user name or a UID prefixed with
|
||||
\fB+\fR. Unless \fINEWUID\fR is supplied, \fINEWUSR\fR must also be
|
||||
either a valid user name or a \fB+\fIUID\fR. Otherwise, both
|
||||
\fINEWUSR\fR and \fINEWUID\fR need not be listed in the system user
|
||||
database.
|
||||
|
||||
As a result, each input file owned by \fIOLDUSR\fR will be
|
||||
stored in archive with owner name \fINEWUSR\fR and UID \fINEWUID\fR.
|
||||
.TP
|
||||
\fB\-p\fR, \fB\-\-preserve\-permissions\fR, \fB\-\-same\-permissions\fR
|
||||
extract information about file permissions (default for superuser)
|
||||
|
||||
90
doc/tar.texi
90
doc/tar.texi
@@ -2742,7 +2742,19 @@ 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.
|
||||
Also see the @option{--group-map} option and comments for the
|
||||
@option{--owner=@var{user}} option.
|
||||
|
||||
@opsummary{group-map}
|
||||
@item --group-map=@var{file}
|
||||
|
||||
Read owner group translation map from @var{file}. This option allows to
|
||||
translate only certain group names and/or UIDs. @xref{override}, for a
|
||||
detailed description. When used together with @option{--group}
|
||||
option, the latter affects only those files whose owner group is not listed
|
||||
in the @var{file}.
|
||||
|
||||
This option does not affect extraction from archives.
|
||||
|
||||
@opsummary{gzip}
|
||||
@opsummary{gunzip}
|
||||
@@ -3163,6 +3175,18 @@ 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. See also
|
||||
@option{--owner-map}, below.
|
||||
|
||||
@opsummary{owner-map}
|
||||
@item --owner-map=@var{file}
|
||||
|
||||
Read owner translation map from @var{file}. This option allows to
|
||||
translate only certain owner names or UIDs. @xref{override}, for a
|
||||
detailed description. When used together with @option{--owner}
|
||||
option, the latter affects only those files whose owner is not listed
|
||||
in the @var{file}.
|
||||
|
||||
This option does not affect extraction from archives.
|
||||
|
||||
@opsummary{pax-option}
|
||||
@@ -5259,6 +5283,70 @@ 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
|
||||
|
||||
The @option{--owner} and @option{--group} options affect all files
|
||||
added to the archive. @GNUTAR{} provides also two options that allow
|
||||
for more detailed control over owner translation:
|
||||
|
||||
@table @option
|
||||
@item --owner-map=@var{file}
|
||||
Read UID translation map from @var{file}.
|
||||
|
||||
When reading, empty lines are ignored. The @samp{#} sign, unless
|
||||
quoted, introduces a comment, which extends to the end of the line.
|
||||
Each nonempty line defines mapping for a single UID. It must consist
|
||||
of two fields separated by any amount of whitespace. The first field
|
||||
defines original username and UID. It can be a valid user name or
|
||||
a valid UID prefixed with a plus sign. In both cases the
|
||||
corresponding UID or user name is inferred from the current host's
|
||||
user database.
|
||||
|
||||
The second field defines the UID and username to map the original one
|
||||
to. Its format can be the same as described above. Otherwise, it can
|
||||
have the form @var{newname}:@var{newuid}, in which case neither
|
||||
@var{newname} nor @var{newuid} are required to be valid as per the
|
||||
user database.
|
||||
|
||||
For example, consider the following file:
|
||||
|
||||
@example
|
||||
+10 bin
|
||||
smith root:0
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
Given this file, each input file that is owner by UID 10 will be
|
||||
stored in archive with owner name @samp{bin} and owner UID
|
||||
corresponding to @samp{bin}. Each file owned by user @samp{smith}
|
||||
will be stored with owner name @samp{root} and owner ID 0. Other
|
||||
files will remain unchanged.
|
||||
|
||||
When used together with @option{--owner-map}, the @option{--owner}
|
||||
option affects only files whose owner is not listed in the map file.
|
||||
|
||||
@item --group-map=@var{file}
|
||||
Read GID translation map from @var{file}.
|
||||
|
||||
The format of @var{file} is the same as for @option{--owner-map}
|
||||
option:
|
||||
|
||||
Each nonempty line defines mapping for a single GID. It must consist
|
||||
of two fields separated by any amount of whitespace. The first field
|
||||
defines original group name and GID. It can be a valid group name or
|
||||
a valid GID prefixed with a plus sign. In both cases the
|
||||
corresponding GID or user name is inferred from the current host's
|
||||
group database.
|
||||
|
||||
The second field defines the GID and group name to map the original one
|
||||
to. Its format can be the same as described above. Otherwise, it can
|
||||
have the form @var{newname}:@var{newgid}, in which case neither
|
||||
@var{newname} nor @var{newgid} are required to be valid as per the
|
||||
group database.
|
||||
|
||||
When used together with @option{--group-map}, the @option{--group}
|
||||
option affects only files whose owner group is not rewritten using the
|
||||
map file.
|
||||
@end table
|
||||
|
||||
@node Ignore Failed Read
|
||||
@subsection Ignore Fail Read
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ tar_SOURCES = \
|
||||
xheader.c\
|
||||
incremen.c\
|
||||
list.c\
|
||||
map.c\
|
||||
misc.c\
|
||||
names.c\
|
||||
sparse.c\
|
||||
|
||||
@@ -952,4 +952,11 @@ void info_free_exclist (struct tar_stat_info *dir);
|
||||
bool excluded_name (char const *name, struct tar_stat_info *st);
|
||||
void exclude_vcs_ignores (void);
|
||||
|
||||
/* Module map.c */
|
||||
void owner_map_read (char const *name);
|
||||
int owner_map_translate (uid_t uid, uid_t *new_uid, char const **new_name);
|
||||
void group_map_read (char const *file);
|
||||
int group_map_translate (gid_t gid, gid_t *new_gid, char const **new_name);
|
||||
|
||||
|
||||
_GL_INLINE_HEADER_END
|
||||
|
||||
16
src/create.c
16
src/create.c
@@ -741,17 +741,17 @@ union block *
|
||||
start_header (struct tar_stat_info *st)
|
||||
{
|
||||
union block *header;
|
||||
char const *uname = NULL;
|
||||
char const *gname = NULL;
|
||||
|
||||
header = write_header_name (st);
|
||||
if (!header)
|
||||
return NULL;
|
||||
|
||||
/* Override some stat fields, if requested to do so. */
|
||||
owner_map_translate (st->stat.st_uid, &st->stat.st_uid, &uname);
|
||||
group_map_translate (st->stat.st_gid, &st->stat.st_gid, &gname);
|
||||
|
||||
if (owner_option != (uid_t) -1)
|
||||
st->stat.st_uid = owner_option;
|
||||
if (group_option != (gid_t) -1)
|
||||
st->stat.st_gid = group_option;
|
||||
if (mode_option)
|
||||
st->stat.st_mode =
|
||||
((st->stat.st_mode & ~MODE_ALL)
|
||||
@@ -910,13 +910,13 @@ start_header (struct tar_stat_info *st)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (owner_name_option)
|
||||
st->uname = xstrdup (owner_name_option);
|
||||
if (uname)
|
||||
st->uname = xstrdup (uname);
|
||||
else
|
||||
uid_to_uname (st->stat.st_uid, &st->uname);
|
||||
|
||||
if (group_name_option)
|
||||
st->gname = xstrdup (group_name_option);
|
||||
if (gname)
|
||||
st->gname = xstrdup (gname);
|
||||
else
|
||||
gid_to_gname (st->stat.st_gid, &st->gname);
|
||||
|
||||
|
||||
283
src/map.c
Normal file
283
src/map.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/* Owner/group mapping for tar
|
||||
|
||||
Copyright 2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
GNU tar 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 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU tar 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include "common.h"
|
||||
#include "wordsplit.h"
|
||||
#include <hash.h>
|
||||
#include <pwd.h>
|
||||
|
||||
struct mapentry
|
||||
{
|
||||
uintmax_t orig_id;
|
||||
uintmax_t new_id;
|
||||
char *new_name;
|
||||
};
|
||||
|
||||
static size_t
|
||||
map_hash (void const *entry, size_t nbuckets)
|
||||
{
|
||||
struct mapentry const *map = entry;
|
||||
return map->orig_id % nbuckets;
|
||||
}
|
||||
|
||||
static bool
|
||||
map_compare (void const *entry1, void const *entry2)
|
||||
{
|
||||
struct mapentry const *map1 = entry1;
|
||||
struct mapentry const *map2 = entry2;
|
||||
return map1->orig_id == map2->orig_id;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_id (uintmax_t *retval,
|
||||
char const *arg, char const *what, uintmax_t maxval,
|
||||
char const *file, unsigned line)
|
||||
{
|
||||
uintmax_t v;
|
||||
char *p;
|
||||
|
||||
errno = 0;
|
||||
v = strtoumax (arg, &p, 10);
|
||||
if (*p || errno)
|
||||
{
|
||||
error (0, 0, _("%s:%u: invalid %s: %s"), file, line, what, arg);
|
||||
return -1;
|
||||
}
|
||||
if (v > maxval)
|
||||
{
|
||||
error (0, 0, _("%s:%u: %s out of range: %s"), file, line, what, arg);
|
||||
return -1;
|
||||
}
|
||||
*retval = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
map_read (Hash_table **ptab, char const *file,
|
||||
uintmax_t (*name_to_id) (char const *), char const *what,
|
||||
uintmax_t maxval)
|
||||
{
|
||||
FILE *fp;
|
||||
char *buf = NULL;
|
||||
size_t bufsize = 0;
|
||||
ssize_t n;
|
||||
struct wordsplit ws;
|
||||
int wsopt;
|
||||
unsigned line;
|
||||
int err = 0;
|
||||
|
||||
fp = fopen (file, "r");
|
||||
if (!fp)
|
||||
open_fatal (file);
|
||||
|
||||
ws.ws_comment = "#";
|
||||
wsopt = WRDSF_COMMENT | WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_SQUEEZE_DELIMS
|
||||
| WRDSF_QUOTE;
|
||||
line = 0;
|
||||
while ((n = getline (&buf, &bufsize, fp)) > 0)
|
||||
{
|
||||
struct mapentry *ent;
|
||||
uintmax_t orig_id, new_id;
|
||||
char *name = NULL;
|
||||
char *colon;
|
||||
|
||||
++line;
|
||||
if (wordsplit (buf, &ws, wsopt))
|
||||
FATAL_ERROR ((0, 0, _("%s:%u: cannot split line: %s"),
|
||||
file, line, wordsplit_strerror (&ws)));
|
||||
wsopt |= WRDSF_REUSE;
|
||||
if (ws.ws_wordc == 0)
|
||||
continue;
|
||||
if (ws.ws_wordc != 2)
|
||||
{
|
||||
error (0, 0, _("%s:%u: malformed line"), file, line);
|
||||
err = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ws.ws_wordv[0][0] == '+')
|
||||
{
|
||||
if (parse_id (&orig_id, ws.ws_wordv[0]+1, what, maxval, file, line))
|
||||
{
|
||||
err = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (name_to_id)
|
||||
{
|
||||
orig_id = name_to_id (ws.ws_wordv[0]);
|
||||
if (orig_id == UINTMAX_MAX)
|
||||
{
|
||||
error (0, 0, _("%s:%u: can't obtain %s of %s"),
|
||||
file, line, what, ws.ws_wordv[0]);
|
||||
err = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
colon = strchr (ws.ws_wordv[1], ':');
|
||||
if (colon)
|
||||
{
|
||||
if (colon > ws.ws_wordv[1])
|
||||
name = ws.ws_wordv[1];
|
||||
*colon++ = 0;
|
||||
if (parse_id (&new_id, colon, what, maxval, file, line))
|
||||
{
|
||||
err = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (ws.ws_wordv[1][0] == '+')
|
||||
{
|
||||
if (parse_id (&new_id, ws.ws_wordv[1], what, maxval, file, line))
|
||||
{
|
||||
err = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name = ws.ws_wordv[1];
|
||||
new_id = name_to_id (ws.ws_wordv[1]);
|
||||
if (new_id == UINTMAX_MAX)
|
||||
{
|
||||
error (0, 0, _("%s:%u: can't obtain %s of %s"),
|
||||
file, line, what, ws.ws_wordv[1]);
|
||||
err = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ent = xmalloc (sizeof (*ent));
|
||||
ent->orig_id = orig_id;
|
||||
ent->new_id = new_id;
|
||||
ent->new_name = name ? xstrdup (name) : NULL;
|
||||
|
||||
if (!((*ptab
|
||||
|| (*ptab = hash_initialize (0, 0, map_hash, map_compare, 0)))
|
||||
&& hash_insert (*ptab, ent)))
|
||||
xalloc_die ();
|
||||
}
|
||||
if (wsopt & WRDSF_REUSE)
|
||||
wordsplit_free (&ws);
|
||||
fclose (fp);
|
||||
if (err)
|
||||
FATAL_ERROR ((0, 0, _("errors reading map file")));
|
||||
}
|
||||
|
||||
/* UID translation */
|
||||
|
||||
static Hash_table *owner_map;
|
||||
|
||||
static uintmax_t
|
||||
name_to_uid (char const *name)
|
||||
{
|
||||
struct passwd *pw = getpwnam (name);
|
||||
return pw ? pw->pw_uid : UINTMAX_MAX;
|
||||
}
|
||||
|
||||
void
|
||||
owner_map_read (char const *file)
|
||||
{
|
||||
map_read (&owner_map, file, name_to_uid, "UID", TYPE_MAXIMUM (uid_t));
|
||||
}
|
||||
|
||||
int
|
||||
owner_map_translate (uid_t uid, uid_t *new_uid, char const **new_name)
|
||||
{
|
||||
int rc = 1;
|
||||
|
||||
if (owner_map)
|
||||
{
|
||||
struct mapentry ent, *res;
|
||||
|
||||
ent.orig_id = uid;
|
||||
res = hash_lookup (owner_map, &ent);
|
||||
if (res)
|
||||
{
|
||||
*new_uid = res->new_id;
|
||||
*new_name = res->new_name;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (owner_option != (uid_t) -1)
|
||||
{
|
||||
*new_uid = owner_option;
|
||||
rc = 0;
|
||||
}
|
||||
if (owner_name_option)
|
||||
{
|
||||
*new_name = owner_name_option;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* GID translation */
|
||||
|
||||
static Hash_table *group_map;
|
||||
|
||||
static uintmax_t
|
||||
name_to_gid (char const *name)
|
||||
{
|
||||
struct group *gr = getgrnam (name);
|
||||
return gr ? gr->gr_gid : UINTMAX_MAX;
|
||||
}
|
||||
|
||||
void
|
||||
group_map_read (char const *file)
|
||||
{
|
||||
map_read (&group_map, file, name_to_gid, "GID", TYPE_MAXIMUM (gid_t));
|
||||
}
|
||||
|
||||
int
|
||||
group_map_translate (gid_t gid, gid_t *new_gid, char const **new_name)
|
||||
{
|
||||
int rc = 1;
|
||||
|
||||
if (group_map)
|
||||
{
|
||||
struct mapentry ent, *res;
|
||||
|
||||
ent.orig_id = gid;
|
||||
res = hash_lookup (group_map, &ent);
|
||||
if (res)
|
||||
{
|
||||
*new_gid = res->new_id;
|
||||
*new_name = res->new_name;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (group_option != (uid_t) -1)
|
||||
{
|
||||
*new_gid = group_option;
|
||||
rc = 0;
|
||||
}
|
||||
if (group_name_option)
|
||||
{
|
||||
*new_name = group_name_option;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
14
src/tar.c
14
src/tar.c
@@ -298,6 +298,7 @@ enum
|
||||
FORCE_LOCAL_OPTION,
|
||||
FULL_TIME_OPTION,
|
||||
GROUP_OPTION,
|
||||
GROUP_MAP_OPTION,
|
||||
IGNORE_CASE_OPTION,
|
||||
IGNORE_COMMAND_ERROR_OPTION,
|
||||
IGNORE_FAILED_READ_OPTION,
|
||||
@@ -340,6 +341,7 @@ enum
|
||||
OVERWRITE_DIR_OPTION,
|
||||
OVERWRITE_OPTION,
|
||||
OWNER_OPTION,
|
||||
OWNER_MAP_OPTION,
|
||||
PAX_OPTION,
|
||||
POSIX_OPTION,
|
||||
PRESERVE_OPTION,
|
||||
@@ -534,6 +536,10 @@ static struct argp_option options[] = {
|
||||
N_("force NAME as owner for added files"), GRID+1 },
|
||||
{"group", GROUP_OPTION, N_("NAME"), 0,
|
||||
N_("force NAME as group for added files"), GRID+1 },
|
||||
{"owner-map", OWNER_MAP_OPTION, N_("FILE"), 0,
|
||||
N_("use FILE to map file owner UIDs and names"), GRID+1 },
|
||||
{"group-map", GROUP_MAP_OPTION, N_("FILE"), 0,
|
||||
N_("use FILE to map file owner GIDs and names"), GRID+1 },
|
||||
{"mtime", MTIME_OPTION, N_("DATE-OR-FILE"), 0,
|
||||
N_("set mtime for added files from DATE-OR-FILE"), GRID+1 },
|
||||
{"mode", MODE_OPTION, N_("CHANGES"), 0,
|
||||
@@ -1996,6 +2002,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
}
|
||||
break;
|
||||
|
||||
case GROUP_MAP_OPTION:
|
||||
group_map_read (arg);
|
||||
break;
|
||||
|
||||
case MODE_OPTION:
|
||||
mode_option = mode_compile (arg);
|
||||
if (!mode_option)
|
||||
@@ -2090,6 +2100,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
}
|
||||
break;
|
||||
|
||||
case OWNER_MAP_OPTION:
|
||||
owner_map_read (arg);
|
||||
break;
|
||||
|
||||
case QUOTE_CHARS_OPTION:
|
||||
for (;*arg; arg++)
|
||||
set_char_quoting (NULL, *arg, 1);
|
||||
|
||||
@@ -140,6 +140,7 @@ TESTSUITE_AT = \
|
||||
lustar01.at\
|
||||
lustar02.at\
|
||||
lustar03.at\
|
||||
map.at\
|
||||
multiv01.at\
|
||||
multiv02.at\
|
||||
multiv03.at\
|
||||
|
||||
71
tests/map.at
Normal file
71
tests/map.at
Normal file
@@ -0,0 +1,71 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2015 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Check the --owner-map and --group-map options.
|
||||
|
||||
AT_SETUP([--owner-map and --group-map])
|
||||
AT_KEYWORDS([owner map])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
export TZ=UTC0
|
||||
|
||||
genfile --file a
|
||||
set -- `genfile --stat=uid,gid a`
|
||||
cat > uid.map <<EOT
|
||||
# Owner mapping
|
||||
+$1 "Joe the Plumber:1234"
|
||||
EOT
|
||||
# Group mapping
|
||||
cat > gid.map <<EOT
|
||||
+$2 "Plumber's Union:5678"
|
||||
EOT
|
||||
|
||||
tar --owner-map=uid.map\
|
||||
--group-map=gid.map\
|
||||
--owner="Fallback Owner:4321" \
|
||||
--group="Fallback Group:8765" \
|
||||
--mtime='@0' \
|
||||
--mode='u=rw,go=r' \
|
||||
-cf 1.tar a
|
||||
|
||||
tar -tvf 1.tar
|
||||
tar --numeric-owner -tvf 1.tar
|
||||
|
||||
> uid.map
|
||||
> gid.map
|
||||
|
||||
tar --owner-map=uid.map\
|
||||
--group-map=gid.map\
|
||||
--owner="Fallback Owner:4321" \
|
||||
--group="Fallback Group:8765" \
|
||||
--mtime='@0' \
|
||||
--mode='u=rw,go=r' \
|
||||
-cf 2.tar a
|
||||
|
||||
tar -tvf 2.tar
|
||||
tar --numeric-owner -tvf 2.tar
|
||||
],
|
||||
[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
|
||||
-rw-r--r-- Fallback Owner/Fallback Group 0 1970-01-01 00:00 a
|
||||
-rw-r--r-- 4321/8765 0 1970-01-01 00:00 a
|
||||
],
|
||||
[],[],[],[gnu])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -349,6 +349,7 @@ m4_include([multiv08.at])
|
||||
|
||||
AT_BANNER([Owner and Groups])
|
||||
m4_include([owner.at])
|
||||
m4_include([map.at])
|
||||
|
||||
AT_BANNER([Sparse files])
|
||||
m4_include([sparse01.at])
|
||||
|
||||
Reference in New Issue
Block a user