diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2015-02-15 22:18:30 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2015-02-15 22:18:30 +0000 |
commit | 908d14f9c35bb3bc8b5ff316e6fb6c06ae6447b7 (patch) | |
tree | f9553e2ff1127585633d94dd12054b12479fb39d | |
parent | e2b2dd619edd58f49d6ce8b43c1da41d66e9a7eb (diff) |
Fix two bugs. The first affected tar files with the same
directory listed twice with nothing created inside the directory
in between the two instances of the directory. The other fixes
extracting symlinks when the -C option is used. From guenther@
OK krw@
-rw-r--r-- | bin/pax/extern.h | 3 | ||||
-rw-r--r-- | bin/pax/file_subs.c | 4 | ||||
-rw-r--r-- | bin/pax/tables.c | 60 |
3 files changed, 60 insertions, 7 deletions
diff --git a/bin/pax/extern.h b/bin/pax/extern.h index 22912087c10..3b3400b26d1 100644 --- a/bin/pax/extern.h +++ b/bin/pax/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.47 2015/02/12 23:44:57 guenther Exp $ */ +/* $OpenBSD: extern.h,v 1.48 2015/02/15 22:18:29 millert Exp $ */ /* $NetBSD: extern.h,v 1.5 1996/03/26 23:54:16 mrg Exp $ */ /*- @@ -286,6 +286,7 @@ void add_atdir(char *, dev_t, ino_t, time_t, time_t); int do_atdir(const char *, dev_t, ino_t); int dir_start(void); void add_dir(char *, struct stat *, int); +void delete_dir(dev_t, ino_t); void proc_dir(int _in_sig); u_int st_hash(const char *, int, int); diff --git a/bin/pax/file_subs.c b/bin/pax/file_subs.c index 2c5475b963c..b71575bdfd6 100644 --- a/bin/pax/file_subs.c +++ b/bin/pax/file_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file_subs.c,v 1.42 2015/02/12 23:44:57 guenther Exp $ */ +/* $OpenBSD: file_subs.c,v 1.43 2015/02/15 22:18:29 millert Exp $ */ /* $NetBSD: file_subs.c,v 1.4 1995/03/21 09:07:18 cgd Exp $ */ /*- @@ -299,6 +299,7 @@ mk_link(char *to, struct stat *to_sb, char *from, int ign) syswarn(1, errno, "Unable to remove %s", from); return(-1); } + delete_dir(sb.st_dev, sb.st_ino); } else if (unlink(from) < 0) { if (!ign) { syswarn(1, errno, "Unable to remove %s", from); @@ -564,6 +565,7 @@ unlnk_exist(char *name, int type) syswarn(1,errno,"Unable to remove directory %s", name); return(-1); } + delete_dir(sb.st_dev, sb.st_ino); return(0); } diff --git a/bin/pax/tables.c b/bin/pax/tables.c index b99dbbe4534..79db2a5e63f 100644 --- a/bin/pax/tables.c +++ b/bin/pax/tables.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tables.c,v 1.42 2015/02/12 23:44:57 guenther Exp $ */ +/* $OpenBSD: tables.c,v 1.43 2015/02/15 22:18:29 millert Exp $ */ /* $NetBSD: tables.c,v 1.4 1995/03/21 09:07:45 cgd Exp $ */ /*- @@ -556,7 +556,13 @@ sltab_add_sym(const char *path0, const char *value0, mode_t mode) } close(fd); - if ((path = strdup(path0)) == NULL) { + if (havechd && *path0 != '/') { + if ((path = realpath(path0, NULL)) == NULL) { + syswarn(1, errno, "Cannot canonicalize %s", path0); + unlink(path0); + return (-1); + } + } else if ((path = strdup(path0)) == NULL) { syswarn(1, errno, "defered symlink path"); unlink(path0); return (-1); @@ -640,7 +646,14 @@ sltab_add_link(const char *path, const struct stat *sb) syswarn(1, errno, "deferred symlink hardlink"); return (-1); } - if ((p->sp_path = strdup(path)) == NULL) { + if (havechd && *path != '/') { + if ((p->sp_path = realpath(path, NULL)) == NULL) { + syswarn(1, errno, "Cannot canonicalize %s", + path); + free(p); + return (-1); + } + } else if ((p->sp_path = strdup(path)) == NULL) { syswarn(1, errno, "defered symlink hardlink path"); free(p); return (-1); @@ -1372,7 +1385,8 @@ do_atdir(const char *name, dev_t dev, ino_t ino) /* * return if we did not find it. */ - if (pt == NULL || strcmp(name, pt->ft.ft_name) == 0) + if (pt == NULL || pt->ft.ft_name == NULL || + strcmp(name, pt->ft.ft_name) == 0) return(-1); /* @@ -1489,6 +1503,35 @@ add_dir(char *name, struct stat *psb, int frc_mode) } /* + * delete_dir() + * When we rmdir a directory, we may want to make sure we don't + * later warn about being unable to set its mode and times. + */ + +void +delete_dir(dev_t dev, ino_t ino) +{ + DIRDATA *dblk; + char *name; + size_t i; + + if (dirp == NULL) + return; + for (i = 0; i < dircnt; i++) { + dblk = &dirp[i]; + + if (dblk->ft.ft_name == NULL) + continue; + if (dblk->ft.ft_dev == dev && dblk->ft.ft_ino == ino) { + name = dblk->ft.ft_name; + dblk->ft.ft_name = NULL; + free(name); + break; + } + } +} + +/* * proc_dir(int in_sig) * process all file modes and times stored for directories CREATED * by pax. If in_sig is set, we're in a signal handler and can't @@ -1508,11 +1551,18 @@ proc_dir(int in_sig) */ cnt = dircnt; while (cnt-- > 0) { + dblk = &dirp[cnt]; + /* + * If we remove a directory we created, we replace the + * ft_name with NULL. Ignore those. + */ + if (dblk->ft.ft_name == NULL) + continue; + /* * frc_mode set, make sure we set the file modes even if * the user didn't ask for it (see file_subs.c for more info) */ - dblk = &dirp[cnt]; set_attr(&dblk->ft, 0, dblk->mode, pmode || dblk->frc_mode, in_sig); if (!in_sig) |