fs/open.c

Source file repositories/reference/linux-study-clean/fs/open.c

File Facts

System
Linux kernel
Corpus path
fs/open.c
Extension
.c
Size
40991 bytes
Lines
1613
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: syscall or user/kernel boundary
Status
core implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

SYSCALL_DEFINE2(truncate, const char __user *, path, long, length)
{
	return ksys_truncate(path, length);
}

#ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE2(truncate, const char __user *, path, compat_off_t, length)
{
	return ksys_truncate(path, length);
}
#endif

int do_ftruncate(struct file *file, loff_t length, unsigned int flags)
{
	struct dentry *dentry = file->f_path.dentry;
	struct inode *inode = dentry->d_inode;
	int error;

	if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
		return -EINVAL;

	/*
	 * Cannot ftruncate over 2^31 bytes without large file support, either
	 * through opening with O_LARGEFILE or by using ftruncate64().
	 */
	if (length > MAX_NON_LFS &&
	    !(file->f_flags & O_LARGEFILE) && !(flags & FTRUNCATE_LFS))
		return -EINVAL;

	/* Check IS_APPEND on real upper inode */
	if (IS_APPEND(file_inode(file)))
		return -EPERM;

	error = security_file_truncate(file);
	if (error)
		return error;

	error = fsnotify_truncate_perm(&file->f_path, length);
	if (error)
		return error;

	scoped_guard(super_write, inode->i_sb)
		return do_truncate(file_mnt_idmap(file), dentry, length,
				   ATTR_MTIME | ATTR_CTIME, file);
}

int ksys_ftruncate(unsigned int fd, loff_t length, unsigned int flags)
{
	if (length < 0)
		return -EINVAL;
	CLASS(fd, f)(fd);
	if (fd_empty(f))
		return -EBADF;

	return do_ftruncate(fd_file(f), length, flags);
}

SYSCALL_DEFINE2(ftruncate, unsigned int, fd, off_t, length)
{
	return ksys_ftruncate(fd, length, 0);
}

#ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE2(ftruncate, unsigned int, fd, compat_off_t, length)
{
	return ksys_ftruncate(fd, length, 0);
}
#endif

/* LFS versions of truncate are only needed on 32 bit machines */
#if BITS_PER_LONG == 32
SYSCALL_DEFINE2(truncate64, const char __user *, path, loff_t, length)
{
	return ksys_truncate(path, length);
}

SYSCALL_DEFINE2(ftruncate64, unsigned int, fd, loff_t, length)
{
	return ksys_ftruncate(fd, length, FTRUNCATE_LFS);
}
#endif /* BITS_PER_LONG == 32 */

#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_TRUNCATE64)
COMPAT_SYSCALL_DEFINE3(truncate64, const char __user *, pathname,
		       compat_arg_u64_dual(length))
{
	return ksys_truncate(pathname, compat_arg_u64_glue(length));
}
#endif

Annotation

Implementation Notes