diff options
author | Philip Guenther <guenther@cvs.openbsd.org> | 2015-02-21 22:48:24 +0000 |
---|---|---|
committer | Philip Guenther <guenther@cvs.openbsd.org> | 2015-02-21 22:48:24 +0000 |
commit | 7eb32e92a3df5f0bcefdb58e386414c1e7d3e6da (patch) | |
tree | fae8ecb2f40763278a08a7eeaa738150b380eea5 /bin/pax | |
parent | 0d78e3742c523340ed11e8491851ca6e38258bc5 (diff) |
Recent changes haven't been completely stable, so revert for the 5.7 release
requested by deraadt@
Diffstat (limited to 'bin/pax')
-rw-r--r-- | bin/pax/ar_subs.c | 8 | ||||
-rw-r--r-- | bin/pax/extern.h | 18 | ||||
-rw-r--r-- | bin/pax/file_subs.c | 153 | ||||
-rw-r--r-- | bin/pax/ftree.c | 10 | ||||
-rw-r--r-- | bin/pax/pat_rep.c | 45 | ||||
-rw-r--r-- | bin/pax/pax.c | 3 | ||||
-rw-r--r-- | bin/pax/pax.h | 20 | ||||
-rw-r--r-- | bin/pax/tables.c | 438 | ||||
-rw-r--r-- | bin/pax/tables.h | 15 | ||||
-rw-r--r-- | bin/pax/tar.c | 117 |
10 files changed, 127 insertions, 700 deletions
diff --git a/bin/pax/ar_subs.c b/bin/pax/ar_subs.c index 6c2a9c8abca..4330abf0b05 100644 --- a/bin/pax/ar_subs.c +++ b/bin/pax/ar_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ar_subs.c,v 1.40 2015/02/12 23:44:57 guenther Exp $ */ +/* $OpenBSD: ar_subs.c,v 1.41 2015/02/21 22:48:23 guenther Exp $ */ /* $NetBSD: ar_subs.c,v 1.5 1995/03/21 09:07:06 cgd Exp $ */ /*- @@ -165,8 +165,6 @@ extract(void) int fd; time_t now; - sltab_start(); - arcn = &archd; /* * figure out archive type; pass any format specific options to the @@ -362,7 +360,6 @@ popd: (void)(*frmt->end_rd)(); (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); ar_close(0); - sltab_process(0); proc_dir(0); pat_chk(); } @@ -761,8 +758,6 @@ copy(void) ARCHD archd; char dirbuf[PAXPATHLEN+1]; - sltab_start(); - arcn = &archd; /* * set up the destination dir path and make sure it is a directory. We @@ -974,7 +969,6 @@ copy(void) */ (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); ar_close(0); - sltab_process(0); proc_dir(0); ftree_chk(); } diff --git a/bin/pax/extern.h b/bin/pax/extern.h index 3b3400b26d1..2bdb6325045 100644 --- a/bin/pax/extern.h +++ b/bin/pax/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.48 2015/02/15 22:18:29 millert Exp $ */ +/* $OpenBSD: extern.h,v 1.49 2015/02/21 22:48:23 guenther Exp $ */ /* $NetBSD: extern.h,v 1.5 1996/03/26 23:54:16 mrg Exp $ */ /*- @@ -147,8 +147,6 @@ int set_ids(char *, uid_t, gid_t); int fset_ids(char *, int, uid_t, gid_t); void set_pmode(char *, mode_t); void fset_pmode(char *, int, mode_t); -int set_attr(const struct file_times *, int _force_times, mode_t, int _do_mode, - int _in_sig); int file_write(int, char *, int, int *, int *, int, char *); void file_flush(int, char *, int); void rdfile_close(ARCHD *, int *); @@ -202,7 +200,6 @@ int pat_sel(ARCHD *); int pat_match(ARCHD *); int mod_name(ARCHD *); int set_dest(ARCHD *, char *, int); -int has_dotdot(const char *); /* * pax.c @@ -264,29 +261,18 @@ void purg_lnk(ARCHD *); void lnk_end(void); int ftime_start(void); int chk_ftime(ARCHD *); -int sltab_start(void); -int sltab_add_sym(const char *_path, const char *_value, mode_t _mode); -int sltab_add_link(const char *, const struct stat *); -void sltab_process(int _in_sig); int name_start(void); int add_name(char *, int, char *); void sub_name(char *, int *, size_t); -#ifndef NOCPIO int dev_start(void); int add_dev(ARCHD *); int map_dev(ARCHD *, u_long, u_long); -#else -# define dev_start() 0 -# define add_dev(x) 0 -# define map_dev(x,y,z) 0 -#endif /* NOCPIO */ int atdir_start(void); void atdir_end(void); void add_atdir(char *, dev_t, ino_t, time_t, time_t); -int do_atdir(const char *, dev_t, ino_t); +int get_atdir(dev_t, ino_t, time_t *, time_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 b71575bdfd6..ca09acabab8 100644 --- a/bin/pax/file_subs.c +++ b/bin/pax/file_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file_subs.c,v 1.43 2015/02/15 22:18:29 millert Exp $ */ +/* $OpenBSD: file_subs.c,v 1.44 2015/02/21 22:48:23 guenther Exp $ */ /* $NetBSD: file_subs.c,v 1.4 1995/03/21 09:07:18 cgd Exp $ */ /*- @@ -56,6 +56,10 @@ mk_link(char *, struct stat *, char *, int); * and setting access modes, uid/gid and times of files */ +#define FILEBITS (S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) +#define SETBITS (S_ISUID | S_ISGID) +#define ABITS (FILEBITS | SETBITS) + /* * file_creat() * Create and open a file. @@ -166,7 +170,6 @@ int lnk_creat(ARCHD *arcn) { struct stat sb; - int res; /* * we may be running as root, so we have to be sure that link target @@ -184,18 +187,7 @@ lnk_creat(ARCHD *arcn) return(-1); } - res = mk_link(arcn->ln_name, &sb, arcn->name, 0); - if (res == 0) { - /* check for a hardlink to a placeholder symlink */ - res = sltab_add_link(arcn->name, &sb); - - if (res < 0) { - /* arrgh, it failed, clean up */ - unlink(arcn->name); - } - } - - return (res); + return(mk_link(arcn->ln_name, &sb, arcn->name, 0)); } /* @@ -299,7 +291,6 @@ 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); @@ -353,7 +344,7 @@ node_creat(ARCHD *arcn) struct stat sb; char target[PATH_MAX]; char *nm = arcn->name; - int len, defer_pmode = 0; + int len; /* * create node based on type, if that fails try to unlink the node and @@ -413,21 +404,7 @@ badlink: nm); return(-1); case PAX_SLK: - if (arcn->ln_name[0] != '/' && - !has_dotdot(arcn->ln_name)) - res = symlink(arcn->ln_name, nm); - else { - /* - * absolute symlinks and symlinks with ".." - * have to be deferred to prevent the archive - * from bootstrapping itself to outside the - * working directory. - */ - res = sltab_add_sym(nm, arcn->ln_name, - arcn->sb.st_mode); - if (res == 0) - defer_pmode = 1; - } + res = symlink(arcn->ln_name, nm); break; case PAX_CTG: case PAX_HLK: @@ -481,7 +458,7 @@ badlink: */ if (!pmode || res) arcn->sb.st_mode &= ~(SETBITS); - if (pmode && !defer_pmode) + if (pmode) set_pmode(nm, arcn->sb.st_mode); if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) { @@ -492,36 +469,33 @@ badlink: * rights. This allows nodes in the archive that are children * of this directory to be extracted without failure. Both time * and modes will be fixed after the entire archive is read and - * before pax exits. To do that safely, we want the dev+ino - * of the directory we created. + * before pax exits. */ - if (lstat(nm, &sb) < 0) { - syswarn(0, errno,"Could not access %s (stat)", nm); - } else if (access(nm, R_OK | W_OK | X_OK) < 0) { - /* - * We have to add rights to the dir, so we make - * sure to restore the mode. The mode must be - * restored AS CREATED and not as stored if - * pmode is not set. - */ - set_pmode(nm, - ((sb.st_mode & FILEBITS) | S_IRWXU)); - if (!pmode) - arcn->sb.st_mode = sb.st_mode; + 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(nm,file_mode | S_IRWXU); + } else { + /* + * We have to add rights to the dir, so we make + * sure to restore the mode. The mode must be + * restored AS CREATED and not as stored if + * pmode is not set. + */ + set_pmode(nm, + ((sb.st_mode & FILEBITS) | S_IRWXU)); + if (!pmode) + arcn->sb.st_mode = sb.st_mode; + } /* - * we have to force the mode to what was set - * here, since we changed it from the default - * as created. + * we have to force the mode to what was set here, + * since we changed it from the default as created. */ - arcn->sb.st_dev = sb.st_dev; - arcn->sb.st_ino = sb.st_ino; add_dir(nm, &(arcn->sb), 1); - } else if (pmode || patime || pmtime) { - arcn->sb.st_dev = sb.st_dev; - arcn->sb.st_ino = sb.st_ino; + } else if (pmode || patime || pmtime) add_dir(nm, &(arcn->sb), 0); - } } if (patime || pmtime) @@ -565,7 +539,6 @@ 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); } @@ -793,60 +766,6 @@ fset_pmode(char *fnm, int fd, mode_t mode) } /* - * set_attr() - * Given a DIRDATA, restore the mode and times as indicated, but - * only after verifying that it's the directory that we wanted. - */ -int -set_attr(const struct file_times *ft, int force_times, mode_t mode, - int do_mode, int in_sig) -{ - struct stat sb; - int fd, r; - - if (!do_mode && !force_times && !patime && !pmtime) - return (0); - - /* - * We could legitimately go through a symlink here, - * so do *not* use O_NOFOLLOW. The dev+ino check will - * protect us from evil. - */ - fd = open(ft->ft_name, O_RDONLY | O_DIRECTORY); - if (fd == -1) { - if (!in_sig) - syswarn(1, errno, "Unable to restore mode and times" - " for directory: %s", ft->ft_name); - return (-1); - } - - if (fstat(fd, &sb) == -1) { - if (!in_sig) - syswarn(1, errno, "Unable to stat directory: %s", - ft->ft_name); - r = -1; - } else if (ft->ft_ino != sb.st_ino || ft->ft_dev != sb.st_dev) { - if (!in_sig) - paxwarn(1, "Directory vanished before restoring" - " mode and times: %s", ft->ft_name); - r = -1; - } else { - /* Whew, it's a match! Is there anything to change? */ - if (do_mode && (mode & ABITS) != (sb.st_mode & ABITS)) - fset_pmode(ft->ft_name, fd, mode); - if (((force_times || patime) && ft->ft_atime != sb.st_atime) || - ((force_times || pmtime) && ft->ft_mtime != sb.st_mtime)) - fset_ftime(ft->ft_name, fd, ft->ft_mtime, - ft->ft_atime, force_times); - r = 0; - } - close(fd); - - return (r); -} - - -/* * file_write() * Write/copy a file (during copy or archive extract). This routine knows * how to copy files with lseek holes in it. (Which are read as file @@ -1038,15 +957,15 @@ rdfile_close(ARCHD *arcn, int *fd) if (*fd < 0) return; + (void)close(*fd); + *fd = -1; + if (!tflag) + return; + /* * user wants last access time reset */ - if (tflag) - fset_ftime(arcn->org_name, *fd, arcn->sb.st_mtime, - arcn->sb.st_atime, 1); - - (void)close(*fd); - *fd = -1; + set_ftime(arcn->org_name, arcn->sb.st_mtime, arcn->sb.st_atime, 1); } /* diff --git a/bin/pax/ftree.c b/bin/pax/ftree.c index cab8723bef0..00f811e358d 100644 --- a/bin/pax/ftree.c +++ b/bin/pax/ftree.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ftree.c,v 1.35 2015/02/11 23:14:46 guenther Exp $ */ +/* $OpenBSD: ftree.c,v 1.36 2015/02/21 22:48:23 guenther Exp $ */ /* $NetBSD: ftree.c,v 1.4 1995/03/21 09:07:21 cgd Exp $ */ /*- @@ -337,6 +337,8 @@ int next_file(ARCHD *arcn) { int cnt; + time_t atime; + time_t mtime; /* * ftree_sel() might have set the ftree_skip flag if the user has the @@ -391,10 +393,10 @@ next_file(ARCHD *arcn) * remember to force the time (this is -t on a read * directory, not a created directory). */ - if (!tflag) + if (!tflag || (get_atdir(ftent->fts_statp->st_dev, + ftent->fts_statp->st_ino, &mtime, &atime) < 0)) continue; - do_atdir(ftent->fts_path, ftent->fts_statp->st_dev, - ftent->fts_statp->st_ino); + set_ftime(ftent->fts_path, mtime, atime, 1); continue; case FTS_DC: /* diff --git a/bin/pax/pat_rep.c b/bin/pax/pat_rep.c index 8094ee3a3e8..55def38fa9c 100644 --- a/bin/pax/pat_rep.c +++ b/bin/pax/pat_rep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pat_rep.c,v 1.36 2015/02/12 23:44:57 guenther Exp $ */ +/* $OpenBSD: pat_rep.c,v 1.37 2015/02/21 22:48:23 guenther Exp $ */ /* $NetBSD: pat_rep.c,v 1.4 1995/03/21 09:07:33 cgd Exp $ */ /*- @@ -583,25 +583,6 @@ range_match(char *pattern, int test) } /* - * has_dotdot() - * Returns true iff the supplied path contains a ".." component. - */ - -int -has_dotdot(const char *path) -{ - const char *p = path; - - while ((p = strstr(p, "..")) != NULL) { - if ((p == path || p[-1] == '/') && - (p[2] == '/' || p[2] == '\0')) - return (1); - p += 2; - } - return (0); -} - -/* * mod_name() * modify a selected file name. first attempt to apply replacement string * expressions, then apply interactive file rename. We apply replacement @@ -651,30 +632,6 @@ mod_name(ARCHD *arcn) paxwarn(0, "Removing leading / from absolute path names in the archive"); } } - if (rmleadslash) { - const char *last = NULL; - const char *p = arcn->name; - - while ((p = strstr(p, "..")) != NULL) { - if ((p == arcn->name || p[-1] == '/') && - (p[2] == '/' || p[2] == '\0')) - last = p + 2; - p += 2; - } - if (last != NULL) { - last++; - paxwarn(1, "Removing leading \"%.*s\"", - (int)(last - arcn->name), arcn->name); - arcn->nlen = strlen(last); - if (arcn->nlen > 0) - memmove(arcn->name, last, arcn->nlen + 1); - else { - arcn->name[0] = '.'; - arcn->name[1] = '\0'; - arcn->nlen = 1; - } - } - } /* * IMPORTANT: We have a problem. what do we do with symlinks? diff --git a/bin/pax/pax.c b/bin/pax/pax.c index 67a1c47bbd8..8e2bf4c439a 100644 --- a/bin/pax/pax.c +++ b/bin/pax/pax.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pax.c,v 1.39 2015/02/12 23:44:57 guenther Exp $ */ +/* $OpenBSD: pax.c,v 1.40 2015/02/21 22:48:23 guenther Exp $ */ /* $NetBSD: pax.c,v 1.5 1996/03/26 23:54:20 mrg Exp $ */ /*- @@ -311,7 +311,6 @@ sig_cleanup(int which_sig) (void) write(STDERR_FILENO, errbuf, strlen(errbuf)); ar_close(1); - sltab_process(1); proc_dir(1); if (tflag) atdir_end(); diff --git a/bin/pax/pax.h b/bin/pax/pax.h index 4ef7dcdfa3e..ef2c78f49f4 100644 --- a/bin/pax/pax.h +++ b/bin/pax/pax.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pax.h,v 1.23 2015/02/11 23:14:46 guenther Exp $ */ +/* $OpenBSD: pax.h,v 1.24 2015/02/21 22:48:23 guenther Exp $ */ /* $NetBSD: pax.h,v 1.3 1995/03/21 09:07:41 cgd Exp $ */ /*- @@ -211,20 +211,6 @@ typedef struct { } FSUB; /* - * Time data for a given file. This is usually embedded in a structure - * indexed by dev+ino, by name, by order in the archive, etc. set_attr() - * takes one of these and will only change the times or mode if the file - * at the given name has the indicated dev+ino. - */ -struct file_times { - ino_t ft_ino; /* inode number to verify */ - time_t ft_mtime; /* times to set */ - time_t ft_atime; - char *ft_name; /* name of file to set the times on */ - dev_t ft_dev; /* device number to verify */ -}; - -/* * Format Specific Options List * * Used to pass format options to the format options handler @@ -243,10 +229,6 @@ typedef struct oplist { #define MINOR(x) minor(x) #define TODEV(x, y) makedev((x), (y)) -#define FILEBITS (S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) -#define SETBITS (S_ISUID | S_ISGID) -#define ABITS (FILEBITS | SETBITS) - /* * General Defines */ diff --git a/bin/pax/tables.c b/bin/pax/tables.c index 79db2a5e63f..abc0ab4ff8f 100644 --- a/bin/pax/tables.c +++ b/bin/pax/tables.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tables.c,v 1.43 2015/02/15 22:18:29 millert Exp $ */ +/* $OpenBSD: tables.c,v 1.44 2015/02/21 22:48:23 guenther Exp $ */ /* $NetBSD: tables.c,v 1.4 1995/03/21 09:07:45 cgd Exp $ */ /*- @@ -37,7 +37,6 @@ #include <sys/types.h> #include <sys/time.h> #include <sys/stat.h> -#include <fcntl.h> #include <limits.h> #include <signal.h> #include <stdio.h> @@ -74,6 +73,8 @@ static size_t dirsize; /* size of dirp table */ static size_t dircnt = 0; /* entries in dir time/mode storage */ static int ffd = -1; /* tmp file for file time table name storage */ +static DEVT *chk_dev(dev_t, int); + /* * hard link table routines * @@ -462,343 +463,6 @@ chk_ftime(ARCHD *arcn) } /* - * escaping (absolute or w/"..") symlink table routines - * - * By default, an archive shouldn't be able extract to outside of the - * current directory. What should we do if the archive contains a symlink - * whose value is either absolute or contains ".." components? What we'll - * do is initially create the path as an empty file (to block attempts to - * reference _through_ it) and instead record its path and desired - * final value and mode. Then once all the other archive - * members are created (but before the pass to set timestamps on - * directories) we'll process those records, replacing the placeholder with - * the correct symlink and setting them to the correct mode, owner, group, - * and timestamps. - * - * Note: we also need to handle hardlinks to symlinks (barf) as well as - * hardlinks whose target is replaced by a later entry in the archive (barf^2). - * - * So we track things by dev+ino of the placeholder file, associating with - * that the value and mode of the final symlink and a list of paths that - * should all be hardlinks of that. We'll 'store' the symlink's desired - * timestamps, owner, and group by setting them on the placeholder file. - * - * The operations are: - * a) create an escaping symlink: create the placeholder file and add an entry - * for the new link - * b) create a hardlink: do the link. If the target turns out to be a - * zero-length file whose dev+ino are in the symlink table, then add this - * path to the list of names for that link - * c) perform deferred processing: for each entry, check each associated path: - * if it's a zero-length file with the correct dev+ino then recreate it as - * the specified symlink or hardlink to the first such - */ - -struct slpath { - char *sp_path; - struct slpath *sp_next; -}; -struct slinode { - ino_t sli_ino; - char *sli_value; - struct slpath sli_paths; - struct slinode *sli_fow; /* hash table chain */ - dev_t sli_dev; - mode_t sli_mode; -}; - -static struct slinode **slitab = NULL; - -/* - * sltab_start() - * create the hash table - * Return: - * 0 if the table and file was created ok, -1 otherwise - */ - -int -sltab_start(void) -{ - - if ((slitab = calloc(SL_TAB_SZ, sizeof *slitab)) == NULL) { - syswarn(1, errno, "symlink table"); - return(-1); - } - - return(0); -} - -/* - * sltab_add_sym() - * Create the placeholder and tracking info for an escaping symlink. - * Return: - * 0 on success, -1 otherwise - */ - -int -sltab_add_sym(const char *path0, const char *value0, mode_t mode) -{ - struct stat sb; - struct slinode *s; - struct slpath *p; - char *path, *value; - u_int indx; - int fd; - - /* create the placeholder */ - fd = open(path0, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0600); - if (fd == -1) - return (-1); - if (fstat(fd, &sb) == -1) { - unlink(path0); - close(fd); - return (-1); - } - close(fd); - - 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); - } - if ((value = strdup(value0)) == NULL) { - syswarn(1, errno, "defered symlink value"); - unlink(path); - free(path); - return (-1); - } - - /* now check the hash table for conflicting entry */ - indx = (sb.st_ino ^ sb.st_dev) % SL_TAB_SZ; - for (s = slitab[indx]; s != NULL; s = s->sli_fow) { - if (s->sli_ino != sb.st_ino || s->sli_dev != sb.st_dev) - continue; - - /* - * One of our placeholders got removed behind our back and - * we've reused the inode. Weird, but clean up the mess. - */ - free(s->sli_value); - free(s->sli_paths.sp_path); - p = s->sli_paths.sp_next; - while (p != NULL) { - struct slpath *next_p = p->sp_next; - - free(p->sp_path); - free(p); - p = next_p; - } - goto set_value; - } - - /* Normal case: create a new node */ - if ((s = malloc(sizeof *s)) == NULL) { - syswarn(1, errno, "defered symlink"); - unlink(path); - free(path); - free(value); - return (-1); - } - s->sli_ino = sb.st_ino; - s->sli_dev = sb.st_dev; - s->sli_fow = slitab[indx]; - slitab[indx] = s; - -set_value: - s->sli_paths.sp_path = path; - s->sli_paths.sp_next = NULL; - s->sli_value = value; - s->sli_mode = mode; - return (0); -} - -/* - * sltab_add_link() - * A hardlink was created; if it looks like a placeholder, handle the - * tracking. - * Return: - * 0 if things are ok, -1 if something went wrong - */ - -int -sltab_add_link(const char *path, const struct stat *sb) -{ - struct slinode *s; - struct slpath *p; - u_int indx; - - if (!S_ISREG(sb->st_mode) || sb->st_size != 0) - return (1); - - /* find the hash table entry for this hardlink */ - indx = (sb->st_ino ^ sb->st_dev) % SL_TAB_SZ; - for (s = slitab[indx]; s != NULL; s = s->sli_fow) { - if (s->sli_ino != sb->st_ino || s->sli_dev != sb->st_dev) - continue; - - if ((p = malloc(sizeof *p)) == NULL) { - syswarn(1, errno, "deferred symlink hardlink"); - return (-1); - } - 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); - } - - /* link it in */ - p->sp_next = s->sli_paths.sp_next; - s->sli_paths.sp_next = p; - return (0); - } - - /* not found */ - return (1); -} - - -static int -sltab_process_one(struct slinode *s, struct slpath *p, const char *first, - int in_sig) -{ - struct stat sb; - char *path = p->sp_path; - mode_t mode; - int err; - - /* - * is it the expected placeholder? This can fail legimately - * if the archive overwrote the link with another, later entry, - * so don't warn. - */ - if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode) || sb.st_size != 0 || - sb.st_ino != s->sli_ino || sb.st_dev != s->sli_dev) - return (0); - - if (unlink(path) && errno != ENOENT) { - if (!in_sig) - syswarn(1, errno, "deferred symlink removal"); - return (0); - } - - err = 0; - if (first != NULL) { - /* add another hardlink to the existing symlink */ - if (linkat(AT_FDCWD, first, AT_FDCWD, path, 0) == 0) - return (0); - - /* - * Couldn't hardlink the symlink for some reason, so we'll - * try creating it as its own symlink, but save the error - * for reporting if that fails. - */ - err = errno; - } - - if (symlink(s->sli_value, path)) { - if (!in_sig) { - const char *qualifier = ""; - if (err) - qualifier = " hardlink"; - else - err = errno; - - syswarn(1, err, "deferred symlink%s: %s", - qualifier, path); - } - return (0); - } - - /* success, so set the id, mode, and times */ - mode = s->sli_mode; - if (pids) { - /* if can't set the ids, force the set[ug]id bits off */ - if (set_ids(path, sb.st_uid, sb.st_gid)) - mode &= ~(SETBITS); - } - - if (pmode) - set_pmode(path, mode); - - if (patime || pmtime) - set_ftime(path, sb.st_mtime, sb.st_atime, 0); - - /* - * If we tried to link to first but failed, then this new symlink - * might be a better one to try in the future. Guess from the errno. - */ - if (err == 0 || err == ENOENT || err == EMLINK || err == EOPNOTSUPP) - return (1); - return (0); -} - -/* - * sltab_process() - * Do all the delayed process for escape symlinks - */ - -void -sltab_process(int in_sig) -{ - struct slinode *s; - struct slpath *p; - char *first; - u_int indx; - - if (slitab == NULL) - return; - - /* walk across the entire hash table */ - for (indx = 0; indx < SL_TAB_SZ; indx++) { - while ((s = slitab[indx]) != NULL) { - /* pop this entry */ - slitab[indx] = s->sli_fow; - - first = NULL; - p = &s->sli_paths; - while (1) { - struct slpath *next_p; - - if (sltab_process_one(s, p, first, in_sig)) { - if (!in_sig) - free(first); - first = p->sp_path; - } else if (!in_sig) - free(p->sp_path); - - if ((next_p = p->sp_next) == NULL) - break; - *p = *next_p; - if (!in_sig) - free(next_p); - } - if (!in_sig) { - free(first); - free(s->sli_value); - free(s); - } - } - } - if (!in_sig) - free(slitab); - slitab = NULL; -} - - -/* * Interactive rename table routines * * The interactive rename table keeps track of the new names that the user @@ -943,7 +607,6 @@ sub_name(char *oname, int *onamelen, size_t onamesize) */ } -#ifndef NOCPIO /* * device/inode mapping table routines * (used with formats that store device and inodes fields) @@ -984,8 +647,6 @@ sub_name(char *oname, int *onamelen, size_t onamesize) * (for more info see table.h for the data structures involved). */ -static DEVT *chk_dev(dev_t, int); - /* * dev_start() * create the device mapping table @@ -1211,7 +872,6 @@ map_dev(ARCHD *arcn, u_long dev_mask, u_long ino_mask) paxwarn(0, "Archive may create improper hard links when extracted"); return(0); } -#endif /* NOCPIO */ /* * directory access/mod time reset table routines (for directories READ by pax) @@ -1278,7 +938,7 @@ atdir_end(void) * not read by pax. Read time reset is controlled by -t. */ for (; pt != NULL; pt = pt->fow) - set_attr(&pt->ft, 1, 0, 0, 0); + set_ftime(pt->name, pt->mtime, pt->atime, 1); } } @@ -1308,7 +968,7 @@ add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime) indx = ((unsigned)ino) % A_TAB_SZ; if ((pt = atab[indx]) != NULL) { while (pt != NULL) { - if ((pt->ft.ft_ino == ino) && (pt->ft.ft_dev == dev)) + if ((pt->ino == ino) && (pt->dev == dev)) break; pt = pt->fow; } @@ -1326,11 +986,11 @@ add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime) sigfillset(&allsigs); sigprocmask(SIG_BLOCK, &allsigs, &savedsigs); if ((pt = malloc(sizeof *pt)) != NULL) { - if ((pt->ft.ft_name = strdup(fname)) != NULL) { - pt->ft.ft_dev = dev; - pt->ft.ft_ino = ino; - pt->ft.ft_mtime = mtime; - pt->ft.ft_atime = atime; + if ((pt->name = strdup(fname)) != NULL) { + pt->dev = dev; + pt->ino = ino; + pt->mtime = mtime; + pt->atime = atime; pt->fow = atab[indx]; atab[indx] = pt; sigprocmask(SIG_SETMASK, &savedsigs, NULL); @@ -1355,7 +1015,7 @@ add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime) */ int -do_atdir(const char *name, dev_t dev, ino_t ino) +get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) { ATDIR *pt; ATDIR **ppt; @@ -1373,7 +1033,7 @@ do_atdir(const char *name, dev_t dev, ino_t ino) ppt = &(atab[indx]); while (pt != NULL) { - if ((pt->ft.ft_ino == ino) && (pt->ft.ft_dev == dev)) + if ((pt->ino == ino) && (pt->dev == dev)) break; /* * no match, go to next one @@ -1385,19 +1045,19 @@ do_atdir(const char *name, dev_t dev, ino_t ino) /* * return if we did not find it. */ - if (pt == NULL || pt->ft.ft_name == NULL || - strcmp(name, pt->ft.ft_name) == 0) + if (pt == NULL) return(-1); /* - * found it. set the times and remove the entry from the table. + * found it. return the times and remove the entry from the table. */ - set_attr(&pt->ft, 1, 0, 0, 0); sigfillset(&allsigs); sigprocmask(SIG_BLOCK, &allsigs, &savedsigs); *ppt = pt->fow; sigprocmask(SIG_SETMASK, &savedsigs, NULL); - free(pt->ft.ft_name); + *mtime = pt->mtime; + *atime = pt->atime; + free(pt->name); free(pt); return(0); } @@ -1417,8 +1077,12 @@ do_atdir(const char *name, dev_t dev, ino_t ino) * times and file permissions specified by the archive are stored. After all * files have been extracted (or copied), these directories have their times * and file modes reset to the stored values. The directory info is restored in - * reverse order as entries were added from root to leaf: to restore atime - * properly, we must go backwards. + * reverse order as entries were added to the data file from root to leaf. To + * restore atime properly, we must go backwards. The data file consists of + * records with two parts, the file name followed by a DIRDATA trailer. The + * fixed sized trailer contains the size of the name plus the off_t location in + * the file. To restore we work backwards through the file reading the trailer + * then the file name. */ /* @@ -1486,16 +1150,14 @@ add_dir(char *name, struct stat *psb, int frc_mode) sigprocmask(SIG_SETMASK, &savedsigs, NULL); } dblk = &dirp[dircnt]; - if ((dblk->ft.ft_name = strdup(name)) == NULL) { + if ((dblk->name = strdup(name)) == NULL) { paxwarn(1, "Unable to store mode and times for created" " directory: %s", name); return; } - dblk->ft.ft_mtime = psb->st_mtime; - dblk->ft.ft_atime = psb->st_atime; - dblk->ft.ft_ino = psb->st_ino; - dblk->ft.ft_dev = psb->st_dev; - dblk->mode = psb->st_mode & ABITS; + dblk->mode = psb->st_mode & 0xffff; + dblk->mtime = psb->st_mtime; + dblk->atime = psb->st_atime; dblk->frc_mode = frc_mode; sigprocmask(SIG_BLOCK, &allsigs, &savedsigs); ++dircnt; @@ -1503,35 +1165,6 @@ 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 @@ -1551,22 +1184,17 @@ 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) */ - set_attr(&dblk->ft, 0, dblk->mode, pmode || dblk->frc_mode, - in_sig); + dblk = &dirp[cnt]; + if (pmode || dblk->frc_mode) + set_pmode(dblk->name, dblk->mode); + if (patime || pmtime) + set_ftime(dblk->name, dblk->mtime, dblk->atime, 0); if (!in_sig) - free(dblk->ft.ft_name); + free(dblk->name); } if (!in_sig) diff --git a/bin/pax/tables.h b/bin/pax/tables.h index 45dc40aed60..57fe2528e3c 100644 --- a/bin/pax/tables.h +++ b/bin/pax/tables.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tables.h,v 1.13 2015/02/12 23:44:57 guenther Exp $ */ +/* $OpenBSD: tables.h,v 1.14 2015/02/21 22:48:23 guenther Exp $ */ /* $NetBSD: tables.h,v 1.3 1995/03/21 09:07:47 cgd Exp $ */ /*- @@ -50,7 +50,6 @@ #define N_TAB_SZ 541 /* interactive rename hash table */ #define D_TAB_SZ 317 /* unique device mapping table */ #define A_TAB_SZ 317 /* ftree dir access time reset table */ -#define SL_TAB_SZ 317 /* escape symlink tables */ #define MAXKEYLEN 64 /* max number of chars for hash */ #define DIRP_SIZE 64 /* initial size of created dir table */ @@ -144,8 +143,12 @@ typedef struct dlist { */ typedef struct atdir { - struct file_times ft; + ino_t ino; + time_t mtime; /* access and mod time to reset to */ + time_t atime; + char *name; /* name of directory to reset */ struct atdir *fow; + dev_t dev; /* dev and inode for fast lookup */ } ATDIR; /* @@ -159,7 +162,9 @@ typedef struct atdir { */ typedef struct dirdata { - struct file_times ft; - u_int16_t mode; /* file mode to restore */ + time_t mtime; /* mtime to set */ + time_t atime; /* atime to set */ + char *name; /* file name */ + u_int16_t mode; /* file mode to restore */ u_int16_t frc_mode; /* do we force mode settings? */ } DIRDATA; diff --git a/bin/pax/tar.c b/bin/pax/tar.c index 900c906c497..671c61e70c7 100644 --- a/bin/pax/tar.c +++ b/bin/pax/tar.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tar.c,v 1.54 2015/01/29 19:41:49 guenther Exp $ */ +/* $OpenBSD: tar.c,v 1.55 2015/02/21 22:48:23 guenther Exp $ */ /* $NetBSD: tar.c,v 1.5 1995/03/21 09:07:49 cgd Exp $ */ /*- @@ -58,7 +58,7 @@ static char *name_split(char *, int); static int ul_oct(u_long, char *, int, int); static int uqd_oct(u_quad_t, char *, int, int); #ifndef SMALL -static int rd_xheader(ARCHD *arcn, int, off_t); +static int rd_xheader(ARCHD *, char *, off_t, char); #endif static uid_t uid_nobody; @@ -734,7 +734,7 @@ ustar_id(char *blk, int size) int ustar_rd(ARCHD *arcn, char *buf) { - HD_USTAR *hd = (HD_USTAR *)buf; + HD_USTAR *hd; char *dest; int cnt = 0; dev_t devmajor; @@ -746,30 +746,18 @@ ustar_rd(ARCHD *arcn, char *buf) */ if (ustar_id(buf, BLKMULT) < 0) return(-1); - -#ifndef SMALL -reset: -#endif memset(arcn, 0, sizeof(*arcn)); arcn->org_name = arcn->name; arcn->sb.st_nlink = 1; + hd = (HD_USTAR *)buf; #ifndef SMALL - /* Process Extended headers. */ + /* Process the Extended header. */ if (hd->typeflag == XHDRTYPE || hd->typeflag == GHDRTYPE) { - if (rd_xheader(arcn, hd->typeflag == GHDRTYPE, - (off_t)asc_ul(hd->size, sizeof(hd->size), OCT)) < 0) + if (rd_xheader(arcn, buf, + (off_t)asc_ul(hd->size, sizeof(hd->size), OCT), + hd->typeflag) < 0) return (-1); - - /* Update and check the ustar header. */ - if (rd_wrbuf(buf, BLKMULT) != BLKMULT) - return (-1); - if (ustar_id(buf, BLKMULT) < 0) - return(-1); - - /* if the next block is another extension, reset the values */ - if (hd->typeflag == XHDRTYPE || hd->typeflag == GHDRTYPE) - goto reset; } #endif @@ -1205,84 +1193,51 @@ expandname(char *buf, size_t len, char **gnu_name, const char *name, #ifndef SMALL -/* shortest possible extended record: "5 a=\n" */ -#define MINXHDRSZ 5 - -/* longest record we'll accept */ -#define MAXXHDRSZ BLKMULT +#define MINXHDRSZ 6 static int -rd_xheader(ARCHD *arcn, int global, off_t size) +rd_xheader(ARCHD *arcn, char *buf, off_t size, char typeflag) { - char buf[MAXXHDRSZ]; - unsigned long len; + off_t len; char *delim, *keyword; - char *nextp, *p, *end; - int pad, ret = 0; - - /* before we alter size, make note of how much we have to skip */ - pad = TAR_PAD((unsigned)size); - - p = end = buf; - while (size > 0 || p < end) { - if (size > 0) { - int rdlen; - - /* shift stuff down */ - if (p > buf) { - memmove(buf, p, end - p); - end -= p - buf; - p = buf; - } + char *nextp, *p; - /* fill starting at end */ - rdlen = MINIMUM(size, (buf + sizeof buf) - end); - if (rd_wrbuf(end, rdlen) != rdlen) { - ret = -1; - break; - } - size -= rdlen; - end += rdlen; - } + if (size < MINXHDRSZ) { + paxwarn(1, "Invalid extended header length"); + return (-1); + } + if (rd_wrbuf(buf, size) != size) + return (-1); + if (rd_skip((off_t)BLKMULT - size) < 0) + return (-1); - /* [p, end) is good */ - if (memchr(p, ' ', end - p) == NULL || - !isdigit((unsigned char)*p)) { + for (p = buf; size > 0; size -= len, p = nextp) { + if (!isdigit((unsigned char)*p)) { paxwarn(1, "Invalid extended header record"); - ret = -1; - break; + return (-1); } errno = 0; - len = strtoul(p, &delim, 10); - if (*delim != ' ' || (errno == ERANGE && len == ULONG_MAX) || + len = strtoll(p, &delim, 10); + if (*delim != ' ' || (errno == ERANGE && + (len == LLONG_MIN || len == LLONG_MAX)) || len < MINXHDRSZ) { paxwarn(1, "Invalid extended header record length"); - ret = -1; - break; + return (-1); } - if (len > end - p) { - paxwarn(1, "Extended header record length %lu is " - "out of range", len); - /* if we can just toss this record, do so */ - len -= end - p; - if (len <= size && rd_skip(len) == 0) { - size -= len; - p = end = buf; - continue; - } - ret = -1; - break; + if (len > size) { + paxwarn(1, "Extended header record length %lld is " + "out of range", (long long)len); + return (-1); } nextp = p + len; keyword = p = delim + 1; p = memchr(p, '=', len); if (!p || nextp[-1] != '\n') { paxwarn(1, "Malformed extended header record"); - ret = -1; - break; + return (-1); } *p++ = nextp[-1] = '\0'; - if (!global) { + if (typeflag == XHDRTYPE) { if (!strcmp(keyword, "path")) { arcn->nlen = strlcpy(arcn->name, p, sizeof(arcn->name)); @@ -1291,11 +1246,11 @@ rd_xheader(ARCHD *arcn, int global, off_t size) sizeof(arcn->ln_name)); } } - p = nextp; } - if (rd_skip(size + pad) < 0) + /* Update the ustar header. */ + if (rd_wrbuf(buf, BLKMULT) != BLKMULT) return (-1); - return (ret); + return (0); } #endif |