This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / fs / utimes.c
1 #include <linux/compiler.h>
2 #include <linux/fs.h>
3 #include <linux/linkage.h>
4 #include <linux/namei.h>
5 #include <linux/sched.h>
6 #include <linux/utime.h>
7 #include <linux/mount.h>
8 #include <linux/vs_cowbl.h>
9 #include <asm/uaccess.h>
10 #include <asm/unistd.h>
11
12 #ifdef __ARCH_WANT_SYS_UTIME
13
14 /*
15  * sys_utime() can be implemented in user-level using sys_utimes().
16  * Is this for backwards compatibility?  If so, why not move it
17  * into the appropriate arch directory (for those architectures that
18  * need it).
19  */
20
21 /* If times==NULL, set access and modification to current time,
22  * must be owner or have write permission.
23  * Else, update from *times, must be owner or super user.
24  */
25 asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
26 {
27         int error;
28         struct nameidata nd;
29         struct inode * inode;
30         struct iattr newattrs;
31
32         error = user_path_walk(filename, &nd);
33         if (error)
34                 goto out;
35
36         error = cow_check_and_break(&nd);
37         if (error)
38                 goto dput_and_out;
39         inode = nd.dentry->d_inode;
40
41         /* Don't worry, the checks are done in inode_change_ok() */
42         newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
43         if (times) {
44                 error = -EPERM;
45                 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
46                         goto dput_and_out;
47
48                 error = get_user(newattrs.ia_atime.tv_sec, &times->actime);
49                 newattrs.ia_atime.tv_nsec = 0;
50                 if (!error)
51                         error = get_user(newattrs.ia_mtime.tv_sec, &times->modtime);
52                 newattrs.ia_mtime.tv_nsec = 0;
53                 if (error)
54                         goto dput_and_out;
55
56                 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
57         } else {
58                 error = -EACCES;
59                 if (IS_IMMUTABLE(inode))
60                         goto dput_and_out;
61
62                 if (current->fsuid != inode->i_uid &&
63                     (error = vfs_permission(&nd, MAY_WRITE)) != 0)
64                         goto dput_and_out;
65         }
66         mutex_lock(&inode->i_mutex);
67         error = notify_change(nd.dentry, &newattrs);
68         mutex_unlock(&inode->i_mutex);
69 dput_and_out:
70         path_release(&nd);
71 out:
72         return error;
73 }
74
75 #endif
76
77 /* If times==NULL, set access and modification to current time,
78  * must be owner or have write permission.
79  * Else, update from *times, must be owner or super user.
80  */
81 long do_utimes(int dfd, char __user *filename, struct timeval *times)
82 {
83         int error;
84         struct nameidata nd;
85         struct inode * inode;
86         struct iattr newattrs;
87
88         error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
89         if (error)
90                 goto out;
91
92         error = cow_check_and_break(&nd);
93         if (error)
94                 goto dput_and_out;
95         inode = nd.dentry->d_inode;
96
97         /* Don't worry, the checks are done in inode_change_ok() */
98         newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
99         if (times) {
100                 error = -EPERM;
101                 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
102                         goto dput_and_out;
103
104                 newattrs.ia_atime.tv_sec = times[0].tv_sec;
105                 newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000;
106                 newattrs.ia_mtime.tv_sec = times[1].tv_sec;
107                 newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000;
108                 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
109         } else {
110                 error = -EACCES;
111                 if (IS_IMMUTABLE(inode))
112                         goto dput_and_out;
113
114                 if (current->fsuid != inode->i_uid &&
115                     (error = vfs_permission(&nd, MAY_WRITE)) != 0)
116                         goto dput_and_out;
117         }
118         mutex_lock(&inode->i_mutex);
119         error = notify_change(nd.dentry, &newattrs);
120         mutex_unlock(&inode->i_mutex);
121 dput_and_out:
122         path_release(&nd);
123 out:
124         return error;
125 }
126
127 asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
128 {
129         struct timeval times[2];
130
131         if (utimes && copy_from_user(&times, utimes, sizeof(times)))
132                 return -EFAULT;
133         return do_utimes(dfd, filename, utimes ? times : NULL);
134 }
135
136 asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
137 {
138         return sys_futimesat(AT_FDCWD, filename, utimes);
139 }