linux/fs/ubifs/ioctl.c
<<
>>
Prefs
   1/*
   2 * This file is part of UBIFS.
   3 *
   4 * Copyright (C) 2006-2008 Nokia Corporation.
   5 * Copyright (C) 2006, 2007 University of Szeged, Hungary
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License version 2 as published by
   9 * the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful, but WITHOUT
  12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  14 * more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along with
  17 * this program; if not, write to the Free Software Foundation, Inc., 51
  18 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  19 *
  20 * Authors: Zoltan Sogor
  21 *          Artem Bityutskiy (Битюцкий Артём)
  22 *          Adrian Hunter
  23 */
  24
  25/* This file implements EXT2-compatible extended attribute ioctl() calls */
  26
  27#include <linux/compat.h>
  28#include <linux/mount.h>
  29#include "ubifs.h"
  30
  31/**
  32 * ubifs_set_inode_flags - set VFS inode flags.
  33 * @inode: VFS inode to set flags for
  34 *
  35 * This function propagates flags from UBIFS inode object to VFS inode object.
  36 */
  37void ubifs_set_inode_flags(struct inode *inode)
  38{
  39        unsigned int flags = ubifs_inode(inode)->flags;
  40
  41        inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_DIRSYNC);
  42        if (flags & UBIFS_SYNC_FL)
  43                inode->i_flags |= S_SYNC;
  44        if (flags & UBIFS_APPEND_FL)
  45                inode->i_flags |= S_APPEND;
  46        if (flags & UBIFS_IMMUTABLE_FL)
  47                inode->i_flags |= S_IMMUTABLE;
  48        if (flags & UBIFS_DIRSYNC_FL)
  49                inode->i_flags |= S_DIRSYNC;
  50}
  51
  52/*
  53 * ioctl2ubifs - convert ioctl inode flags to UBIFS inode flags.
  54 * @ioctl_flags: flags to convert
  55 *
  56 * This function convert ioctl flags (@FS_COMPR_FL, etc) to UBIFS inode flags
  57 * (@UBIFS_COMPR_FL, etc).
  58 */
  59static int ioctl2ubifs(int ioctl_flags)
  60{
  61        int ubifs_flags = 0;
  62
  63        if (ioctl_flags & FS_COMPR_FL)
  64                ubifs_flags |= UBIFS_COMPR_FL;
  65        if (ioctl_flags & FS_SYNC_FL)
  66                ubifs_flags |= UBIFS_SYNC_FL;
  67        if (ioctl_flags & FS_APPEND_FL)
  68                ubifs_flags |= UBIFS_APPEND_FL;
  69        if (ioctl_flags & FS_IMMUTABLE_FL)
  70                ubifs_flags |= UBIFS_IMMUTABLE_FL;
  71        if (ioctl_flags & FS_DIRSYNC_FL)
  72                ubifs_flags |= UBIFS_DIRSYNC_FL;
  73
  74        return ubifs_flags;
  75}
  76
  77/*
  78 * ubifs2ioctl - convert UBIFS inode flags to ioctl inode flags.
  79 * @ubifs_flags: flags to convert
  80 *
  81 * This function convert UBIFS (@UBIFS_COMPR_FL, etc) to ioctl flags
  82 * (@FS_COMPR_FL, etc).
  83 */
  84static int ubifs2ioctl(int ubifs_flags)
  85{
  86        int ioctl_flags = 0;
  87
  88        if (ubifs_flags & UBIFS_COMPR_FL)
  89                ioctl_flags |= FS_COMPR_FL;
  90        if (ubifs_flags & UBIFS_SYNC_FL)
  91                ioctl_flags |= FS_SYNC_FL;
  92        if (ubifs_flags & UBIFS_APPEND_FL)
  93                ioctl_flags |= FS_APPEND_FL;
  94        if (ubifs_flags & UBIFS_IMMUTABLE_FL)
  95                ioctl_flags |= FS_IMMUTABLE_FL;
  96        if (ubifs_flags & UBIFS_DIRSYNC_FL)
  97                ioctl_flags |= FS_DIRSYNC_FL;
  98
  99        return ioctl_flags;
 100}
 101
 102static int setflags(struct inode *inode, int flags)
 103{
 104        int oldflags, err, release;
 105        struct ubifs_inode *ui = ubifs_inode(inode);
 106        struct ubifs_info *c = inode->i_sb->s_fs_info;
 107        struct ubifs_budget_req req = { .dirtied_ino = 1,
 108                                        .dirtied_ino_d = ui->data_len };
 109
 110        err = ubifs_budget_space(c, &req);
 111        if (err)
 112                return err;
 113
 114        /*
 115         * The IMMUTABLE and APPEND_ONLY flags can only be changed by
 116         * the relevant capability.
 117         */
 118        mutex_lock(&ui->ui_mutex);
 119        oldflags = ubifs2ioctl(ui->flags);
 120        if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
 121                if (!capable(CAP_LINUX_IMMUTABLE)) {
 122                        err = -EPERM;
 123                        goto out_unlock;
 124                }
 125        }
 126
 127        ui->flags = ioctl2ubifs(flags);
 128        ubifs_set_inode_flags(inode);
 129        inode->i_ctime = ubifs_current_time(inode);
 130        release = ui->dirty;
 131        mark_inode_dirty_sync(inode);
 132        mutex_unlock(&ui->ui_mutex);
 133
 134        if (release)
 135                ubifs_release_budget(c, &req);
 136        if (IS_SYNC(inode))
 137                err = write_inode_now(inode, 1);
 138        return err;
 139
 140out_unlock:
 141        ubifs_err("can't modify inode %lu attributes", inode->i_ino);
 142        mutex_unlock(&ui->ui_mutex);
 143        ubifs_release_budget(c, &req);
 144        return err;
 145}
 146
 147long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 148{
 149        int flags, err;
 150        struct inode *inode = file_inode(file);
 151
 152        switch (cmd) {
 153        case FS_IOC_GETFLAGS:
 154                flags = ubifs2ioctl(ubifs_inode(inode)->flags);
 155
 156                dbg_gen("get flags: %#x, i_flags %#x", flags, inode->i_flags);
 157                return put_user(flags, (int __user *) arg);
 158
 159        case FS_IOC_SETFLAGS: {
 160                if (IS_RDONLY(inode))
 161                        return -EROFS;
 162
 163                if (!inode_owner_or_capable(inode))
 164                        return -EACCES;
 165
 166                if (get_user(flags, (int __user *) arg))
 167                        return -EFAULT;
 168
 169                if (!S_ISDIR(inode->i_mode))
 170                        flags &= ~FS_DIRSYNC_FL;
 171
 172                /*
 173                 * Make sure the file-system is read-write and make sure it
 174                 * will not become read-only while we are changing the flags.
 175                 */
 176                err = mnt_want_write_file(file);
 177                if (err)
 178                        return err;
 179                dbg_gen("set flags: %#x, i_flags %#x", flags, inode->i_flags);
 180                err = setflags(inode, flags);
 181                mnt_drop_write_file(file);
 182                return err;
 183        }
 184
 185        default:
 186                return -ENOTTY;
 187        }
 188}
 189
 190#ifdef CONFIG_COMPAT
 191long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 192{
 193        switch (cmd) {
 194        case FS_IOC32_GETFLAGS:
 195                cmd = FS_IOC_GETFLAGS;
 196                break;
 197        case FS_IOC32_SETFLAGS:
 198                cmd = FS_IOC_SETFLAGS;
 199                break;
 200        default:
 201                return -ENOIOCTLCMD;
 202        }
 203        return ubifs_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
 204}
 205#endif
 206