diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 2001-10-25 16:59:04 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 2001-10-25 16:59:04 +0000 |
commit | 18c63dec1c4a84e38d4d642f7150d1a4dc3768e8 (patch) | |
tree | 16d3e8d8cf988412b4a4a070990644098ffb7494 /bin/pax/file_subs.c | |
parent | bb1dad844e3f323cc1fd72c6cda30c387916153e (diff) |
Make -h and -L follow symlinks on extraction of directories.
This means that existing symbolic links won't get overwritten with a
directory, but instead the directory is created/updated with the privs
from the archive at the end of the symlink chain. Great for unpacking
OpenBSD release tarballs, where you have linked away stuff due to lack of
space on a certain partition etc.
Diffstat (limited to 'bin/pax/file_subs.c')
-rw-r--r-- | bin/pax/file_subs.c | 70 |
1 files changed, 48 insertions, 22 deletions
diff --git a/bin/pax/file_subs.c b/bin/pax/file_subs.c index 670a2fdb309..5288e390c2a 100644 --- a/bin/pax/file_subs.c +++ b/bin/pax/file_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file_subs.c,v 1.14 2001/05/16 03:04:56 mickey Exp $ */ +/* $OpenBSD: file_subs.c,v 1.15 2001/10/25 16:59:03 niklas Exp $ */ /* $NetBSD: file_subs.c,v 1.4 1995/03/21 09:07:18 cgd Exp $ */ /*- @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)file_subs.c 8.1 (Berkeley) 5/31/93"; #else -static char rcsid[] = "$OpenBSD: file_subs.c,v 1.14 2001/05/16 03:04:56 mickey Exp $"; +static char rcsid[] = "$OpenBSD: file_subs.c,v 1.15 2001/10/25 16:59:03 niklas Exp $"; #endif #endif /* not lint */ @@ -400,6 +400,9 @@ node_creat(arcn) register int pass = 0; mode_t file_mode; struct stat sb; + char target[MAXPATHLEN]; + char *nm = arcn->name; + int len; /* * create node based on type, if that fails try to unlink the node and @@ -412,20 +415,43 @@ node_creat(arcn) for (;;) { switch(arcn->type) { case PAX_DIR: - res = mkdir(arcn->name, file_mode); + /* + * If -h (or -L) was given in tar-mode, follow the + * potential symlink chain before trying to create the + * directory. + */ + if (strcmp(NM_TAR, argv0) == 0 && Lflag) { + while (lstat(nm, &sb) == 0 && + S_ISLNK(sb.st_mode)) { + len = readlink(nm, target, + sizeof target - 1); + if (len == -1) { + syswarn(0, errno, + "cannot follow symlink %s in chain for %s", + nm, arcn->name); + res = -1; + goto badlink; + } + target[len] = '\0'; + nm = target; + } + } + res = mkdir(nm, file_mode); + +badlink: if (ign) res = 0; break; case PAX_CHR: file_mode |= S_IFCHR; - res = mknod(arcn->name, file_mode, arcn->sb.st_rdev); + res = mknod(nm, file_mode, arcn->sb.st_rdev); break; case PAX_BLK: file_mode |= S_IFBLK; - res = mknod(arcn->name, file_mode, arcn->sb.st_rdev); + res = mknod(nm, file_mode, arcn->sb.st_rdev); break; case PAX_FIF: - res = mkfifo(arcn->name, file_mode); + res = mkfifo(nm, file_mode); break; case PAX_SCK: /* @@ -433,10 +459,10 @@ node_creat(arcn) */ paxwarn(0, "%s skipped. Sockets cannot be copied or extracted", - arcn->name); + nm); return(-1); case PAX_SLK: - res = symlink(arcn->ln_name, arcn->name); + res = symlink(arcn->ln_name, nm); break; case PAX_CTG: case PAX_HLK: @@ -447,7 +473,7 @@ node_creat(arcn) * we should never get here */ paxwarn(0, "%s has an unknown file type, skipping", - arcn->name); + nm); return(-1); } @@ -463,14 +489,14 @@ node_creat(arcn) * we failed to make the node */ oerrno = errno; - if ((ign = unlnk_exist(arcn->name, arcn->type)) < 0) + if ((ign = unlnk_exist(nm, arcn->type)) < 0) return(-1); if (++pass <= 1) continue; - if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) { - syswarn(1, oerrno, "Could not create: %s", arcn->name); + if (nodirs || chk_path(nm,arcn->sb.st_uid,arcn->sb.st_gid) < 0) { + syswarn(1, oerrno, "Could not create: %s", nm); return(-1); } } @@ -480,8 +506,8 @@ node_creat(arcn) */ if (pids) res = ((arcn->type == PAX_SLK) ? - set_lids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid) : - set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid)); + set_lids(nm, arcn->sb.st_uid, arcn->sb.st_gid) : + set_ids(nm, arcn->sb.st_uid, arcn->sb.st_gid)); else res = 0; @@ -499,7 +525,7 @@ node_creat(arcn) if (!pmode || res) arcn->sb.st_mode &= ~(SETBITS); if (pmode) - set_pmode(arcn->name, arcn->sb.st_mode); + set_pmode(nm, arcn->sb.st_mode); if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) { /* @@ -511,11 +537,11 @@ node_creat(arcn) * and modes will be fixed after the entire archive is read and * before pax exits. */ - if (access(arcn->name, R_OK | W_OK | X_OK) < 0) { - if (lstat(arcn->name, &sb) < 0) { + if (access(nm, R_OK | W_OK | X_OK) < 0) { + if (lstat(nm, &sb) < 0) { syswarn(0, errno,"Could not access %s (stat)", arcn->name); - set_pmode(arcn->name,file_mode | S_IRWXU); + set_pmode(nm,file_mode | S_IRWXU); } else { /* * We have to add rights to the dir, so we make @@ -523,7 +549,7 @@ node_creat(arcn) * restored AS CREATED and not as stored if * pmode is not set. */ - set_pmode(arcn->name, + set_pmode(nm, ((sb.st_mode & FILEBITS) | S_IRWXU)); if (!pmode) arcn->sb.st_mode = sb.st_mode; @@ -533,13 +559,13 @@ node_creat(arcn) * we have to force the mode to what was set here, * since we changed it from the default as created. */ - add_dir(arcn->name, arcn->nlen, &(arcn->sb), 1); + add_dir(nm, strlen(nm), &(arcn->sb), 1); } else if (pmode || patime || pmtime) - add_dir(arcn->name, arcn->nlen, &(arcn->sb), 0); + add_dir(nm, strlen(nm), &(arcn->sb), 0); } if (patime || pmtime) - set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0); + set_ftime(nm, arcn->sb.st_mtime, arcn->sb.st_atime, 0); return(0); } |