1 /* Owner/group mapping for tar
3 Copyright 2015-2017 Free Software Foundation, Inc.
5 This file is part of GNU tar.
7 GNU tar is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 GNU tar is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "wordsplit.h"
34 map_hash (void const *entry
, size_t nbuckets
)
36 struct mapentry
const *map
= entry
;
37 return map
->orig_id
% nbuckets
;
41 map_compare (void const *entry1
, void const *entry2
)
43 struct mapentry
const *map1
= entry1
;
44 struct mapentry
const *map2
= entry2
;
45 return map1
->orig_id
== map2
->orig_id
;
49 parse_id (uintmax_t *retval
,
50 char const *arg
, char const *what
, uintmax_t maxval
,
51 char const *file
, unsigned line
)
57 v
= strtoumax (arg
, &p
, 10);
60 error (0, 0, _("%s:%u: invalid %s: %s"), file
, line
, what
, arg
);
65 error (0, 0, _("%s:%u: %s out of range: %s"), file
, line
, what
, arg
);
73 map_read (Hash_table
**ptab
, char const *file
,
74 uintmax_t (*name_to_id
) (char const *), char const *what
,
86 fp
= fopen (file
, "r");
91 wsopt
= WRDSF_COMMENT
| WRDSF_NOVAR
| WRDSF_NOCMD
| WRDSF_SQUEEZE_DELIMS
94 while ((n
= getline (&buf
, &bufsize
, fp
)) > 0)
97 uintmax_t orig_id
, new_id
;
102 if (wordsplit (buf
, &ws
, wsopt
))
103 FATAL_ERROR ((0, 0, _("%s:%u: cannot split line: %s"),
104 file
, line
, wordsplit_strerror (&ws
)));
105 wsopt
|= WRDSF_REUSE
;
106 if (ws
.ws_wordc
== 0)
108 if (ws
.ws_wordc
!= 2)
110 error (0, 0, _("%s:%u: malformed line"), file
, line
);
115 if (ws
.ws_wordv
[0][0] == '+')
117 if (parse_id (&orig_id
, ws
.ws_wordv
[0]+1, what
, maxval
, file
, line
))
125 orig_id
= name_to_id (ws
.ws_wordv
[0]);
126 if (orig_id
== UINTMAX_MAX
)
128 error (0, 0, _("%s:%u: can't obtain %s of %s"),
129 file
, line
, what
, ws
.ws_wordv
[0]);
135 colon
= strchr (ws
.ws_wordv
[1], ':');
138 if (colon
> ws
.ws_wordv
[1])
139 name
= ws
.ws_wordv
[1];
141 if (parse_id (&new_id
, colon
, what
, maxval
, file
, line
))
147 else if (ws
.ws_wordv
[1][0] == '+')
149 if (parse_id (&new_id
, ws
.ws_wordv
[1], what
, maxval
, file
, line
))
157 name
= ws
.ws_wordv
[1];
158 new_id
= name_to_id (ws
.ws_wordv
[1]);
159 if (new_id
== UINTMAX_MAX
)
161 error (0, 0, _("%s:%u: can't obtain %s of %s"),
162 file
, line
, what
, ws
.ws_wordv
[1]);
168 ent
= xmalloc (sizeof (*ent
));
169 ent
->orig_id
= orig_id
;
170 ent
->new_id
= new_id
;
171 ent
->new_name
= name
? xstrdup (name
) : NULL
;
174 || (*ptab
= hash_initialize (0, 0, map_hash
, map_compare
, 0)))
175 && hash_insert (*ptab
, ent
)))
178 if (wsopt
& WRDSF_REUSE
)
179 wordsplit_free (&ws
);
182 FATAL_ERROR ((0, 0, _("errors reading map file")));
185 /* UID translation */
187 static Hash_table
*owner_map
;
190 name_to_uid (char const *name
)
192 struct passwd
*pw
= getpwnam (name
);
193 return pw
? pw
->pw_uid
: UINTMAX_MAX
;
197 owner_map_read (char const *file
)
199 map_read (&owner_map
, file
, name_to_uid
, "UID", TYPE_MAXIMUM (uid_t
));
203 owner_map_translate (uid_t uid
, uid_t
*new_uid
, char const **new_name
)
209 struct mapentry ent
, *res
;
212 res
= hash_lookup (owner_map
, &ent
);
215 *new_uid
= res
->new_id
;
216 *new_name
= res
->new_name
;
221 if (owner_option
!= (uid_t
) -1)
223 *new_uid
= owner_option
;
226 if (owner_name_option
)
228 *new_name
= owner_name_option
;
235 /* GID translation */
237 static Hash_table
*group_map
;
240 name_to_gid (char const *name
)
242 struct group
*gr
= getgrnam (name
);
243 return gr
? gr
->gr_gid
: UINTMAX_MAX
;
247 group_map_read (char const *file
)
249 map_read (&group_map
, file
, name_to_gid
, "GID", TYPE_MAXIMUM (gid_t
));
253 group_map_translate (gid_t gid
, gid_t
*new_gid
, char const **new_name
)
259 struct mapentry ent
, *res
;
262 res
= hash_lookup (group_map
, &ent
);
265 *new_gid
= res
->new_id
;
266 *new_name
= res
->new_name
;
271 if (group_option
!= (uid_t
) -1)
273 *new_gid
= group_option
;
276 if (group_name_option
)
278 *new_name
= group_name_option
;