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.
This commit is contained in:
Kirk McKusick 2002-07-17 02:03:19 +00:00
parent a1dc209638
commit fb36a3d847
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=100207
10 changed files with 91 additions and 34 deletions

View file

@ -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 */

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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);