summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/pax/extern.h6
-rw-r--r--bin/pax/file_subs.c117
-rw-r--r--bin/pax/ftree.c10
-rw-r--r--bin/pax/pax.h20
-rw-r--r--bin/pax/tables.c55
-rw-r--r--bin/pax/tables.h14
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;