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:
parent
a1dc209638
commit
fb36a3d847
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user