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
  23static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
  24{
  25        struct inode *inode = file->f_path.dentry->d_inode;
  26        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
  27        unsigned int flags = 0;
  28
  29        if (inode->i_flags & S_IMMUTABLE)
  30                flags |= FS_IMMUTABLE_FL;
  31        if (inode->i_flags & S_APPEND)
  32                flags |= FS_APPEND_FL;
  33        if (hip->userflags & HFSPLUS_FLG_NODUMP)
  34                flags |= FS_NODUMP_FL;
  35
  36        return put_user(flags, user_flags);
  37}
  38
  39static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
  40{
  41        struct inode *inode = file->f_path.dentry->d_inode;
  42        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
  43        unsigned int flags;
  44        int err = 0;
  45
  46        err = mnt_want_write(file->f_path.mnt);
  47        if (err)
  48                goto out;
  49
  50        if (!is_owner_or_cap(inode)) {
  51                err = -EACCES;
  52                goto out_drop_write;
  53        }
  54
  55        if (get_user(flags, user_flags)) {
  56                err = -EFAULT;
  57                goto out_drop_write;
  58        }
  59
  60        mutex_lock(&inode->i_mutex);
  61
  62        if ((flags & (FS_IMMUTABLE_FL|FS_APPEND_FL)) ||
  63            inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
  64                if (!capable(CAP_LINUX_IMMUTABLE)) {
  65                        err = -EPERM;
  66                        goto out_unlock_inode;
  67                }
  68        }
  69
  70        /* don't silently ignore unsupported ext2 flags */
  71        if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
  72                err = -EOPNOTSUPP;
  73                goto out_unlock_inode;
  74        }
  75
  76        if (flags & FS_IMMUTABLE_FL)
  77                inode->i_flags |= S_IMMUTABLE;
  78        else
  79                inode->i_flags &= ~S_IMMUTABLE;
  80
  81        if (flags & FS_APPEND_FL)
  82                inode->i_flags |= S_APPEND;
  83        else
  84                inode->i_flags &= ~S_APPEND;
  85
  86        if (flags & FS_NODUMP_FL)
  87                hip->userflags |= HFSPLUS_FLG_NODUMP;
  88        else
  89                hip->userflags &= ~HFSPLUS_FLG_NODUMP;
  90
  91        inode->i_ctime = CURRENT_TIME_SEC;
  92        mark_inode_dirty(inode);
  93
  94out_unlock_inode:
  95        mutex_unlock(&inode->i_mutex);
  96out_drop_write:
  97        mnt_drop_write(file->f_path.mnt);
  98out:
  99        return err;
 100}
 101
 102long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 103{
 104        void __user *argp = (void __user *)arg;
 105
 106        switch (cmd) {
 107        case HFSPLUS_IOC_EXT2_GETFLAGS:
 108                return hfsplus_ioctl_getflags(file, argp);
 109        case HFSPLUS_IOC_EXT2_SETFLAGS:
 110                return hfsplus_ioctl_setflags(file, argp);
 111        default:
 112                return -ENOTTY;
 113        }
 114}
 115
 116int hfsplus_setxattr(struct dentry *dentry, const char *name,
 117                     const void *value, size_t size, int flags)
 118{
 119        struct inode *inode = dentry->d_inode;
 120        struct hfs_find_data fd;
 121        hfsplus_cat_entry entry;
 122        struct hfsplus_cat_file *file;
 123        int res;
 124
 125        if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
 126                return -EOPNOTSUPP;
 127
 128        res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
 129        if (res)
 130                return res;
 131        res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
 132        if (res)
 133                goto out;
 134        hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
 135                        sizeof(struct hfsplus_cat_file));
 136        file = &entry.file;
 137
 138        if (!strcmp(name, "hfs.type")) {
 139                if (size == 4)
 140                        memcpy(&file->user_info.fdType, value, 4);
 141                else
 142                        res = -ERANGE;
 143        } else if (!strcmp(name, "hfs.creator")) {
 144                if (size == 4)
 145                        memcpy(&file->user_info.fdCreator, value, 4);
 146                else
 147                        res = -ERANGE;
 148        } else
 149                res = -EOPNOTSUPP;
 150        if (!res) {
 151                hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
 152                                sizeof(struct hfsplus_cat_file));
 153                hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
 154        }
 155out:
 156        hfs_find_exit(&fd);
 157        return res;
 158}
 159
 160ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
 161                         void *value, size_t size)
 162{
 163        struct inode *inode = dentry->d_inode;
 164        struct hfs_find_data fd;
 165        hfsplus_cat_entry entry;
 166        struct hfsplus_cat_file *file;
 167        ssize_t res = 0;
 168
 169        if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
 170                return -EOPNOTSUPP;
 171
 172        if (size) {
 173                res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
 174                if (res)
 175                        return res;
 176                res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
 177                if (res)
 178                        goto out;
 179                hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
 180                                sizeof(struct hfsplus_cat_file));
 181        }
 182        file = &entry.file;
 183
 184        if (!strcmp(name, "hfs.type")) {
 185                if (size >= 4) {
 186                        memcpy(value, &file->user_info.fdType, 4);
 187                        res = 4;
 188                } else
 189                        res = size ? -ERANGE : 4;
 190        } else if (!strcmp(name, "hfs.creator")) {
 191                if (size >= 4) {
 192                        memcpy(value, &file->user_info.fdCreator, 4);
 193                        res = 4;
 194                } else
 195                        res = size ? -ERANGE : 4;
 196        } else
 197                res = -EOPNOTSUPP;
 198out:
 199        if (size)
 200                hfs_find_exit(&fd);
 201        return res;
 202}
 203
 204#define HFSPLUS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type"))
 205
 206ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
 207{
 208        struct inode *inode = dentry->d_inode;
 209
 210        if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
 211                return -EOPNOTSUPP;
 212
 213        if (!buffer || !size)
 214                return HFSPLUS_ATTRLIST_SIZE;
 215        if (size < HFSPLUS_ATTRLIST_SIZE)
 216                return -ERANGE;
 217        strcpy(buffer, "hfs.type");
 218        strcpy(buffer + sizeof("hfs.type"), "hfs.creator");
 219
 220        return HFSPLUS_ATTRLIST_SIZE;
 221}
 222