tools/llvm: Do not build with symbols
[minix3.git] / minix / servers / vfs / time.c
blob1f890d2135a616987f674393f941555f102418eb
1 /* This file takes care of those system calls that deal with time.
3 * The entry points into this file are
4 * do_utimens: perform the UTIMENS system call
5 */
7 #include "fs.h"
8 #include <minix/callnr.h>
9 #include <minix/com.h>
10 #include <time.h>
11 #include <string.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include "file.h"
15 #include "path.h"
16 #include "vnode.h"
17 #include <minix/vfsif.h>
18 #include "vmnt.h"
20 #define UTIMENS_STYLE 0 /* utimes(2)/utimensat(2) style, named file */
21 #define FUTIMENS_STYLE 1 /* futimens(2)/futimes(2) style, file desc. */
23 /*===========================================================================*
24 * do_utimens *
25 *===========================================================================*/
26 int do_utimens(void)
28 /* Perform the utimens(name, times, flag) system call, and its friends.
29 * Implement a very large but not complete subset of the utimensat()
30 * Posix:2008/XOpen-7 function.
31 * Are handled all the following cases:
32 * . utimensat(AT_FDCWD, "/some/absolute/path", , )
33 * . utimensat(AT_FDCWD, "some/path", , )
34 * . utimens("anything", ) really special case of the above two
35 * . lutimens("anything", ) also really special case of the above
36 * . utimensat(fd, "/some/absolute/path", , ) although fd is useless here
37 * . futimens(fd, )
38 * Are not handled the following cases:
39 * . utimensat(fd, "some/path", , ) path to a file relative to some open fd
41 int r, kind, lookup_flags;
42 struct vnode *vp;
43 struct filp *filp = NULL; /* initialization required by clueless GCC */
44 struct vmnt *vmp;
45 struct timespec actim, modtim, now, newactim, newmodtim;
46 char fullpath[PATH_MAX];
47 struct lookup resolve;
48 vir_bytes vname;
49 size_t vname_length;
51 memset(&now, 0, sizeof(now));
53 /* The case times==NULL is handled by the caller, replaced with UTIME_NOW */
54 actim.tv_sec = job_m_in.m_vfs_utimens.atime;
55 actim.tv_nsec = job_m_in.m_vfs_utimens.ansec;
56 modtim.tv_sec = job_m_in.m_vfs_utimens.mtime;
57 modtim.tv_nsec = job_m_in.m_vfs_utimens.mnsec;
59 if (job_m_in.m_vfs_utimens.name != NULL) {
60 kind = UTIMENS_STYLE;
61 if (job_m_in.m_vfs_utimens.flags & ~AT_SYMLINK_NOFOLLOW)
62 return EINVAL; /* unknown flag */
63 /* Temporarily open the file */
64 vname = (vir_bytes) job_m_in.m_vfs_utimens.name;
65 vname_length = (size_t) job_m_in.m_vfs_utimens.len;
66 if (job_m_in.m_vfs_utimens.flags & AT_SYMLINK_NOFOLLOW)
67 lookup_flags = PATH_RET_SYMLINK;
68 else
69 lookup_flags = PATH_NOFLAGS;
70 lookup_init(&resolve, fullpath, lookup_flags, &vmp, &vp);
71 resolve.l_vmnt_lock = VMNT_READ;
72 resolve.l_vnode_lock = VNODE_READ;
73 /* Temporarily open the file */
74 if (fetch_name(vname, vname_length, fullpath) != OK) return(err_code);
75 if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code);
77 else {
78 kind = FUTIMENS_STYLE;
79 /* Change timestamps on already-opened fd. Is it valid? */
80 if (job_m_in.m_vfs_utimens.flags != 0)
81 return EINVAL; /* unknown flag */
82 if ((filp = get_filp(job_m_in.m_vfs_utimens.fd, VNODE_READ)) == NULL)
83 return err_code;
84 vp = filp->filp_vno;
87 r = OK;
88 /* Only the owner of a file or the super user can change timestamps. */
89 if (vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM;
90 /* Need write permission (or super user) to 'touch' the file */
91 if (r != OK && actim.tv_nsec == UTIME_NOW
92 && modtim.tv_nsec == UTIME_NOW) r = forbidden(fp, vp, W_BIT);
93 if (read_only(vp) != OK) r = EROFS; /* Not even su can touch if R/O */
95 if (r == OK) {
96 /* Do we need to ask for current time? */
97 if (actim.tv_nsec == UTIME_NOW
98 || actim.tv_nsec == UTIME_OMIT
99 || modtim.tv_nsec == UTIME_NOW
100 || modtim.tv_nsec == UTIME_OMIT) {
101 now = clock_timespec();
104 /* Build the request */
105 switch (actim.tv_nsec) {
106 case UTIME_NOW:
107 newactim = now;
108 break;
109 case UTIME_OMIT:
110 newactim.tv_nsec = UTIME_OMIT;
111 /* Be nice with old FS, put a sensible value in
112 * otherwise not used field for seconds
114 newactim.tv_sec = now.tv_sec;
115 break;
116 default:
117 if ( (unsigned)actim.tv_nsec >= 1000000000)
118 r = EINVAL;
119 else
120 newactim = actim;
121 break;
123 switch (modtim.tv_nsec) {
124 case UTIME_NOW:
125 newmodtim = now;
126 break;
127 case UTIME_OMIT:
128 newmodtim.tv_nsec = UTIME_OMIT;
129 /* Be nice with old FS, put a sensible value */
130 newmodtim.tv_sec = now.tv_sec;
131 break;
132 default:
133 if ( (unsigned)modtim.tv_nsec >= 1000000000)
134 r = EINVAL;
135 else
136 newmodtim = modtim;
137 break;
141 if (r == OK)
142 /* Issue request */
143 r = req_utime(vp->v_fs_e, vp->v_inode_nr, &newactim, &newmodtim);
145 if (kind == UTIMENS_STYLE) {
146 /* Close the temporary */
147 unlock_vnode(vp);
148 unlock_vmnt(vmp);
149 put_vnode(vp);
151 else { /* Change timestamps on opened fd. */
152 unlock_filp(filp);
154 return r;