linux/fs/jfs/ioctl.c
<<
>>
Prefs
   1/*
   2 * linux/fs/jfs/ioctl.c
   3 *
   4 * Copyright (C) 2006 Herbert Poetzl
   5 * adapted from Remy Card's ext2/ioctl.c
   6 */
   7
   8#include <linux/fs.h>
   9#include <linux/ctype.h>
  10#include <linux/capability.h>
  11#include <linux/mount.h>
  12#include <linux/time.h>
  13#include <linux/sched.h>
  14#include <asm/current.h>
  15#include <asm/uaccess.h>
  16
  17#include "jfs_incore.h"
  18#include "jfs_dinode.h"
  19#include "jfs_inode.h"
  20
  21
  22static struct {
  23        long jfs_flag;
  24        long ext2_flag;
  25} jfs_map[] = {
  26        {JFS_NOATIME_FL,        FS_NOATIME_FL},
  27        {JFS_DIRSYNC_FL,        FS_DIRSYNC_FL},
  28        {JFS_SYNC_FL,           FS_SYNC_FL},
  29        {JFS_SECRM_FL,          FS_SECRM_FL},
  30        {JFS_UNRM_FL,           FS_UNRM_FL},
  31        {JFS_APPEND_FL,         FS_APPEND_FL},
  32        {JFS_IMMUTABLE_FL,      FS_IMMUTABLE_FL},
  33        {0, 0},
  34};
  35
  36static long jfs_map_ext2(unsigned long flags, int from)
  37{
  38        int index=0;
  39        long mapped=0;
  40
  41        while (jfs_map[index].jfs_flag) {
  42                if (from) {
  43                        if (jfs_map[index].ext2_flag & flags)
  44                                mapped |= jfs_map[index].jfs_flag;
  45                } else {
  46                        if (jfs_map[index].jfs_flag & flags)
  47                                mapped |= jfs_map[index].ext2_flag;
  48                }
  49                index++;
  50        }
  51        return mapped;
  52}
  53
  54
  55long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  56{
  57        struct inode *inode = filp->f_dentry->d_inode;
  58        struct jfs_inode_info *jfs_inode = JFS_IP(inode);
  59        unsigned int flags;
  60
  61        switch (cmd) {
  62        case JFS_IOC_GETFLAGS:
  63                jfs_get_inode_flags(jfs_inode);
  64                flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE;
  65                flags = jfs_map_ext2(flags, 0);
  66                return put_user(flags, (int __user *) arg);
  67        case JFS_IOC_SETFLAGS: {
  68                unsigned int oldflags;
  69                int err;
  70
  71                err = mnt_want_write(filp->f_path.mnt);
  72                if (err)
  73                        return err;
  74
  75                if (!inode_owner_or_capable(inode)) {
  76                        err = -EACCES;
  77                        goto setflags_out;
  78                }
  79                if (get_user(flags, (int __user *) arg)) {
  80                        err = -EFAULT;
  81                        goto setflags_out;
  82                }
  83
  84                flags = jfs_map_ext2(flags, 1);
  85                if (!S_ISDIR(inode->i_mode))
  86                        flags &= ~JFS_DIRSYNC_FL;
  87
  88                /* Is it quota file? Do not allow user to mess with it */
  89                if (IS_NOQUOTA(inode)) {
  90                        err = -EPERM;
  91                        goto setflags_out;
  92                }
  93
  94                /* Lock against other parallel changes of flags */
  95                mutex_lock(&inode->i_mutex);
  96
  97                jfs_get_inode_flags(jfs_inode);
  98                oldflags = jfs_inode->mode2;
  99
 100                /*
 101                 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
 102                 * the relevant capability.
 103                 */
 104                if ((oldflags & JFS_IMMUTABLE_FL) ||
 105                        ((flags ^ oldflags) &
 106                        (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) {
 107                        if (!capable(CAP_LINUX_IMMUTABLE)) {
 108                                mutex_unlock(&inode->i_mutex);
 109                                err = -EPERM;
 110                                goto setflags_out;
 111                        }
 112                }
 113
 114                flags = flags & JFS_FL_USER_MODIFIABLE;
 115                flags |= oldflags & ~JFS_FL_USER_MODIFIABLE;
 116                jfs_inode->mode2 = flags;
 117
 118                jfs_set_inode_flags(inode);
 119                mutex_unlock(&inode->i_mutex);
 120                inode->i_ctime = CURRENT_TIME_SEC;
 121                mark_inode_dirty(inode);
 122setflags_out:
 123                mnt_drop_write(filp->f_path.mnt);
 124                return err;
 125        }
 126        default:
 127                return -ENOTTY;
 128        }
 129}
 130
 131#ifdef CONFIG_COMPAT
 132long jfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 133{
 134        /* While these ioctl numbers defined with 'long' and have different
 135         * numbers than the 64bit ABI,
 136         * the actual implementation only deals with ints and is compatible.
 137         */
 138        switch (cmd) {
 139        case JFS_IOC_GETFLAGS32:
 140                cmd = JFS_IOC_GETFLAGS;
 141                break;
 142        case JFS_IOC_SETFLAGS32:
 143                cmd = JFS_IOC_SETFLAGS;
 144                break;
 145        }
 146        return jfs_ioctl(filp, cmd, arg);
 147}
 148#endif
 149