Subsecond timestamps support for FS
Expand REQ_UTIME to include tv_nsec members (as in struct timespec) in addition to tv_sec==time_t Designed with help from David van Moolenbroek
This commit is contained in:
parent
df9d28ebe7
commit
4069cef7f9
8 changed files with 163 additions and 39 deletions
|
@ -6,6 +6,7 @@
|
|||
|
||||
/* VFS/FS request fields */
|
||||
#define REQ_ACTIME m9_l2
|
||||
#define REQ_ACNSEC m9_l4
|
||||
#define REQ_COUNT m9_l2
|
||||
#define REQ_DEV m9_l5
|
||||
#define REQ_DEV2 m9_l1
|
||||
|
@ -19,6 +20,7 @@
|
|||
#define REQ_MEM_SIZE m9_l5
|
||||
#define REQ_MODE m9_s3
|
||||
#define REQ_MODTIME m9_l3
|
||||
#define REQ_MODNSEC m9_l5
|
||||
#define REQ_NBYTES m9_l5
|
||||
#define REQ_PATH_LEN m9_s2
|
||||
#define REQ_PATH_SIZE m9_l5
|
||||
|
|
|
@ -158,11 +158,39 @@ int do_utime()
|
|||
if ((r = verify_inode(ino, path, NULL)) != OK)
|
||||
return r;
|
||||
|
||||
attr.a_mask = SFFS_ATTR_ATIME | SFFS_ATTR_MTIME;
|
||||
attr.a_atime.tv_sec = m_in.REQ_ACTIME;
|
||||
attr.a_atime.tv_nsec = 0;
|
||||
attr.a_mtime.tv_sec = m_in.REQ_MODTIME;
|
||||
attr.a_mtime.tv_nsec = 0;
|
||||
attr.a_mask = 0;
|
||||
|
||||
switch(m_in.REQ_ACNSEC) {
|
||||
case UTIME_OMIT: /* do not touch */
|
||||
break;
|
||||
case UTIME_NOW:
|
||||
/* XXX VFS should have time() into ACTIME, for compat; we trust it! */
|
||||
m_in.REQ_ACNSEC = 0;
|
||||
/*FALLTHROUGH*/
|
||||
default:
|
||||
/* cases m_in.REQ_ACNSEC < 0 || m_in.REQ_ACNSEC >= 1E9
|
||||
* are caught by VFS to cooperate with old instances of EXT2
|
||||
*/
|
||||
attr.a_atime.tv_sec = m_in.REQ_ACTIME;
|
||||
attr.a_atime.tv_nsec = m_in.REQ_ACNSEC;
|
||||
attr.a_mask |= SFFS_ATTR_ATIME;
|
||||
break;
|
||||
}
|
||||
switch(m_in.REQ_MODNSEC) {
|
||||
case UTIME_OMIT: /* do not touch */
|
||||
break;
|
||||
case UTIME_NOW:
|
||||
/* XXX VFS should have time() into MODTIME, for compat; we trust it! */
|
||||
m_in.REQ_MODNSEC = 0;
|
||||
/*FALLTHROUGH*/
|
||||
default:
|
||||
/* cases m_in.REQ_MODNSEC < 0 || m_in.REQ_MODNSEC >= 1E9
|
||||
* are caught by VFS to cooperate with old instances
|
||||
*/
|
||||
attr.a_mtime.tv_sec = m_in.REQ_MODTIME;
|
||||
attr.a_mtime.tv_nsec = m_in.REQ_MODNSEC;
|
||||
attr.a_mask |= SFFS_ATTR_MTIME;
|
||||
break;
|
||||
}
|
||||
return sffs_table->t_setattr(path, &attr);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <minix/callnr.h>
|
||||
#include <minix/com.h>
|
||||
#include "inode.h"
|
||||
#include <sys/stat.h>
|
||||
#include <minix/vfsif.h>
|
||||
|
||||
|
||||
|
@ -21,13 +22,53 @@ int fs_utime()
|
|||
if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
|
||||
return(EINVAL);
|
||||
|
||||
/* Only the owner of a file or the super_user can change its time. */
|
||||
/*
|
||||
* Only the owner of a file or the super_user can change the timestamps.
|
||||
* Here we assume VFS did that check before.
|
||||
*/
|
||||
|
||||
r = OK;
|
||||
if(read_only(rip) != OK) r = EROFS; /* not even su can touch if R/O */
|
||||
if(r == OK) {
|
||||
rip->i_atime = fs_m_in.REQ_ACTIME;
|
||||
rip->i_mtime = fs_m_in.REQ_MODTIME;
|
||||
rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */
|
||||
switch(fs_m_in.REQ_ACNSEC) {
|
||||
case UTIME_NOW:
|
||||
rip->i_update |= ATIME;
|
||||
break;
|
||||
case UTIME_OMIT: /* do not touch */
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* cases fs_m_in.REQ_ACNSEC < 0 || fs_m_in.REQ_ACNSEC >= 1E9
|
||||
* are caught by VFS to cooperate with old instances of EXT2
|
||||
*/
|
||||
rip->i_atime = fs_m_in.REQ_ACTIME;
|
||||
/*
|
||||
* Ext2FS does not support better than second resolution,
|
||||
* so we discard REQ_ACNSEC to round down
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
switch(fs_m_in.REQ_MODNSEC) {
|
||||
case UTIME_NOW:
|
||||
rip->i_update |= MTIME;
|
||||
break;
|
||||
case UTIME_OMIT: /* do not touch */
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* cases fs_m_in.REQ_MODNSEC < 0 || fs_m_in.REQ_MODNSEC >= 1E9
|
||||
* are caught by VFS to cooperate with old instances of EXT2
|
||||
*/
|
||||
rip->i_mtime = fs_m_in.REQ_MODTIME;
|
||||
/*
|
||||
* Ext2FS does not support better than second resolution,
|
||||
* so we discard REQ_MODNSEC to round down
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
rip->i_dirt = IN_DIRTY;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "fs.h"
|
||||
#include "inode.h"
|
||||
#include <sys/stat.h>
|
||||
#include <minix/vfsif.h>
|
||||
|
||||
|
||||
|
@ -15,13 +16,53 @@ int fs_utime()
|
|||
if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
|
||||
return(EINVAL);
|
||||
|
||||
/* Only the owner of a file or the super_user can change its time. */
|
||||
/*
|
||||
* Only the owner of a file or the super_user can change the timestamps.
|
||||
* Here we assume VFS did that check before.
|
||||
*/
|
||||
|
||||
r = OK;
|
||||
if(read_only(rip) != OK) r = EROFS; /* not even su can touch if R/O */
|
||||
if(r == OK) {
|
||||
rip->i_atime = fs_m_in.REQ_ACTIME;
|
||||
rip->i_mtime = fs_m_in.REQ_MODTIME;
|
||||
rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */
|
||||
switch(fs_m_in.REQ_ACNSEC) {
|
||||
case UTIME_NOW:
|
||||
rip->i_update |= ATIME;
|
||||
break;
|
||||
case UTIME_OMIT: /* do not touch */
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* cases fs_m_in.REQ_ACNSEC < 0 || fs_m_in.REQ_ACNSEC >= 1E9
|
||||
* are caught by VFS to cooperate with old instances of MFS
|
||||
*/
|
||||
rip->i_atime = fs_m_in.REQ_ACTIME;
|
||||
/*
|
||||
* MFS does not support better than second resolution,
|
||||
* so we discard REQ_ACNSEC to round down
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
switch(fs_m_in.REQ_MODNSEC) {
|
||||
case UTIME_NOW:
|
||||
rip->i_update |= MTIME;
|
||||
break;
|
||||
case UTIME_OMIT: /* do not touch */
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* cases fs_m_in.REQ_MODNSEC < 0 || fs_m_in.REQ_MODNSEC >= 1E9
|
||||
* are caught by VFS to cooperate with old instances of MFS
|
||||
*/
|
||||
rip->i_mtime = fs_m_in.REQ_MODTIME;
|
||||
/*
|
||||
* MFS does not support better than second resolution,
|
||||
* so we discard REQ_MODNSEC to round down
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
IN_MARKDIRTY(rip);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
/* Structs used in prototypes must be declared as such first. */
|
||||
struct filp;
|
||||
struct fproc;
|
||||
struct timespec;
|
||||
struct vmnt;
|
||||
struct vnode;
|
||||
struct lookup;
|
||||
|
@ -261,7 +262,8 @@ int req_stat(endpoint_t fs_e, ino_t inode_nr, endpoint_t proc_e, vir_bytes buf);
|
|||
int req_sync(endpoint_t fs_e);
|
||||
int req_unlink(endpoint_t fs_e, ino_t inode_nr, char *lastc);
|
||||
int req_unmount(endpoint_t fs_e);
|
||||
int req_utime(endpoint_t fs_e, ino_t inode_nr, time_t actime, time_t modtime);
|
||||
int req_utime(endpoint_t fs_e, ino_t inode_nr, struct timespec * actv,
|
||||
struct timespec * modtv);
|
||||
int req_newdriver(endpoint_t fs_e, dev_t dev, char *label);
|
||||
|
||||
/* stadir.c */
|
||||
|
@ -291,7 +293,7 @@ int tll_unlock(tll_t *tllp);
|
|||
void tll_upgrade(tll_t *tllp);
|
||||
|
||||
/* utility.c */
|
||||
time_t clock_time(void);
|
||||
struct timespec clock_timespec(void);
|
||||
unsigned conv2(int norm, int w);
|
||||
long conv4(int norm, long x);
|
||||
int copy_name(size_t len, char *dest);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <minix/endpoint.h>
|
||||
#include <minix/u64.h>
|
||||
#include <unistd.h>
|
||||
#include <minix/vfsif.h>
|
||||
#include <time.h>
|
||||
#include "fproc.h"
|
||||
#include "vmnt.h"
|
||||
#include "vnode.h"
|
||||
|
@ -1038,19 +1038,21 @@ endpoint_t fs_e;
|
|||
/*===========================================================================*
|
||||
* req_utime *
|
||||
*===========================================================================*/
|
||||
int req_utime(fs_e, inode_nr, actime, modtime)
|
||||
endpoint_t fs_e;
|
||||
ino_t inode_nr;
|
||||
time_t actime;
|
||||
time_t modtime;
|
||||
int req_utime(endpoint_t fs_e, ino_t inode_nr, struct timespec * actimespec,
|
||||
struct timespec * modtimespec)
|
||||
{
|
||||
message m;
|
||||
|
||||
assert(actimespec != NULL);
|
||||
assert(modtimespec != NULL);
|
||||
|
||||
/* Fill in request message */
|
||||
m.m_type = REQ_UTIME;
|
||||
m.REQ_INODE_NR = inode_nr;
|
||||
m.REQ_ACTIME = actime;
|
||||
m.REQ_MODTIME = modtime;
|
||||
m.REQ_ACTIME = actimespec->tv_sec;
|
||||
m.REQ_MODTIME = modtimespec->tv_sec;
|
||||
m.REQ_ACNSEC = actimespec->tv_nsec;
|
||||
m.REQ_MODNSEC = modtimespec->tv_nsec;
|
||||
|
||||
/* Send/rec request */
|
||||
return fs_sendrec(fs_e, &m);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "fs.h"
|
||||
#include <minix/callnr.h>
|
||||
#include <minix/com.h>
|
||||
#include <time.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "path.h"
|
||||
|
@ -22,7 +23,7 @@ int do_utime()
|
|||
{
|
||||
/* Perform the utime(name, timep) system call. */
|
||||
int r;
|
||||
time_t actime, modtime, newactime, newmodtime;
|
||||
struct timespec actim, modtim, newactim, newmodtim;
|
||||
struct vnode *vp;
|
||||
struct vmnt *vmp;
|
||||
char fullpath[PATH_MAX];
|
||||
|
@ -32,8 +33,9 @@ int do_utime()
|
|||
|
||||
vname = (vir_bytes) job_m_in.utime_file;
|
||||
vname_length = (size_t) job_m_in.utime_length;
|
||||
actime = job_m_in.utime_actime;
|
||||
modtime = job_m_in.utime_modtime;
|
||||
actim.tv_sec = job_m_in.utime_actime;
|
||||
modtim.tv_sec = job_m_in.utime_modtime;
|
||||
actim.tv_nsec = modtim.tv_nsec = 0;
|
||||
|
||||
/* Adjust for case of 'timep' being NULL;
|
||||
* utime_strlen then holds the actual size: strlen(name)+1 */
|
||||
|
@ -48,7 +50,7 @@ int do_utime()
|
|||
if (fetch_name(vname, len, fullpath) != OK) return(err_code);
|
||||
if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code);
|
||||
|
||||
/* Only the owner of a file or the super user can change its name. */
|
||||
/* Only the owner of a file or the super user can change timestamps. */
|
||||
r = OK;
|
||||
if (vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM;
|
||||
if (vname_length == 0 && r != OK) r = forbidden(fp, vp, W_BIT);
|
||||
|
@ -56,12 +58,12 @@ int do_utime()
|
|||
if (r == OK) {
|
||||
/* Issue request */
|
||||
if (vname_length == 0) {
|
||||
newactime = newmodtime = clock_time();
|
||||
newactim = newmodtim = clock_timespec();
|
||||
} else {
|
||||
newactime = actime;
|
||||
newmodtime = modtime;
|
||||
newactim = actim;
|
||||
newmodtim = modtim;
|
||||
}
|
||||
r = req_utime(vp->v_fs_e, vp->v_inode_nr, newactime, newmodtime);
|
||||
r = req_utime(vp->v_fs_e, vp->v_inode_nr, &newactim, &newmodtim);
|
||||
}
|
||||
|
||||
unlock_vnode(vp);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* This file contains a few general purpose utility routines.
|
||||
*
|
||||
* The entry points into this file are
|
||||
* clock_time: ask the clock task for the real time
|
||||
* clock_timespec: ask the clock task for the real time
|
||||
* copy: copy a block of data
|
||||
* fetch_name: go get a path name from user space
|
||||
* no_sys: reject a system call that FS does not handle
|
||||
|
@ -18,6 +18,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "param.h"
|
||||
|
@ -141,9 +142,9 @@ int isokendpt_f(char *file, int line, endpoint_t endpoint, int *proc,
|
|||
|
||||
|
||||
/*===========================================================================*
|
||||
* clock_time *
|
||||
* clock_timespec *
|
||||
*===========================================================================*/
|
||||
time_t clock_time()
|
||||
struct timespec clock_timespec(void)
|
||||
{
|
||||
/* This routine returns the time in seconds since 1.1.1970. MINIX is an
|
||||
* astrophysically naive system that assumes the earth rotates at a constant
|
||||
|
@ -151,15 +152,20 @@ time_t clock_time()
|
|||
*/
|
||||
|
||||
register int r;
|
||||
struct timespec tv;
|
||||
clock_t uptime;
|
||||
clock_t realtime;
|
||||
time_t boottime;
|
||||
|
||||
r = getuptime(&uptime, &realtime, &boottime);
|
||||
if (r != OK)
|
||||
panic("clock_time err: %d", r);
|
||||
panic("clock_timespec err: %d", r);
|
||||
|
||||
return( (time_t) (boottime + (realtime/system_hz)));
|
||||
tv.tv_sec = (time_t) (boottime + (realtime/system_hz));
|
||||
/* We do not want to overflow, and system_hz can be as high as 50kHz */
|
||||
assert(system_hz < LONG_MAX/40000);
|
||||
tv.tv_nsec = (realtime%system_hz) * 40000 / system_hz * 25000;
|
||||
return tv;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
Loading…
Reference in a new issue