diff options
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 213 |
1 files changed, 50 insertions, 163 deletions
@@ -6,7 +6,6 @@ #include <linux/string.h> #include <linux/mm.h> -#include <linux/utime.h> #include <linux/file.h> #include <linux/smp_lock.h> #include <linux/quotaops.h> @@ -29,8 +28,6 @@ #include <linux/rcupdate.h> #include <linux/audit.h> -#include <asm/unistd.h> - int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) { int retval = -ENODEV; @@ -353,137 +350,6 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length) } #endif -#ifdef __ARCH_WANT_SYS_UTIME - -/* - * sys_utime() can be implemented in user-level using sys_utimes(). - * Is this for backwards compatibility? If so, why not move it - * into the appropriate arch directory (for those architectures that - * need it). - */ - -/* If times==NULL, set access and modification to current time, - * must be owner or have write permission. - * Else, update from *times, must be owner or super user. - */ -asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times) -{ - int error; - struct nameidata nd; - struct inode * inode; - struct iattr newattrs; - - error = user_path_walk(filename, &nd); - if (error) - goto out; - inode = nd.dentry->d_inode; - - error = -EROFS; - if (IS_RDONLY(inode)) - goto dput_and_out; - - /* Don't worry, the checks are done in inode_change_ok() */ - newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; - if (times) { - error = -EPERM; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - goto dput_and_out; - - error = get_user(newattrs.ia_atime.tv_sec, ×->actime); - newattrs.ia_atime.tv_nsec = 0; - if (!error) - error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime); - newattrs.ia_mtime.tv_nsec = 0; - if (error) - goto dput_and_out; - - newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; - } else { - error = -EACCES; - if (IS_IMMUTABLE(inode)) - goto dput_and_out; - - if (current->fsuid != inode->i_uid && - (error = vfs_permission(&nd, MAY_WRITE)) != 0) - goto dput_and_out; - } - mutex_lock(&inode->i_mutex); - error = notify_change(nd.dentry, &newattrs); - mutex_unlock(&inode->i_mutex); -dput_and_out: - path_release(&nd); -out: - return error; -} - -#endif - -/* If times==NULL, set access and modification to current time, - * must be owner or have write permission. - * Else, update from *times, must be owner or super user. - */ -long do_utimes(int dfd, char __user *filename, struct timeval *times) -{ - int error; - struct nameidata nd; - struct inode * inode; - struct iattr newattrs; - - error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); - - if (error) - goto out; - inode = nd.dentry->d_inode; - - error = -EROFS; - if (IS_RDONLY(inode)) - goto dput_and_out; - - /* Don't worry, the checks are done in inode_change_ok() */ - newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; - if (times) { - error = -EPERM; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - goto dput_and_out; - - newattrs.ia_atime.tv_sec = times[0].tv_sec; - newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000; - newattrs.ia_mtime.tv_sec = times[1].tv_sec; - newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000; - newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; - } else { - error = -EACCES; - if (IS_IMMUTABLE(inode)) - goto dput_and_out; - - if (current->fsuid != inode->i_uid && - (error = vfs_permission(&nd, MAY_WRITE)) != 0) - goto dput_and_out; - } - mutex_lock(&inode->i_mutex); - error = notify_change(nd.dentry, &newattrs); - mutex_unlock(&inode->i_mutex); -dput_and_out: - path_release(&nd); -out: - return error; -} - -asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes) -{ - struct timeval times[2]; - - if (utimes && copy_from_user(×, utimes, sizeof(times))) - return -EFAULT; - return do_utimes(dfd, filename, utimes ? times : NULL); -} - -asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes) -{ - return sys_futimesat(AT_FDCWD, filename, utimes); -} - - /* * access() needs to use the real uid/gid, not the effective uid/gid. * We do this by temporarily clearing all FS-related capabilities and @@ -520,15 +386,21 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) current->cap_effective = current->cap_permitted; res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); - if (!res) { - res = vfs_permission(&nd, mode); - /* SuS v2 requires we report a read only fs too */ - if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode) - && !special_file(nd.dentry->d_inode->i_mode)) - res = -EROFS; - path_release(&nd); - } + if (res) + goto out; + + res = vfs_permission(&nd, mode); + /* SuS v2 requires we report a read only fs too */ + if(res || !(mode & S_IWOTH) || + special_file(nd.dentry->d_inode->i_mode)) + goto out_path_release; + + if(IS_RDONLY(nd.dentry->d_inode)) + res = -EROFS; +out_path_release: + path_release(&nd); +out: current->fsuid = old_fsuid; current->fsgid = old_fsgid; current->cap_effective = old_cap; @@ -546,7 +418,8 @@ asmlinkage long sys_chdir(const char __user * filename) struct nameidata nd; int error; - error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd); + error = __user_walk(filename, + LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd); if (error) goto out; @@ -736,10 +609,11 @@ asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group) int error; error = user_path_walk(filename, &nd); - if (!error) { - error = chown_common(nd.dentry, user, group); - path_release(&nd); - } + if (error) + goto out; + error = chown_common(nd.dentry, user, group); + path_release(&nd); +out: return error; } @@ -755,10 +629,10 @@ asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; error = __user_walk_fd(dfd, filename, follow, &nd); - if (!error) { - error = chown_common(nd.dentry, user, group); - path_release(&nd); - } + if (error) + goto out; + error = chown_common(nd.dentry, user, group); + path_release(&nd); out: return error; } @@ -769,10 +643,11 @@ asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group int error; error = user_path_walk_link(filename, &nd); - if (!error) { - error = chown_common(nd.dentry, user, group); - path_release(&nd); - } + if (error) + goto out; + error = chown_common(nd.dentry, user, group); + path_release(&nd); +out: return error; } @@ -781,15 +656,17 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) { struct file * file; int error = -EBADF; + struct dentry * dentry; file = fget(fd); - if (file) { - struct dentry * dentry; - dentry = file->f_dentry; - audit_inode(NULL, dentry->d_inode); - error = chown_common(dentry, user, group); - fput(file); - } + if (!file) + goto out; + + dentry = file->f_dentry; + audit_inode(NULL, dentry->d_inode); + error = chown_common(dentry, user, group); + fput(file); +out: return error; } @@ -1172,6 +1049,7 @@ asmlinkage long sys_close(unsigned int fd) struct file * filp; struct files_struct *files = current->files; struct fdtable *fdt; + int retval; spin_lock(&files->file_lock); fdt = files_fdtable(files); @@ -1184,7 +1062,16 @@ asmlinkage long sys_close(unsigned int fd) FD_CLR(fd, fdt->close_on_exec); __put_unused_fd(files, fd); spin_unlock(&files->file_lock); - return filp_close(filp, files); + retval = filp_close(filp, files); + + /* can't restart close syscall because file table entry was cleared */ + if (unlikely(retval == -ERESTARTSYS || + retval == -ERESTARTNOINTR || + retval == -ERESTARTNOHAND || + retval == -ERESTART_RESTARTBLOCK)) + retval = -EINTR; + + return retval; out_unlock: spin_unlock(&files->file_lock); |