^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/fs/hfsplus/ioctl.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2003
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Ethan Benson <erbenson@alaska.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * partially derived from linux/fs/ext2/ioctl.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (C) 1993, 1994, 1995
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Remy Card (card@masi.ibp.fr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Laboratoire MASI - Institut Blaise Pascal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Universite Pierre et Marie Curie (Paris VI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * hfsplus ioctls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/capability.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/mount.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "hfsplus_fs.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * "Blessing" an HFS+ filesystem writes metadata to the superblock informing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * the platform firmware which file to boot from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct dentry *dentry = file->f_path.dentry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct inode *inode = d_inode(dentry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct hfsplus_vh *vh = sbi->s_vhdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct hfsplus_vh *bvh = sbi->s_backup_vhdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) u32 cnid = (unsigned long)dentry->d_fsdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) if (!capable(CAP_SYS_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) mutex_lock(&sbi->vh_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /* Directory containing the bootable system */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) vh->finder_info[0] = bvh->finder_info[0] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) cpu_to_be32(parent_ino(dentry));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * Bootloader. Just using the inode here breaks in the case of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * hard links - the firmware wants the ID of the hard link file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * but the inode points at the indirect inode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) vh->finder_info[1] = bvh->finder_info[1] = cpu_to_be32(cnid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* Per spec, the OS X system folder - same as finder_info[0] here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) vh->finder_info[5] = bvh->finder_info[5] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) cpu_to_be32(parent_ino(dentry));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) mutex_unlock(&sbi->vh_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static inline unsigned int hfsplus_getflags(struct inode *inode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned int flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (inode->i_flags & S_IMMUTABLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) flags |= FS_IMMUTABLE_FL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (inode->i_flags & S_APPEND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) flags |= FS_APPEND_FL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (hip->userflags & HFSPLUS_FLG_NODUMP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) flags |= FS_NODUMP_FL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct inode *inode = file_inode(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) unsigned int flags = hfsplus_getflags(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return put_user(flags, user_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct inode *inode = file_inode(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) unsigned int flags, new_fl = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) unsigned int oldflags = hfsplus_getflags(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) err = mnt_want_write_file(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (!inode_owner_or_capable(inode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) err = -EACCES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) goto out_drop_write;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (get_user(flags, user_flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) err = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) goto out_drop_write;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) inode_lock(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) goto out_unlock_inode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /* don't silently ignore unsupported ext2 flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) err = -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) goto out_unlock_inode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (flags & FS_IMMUTABLE_FL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) new_fl |= S_IMMUTABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (flags & FS_APPEND_FL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) new_fl |= S_APPEND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (flags & FS_NODUMP_FL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) hip->userflags |= HFSPLUS_FLG_NODUMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) hip->userflags &= ~HFSPLUS_FLG_NODUMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) inode->i_ctime = current_time(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) mark_inode_dirty(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) out_unlock_inode:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) inode_unlock(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) out_drop_write:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) mnt_drop_write_file(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) void __user *argp = (void __user *)arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) case HFSPLUS_IOC_EXT2_GETFLAGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return hfsplus_ioctl_getflags(file, argp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) case HFSPLUS_IOC_EXT2_SETFLAGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return hfsplus_ioctl_setflags(file, argp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) case HFSPLUS_IOC_BLESS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return hfsplus_ioctl_bless(file, argp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return -ENOTTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }