linux/fs/hfsplus/ioctl.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/hfsplus/ioctl.c
   3 *
   4 * Copyright (C) 2003
   5 * Ethan Benson <erbenson@alaska.net>
   6 * partially derived from linux/fs/ext2/ioctl.c
   7 * Copyright (C) 1993, 1994, 1995
   8 * Remy Card (card@masi.ibp.fr)
   9 * Laboratoire MASI - Institut Blaise Pascal
  10 * Universite Pierre et Marie Curie (Paris VI)
  11 *
  12 * hfsplus ioctls
  13 */
  14
  15#include <linux/capability.h>
  16#include <linux/fs.h>
  17#include <linux/mount.h>
  18#include <linux/sched.h>
  19#include <linux/xattr.h>
  20#include <asm/uaccess.h>
  21#include "hfsplus_fs.h"
  22
  23/*
  24 * "Blessing" an HFS+ filesystem writes metadata to the superblock informing
  25 * the platform firmware which file to boot from
  26 */
  27static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags)
  28{
  29        struct dentry *dentry = file->f_path.dentry;
  30        struct inode *inode = dentry->d_inode;
  31        struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
  32        struct hfsplus_vh *vh = sbi->s_vhdr;
  33        struct hfsplus_vh *bvh = sbi->s_backup_vhdr;
  34        u32 cnid = (unsigned long)dentry->d_fsdata;
  35
  36        if (!capable(CAP_SYS_ADMIN))
  37                return -EPERM;
  38
  39        mutex_lock(&sbi->vh_mutex);
  40
  41        /* Directory containing the bootable system */
  42        vh->finder_info[0] = bvh->finder_info[0] =
  43                cpu_to_be32(parent_ino(dentry));
  44
  45        /*
  46         * Bootloader. Just using the inode here breaks in the case of
  47         * hard links - the firmware wants the ID of the hard link file,
  48         * but the inode points at the indirect inode
  49         */
  50        vh->finder_info[1] = bvh->finder_info[1] = cpu_to_be32(cnid);
  51
  52        /* Per spec, the OS X system folder - same as finder_info[0] here */
  53        vh->finder_info[5] = bvh->finder_info[5] =
  54                cpu_to_be32(parent_ino(dentry));
  55
  56        mutex_unlock(&sbi->vh_mutex);
  57        return 0;
  58}
  59
  60static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
  61{
  62        struct inode *inode = file->f_path.dentry->d_inode;
  63        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
  64        unsigned int flags = 0;
  65
  66        if (inode->i_flags & S_IMMUTABLE)
  67                flags |= FS_IMMUTABLE_FL;
  68        if (inode->i_flags & S_APPEND)
  69                flags |= FS_APPEND_FL;
  70        if (hip->userflags & HFSPLUS_FLG_NODUMP)
  71                flags |= FS_NODUMP_FL;
  72
  73        return put_user(flags, user_flags);
  74}
  75
  76static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
  77{
  78        struct inode *inode = file->f_path.dentry->d_inode;
  79        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
  80        unsigned int flags;
  81        int err = 0;
  82
  83        err = mnt_want_write_file(file);
  84        if (err)
  85                goto out;
  86
  87        if (!inode_owner_or_capable(inode)) {
  88                err = -EACCES;
  89                goto out_drop_write;
  90        }
  91
  92        if (get_user(flags, user_flags)) {
  93                err = -EFAULT;
  94                goto out_drop_write;
  95        }
  96
  97        mutex_lock(&inode->i_mutex);
  98
  99        if ((flags & (FS_IMMUTABLE_FL|FS_APPEND_FL)) ||
 100            inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
 101                if (!capable(CAP_LINUX_IMMUTABLE)) {
 102                        err = -EPERM;
 103                        goto out_unlock_inode;
 104                }
 105        }
 106
 107        /* don't silently ignore unsupported ext2 flags */
 108        if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
 109                err = -EOPNOTSUPP;
 110                goto out_unlock_inode;
 111        }
 112
 113        if (flags & FS_IMMUTABLE_FL)
 114                inode->i_flags |= S_IMMUTABLE;
 115        else
 116                inode->i_flags &= ~S_IMMUTABLE;
 117
 118        if (flags & FS_APPEND_FL)
 119                inode->i_flags |= S_APPEND;
 120        else
 121                inode->i_flags &= ~S_APPEND;
 122
 123        if (flags & FS_NODUMP_FL)
 124                hip->userflags |= HFSPLUS_FLG_NODUMP;
 125        else
 126                hip->userflags &= ~HFSPLUS_FLG_NODUMP;
 127
 128        inode->i_ctime = CURRENT_TIME_SEC;
 129        mark_inode_dirty(inode);
 130
 131out_unlock_inode:
 132        mutex_unlock(&inode->i_mutex);
 133out_drop_write:
 134        mnt_drop_write_file(file);
 135out:
 136        return err;
 137}
 138
 139long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 140{
 141        void __user *argp = (void __user *)arg;
 142
 143        switch (cmd) {
 144        case HFSPLUS_IOC_EXT2_GETFLAGS:
 145                return hfsplus_ioctl_getflags(file, argp);
 146        case HFSPLUS_IOC_EXT2_SETFLAGS:
 147                return hfsplus_ioctl_setflags(file, argp);
 148        case HFSPLUS_IOC_BLESS:
 149                return hfsplus_ioctl_bless(file, argp);
 150        default:
 151                return -ENOTTY;
 152        }
 153}
 154
 155int hfsplus_setxattr(struct dentry *dentry, const char *name,
 156                     const void *value, size_t size, int flags)
 157{
 158        struct inode *inode = dentry->d_inode;
 159        struct hfs_find_data fd;
 160        hfsplus_cat_entry entry;
 161        struct hfsplus_cat_file *file;
 162        int res;
 163
 164        if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
 165                return -EOPNOTSUPP;
 166
 167        res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
 168        if (res)
 169                return res;
 170        res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
 171        if (res)
 172                goto out;
 173        hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
 174                        sizeof(struct hfsplus_cat_file));
 175        file = &entry.file;
 176
 177        if (!strcmp(name, "hfs.type")) {
 178                if (size == 4)
 179                        memcpy(&file->user_info.fdType, value, 4);
 180                else
 181                        res = -ERANGE;
 182        } else if (!strcmp(name, "hfs.creator")) {
 183                if (size == 4)
 184                        memcpy(&file->user_info.fdCreator, value, 4);
 185                else
 186                        res = -ERANGE;
 187        } else
 188                res = -EOPNOTSUPP;
 189        if (!res) {
 190                hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
 191                                sizeof(struct hfsplus_cat_file));
 192                hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
 193        }
 194out:
 195        hfs_find_exit(&fd);
 196        return res;
 197}
 198
 199ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
 200                         void *value, size_t size)
 201{
 202        struct inode *inode = dentry->d_inode;
 203        struct hfs_find_data fd;
 204        hfsplus_cat_entry entry;
 205        struct hfsplus_cat_file *file;
 206        ssize_t res = 0;
 207
 208        if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
 209                return -EOPNOTSUPP;
 210
 211        if (size) {
 212                res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
 213                if (res)
 214                        return res;
 215                res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
 216                if (res)
 217                        goto out;
 218                hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
 219                                sizeof(struct hfsplus_cat_file));
 220        }
 221        file = &entry.file;
 222
 223        if (!strcmp(name, "hfs.type")) {
 224                if (size >= 4) {
 225                        memcpy(value, &file->user_info.fdType, 4);
 226                        res = 4;
 227                } else
 228                        res = size ? -ERANGE : 4;
 229        } else if (!strcmp(name, "hfs.creator")) {
 230                if (size >= 4) {
 231                        memcpy(value, &file->user_info.fdCreator, 4);
 232                        res = 4;
 233                } else
 234                        res = size ? -ERANGE : 4;
 235        } else
 236                res = -EOPNOTSUPP;
 237out:
 238        if (size)
 239                hfs_find_exit(&fd);
 240        return res;
 241}
 242
 243#define HFSPLUS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type"))
 244
 245ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
 246{
 247        struct inode *inode = dentry->d_inode;
 248
 249        if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
 250                return -EOPNOTSUPP;
 251
 252        if (!buffer || !size)
 253                return HFSPLUS_ATTRLIST_SIZE;
 254        if (size < HFSPLUS_ATTRLIST_SIZE)
 255                return -ERANGE;
 256        strcpy(buffer, "hfs.type");
 257        strcpy(buffer + sizeof("hfs.type"), "hfs.creator");
 258
 259        return HFSPLUS_ATTRLIST_SIZE;
 260}
 261
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.