diff options
-rw-r--r-- | lib/xwrap.c | 6 | ||||
-rw-r--r-- | toys/posix/tar.c | 21 |
2 files changed, 18 insertions, 9 deletions
diff --git a/lib/xwrap.c b/lib/xwrap.c index 1a3ef837..591c9513 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -525,7 +525,8 @@ void xstat(char *path, struct stat *st) // Canonicalize path, even to file with one or more missing components at end. // Returns allocated string for pathname or NULL if doesn't exist -// exact = 1 file must exist, 0 dir must exist, -1 show theoretical location +// exact = 1 file must exist, 0 dir must exist, -1 show theoretical location, +// -2 don't resolve last file char *xabspath(char *path, int exact) { struct string_list *todo, *done = 0; @@ -570,7 +571,8 @@ char *xabspath(char *path, int exact) } // Is this a symlink? - len = readlinkat(dirfd, new->str, libbuf, sizeof(libbuf)); + if (exact == -2 && !todo) len = 0; + else len = readlinkat(dirfd, new->str, libbuf, sizeof(libbuf)); if (len>4095) goto error; // Not a symlink: add to linked list, move dirfd, fail if error diff --git a/toys/posix/tar.c b/toys/posix/tar.c index 78ff9a1e..ff129819 100644 --- a/toys/posix/tar.c +++ b/toys/posix/tar.c @@ -386,25 +386,32 @@ static void wsettime(char *s, long long sec) } // Do pending directory utimes(), NULL to flush all. -static int dirflush(char *name) +static int dirflush(char *name, int isdir) { char *s = 0, *ss; // Barf if name not in TT.cwd if (name) { - ss = s = xabspath(name, -1); - if (TT.cwd[1] && (!strstart(&ss, TT.cwd) || *ss!='/')) { - error_msg("'%s' not under '%s'", name, TT.cwd); + if (!(ss = s = xabspath(name, -1-isdir))) { + error_msg("'%s' bad symlink", name); + + return 1; + } + if (TT.cwd[1] && (!strstart(&ss, TT.cwd) || (*ss && *ss!='/'))) { + error_msg("'%s' %s not under '%s'", name, s, TT.cwd); free(s); return 1; } + // --restrict means first entry extracted is what everything must be under if (FLAG(restrict)) { free(TT.cwd); TT.cwd = strdup(s); toys.optflags ^= FLAG_restrict; } + // use resolved name so trailing / is stripped + if (isdir) unlink(s); } // Set deferred utimes() for directories this file isn't under. @@ -467,14 +474,14 @@ static void extract_to_disk(void) char *name = TT.hdr.name; int ala = TT.hdr.mode; - if (dirflush(name)) { + if (dirflush(name, S_ISDIR(ala))) { if (S_ISREG(ala) && !TT.hdr.link_target) skippy(TT.hdr.size); return; } // create path before file if necessary - if (strrchr(name, '/') && mkpath(name) && errno !=EEXIST) + if (strrchr(name, '/') && mkpath(name) && errno!=EEXIST) return perror_msg(":%s: can't mkdir", name); // remove old file, if exists @@ -895,7 +902,7 @@ void tar_main(void) } unpack_tar(hdr); - dirflush(0); + dirflush(0, 0); // Each time a TT.incl entry is seen it's moved to the end of the list, // with TT.seen pointing to first seen list entry. Anything between |