/* * linux/fs/open.c * * Copyright (C) 1991, 1992 Linus Torvalds */ #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>#include <linux/fsnotify.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/tty.h>#include <linux/namei.h>#include <linux/backing-dev.h>#include <linux/capability.h>#include <linux/security.h>#include <linux/mount.h>#include <linux/vfs.h>#include <linux/fcntl.h>#include <asm/uaccess.h>#include <linux/fs.h>#include <linux/personality.h>#include <linux/pagemap.h>#include <linux/syscalls.h>#include <linux/rcupdate.h>#include <linux/audit.h> #include <asm/unistd.h> int vfs_statfs(struct super_block *sb, struct kstatfs *buf){ int retval = -ENODEV; if (sb) { retval = -ENOSYS; if (sb->s_op->statfs) { memset(buf, 0, sizeof(*buf)); retval = security_sb_statfs(sb); if (retval) return retval; retval = sb->s_op->statfs(sb, buf); if (retval == 0 && buf->f_frsize == 0) buf->f_frsize = buf->f_bsize; } } return retval;} EXPORT_SYMBOL(vfs_statfs); static int vfs_statfs_native(struct super_block *sb, struct statfs *buf){ struct kstatfs st; int retval; retval = vfs_statfs(sb, &st); if (retval) return retval; if (sizeof(*buf) == sizeof(st)) memcpy(buf, &st, sizeof(st)); else { if (sizeof buf->f_blocks == 4) { if ((st.f_blocks | st.f_bfree | st.f_bavail) & 0xffffffff00000000ULL) return -EOVERFLOW; /* * f_files and f_ffree may be -1; it's okay to stuff * that into 32 bits */ if (st.f_files != -1 && (st.f_files & 0xffffffff00000000ULL)) return -EOVERFLOW; if (st.f_ffree != -1 && (st.f_ffree & 0xffffffff00000000ULL)) return -EOVERFLOW; } buf->f_type = st.f_type; buf->f_bsize = st.f_bsize; buf->f_blocks = st.f_blocks; buf->f_bfree = st.f_bfree; buf->f_bavail = st.f_bavail; buf->f_files = st.f_files; buf->f_ffree = st.f_ffree; buf->f_fsid = st.f_fsid; buf->f_namelen = st.f_namelen; buf->f_frsize = st.f_frsize; memset(buf->f_spare, 0, sizeof(buf->f_spare)); } return 0;} static int vfs_statfs64(struct super_block *sb, struct statfs64 *buf){ struct kstatfs st; int retval; retval = vfs_statfs(sb, &st); if (retval) return retval; if (sizeof(*buf) == sizeof(st)) memcpy(buf, &st, sizeof(st)); else { buf->f_type = st.f_type; buf->f_bsize = st.f_bsize; buf->f_blocks = st.f_blocks; buf->f_bfree = st.f_bfree; buf->f_bavail = st.f_bavail; buf->f_files = st.f_files; buf->f_ffree = st.f_ffree; buf->f_fsid = st.f_fsid; buf->f_namelen = st.f_namelen; buf->f_frsize = st.f_frsize; memset(buf->f_spare, 0, sizeof(buf->f_spare)); } return 0;} asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf){ struct nameidata nd; int error; error = user_path_walk(path, &nd); if (!error) { struct statfs tmp; error = vfs_statfs_native(nd.dentry->d_inode->i_sb, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; path_release(&nd); } return error;} asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64 __user *buf){ struct nameidata nd; long error; if (sz != sizeof(*buf)) return -EINVAL; error = user_path_walk(path, &nd); if (!error) { struct statfs64 tmp; error = vfs_statfs64(nd.dentry->d_inode->i_sb, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; path_release(&nd); } return error;} asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf){ struct file * file; struct statfs tmp; int error; error = -EBADF; file = fget(fd); if (!file) goto out; error = vfs_statfs_native(file->f_dentry->d_inode->i_sb, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file);out: return error;} asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user *buf){ struct file * file; struct statfs64 tmp; int error; if (sz != sizeof(*buf)) return -EINVAL; error = -EBADF; file = fget(fd); if (!file) goto out; error = vfs_statfs64(file->f_dentry->d_inode->i_sb, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file);out: return error;} int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, struct file *filp){ int err; struct iattr newattrs; /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ if (length < 0) return -EINVAL; newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | time_attrs; if (filp) { newattrs.ia_file = filp; newattrs.ia_valid |= ATTR_FILE; } mutex_lock(&dentry->d_inode->i_mutex); err = notify_change(dentry, &newattrs); mutex_unlock(&dentry->d_inode->i_mutex); return err;} static long do_sys_truncate(const char __user * path, loff_t length){ struct nameidata nd; struct inode * inode; int error; error = -EINVAL; if (length < 0) /* sorry, but loff_t says... */ goto out; error = user_path_walk(path, &nd); if (error) goto out; inode = nd.dentry->d_inode; /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ error = -EISDIR; if (S_ISDIR(inode->i_mode)) goto dput_and_out; error = -EINVAL; if (!S_ISREG(inode->i_mode)) goto dput_and_out; error = vfs_permission(&nd, MAY_WRITE); if (error) goto dput_and_out; error = -EROFS; if (IS_RDONLY(inode)) goto dput_and_out; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto dput_and_out; /* * Make sure that there are no leases. */ error = break_lease(inode, FMODE_WRITE); if (error) goto dput_and_out; error = get_write_access(inode); if (error) goto dput_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); dput_and_out: path_release(&nd);out: return error;} asmlinkage long sys_truncate(const char __user * path, unsigned long length){ /* on 32-bit boxen it will cut the range 2^31--2^32-1 off */ return do_sys_truncate(path, (long)length);} static long do_sys_ftruncate(unsigned int fd, loff_t length, int small){ struct inode * inode; struct dentry *dentry; struct file * file; int error; error = -EINVAL; if (length < 0) goto out; error = -EBADF; file = fget(fd); if (!file) goto out; /* explicitly opened as large or we are on 64-bit box */ if (file->f_flags & O_LARGEFILE) small = 0; dentry = file->f_dentry; inode = dentry->d_inode; error = -EINVAL; if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) goto out_putf; error = -EINVAL; /* Cannot ftruncate over 2^31 bytes without large file support */ if (small && length > MAX_NON_LFS) goto out_putf; error = -EPERM; if (IS_APPEND(inode)) goto out_putf; error = locks_verify_truncate(inode, file, length); if (!error) error = do_truncate(dentry, length, 0, file);out_putf: fput(file);out: return error;} asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length){ long ret = do_sys_ftruncate(fd, length, 1); /* avoid REGPARM breakage on x86: */ prevent_tail_call(ret); return ret;} /* LFS versions of truncate are only needed on 32 bit machines */#if BITS_PER_LONG == 32asmlinkage long sys_truncate64(const char __user * path, loff_t length){ return do_sys_truncate(path, length);} asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length){ long ret = do_sys_ftruncate(fd, length, 0); /* avoid REGPARM breakage on x86: */ prevent_tail_call(ret); return ret;}#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 * switching the fsuid/fsgid around to the real ones. */asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode){ struct nameidata nd; int old_fsuid, old_fsgid; kernel_cap_t old_cap; int res; if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ return -EINVAL;Lines 1–500 of 1234. Load more
/* * linux/fs/open.c * * Copyright (C) 1991, 1992 Linus Torvalds */ #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> #include <linux/fsnotify.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/namei.h> #include <linux/backing-dev.h> #include <linux/capability.h> #include <linux/security.h> #include <linux/mount.h> #include <linux/vfs.h> #include <linux/fcntl.h> #include <asm/uaccess.h> #include <linux/fs.h> #include <linux/personality.h> #include <linux/pagemap.h> #include <linux/syscalls.h> #include <linux/rcupdate.h> #include <linux/audit.h> #include <asm/unistd.h> int vfs_statfs(struct super_block *sb, struct kstatfs *buf) { int retval = -ENODEV; if (sb) { retval = -ENOSYS; if (sb->s_op->statfs) { memset(buf, 0, sizeof(*buf)); retval = security_sb_statfs(sb); if (retval) return retval; retval = sb->s_op->statfs(sb, buf); if (retval == 0 && buf->f_frsize == 0) buf->f_frsize = buf->f_bsize; } } return retval; } EXPORT_SYMBOL(vfs_statfs); static int vfs_statfs_native(struct super_block *sb, struct statfs *buf) { struct kstatfs st; int retval; retval = vfs_statfs(sb, &st); if (retval) return retval; if (sizeof(*buf) == sizeof(st)) memcpy(buf, &st, sizeof(st)); else { if (sizeof buf->f_blocks == 4) { if ((st.f_blocks | st.f_bfree | st.f_bavail) & 0xffffffff00000000ULL) return -EOVERFLOW; /* * f_files and f_ffree may be -1; it's okay to stuff * that into 32 bits */ if (st.f_files != -1 && (st.f_files & 0xffffffff00000000ULL)) return -EOVERFLOW; if (st.f_ffree != -1 && (st.f_ffree & 0xffffffff00000000ULL)) return -EOVERFLOW; } buf->f_type = st.f_type; buf->f_bsize = st.f_bsize; buf->f_blocks = st.f_blocks; buf->f_bfree = st.f_bfree; buf->f_bavail = st.f_bavail; buf->f_files = st.f_files; buf->f_ffree = st.f_ffree; buf->f_fsid = st.f_fsid; buf->f_namelen = st.f_namelen; buf->f_frsize = st.f_frsize; memset(buf->f_spare, 0, sizeof(buf->f_spare)); } return 0; } static int vfs_statfs64(struct super_block *sb, struct statfs64 *buf) { struct kstatfs st; int retval; retval = vfs_statfs(sb, &st); if (retval) return retval; if (sizeof(*buf) == sizeof(st)) memcpy(buf, &st, sizeof(st)); else { buf->f_type = st.f_type; buf->f_bsize = st.f_bsize; buf->f_blocks = st.f_blocks; buf->f_bfree = st.f_bfree; buf->f_bavail = st.f_bavail; buf->f_files = st.f_files; buf->f_ffree = st.f_ffree; buf->f_fsid = st.f_fsid; buf->f_namelen = st.f_namelen; buf->f_frsize = st.f_frsize; memset(buf->f_spare, 0, sizeof(buf->f_spare)); } return 0; } asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf) { struct nameidata nd; int error; error = user_path_walk(path, &nd); if (!error) { struct statfs tmp; error = vfs_statfs_native(nd.dentry->d_inode->i_sb, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; path_release(&nd); } return error; } asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64 __user *buf) { struct nameidata nd; long error; if (sz != sizeof(*buf)) return -EINVAL; error = user_path_walk(path, &nd); if (!error) { struct statfs64 tmp; error = vfs_statfs64(nd.dentry->d_inode->i_sb, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; path_release(&nd); } return error; } asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf) { struct file * file; struct statfs tmp; int error; error = -EBADF; file = fget(fd); if (!file) goto out; error = vfs_statfs_native(file->f_dentry->d_inode->i_sb, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file); out: return error; } asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user *buf) { struct file * file; struct statfs64 tmp; int error; if (sz != sizeof(*buf)) return -EINVAL; error = -EBADF; file = fget(fd); if (!file) goto out; error = vfs_statfs64(file->f_dentry->d_inode->i_sb, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file); out: return error; } int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, struct file *filp) { int err; struct iattr newattrs; /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ if (length < 0) return -EINVAL; newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | time_attrs; if (filp) { newattrs.ia_file = filp; newattrs.ia_valid |= ATTR_FILE; } mutex_lock(&dentry->d_inode->i_mutex); err = notify_change(dentry, &newattrs); mutex_unlock(&dentry->d_inode->i_mutex); return err; } static long do_sys_truncate(const char __user * path, loff_t length) { struct nameidata nd; struct inode * inode; int error; error = -EINVAL; if (length < 0) /* sorry, but loff_t says... */ goto out; error = user_path_walk(path, &nd); if (error) goto out; inode = nd.dentry->d_inode; /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ error = -EISDIR; if (S_ISDIR(inode->i_mode)) goto dput_and_out; error = -EINVAL; if (!S_ISREG(inode->i_mode)) goto dput_and_out; error = vfs_permission(&nd, MAY_WRITE); if (error) goto dput_and_out; error = -EROFS; if (IS_RDONLY(inode)) goto dput_and_out; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto dput_and_out; /* * Make sure that there are no leases. */ error = break_lease(inode, FMODE_WRITE); if (error) goto dput_and_out; error = get_write_access(inode); if (error) goto dput_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); dput_and_out: path_release(&nd); out: return error; } asmlinkage long sys_truncate(const char __user * path, unsigned long length) { /* on 32-bit boxen it will cut the range 2^31--2^32-1 off */ return do_sys_truncate(path, (long)length); } static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) { struct inode * inode; struct dentry *dentry; struct file * file; int error; error = -EINVAL; if (length < 0) goto out; error = -EBADF; file = fget(fd); if (!file) goto out; /* explicitly opened as large or we are on 64-bit box */ if (file->f_flags & O_LARGEFILE) small = 0; dentry = file->f_dentry; inode = dentry->d_inode; error = -EINVAL; if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) goto out_putf; error = -EINVAL; /* Cannot ftruncate over 2^31 bytes without large file support */ if (small && length > MAX_NON_LFS) goto out_putf; error = -EPERM; if (IS_APPEND(inode)) goto out_putf; error = locks_verify_truncate(inode, file, length); if (!error) error = do_truncate(dentry, length, 0, file); out_putf: fput(file); out: return error; } asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length) { long ret = do_sys_ftruncate(fd, length, 1); /* avoid REGPARM breakage on x86: */ prevent_tail_call(ret); return ret; } /* LFS versions of truncate are only needed on 32 bit machines */ #if BITS_PER_LONG == 32 asmlinkage long sys_truncate64(const char __user * path, loff_t length) { return do_sys_truncate(path, length); } asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length) { long ret = do_sys_ftruncate(fd, length, 0); /* avoid REGPARM breakage on x86: */ prevent_tail_call(ret); return ret; } #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 * switching the fsuid/fsgid around to the real ones. */ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) { struct nameidata nd; int old_fsuid, old_fsgid; kernel_cap_t old_cap; int res; if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ return -EINVAL;