X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=fs%2Fopen.c;h=1d9e5e98bf4e725615cc3cfcd269dc2cab5101e4;hb=85923b124624eb49ebef4731bb6b5670e792ff57;hp=ca9981c4a658247bb6e29aaaaad8fa88f4d99dd8;hpb=5335a40be6867eff986a31bcd8fc82a5cb1e16bb;p=powerpc.git diff --git a/fs/open.c b/fs/open.c index ca9981c4a6..1d9e5e98bf 100644 --- a/fs/open.c +++ b/fs/open.c @@ -26,6 +26,7 @@ #include #include #include +#include int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) { @@ -210,6 +211,9 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, newattrs.ia_valid |= ATTR_FILE; } + /* Remove suid/sgid on truncate too */ + newattrs.ia_valid |= should_remove_suid(dentry); + mutex_lock(&dentry->d_inode->i_mutex); err = notify_change(dentry, &newattrs); mutex_unlock(&dentry->d_inode->i_mutex); @@ -252,24 +256,26 @@ static long do_sys_truncate(const char __user * path, loff_t length) if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto dput_and_out; - /* - * Make sure that there are no leases. - */ - error = break_lease(inode, FMODE_WRITE); + error = get_write_access(inode); if (error) goto dput_and_out; - error = get_write_access(inode); + /* + * Make sure that there are no leases. get_write_access() protects + * against the truncate racing with a lease-granting setlease(). + */ + error = break_lease(inode, FMODE_WRITE); if (error) - goto dput_and_out; + goto put_write_and_out; error = locks_verify_truncate(inode, NULL, length); if (!error) { DQUOT_INIT(inode); error = do_truncate(nd.dentry, length, 0, NULL); } - put_write_access(inode); +put_write_and_out: + put_write_access(inode); dput_and_out: path_release(&nd); out: @@ -349,6 +355,64 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length) } #endif +asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len) +{ + struct file *file; + struct inode *inode; + long ret = -EINVAL; + + if (offset < 0 || len <= 0) + goto out; + + /* Return error if mode is not supported */ + ret = -EOPNOTSUPP; + if (mode && !(mode & FALLOC_FL_KEEP_SIZE)) + goto out; + + ret = -EBADF; + file = fget(fd); + if (!file) + goto out; + if (!(file->f_mode & FMODE_WRITE)) + goto out_fput; + /* + * Revalidate the write permissions, in case security policy has + * changed since the files were opened. + */ + ret = security_file_permission(file, MAY_WRITE); + if (ret) + goto out_fput; + + inode = file->f_path.dentry->d_inode; + + ret = -ESPIPE; + if (S_ISFIFO(inode->i_mode)) + goto out_fput; + + ret = -ENODEV; + /* + * Let individual file system decide if it supports preallocation + * for directories or not. + */ + if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) + goto out_fput; + + ret = -EFBIG; + /* Check for wrap through zero too */ + if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) + goto out_fput; + + if (inode->i_op && inode->i_op->fallocate) + ret = inode->i_op->fallocate(inode, mode, offset, len); + else + ret = -EOPNOTSUPP; + +out_fput: + fput(file); +out: + return ret; +} + /* * access() needs to use the real uid/gid, not the effective uid/gid. * We do this by temporarily clearing all FS-related capabilities and @@ -852,7 +916,7 @@ EXPORT_SYMBOL(dentry_open); /* * Find an empty file descriptor entry, and mark it busy. */ -int get_unused_fd(void) +int get_unused_fd_flags(int flags) { struct files_struct * files = current->files; int fd, error; @@ -888,7 +952,10 @@ repeat: } FD_SET(fd, fdt->open_fds); - FD_CLR(fd, fdt->close_on_exec); + if (flags & O_CLOEXEC) + FD_SET(fd, fdt->close_on_exec); + else + FD_CLR(fd, fdt->close_on_exec); files->next_fd = fd + 1; #if 1 /* Sanity check */ @@ -904,6 +971,11 @@ out: return error; } +int get_unused_fd(void) +{ + return get_unused_fd_flags(0); +} + EXPORT_SYMBOL(get_unused_fd); static void __put_unused_fd(struct files_struct *files, unsigned int fd) @@ -956,7 +1028,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, int mode) int fd = PTR_ERR(tmp); if (!IS_ERR(tmp)) { - fd = get_unused_fd(); + fd = get_unused_fd_flags(flags); if (fd >= 0) { struct file *f = do_filp_open(dfd, tmp, flags, mode); if (IS_ERR(f)) {