summaryrefslogtreecommitdiff
path: root/bin/pax/file_subs.c
diff options
context:
space:
mode:
authorPhilip Guenther <guenther@cvs.openbsd.org>2015-02-11 23:14:47 +0000
committerPhilip Guenther <guenther@cvs.openbsd.org>2015-02-11 23:14:47 +0000
commit74e19fb222f0da41bf9c3e7aaed9fb36e43e9dba (patch)
tree054ba50c6c2f7808e7e66a27f198804585c7bfee /bin/pax/file_subs.c
parentcdb3a208e6fc7860ce3497d03d3b26434e9d9653 (diff)
Take II, this time without an incorrect mode test.
For directories whose times or mode will be fixed up in the clean-up pass, record their dev+ino and then use open(O_DIRECTORY)+fstat() to verify that we're updating the correct directory before using futimens() and fchmod(). ok sthen@ millert@
Diffstat (limited to 'bin/pax/file_subs.c')
-rw-r--r--bin/pax/file_subs.c117
1 files changed, 85 insertions, 32 deletions
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;
}
/*