/* 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
#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
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);
}
#include <minix/callnr.h>
#include <minix/com.h>
#include "inode.h"
+#include <sys/stat.h>
#include <minix/vfsif.h>
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 */
- rip->i_dirt = IN_DIRTY;
+ 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;
}
put_inode(rip);
#include "fs.h"
#include "inode.h"
+#include <sys/stat.h>
#include <minix/vfsif.h>
{
register struct inode *rip;
register int r;
-
+
/* Temporarily open the file. */
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 */
- IN_MARKDIRTY(rip);
+ 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);
}
put_inode(rip);
/* Structs used in prototypes must be declared as such first. */
struct filp;
struct fproc;
+struct timespec;
struct vmnt;
struct vnode;
struct lookup;
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 */
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);
#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"
/*===========================================================================*
* 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);
#include "fs.h"
#include <minix/callnr.h>
#include <minix/com.h>
+#include <time.h>
#include "file.h"
#include "fproc.h"
#include "path.h"
{
/* 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];
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 */
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);
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);
/* 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
#include <stdlib.h>
#include <string.h>
#include <assert.h>
+#include <time.h>
#include "file.h"
#include "fproc.h"
#include "param.h"
/*===========================================================================*
- * 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
*/
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;
}
/*===========================================================================*