X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fmap.c;fp=src%2Fmap.c;h=0cd986192c19f99aa9d13d60b8e6c4822c3e2265;hb=d30babc23b4f25be970ada2e63a50220a3672281;hp=0000000000000000000000000000000000000000;hpb=4aa85f09e755fc827cd5ab6225f20c83cd42245d;p=debian%2Ftar diff --git a/src/map.c b/src/map.c new file mode 100644 index 00000000..0cd98619 --- /dev/null +++ b/src/map.c @@ -0,0 +1,283 @@ +/* Owner/group mapping for tar + + Copyright 2015-2016 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 . */ + +#include +#include "common.h" +#include "wordsplit.h" +#include +#include + +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; +}