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
8 #include <minix/callnr.h>
17 #include <minix/vfsif.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 /*===========================================================================*
25 *===========================================================================*/
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
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
;
43 struct filp
*filp
= NULL
; /* initialization required by clueless GCC */
45 struct timespec actim
, modtim
, now
, newactim
, newmodtim
;
46 char fullpath
[PATH_MAX
];
47 struct lookup resolve
;
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
) {
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
;
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
);
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
)
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 */
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 (void)clock_time(&now
);
104 /* Build the request */
105 switch (actim
.tv_nsec
) {
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
;
117 if ( (unsigned)actim
.tv_nsec
>= 1000000000)
123 switch (modtim
.tv_nsec
) {
128 newmodtim
.tv_nsec
= UTIME_OMIT
;
129 /* Be nice with old FS, put a sensible value */
130 newmodtim
.tv_sec
= now
.tv_sec
;
133 if ( (unsigned)modtim
.tv_nsec
>= 1000000000)
143 r
= req_utime(vp
->v_fs_e
, vp
->v_inode_nr
, &newactim
, &newmodtim
);
145 if (kind
== UTIMENS_STYLE
) {
146 /* Close the temporary */
151 else { /* Change timestamps on opened fd. */