aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlberto Bertogli <albertito@gmail.com>2007-05-08 03:23:16 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:14:57 -0400
commit5822b7faca709c03a59c2929005bfe9caffe6592 (patch)
tree4de7b322cfd25794a79cb46b0feab1113785f7a8
parent0e6b9c98be1b517bf99a21d8a7036a8a21e47dd1 (diff)
uml: make hostfs_setattr() support operations on unlinked open files
This patch allows hostfs_setattr() to work on unlinked open files by calling set_attr() (the userspace part) with the inode's fd. Without this, applications that depend on doing attribute changes to unlinked open files will fail. It works by using the fd versions instead of the path ones (for example fchmod() instead of chmod(), fchown() instead of chown()) when an fd is available. Signed-off-by: Alberto Bertogli <albertito@gmail.com> Signed-off-by: Jeff Dike <jdike@linux.intel.com> Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/hostfs/hostfs.h4
-rw-r--r--fs/hostfs/hostfs_kern.c6
-rw-r--r--fs/hostfs/hostfs_user.c108
3 files changed, 74 insertions, 44 deletions
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index 70543b17e4c7..d8850c701564 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -55,7 +55,7 @@ extern int stat_file(const char *path, unsigned long long *inode_out,
55 int *mode_out, int *nlink_out, int *uid_out, int *gid_out, 55 int *mode_out, int *nlink_out, int *uid_out, int *gid_out,
56 unsigned long long *size_out, struct timespec *atime_out, 56 unsigned long long *size_out, struct timespec *atime_out,
57 struct timespec *mtime_out, struct timespec *ctime_out, 57 struct timespec *mtime_out, struct timespec *ctime_out,
58 int *blksize_out, unsigned long long *blocks_out); 58 int *blksize_out, unsigned long long *blocks_out, int fd);
59extern int access_file(char *path, int r, int w, int x); 59extern int access_file(char *path, int r, int w, int x);
60extern int open_file(char *path, int r, int w, int append); 60extern int open_file(char *path, int r, int w, int append);
61extern int file_type(const char *path, int *maj, int *min); 61extern int file_type(const char *path, int *maj, int *min);
@@ -71,7 +71,7 @@ extern int lseek_file(int fd, long long offset, int whence);
71extern int fsync_file(int fd, int datasync); 71extern int fsync_file(int fd, int datasync);
72extern int file_create(char *name, int ur, int uw, int ux, int gr, 72extern int file_create(char *name, int ur, int uw, int ux, int gr,
73 int gw, int gx, int or, int ow, int ox); 73 int gw, int gx, int or, int ow, int ox);
74extern int set_attr(const char *file, struct hostfs_iattr *attrs); 74extern int set_attr(const char *file, struct hostfs_iattr *attrs, int fd);
75extern int make_symlink(const char *from, const char *to); 75extern int make_symlink(const char *from, const char *to);
76extern int unlink_file(const char *file); 76extern int unlink_file(const char *file);
77extern int do_mkdir(const char *file, int mode); 77extern int do_mkdir(const char *file, int mode);
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index fd301a910122..4e8bb2fba048 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -147,7 +147,7 @@ static int read_name(struct inode *ino, char *name)
147 147
148 err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid, 148 err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
149 &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime, 149 &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
150 &ino->i_ctime, &i_blksize, &i_blocks); 150 &ino->i_ctime, &i_blksize, &i_blocks, -1);
151 if(err) 151 if(err)
152 return(err); 152 return(err);
153 153
@@ -820,6 +820,8 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
820 char *name; 820 char *name;
821 int err; 821 int err;
822 822
823 int fd = HOSTFS_I(dentry->d_inode)->fd;
824
823 err = inode_change_ok(dentry->d_inode, attr); 825 err = inode_change_ok(dentry->d_inode, attr);
824 if (err) 826 if (err)
825 return err; 827 return err;
@@ -864,7 +866,7 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
864 } 866 }
865 name = dentry_name(dentry, 0); 867 name = dentry_name(dentry, 0);
866 if(name == NULL) return(-ENOMEM); 868 if(name == NULL) return(-ENOMEM);
867 err = set_attr(name, &attrs); 869 err = set_attr(name, &attrs, fd);
868 kfree(name); 870 kfree(name);
869 if(err) 871 if(err)
870 return(err); 872 return(err);
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index 1ed5ea389f15..0acf562a5f06 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -21,12 +21,16 @@ int stat_file(const char *path, unsigned long long *inode_out, int *mode_out,
21 int *nlink_out, int *uid_out, int *gid_out, 21 int *nlink_out, int *uid_out, int *gid_out,
22 unsigned long long *size_out, struct timespec *atime_out, 22 unsigned long long *size_out, struct timespec *atime_out,
23 struct timespec *mtime_out, struct timespec *ctime_out, 23 struct timespec *mtime_out, struct timespec *ctime_out,
24 int *blksize_out, unsigned long long *blocks_out) 24 int *blksize_out, unsigned long long *blocks_out, int fd)
25{ 25{
26 struct stat64 buf; 26 struct stat64 buf;
27 27
28 if(lstat64(path, &buf) < 0) 28 if(fd >= 0) {
29 if (fstat64(fd, &buf) < 0)
30 return(-errno);
31 } else if(lstat64(path, &buf) < 0) {
29 return(-errno); 32 return(-errno);
33 }
30 34
31 if(inode_out != NULL) *inode_out = buf.st_ino; 35 if(inode_out != NULL) *inode_out = buf.st_ino;
32 if(mode_out != NULL) *mode_out = buf.st_mode; 36 if(mode_out != NULL) *mode_out = buf.st_mode;
@@ -202,58 +206,82 @@ int file_create(char *name, int ur, int uw, int ux, int gr,
202 return(fd); 206 return(fd);
203} 207}
204 208
205int set_attr(const char *file, struct hostfs_iattr *attrs) 209int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
206{ 210{
207 struct utimbuf buf; 211 struct timeval times[2];
212 struct timespec atime_ts, mtime_ts;
208 int err, ma; 213 int err, ma;
209 214
210 if(attrs->ia_valid & HOSTFS_ATTR_MODE){ 215 if (attrs->ia_valid & HOSTFS_ATTR_MODE) {
211 if(chmod(file, attrs->ia_mode) != 0) return(-errno); 216 if (fd >= 0) {
212 } 217 if (fchmod(fd, attrs->ia_mode) != 0)
213 if(attrs->ia_valid & HOSTFS_ATTR_UID){ 218 return (-errno);
214 if(chown(file, attrs->ia_uid, -1)) return(-errno); 219 } else if (chmod(file, attrs->ia_mode) != 0) {
220 return (-errno);
221 }
215 } 222 }
216 if(attrs->ia_valid & HOSTFS_ATTR_GID){ 223 if (attrs->ia_valid & HOSTFS_ATTR_UID) {
217 if(chown(file, -1, attrs->ia_gid)) return(-errno); 224 if (fd >= 0) {
225 if (fchown(fd, attrs->ia_uid, -1))
226 return (-errno);
227 } else if(chown(file, attrs->ia_uid, -1)) {
228 return (-errno);
229 }
218 } 230 }
219 if(attrs->ia_valid & HOSTFS_ATTR_SIZE){ 231 if (attrs->ia_valid & HOSTFS_ATTR_GID) {
220 if(truncate(file, attrs->ia_size)) return(-errno); 232 if (fd >= 0) {
233 if (fchown(fd, -1, attrs->ia_gid))
234 return (-errno);
235 } else if (chown(file, -1, attrs->ia_gid)) {
236 return (-errno);
237 }
221 } 238 }
222 ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET; 239 if (attrs->ia_valid & HOSTFS_ATTR_SIZE) {
223 if((attrs->ia_valid & ma) == ma){ 240 if (fd >= 0) {
224 buf.actime = attrs->ia_atime.tv_sec; 241 if (ftruncate(fd, attrs->ia_size))
225 buf.modtime = attrs->ia_mtime.tv_sec; 242 return (-errno);
226 if(utime(file, &buf) != 0) return(-errno); 243 } else if (truncate(file, attrs->ia_size)) {
244 return (-errno);
245 }
227 } 246 }
228 else { 247
229 struct timespec ts; 248 /* Update accessed and/or modified time, in two parts: first set
230 249 * times according to the changes to perform, and then call futimes()
231 if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){ 250 * or utimes() to apply them. */
232 err = stat_file(file, NULL, NULL, NULL, NULL, NULL, 251 ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET);
233 NULL, NULL, &ts, NULL, NULL, NULL); 252 if (attrs->ia_valid & ma) {
234 if(err != 0) 253 err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
235 return(err); 254 &atime_ts, &mtime_ts, NULL, NULL, NULL, fd);
236 buf.actime = attrs->ia_atime.tv_sec; 255 if (err != 0)
237 buf.modtime = ts.tv_sec; 256 return err;
238 if(utime(file, &buf) != 0) 257
239 return(-errno); 258 times[0].tv_sec = atime_ts.tv_sec;
259 times[0].tv_usec = atime_ts.tv_nsec * 1000;
260 times[1].tv_sec = mtime_ts.tv_sec;
261 times[1].tv_usec = mtime_ts.tv_nsec * 1000;
262
263 if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) {
264 times[0].tv_sec = attrs->ia_atime.tv_sec;
265 times[0].tv_usec = attrs->ia_atime.tv_nsec * 1000;
240 } 266 }
241 if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){ 267 if (attrs->ia_valid & HOSTFS_ATTR_MTIME_SET) {
242 err = stat_file(file, NULL, NULL, NULL, NULL, NULL, 268 times[1].tv_sec = attrs->ia_mtime.tv_sec;
243 NULL, &ts, NULL, NULL, NULL, NULL); 269 times[1].tv_usec = attrs->ia_mtime.tv_nsec * 1000;
244 if(err != 0) 270 }
245 return(err); 271
246 buf.actime = ts.tv_sec; 272 if (fd >= 0) {
247 buf.modtime = attrs->ia_mtime.tv_sec; 273 if (futimes(fd, times) != 0)
248 if(utime(file, &buf) != 0) 274 return (-errno);
249 return(-errno); 275 } else if (utimes(file, times) != 0) {
276 return (-errno);
250 } 277 }
251 } 278 }
279
252 if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ; 280 if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ;
253 if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){ 281 if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){
254 err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL, 282 err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
255 &attrs->ia_atime, &attrs->ia_mtime, NULL, 283 &attrs->ia_atime, &attrs->ia_mtime, NULL,
256 NULL, NULL); 284 NULL, NULL, fd);
257 if(err != 0) return(err); 285 if(err != 0) return(err);
258 } 286 }
259 return(0); 287 return(0);