diff options
-rw-r--r-- | bin/pax/extern.h | 6 | ||||
-rw-r--r-- | bin/pax/file_subs.c | 117 | ||||
-rw-r--r-- | bin/pax/ftree.c | 10 | ||||
-rw-r--r-- | bin/pax/pax.h | 20 | ||||
-rw-r--r-- | bin/pax/tables.c | 55 | ||||
-rw-r--r-- | bin/pax/tables.h | 14 |
6 files changed, 141 insertions, 81 deletions
diff --git a/bin/pax/extern.h b/bin/pax/extern.h index 47d69d146e9..4e11e0df142 100644 --- a/bin/pax/extern.h +++ b/bin/pax/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.44 2015/02/05 22:32:20 sthen Exp $ */ +/* $OpenBSD: extern.h,v 1.45 2015/02/11 23:14:46 guenther Exp $ */ /* $NetBSD: extern.h,v 1.5 1996/03/26 23:54:16 mrg Exp $ */ /*- @@ -147,6 +147,8 @@ 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 *); @@ -270,7 +272,7 @@ int map_dev(ARCHD *, u_long, u_long); int atdir_start(void); void atdir_end(void); void add_atdir(char *, dev_t, ino_t, time_t, time_t); -int get_atdir(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 proc_dir(int _in_sig); diff --git a/bin/pax/file_subs.c b/bin/pax/file_subs.c index f4054b53b89..ca546c080a6 100644 --- a/bin/pax/file_subs.c +++ b/bin/pax/file_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file_subs.c,v 1.40 2015/02/05 22:32:20 sthen Exp $ */ +/* $OpenBSD: file_subs.c,v 1.41 2015/02/11 23:14:46 guenther Exp $ */ /* $NetBSD: file_subs.c,v 1.4 1995/03/21 09:07:18 cgd Exp $ */ /*- @@ -56,10 +56,6 @@ 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. @@ -469,33 +465,36 @@ 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. + * before pax exits. To do that safely, we want the dev+ino + * of the directory we created. */ - 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; - } + 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; /* - * 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) + } else if (pmode || patime || pmtime) { + arcn->sb.st_dev = sb.st_dev; + arcn->sb.st_ino = sb.st_ino; add_dir(nm, &(arcn->sb), 0); + } } if (patime || pmtime) @@ -766,6 +765,60 @@ 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 @@ -957,15 +1010,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 */ - set_ftime(arcn->org_name, arcn->sb.st_mtime, arcn->sb.st_atime, 1); + if (tflag) + fset_ftime(arcn->org_name, *fd, arcn->sb.st_mtime, + arcn->sb.st_atime, 1); + + (void)close(*fd); + *fd = -1; } /* diff --git a/bin/pax/ftree.c b/bin/pax/ftree.c index 95eac24f8cb..cab8723bef0 100644 --- a/bin/pax/ftree.c +++ b/bin/pax/ftree.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ftree.c,v 1.34 2015/02/05 22:32:20 sthen Exp $ */ +/* $OpenBSD: ftree.c,v 1.35 2015/02/11 23:14:46 guenther Exp $ */ /* $NetBSD: ftree.c,v 1.4 1995/03/21 09:07:21 cgd Exp $ */ /*- @@ -337,8 +337,6 @@ 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 @@ -393,10 +391,10 @@ next_file(ARCHD *arcn) * remember to force the time (this is -t on a read * directory, not a created directory). */ - if (!tflag || (get_atdir(ftent->fts_statp->st_dev, - ftent->fts_statp->st_ino, &mtime, &atime) < 0)) + if (!tflag) continue; - set_ftime(ftent->fts_path, mtime, atime, 1); + do_atdir(ftent->fts_path, ftent->fts_statp->st_dev, + ftent->fts_statp->st_ino); continue; case FTS_DC: /* diff --git a/bin/pax/pax.h b/bin/pax/pax.h index 157b33282b2..4ef7dcdfa3e 100644 --- a/bin/pax/pax.h +++ b/bin/pax/pax.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pax.h,v 1.22 2015/02/05 22:32:20 sthen Exp $ */ +/* $OpenBSD: pax.h,v 1.23 2015/02/11 23:14:46 guenther Exp $ */ /* $NetBSD: pax.h,v 1.3 1995/03/21 09:07:41 cgd Exp $ */ /*- @@ -211,6 +211,20 @@ 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 @@ -229,6 +243,10 @@ 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 0b4432b4d58..06f5c8a04c9 100644 --- a/bin/pax/tables.c +++ b/bin/pax/tables.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tables.c,v 1.39 2015/02/05 22:32:20 sthen Exp $ */ +/* $OpenBSD: tables.c,v 1.40 2015/02/11 23:14:46 guenther Exp $ */ /* $NetBSD: tables.c,v 1.4 1995/03/21 09:07:45 cgd Exp $ */ /*- @@ -938,7 +938,7 @@ atdir_end(void) * not read by pax. Read time reset is controlled by -t. */ for (; pt != NULL; pt = pt->fow) - set_ftime(pt->name, pt->mtime, pt->atime, 1); + set_attr(&pt->ft, 1, 0, 0, 0); } } @@ -968,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->ino == ino) && (pt->dev == dev)) + if ((pt->ft.ft_ino == ino) && (pt->ft.ft_dev == dev)) break; pt = pt->fow; } @@ -986,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->name = strdup(fname)) != NULL) { - pt->dev = dev; - pt->ino = ino; - pt->mtime = mtime; - pt->atime = atime; + 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; pt->fow = atab[indx]; atab[indx] = pt; sigprocmask(SIG_SETMASK, &savedsigs, NULL); @@ -1015,7 +1015,7 @@ add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime) */ int -get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) +do_atdir(const char *name, dev_t dev, ino_t ino) { ATDIR *pt; ATDIR **ppt; @@ -1033,7 +1033,7 @@ get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) ppt = &(atab[indx]); while (pt != NULL) { - if ((pt->ino == ino) && (pt->dev == dev)) + if ((pt->ft.ft_ino == ino) && (pt->ft.ft_dev == dev)) break; /* * no match, go to next one @@ -1045,19 +1045,18 @@ get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) /* * return if we did not find it. */ - if (pt == NULL) + if (pt == NULL || strcmp(name, pt->ft.ft_name) == 0) return(-1); /* - * found it. return the times and remove the entry from the table. + * found it. set 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); - *mtime = pt->mtime; - *atime = pt->atime; - free(pt->name); + free(pt->ft.ft_name); free(pt); return(0); } @@ -1077,12 +1076,8 @@ get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) * 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 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. + * reverse order as entries were added from root to leaf: to restore atime + * properly, we must go backwards. */ /* @@ -1150,14 +1145,16 @@ add_dir(char *name, struct stat *psb, int frc_mode) sigprocmask(SIG_SETMASK, &savedsigs, NULL); } dblk = &dirp[dircnt]; - if ((dblk->name = strdup(name)) == NULL) { + if ((dblk->ft.ft_name = strdup(name)) == NULL) { paxwarn(1, "Unable to store mode and times for created" " directory: %s", name); return; } - dblk->mode = psb->st_mode & 0xffff; - dblk->mtime = psb->st_mtime; - dblk->atime = psb->st_atime; + 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->frc_mode = frc_mode; sigprocmask(SIG_BLOCK, &allsigs, &savedsigs); ++dircnt; @@ -1189,12 +1186,10 @@ proc_dir(int in_sig) * the user didn't ask for it (see file_subs.c for more info) */ 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); + set_attr(&dblk->ft, 0, dblk->mode, pmode || dblk->frc_mode, + in_sig); if (!in_sig) - free(dblk->name); + free(dblk->ft.ft_name); } if (!in_sig) diff --git a/bin/pax/tables.h b/bin/pax/tables.h index 936ad40e285..f4ac151f911 100644 --- a/bin/pax/tables.h +++ b/bin/pax/tables.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tables.h,v 1.11 2015/02/05 22:32:20 sthen Exp $ */ +/* $OpenBSD: tables.h,v 1.12 2015/02/11 23:14:46 guenther Exp $ */ /* $NetBSD: tables.h,v 1.3 1995/03/21 09:07:47 cgd Exp $ */ /*- @@ -143,12 +143,8 @@ typedef struct dlist { */ typedef struct atdir { - ino_t ino; - time_t mtime; /* access and mod time to reset to */ - time_t atime; - char *name; /* name of directory to reset */ + struct file_times ft; struct atdir *fow; - dev_t dev; /* dev and inode for fast lookup */ } ATDIR; /* @@ -162,9 +158,7 @@ typedef struct atdir { */ typedef struct dirdata { - time_t mtime; /* mtime to set */ - time_t atime; /* atime to set */ - char *name; /* file name */ - u_int16_t mode; /* file mode to restore */ + struct file_times ft; + u_int16_t mode; /* file mode to restore */ u_int16_t frc_mode; /* do we force mode settings? */ } DIRDATA; |