summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2002-07-17 02:03:19 +0000
committermckusick <mckusick@FreeBSD.org>2002-07-17 02:03:19 +0000
commit3abb526f86a27b005f352fb91f605228876fa8f7 (patch)
tree5b5d1d91499a541486f56f84b49c10edeafd66b2
parent9498a983a938cec96851b64642f0b62bba7d1827 (diff)
downloadFreeBSD-src-3abb526f86a27b005f352fb91f605228876fa8f7.zip
FreeBSD-src-3abb526f86a27b005f352fb91f605228876fa8f7.tar.gz
Change utimes to set the file creation time (for filesystems that
support creation times such as UFS2) to the value of the modification time if the value of the modification time is older than the current creation time. See utimes(2) for further details. Sponsored by: DARPA & NAI Labs.
-rw-r--r--include/protocols/dumprestore.h4
-rw-r--r--lib/libc/sys/utimes.29
-rw-r--r--sbin/dump/traverse.c8
-rw-r--r--sbin/restore/dirs.c18
-rw-r--r--sbin/restore/restore.h2
-rw-r--r--sbin/restore/tape.c28
-rw-r--r--sys/kern/vfs_extattr.c21
-rw-r--r--sys/kern/vfs_subr.c2
-rw-r--r--sys/kern/vfs_syscalls.c21
-rw-r--r--sys/ufs/ufs/ufs_vnops.c12
10 files changed, 91 insertions, 34 deletions
diff --git a/include/protocols/dumprestore.h b/include/protocols/dumprestore.h
index 6daecc1..6abf922 100644
--- a/include/protocols/dumprestore.h
+++ b/include/protocols/dumprestore.h
@@ -93,8 +93,8 @@ union u_spcl {
int32_t c_mtimensec; /* last modified time, nanosecs */
int32_t c_spare2[2]; /* old ctime */
int32_t c_rdev; /* for devices, device number */
- int32_t c_createtimensec; /* creation time, nanosecs */
- int64_t c_createtime; /* creation time, seconds */
+ int32_t c_birthtimensec; /* creation time, nanosecs */
+ int64_t c_birthtime; /* creation time, seconds */
int64_t c_atime; /* last access time, seconds */
int64_t c_mtime; /* last modified time, seconds */
int32_t c_spare4[7]; /* old block pointers */
diff --git a/lib/libc/sys/utimes.2 b/lib/libc/sys/utimes.2
index 5d9691f..3c28302 100644
--- a/lib/libc/sys/utimes.2
+++ b/lib/libc/sys/utimes.2
@@ -75,6 +75,15 @@ is
it is assumed to point to an array of two timeval structures.
The access time is set to the value of the first element, and the
modification time is set to the value of the second element.
+For filesystems that support file birth (creation) times (such as
+.Dv UFS2 ),
+the birth time will be set to the value of the second element
+if the second element is older than the currently set birth time.
+To set both a birth time and a modification time,
+two calls are required; the first to set the birth time
+and the second to set the (presumably newer) modification time.
+Ideally a new system call will be added that allows the setting
+of all three times at once.
The caller must be the owner of the file or be the super-user.
.Pp
In either case, the inode-change-time of the file is set to the current
diff --git a/sbin/dump/traverse.c b/sbin/dump/traverse.c
index 733ac26..4cbce6e 100644
--- a/sbin/dump/traverse.c
+++ b/sbin/dump/traverse.c
@@ -407,8 +407,8 @@ dumpino(union dinode *dp, ino_t ino)
spcl.c_atimensec = dp->dp1.di_atimensec;
spcl.c_mtime = _time32_to_time(dp->dp1.di_mtime);
spcl.c_mtimensec = dp->dp1.di_mtimensec;
- spcl.c_createtime = 0;
- spcl.c_createtimensec = 0;
+ spcl.c_birthtime = 0;
+ spcl.c_birthtimensec = 0;
spcl.c_rdev = dp->dp1.di_rdev;
spcl.c_file_flags = dp->dp1.di_flags;
spcl.c_uid = dp->dp1.di_uid;
@@ -420,8 +420,8 @@ dumpino(union dinode *dp, ino_t ino)
spcl.c_atimensec = dp->dp2.di_atimensec;
spcl.c_mtime = _time64_to_time(dp->dp2.di_mtime);
spcl.c_mtimensec = dp->dp2.di_mtimensec;
- spcl.c_createtime = _time64_to_time(dp->dp2.di_createtime);
- spcl.c_createtimensec = dp->dp2.di_creatensec;
+ spcl.c_birthtime = _time64_to_time(dp->dp2.di_birthtime);
+ spcl.c_birthtimensec = dp->dp2.di_birthnsec;
spcl.c_rdev = dp->dp2.di_rdev;
spcl.c_file_flags = dp->dp2.di_flags;
spcl.c_uid = dp->dp2.di_uid;
diff --git a/sbin/restore/dirs.c b/sbin/restore/dirs.c
index 323e9ff..dba5738 100644
--- a/sbin/restore/dirs.c
+++ b/sbin/restore/dirs.c
@@ -82,7 +82,8 @@ static struct inotab *inotab[HASHSIZE];
*/
struct modeinfo {
ino_t ino;
- struct timeval timep[2];
+ struct timeval ctimep[2];
+ struct timeval mtimep[2];
mode_t mode;
uid_t uid;
gid_t gid;
@@ -597,7 +598,8 @@ setdirmodes(int flags)
if (!Nflag) {
(void) chown(cp, node.uid, node.gid);
(void) chmod(cp, node.mode);
- utimes(cp, node.timep);
+ utimes(cp, node.ctimep);
+ utimes(cp, node.mtimep);
(void) chflags(cp, node.flags);
}
ep->e_flags &= ~NEW;
@@ -685,10 +687,14 @@ allocinotab(struct context *ctxp, long seekpt)
if (mf == NULL)
return (itp);
node.ino = ctxp->ino;
- node.timep[0].tv_sec = ctxp->atime_sec;
- node.timep[0].tv_usec = ctxp->atime_nsec / 1000;
- node.timep[1].tv_sec = ctxp->mtime_sec;
- node.timep[1].tv_usec = ctxp->mtime_nsec / 1000;
+ node.mtimep[0].tv_sec = ctxp->atime_sec;
+ node.mtimep[0].tv_usec = ctxp->atime_nsec / 1000;
+ node.mtimep[1].tv_sec = ctxp->mtime_sec;
+ node.mtimep[1].tv_usec = ctxp->mtime_nsec / 1000;
+ node.ctimep[0].tv_sec = ctxp->atime_sec;
+ node.ctimep[0].tv_usec = ctxp->atime_nsec / 1000;
+ node.ctimep[1].tv_sec = ctxp->birthtime_sec;
+ node.ctimep[1].tv_usec = ctxp->birthtime_nsec / 1000;
node.mode = ctxp->mode;
node.flags = ctxp->file_flags;
node.uid = ctxp->uid;
diff --git a/sbin/restore/restore.h b/sbin/restore/restore.h
index cb10d81..6aff827 100644
--- a/sbin/restore/restore.h
+++ b/sbin/restore/restore.h
@@ -113,8 +113,10 @@ struct context {
int rdev; /* device number of file */
time_t atime_sec; /* access time seconds */
time_t mtime_sec; /* modified time seconds */
+ time_t birthtime_sec; /* creation time seconds */
int atime_nsec; /* access time nanoseconds */
int mtime_nsec; /* modified time nanoseconds */
+ int birthtime_nsec; /* creation time nanoseconds */
off_t size; /* size of file */
char *name; /* name of file */
} curfile;
diff --git a/sbin/restore/tape.c b/sbin/restore/tape.c
index 2b2ab91..1392f59 100644
--- a/sbin/restore/tape.c
+++ b/sbin/restore/tape.c
@@ -521,15 +521,19 @@ extractfile(char *name)
{
int flags;
mode_t mode;
- struct timeval timep[2];
+ struct timeval mtimep[2], ctimep[2];
struct entry *ep;
curfile.name = name;
curfile.action = USING;
- timep[0].tv_sec = curfile.atime_sec;
- timep[0].tv_usec = curfile.atime_nsec / 1000;
- timep[1].tv_sec = curfile.mtime_sec;
- timep[1].tv_usec = curfile.mtime_nsec / 1000;
+ mtimep[0].tv_sec = curfile.atime_sec;
+ mtimep[0].tv_usec = curfile.atime_nsec / 1000;
+ mtimep[1].tv_sec = curfile.mtime_sec;
+ mtimep[1].tv_usec = curfile.mtime_nsec / 1000;
+ ctimep[0].tv_sec = curfile.atime_sec;
+ ctimep[0].tv_usec = curfile.atime_nsec / 1000;
+ ctimep[1].tv_sec = curfile.birthtime_sec;
+ ctimep[1].tv_usec = curfile.birthtime_nsec / 1000;
mode = curfile.mode;
flags = curfile.file_flags;
switch (mode & IFMT) {
@@ -567,7 +571,8 @@ extractfile(char *name)
if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
(void) lchown(name, curfile.uid, curfile.gid);
(void) lchmod(name, mode);
- (void) lutimes(name, timep);
+ (void) lutimes(name, ctimep);
+ (void) lutimes(name, mtimep);
return (GOOD);
}
return (FAIL);
@@ -588,7 +593,8 @@ extractfile(char *name)
}
(void) chown(name, curfile.uid, curfile.gid);
(void) chmod(name, mode);
- (void) utimes(name, timep);
+ (void) utimes(name, ctimep);
+ (void) utimes(name, mtimep);
(void) chflags(name, flags);
skipfile();
return (GOOD);
@@ -610,7 +616,8 @@ extractfile(char *name)
}
(void) chown(name, curfile.uid, curfile.gid);
(void) chmod(name, mode);
- (void) utimes(name, timep);
+ (void) utimes(name, ctimep);
+ (void) utimes(name, mtimep);
(void) chflags(name, flags);
skipfile();
return (GOOD);
@@ -634,7 +641,8 @@ extractfile(char *name)
(void) fchmod(ofile, mode);
getfile(xtrfile, xtrskip);
(void) close(ofile);
- utimes(name, timep);
+ (void) utimes(name, ctimep);
+ (void) utimes(name, mtimep);
(void) chflags(name, flags);
return (GOOD);
}
@@ -1174,6 +1182,8 @@ findinode(struct s_spcl *header)
curfile.atime_nsec = header->c_atimensec;
curfile.mtime_sec = header->c_mtime;
curfile.mtime_nsec = header->c_mtimensec;
+ curfile.birthtime_sec = header->c_birthtime;
+ curfile.birthtime_nsec = header->c_birthtimensec;
curfile.size = header->c_size;
curfile.ino = header->c_inumber;
break;
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index 5fc5652..b787bc2 100644
--- a/sys/kern/vfs_extattr.c
+++ b/sys/kern/vfs_extattr.c
@@ -82,7 +82,7 @@ static int setfown(struct thread *td, struct vnode *, uid_t, gid_t);
static int setfmode(struct thread *td, struct vnode *, int);
static int setfflags(struct thread *td, struct vnode *, int);
static int setutimes(struct thread *td, struct vnode *,
- const struct timespec *, int);
+ const struct timespec *, int, int);
static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
struct thread *td);
@@ -2116,13 +2116,14 @@ getutimes(usrtvp, tsp)
* Common implementation code for utimes(), lutimes(), and futimes().
*/
static int
-setutimes(td, vp, ts, nullflag)
+setutimes(td, vp, ts, numtimes, nullflag)
struct thread *td;
struct vnode *vp;
const struct timespec *ts;
+ int numtimes;
int nullflag;
{
- int error;
+ int error, setbirthtime;
struct mount *mp;
struct vattr vattr;
@@ -2130,9 +2131,17 @@ setutimes(td, vp, ts, nullflag)
return (error);
VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
+ setbirthtime = 0;
+ if (numtimes < 3 && VOP_GETATTR(vp, &vattr, td->td_ucred, td) == 0 &&
+ timespeccmp(&ts[1], &vattr.va_birthtime, < ))
+ setbirthtime = 1;
VATTR_NULL(&vattr);
vattr.va_atime = ts[0];
vattr.va_mtime = ts[1];
+ if (setbirthtime)
+ vattr.va_birthtime = ts[1];
+ if (numtimes > 2)
+ vattr.va_birthtime = ts[2];
if (nullflag)
vattr.va_vaflags |= VA_UTIMES_NULL;
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
@@ -2171,7 +2180,7 @@ utimes(td, uap)
if ((error = namei(&nd)) != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
- error = setutimes(td, nd.ni_vp, ts, usrtvp == NULL);
+ error = setutimes(td, nd.ni_vp, ts, 2, usrtvp == NULL);
vrele(nd.ni_vp);
return (error);
}
@@ -2206,7 +2215,7 @@ lutimes(td, uap)
if ((error = namei(&nd)) != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
- error = setutimes(td, nd.ni_vp, ts, usrtvp == NULL);
+ error = setutimes(td, nd.ni_vp, ts, 2, usrtvp == NULL);
vrele(nd.ni_vp);
return (error);
}
@@ -2239,7 +2248,7 @@ futimes(td, uap)
return (error);
if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
- error = setutimes(td, (struct vnode *)fp->f_data, ts, usrtvp == NULL);
+ error = setutimes(td, (struct vnode *)fp->f_data, ts, 2, usrtvp==NULL);
fdrop(fp, td);
return (error);
}
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 3ebb88e..9fd2b0f 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -518,6 +518,8 @@ vattr_null(vap)
vap->va_mtime.tv_nsec = VNOVAL;
vap->va_ctime.tv_sec = VNOVAL;
vap->va_ctime.tv_nsec = VNOVAL;
+ vap->va_birthtime.tv_sec = VNOVAL;
+ vap->va_birthtime.tv_nsec = VNOVAL;
vap->va_flags = VNOVAL;
vap->va_gen = VNOVAL;
vap->va_vaflags = 0;
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 5fc5652..b787bc2 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -82,7 +82,7 @@ static int setfown(struct thread *td, struct vnode *, uid_t, gid_t);
static int setfmode(struct thread *td, struct vnode *, int);
static int setfflags(struct thread *td, struct vnode *, int);
static int setutimes(struct thread *td, struct vnode *,
- const struct timespec *, int);
+ const struct timespec *, int, int);
static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
struct thread *td);
@@ -2116,13 +2116,14 @@ getutimes(usrtvp, tsp)
* Common implementation code for utimes(), lutimes(), and futimes().
*/
static int
-setutimes(td, vp, ts, nullflag)
+setutimes(td, vp, ts, numtimes, nullflag)
struct thread *td;
struct vnode *vp;
const struct timespec *ts;
+ int numtimes;
int nullflag;
{
- int error;
+ int error, setbirthtime;
struct mount *mp;
struct vattr vattr;
@@ -2130,9 +2131,17 @@ setutimes(td, vp, ts, nullflag)
return (error);
VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
+ setbirthtime = 0;
+ if (numtimes < 3 && VOP_GETATTR(vp, &vattr, td->td_ucred, td) == 0 &&
+ timespeccmp(&ts[1], &vattr.va_birthtime, < ))
+ setbirthtime = 1;
VATTR_NULL(&vattr);
vattr.va_atime = ts[0];
vattr.va_mtime = ts[1];
+ if (setbirthtime)
+ vattr.va_birthtime = ts[1];
+ if (numtimes > 2)
+ vattr.va_birthtime = ts[2];
if (nullflag)
vattr.va_vaflags |= VA_UTIMES_NULL;
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
@@ -2171,7 +2180,7 @@ utimes(td, uap)
if ((error = namei(&nd)) != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
- error = setutimes(td, nd.ni_vp, ts, usrtvp == NULL);
+ error = setutimes(td, nd.ni_vp, ts, 2, usrtvp == NULL);
vrele(nd.ni_vp);
return (error);
}
@@ -2206,7 +2215,7 @@ lutimes(td, uap)
if ((error = namei(&nd)) != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
- error = setutimes(td, nd.ni_vp, ts, usrtvp == NULL);
+ error = setutimes(td, nd.ni_vp, ts, 2, usrtvp == NULL);
vrele(nd.ni_vp);
return (error);
}
@@ -2239,7 +2248,7 @@ futimes(td, uap)
return (error);
if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
- error = setutimes(td, (struct vnode *)fp->f_data, ts, usrtvp == NULL);
+ error = setutimes(td, (struct vnode *)fp->f_data, ts, 2, usrtvp==NULL);
fdrop(fp, td);
return (error);
}
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index 975b7a9..0ef9ed2 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -558,7 +558,9 @@ ufs_setattr(ap)
if ((error = UFS_TRUNCATE(vp, vap->va_size, 0, cred, td)) != 0)
return (error);
}
- if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+ if (vap->va_atime.tv_sec != VNOVAL ||
+ vap->va_mtime.tv_sec != VNOVAL ||
+ vap->va_birthtime.tv_sec != VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
if ((ip->i_flags & SF_SNAPSHOT) != 0)
@@ -579,6 +581,9 @@ ufs_setattr(ap)
ip->i_flag |= IN_ACCESS;
if (vap->va_mtime.tv_sec != VNOVAL)
ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ if (vap->va_birthtime.tv_sec != VNOVAL &&
+ ip->i_ump->um_fstype == UFS2)
+ ip->i_flag |= IN_MODIFIED;
ufs_itimes(vp);
if (vap->va_atime.tv_sec != VNOVAL) {
DIP(ip, i_atime) = vap->va_atime.tv_sec;
@@ -588,6 +593,11 @@ ufs_setattr(ap)
DIP(ip, i_mtime) = vap->va_mtime.tv_sec;
DIP(ip, i_mtimensec) = vap->va_mtime.tv_nsec;
}
+ if (vap->va_birthtime.tv_sec != VNOVAL &&
+ ip->i_ump->um_fstype == UFS2) {
+ ip->i_din2->di_birthtime = vap->va_birthtime.tv_sec;
+ ip->i_din2->di_birthnsec = vap->va_birthtime.tv_nsec;
+ }
error = UFS_UPDATE(vp, 0);
if (error)
return (error);
OpenPOWER on IntegriCloud