aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2022-04-02 19:33:14 -0500
committerRob Landley <rob@landley.net>2022-04-02 19:33:14 -0500
commit72e7e3821b4a0cce07e6d1450efef09ca9d3a5db (patch)
treef7f7bb424ff5cc93c9e5d166d805915e71c55ca9
parentcfea8f012d6d755026e27297dca5293c4973b2d4 (diff)
downloadtoybox-72e7e3821b4a0cce07e6d1450efef09ca9d3a5db.tar.gz
Add tar --strip-components.
Also in lib/ add bufget name variants for password and group.
-rw-r--r--lib/lib.c29
-rw-r--r--lib/lib.h2
-rw-r--r--toys/posix/tar.c42
3 files changed, 50 insertions, 23 deletions
diff --git a/lib/lib.c b/lib/lib.c
index 3f709f07..cf0a9582 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -1252,7 +1252,7 @@ char *next_printf(char *s, char **start)
}
// Return cached passwd entries.
-struct passwd *bufgetpwuid(uid_t uid)
+struct passwd *bufgetpwnamuid(char *name, uid_t uid)
{
struct pwuidbuf_list {
struct pwuidbuf_list *next;
@@ -1264,11 +1264,14 @@ struct passwd *bufgetpwuid(uid_t uid)
// If we already have this one, return it.
for (list = pwuidbuf; list; list = list->next)
- if (list->pw.pw_uid == uid) return &(list->pw);
+ if (name ? !strcmp(name, list->pw.pw_name) : list->pw.pw_uid==uid)
+ return &(list->pw);
for (;;) {
list = xrealloc(list, size *= 2);
- errno = getpwuid_r(uid, &list->pw, sizeof(*list)+(char *)list,
+ if (name) errno = getpwnam_r(name, &list->pw, sizeof(*list)+(char *)list,
+ size-sizeof(*list), &temp);
+ else errno = getpwuid_r(uid, &list->pw, sizeof(*list)+(char *)list,
size-sizeof(*list), &temp);
if (errno != ERANGE) break;
}
@@ -1284,8 +1287,13 @@ struct passwd *bufgetpwuid(uid_t uid)
return &list->pw;
}
+struct passwd *bufgetpwuid(uid_t uid)
+{
+ return bufgetpwnamuid(0, uid);
+}
+
// Return cached group entries.
-struct group *bufgetgrgid(gid_t gid)
+struct group *bufgetgrnamgid(char *name, gid_t gid)
{
struct grgidbuf_list {
struct grgidbuf_list *next;
@@ -1296,11 +1304,14 @@ struct group *bufgetgrgid(gid_t gid)
unsigned size = 256;
for (list = grgidbuf; list; list = list->next)
- if (list->gr.gr_gid == gid) return &(list->gr);
+ if (name ? !strcmp(name, list->gr.gr_name) : list->gr.gr_gid==gid)
+ return &(list->gr);
for (;;) {
list = xrealloc(list, size *= 2);
- errno = getgrgid_r(gid, &list->gr, sizeof(*list)+(char *)list,
+ if (name) errno = getgrnam_r(name, &list->gr, sizeof(*list)+(char *)list,
+ size-sizeof(*list), &temp);
+ else errno = getgrgid_r(gid, &list->gr, sizeof(*list)+(char *)list,
size-sizeof(*list), &temp);
if (errno != ERANGE) break;
}
@@ -1315,6 +1326,12 @@ struct group *bufgetgrgid(gid_t gid)
return &list->gr;
}
+struct group *bufgetgrgid(gid_t gid)
+{
+ return bufgetgrnamgid(0, gid);
+}
+
+
// Always null terminates, returns 0 for failure, len for success
int readlinkat0(int dirfd, char *path, char *buf, int len)
{
diff --git a/lib/lib.h b/lib/lib.h
index 6e9a2640..1721dd67 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -260,7 +260,9 @@ int qstrcmp(const void *a, const void *b);
void create_uuid(char *uuid);
char *show_uuid(char *uuid);
char *next_printf(char *s, char **start);
+struct passwd *bufgetpwnamuid(char *name, uid_t uid);
struct passwd *bufgetpwuid(uid_t uid);
+struct group *bufgetgrnamgid(char *name, gid_t gid);
struct group *bufgetgrgid(gid_t gid);
int readlinkat0(int dirfd, char *path, char *buf, int len);
int readlink0(char *path, char *buf, int len);
diff --git a/toys/posix/tar.c b/toys/posix/tar.c
index f6330ac3..9cf1a5c9 100644
--- a/toys/posix/tar.c
+++ b/toys/posix/tar.c
@@ -17,7 +17,7 @@
* Why --exclude pattern but no --include? tar cvzf a.tgz dir --include '*.txt'
*
-USE_TAR(NEWTOY(tar, "&(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TAR(NEWTOY(tar, "&(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]", TOYFLAG_USR|TOYFLAG_BIN))
config TAR
bool "tar"
@@ -38,9 +38,9 @@ config TAR
--mode MODE Adjust permissions --owner NAME[:UID] Set file ownership
--mtime TIME Override timestamps --group NAME[:GID] Set file group
--sparse Record sparse files --selinux Save/restore labels
- --restrict All archive contents must extract under one subdirectory
- --numeric-owner Save/use/display uid and gid, not user/group name
- --no-recursion Don't store directory contents
+ --restrict All under one dir --no-recursion Skip dir contents
+ --numeric-owner Use numeric uid/gid, not user/group names
+ --strip-components NUM Ignore first NUM directory components when extracting
-I PROG Filter through PROG to compress or PROG -d to decompress
*/
@@ -52,6 +52,7 @@ GLOBALS(
struct arg_list *T, *X;
char *I, *to_command, *owner, *group, *mtime, *mode;
struct arg_list *exclude;
+ long strip_components;
struct double_list *incl, *excl, *seen;
struct string_list *dirs;
@@ -520,7 +521,15 @@ error:
static void extract_to_disk(void)
{
char *name = TT.hdr.name;
- int ala = TT.hdr.mode;
+ int ala = TT.hdr.mode, strip;
+
+ for (strip = 0; strip < TT.strip_components; strip++) {
+ char *s = strchr(name, '/');
+
+ if (s && s[1]) name = s+1;
+ else if (S_ISDIR(ala)) return;
+ else break;
+ }
if (dirflush(name, S_ISDIR(ala))) {
if (S_ISREG(ala) && !TT.hdr.link_target) skippy(TT.hdr.size);
@@ -543,17 +552,16 @@ static void extract_to_disk(void)
return perror_msg("can't link '%s' -> '%s'", name, TT.hdr.link_target);
// write contents
} else {
- int fd = xcreate(name,
- WARN_ONLY|O_WRONLY|O_CREAT|(FLAG(overwrite)?O_TRUNC:O_EXCL),
- ala & 07777);
- if (fd != -1) sendfile_sparse(fd);
+ int fd = WARN_ONLY|O_WRONLY|O_CREAT|(FLAG(overwrite) ? O_TRUNC : O_EXCL);
+
+ if ((fd = xcreate(name, fd, ala&07777)) != -1) sendfile_sparse(fd);
else return skippy(TT.hdr.size);
}
} else if (S_ISDIR(ala)) {
if ((mkdir(name, 0700) == -1) && errno != EEXIST)
- return perror_msg("%s: can't create", TT.hdr.name);
+ return perror_msg("%s: can't create", name);
} else if (S_ISLNK(ala)) {
- if (symlink(TT.hdr.link_target, TT.hdr.name))
+ if (symlink(TT.hdr.link_target, name))
return perror_msg("can't link '%s' -> '%s'", name, TT.hdr.link_target);
} else if (mknod(name, ala, TT.hdr.device))
return perror_msg("can't create '%s'", name);
@@ -564,20 +572,20 @@ static void extract_to_disk(void)
if (TT.owner) TT.hdr.uid = TT.ouid;
else if (!FLAG(numeric_owner) && *TT.hdr.uname) {
- struct passwd *pw = getpwnam(TT.hdr.uname);
+ struct passwd *pw = bufgetpwnamuid(TT.hdr.uname, 0);
if (pw && (TT.owner || !FLAG(numeric_owner))) TT.hdr.uid = pw->pw_uid;
}
if (TT.group) TT.hdr.gid = TT.ggid;
else if (!FLAG(numeric_owner) && *TT.hdr.uname) {
- struct group *gr = getgrnam(TT.hdr.gname);
+ struct group *gr = bufgetgrnamgid(TT.hdr.gname, 0);
if (gr) TT.hdr.gid = gr->gr_gid;
}
if (lchown(name, u, g)) perror_msg("chown %d:%d '%s'", u, g, name);;
}
- if (!S_ISLNK(ala)) chmod(TT.hdr.name, FLAG(p) ? ala : ala&0777);
+ if (!S_ISLNK(ala)) chmod(name, FLAG(p) ? ala : ala&0777);
// Apply mtime.
if (!FLAG(m)) {
@@ -592,7 +600,7 @@ static void extract_to_disk(void)
strcpy(sl->str+sizeof(long long), name);
sl->next = TT.dirs;
TT.dirs = sl;
- } else wsettime(TT.hdr.name, TT.hdr.mtime);
+ } else wsettime(name, TT.hdr.mtime);
}
}
@@ -721,13 +729,13 @@ static void unpack_tar(char *first)
if (TT.owner) TT.hdr.uid = TT.ouid;
else if (!FLAG(numeric_owner)) {
- struct passwd *pw = getpwnam(TT.hdr.uname);
+ struct passwd *pw = bufgetpwnamuid(TT.hdr.uname, 0);
if (pw && (TT.owner || !FLAG(numeric_owner))) TT.hdr.uid = pw->pw_uid;
}
if (TT.group) TT.hdr.gid = TT.ggid;
else if (!FLAG(numeric_owner)) {
- struct group *gr = getgrnam(TT.hdr.gname);
+ struct group *gr = bufgetgrnamgid(TT.hdr.gname, 0);
if (gr) TT.hdr.gid = gr->gr_gid;
}