diff options
author | Tony Solomonik <tony.solomonik@gmail.com> | 2024-02-02 14:17:23 +0200 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2024-02-09 08:57:56 -0700 |
commit | 5f0d594c602f870e3a3872f7ea42bf846a1d26cf (patch) | |
tree | 5efd86c12d353c1d26b30944ce7fbc2768ecf169 /fs/open.c | |
parent | a6e959bd3d6bfe8a3daeeacb714a299b9094a6cb (diff) |
Add do_ftruncate that truncates a struct file
do_sys_ftruncate receives a file descriptor, fgets the struct file, and
finally actually truncates the file.
do_ftruncate allows for passing in a file directly, with the caller
already holding a reference to it.
Signed-off-by: Tony Solomonik <tony.solomonik@gmail.com>
Reviewed-by: Christian Brauner <brauner@kernel.org>
Link: https://lore.kernel.org/r/20240202121724.17461-2-tony.solomonik@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 53 |
1 files changed, 28 insertions, 25 deletions
diff --git a/fs/open.c b/fs/open.c index a84d21e55c39..0410cb52bb4b 100644 --- a/fs/open.c +++ b/fs/open.c @@ -154,49 +154,52 @@ COMPAT_SYSCALL_DEFINE2(truncate, const char __user *, path, compat_off_t, length } #endif -long do_sys_ftruncate(unsigned int fd, loff_t length, int small) +long do_ftruncate(struct file *file, loff_t length, int small) { struct inode *inode; struct dentry *dentry; - struct fd f; int error; - error = -EINVAL; - if (length < 0) - goto out; - error = -EBADF; - f = fdget(fd); - if (!f.file) - goto out; - /* explicitly opened as large or we are on 64-bit box */ - if (f.file->f_flags & O_LARGEFILE) + if (file->f_flags & O_LARGEFILE) small = 0; - dentry = f.file->f_path.dentry; + dentry = file->f_path.dentry; inode = dentry->d_inode; - error = -EINVAL; - if (!S_ISREG(inode->i_mode) || !(f.file->f_mode & FMODE_WRITE)) - goto out_putf; + if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) + return -EINVAL; - error = -EINVAL; /* Cannot ftruncate over 2^31 bytes without large file support */ if (small && length > MAX_NON_LFS) - goto out_putf; + return -EINVAL; - error = -EPERM; /* Check IS_APPEND on real upper inode */ - if (IS_APPEND(file_inode(f.file))) - goto out_putf; + if (IS_APPEND(file_inode(file))) + return -EPERM; sb_start_write(inode->i_sb); - error = security_file_truncate(f.file); + error = security_file_truncate(file); if (!error) - error = do_truncate(file_mnt_idmap(f.file), dentry, length, - ATTR_MTIME | ATTR_CTIME, f.file); + error = do_truncate(file_mnt_idmap(file), dentry, length, + ATTR_MTIME | ATTR_CTIME, file); sb_end_write(inode->i_sb); -out_putf: + + return error; +} + +long do_sys_ftruncate(unsigned int fd, loff_t length, int small) +{ + struct fd f; + int error; + + if (length < 0) + return -EINVAL; + f = fdget(fd); + if (!f.file) + return -EBADF; + + error = do_ftruncate(f.file, length, small); + fdput(f); -out: return error; } |