linux/fs/fat/file.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/fat/file.c
   3 *
   4 *  Written 1992,1993 by Werner Almesberger
   5 *
   6 *  regular file handling primitives for fat-based filesystems
   7 */
   8
   9#include <linux/capability.h>
  10#include <linux/module.h>
  11#include <linux/mount.h>
  12#include <linux/time.h>
  13#include <linux/buffer_head.h>
  14#include <linux/writeback.h>
  15#include <linux/backing-dev.h>
  16#include <linux/blkdev.h>
  17#include <linux/fsnotify.h>
  18#include <linux/security.h>
  19#include "fat.h"
  20
  21static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr)
  22{
  23        u32 attr;
  24
  25        mutex_lock(&inode->i_mutex);
  26        attr = fat_make_attrs(inode);
  27        mutex_unlock(&inode->i_mutex);
  28
  29        return put_user(attr, user_attr);
  30}
  31
  32static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr)
  33{
  34        struct inode *inode = file->f_path.dentry->d_inode;
  35        struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
  36        int is_dir = S_ISDIR(inode->i_mode);
  37        u32 attr, oldattr;
  38        struct iattr ia;
  39        int err;
  40
  41        err = get_user(attr, user_attr);
  42        if (err)
  43                goto out;
  44
  45        mutex_lock(&inode->i_mutex);
  46        err = mnt_want_write(file->f_path.mnt);
  47        if (err)
  48                goto out_unlock_inode;
  49
  50        /*
  51         * ATTR_VOLUME and ATTR_DIR cannot be changed; this also
  52         * prevents the user from turning us into a VFAT
  53         * longname entry.  Also, we obviously can't set
  54         * any of the NTFS attributes in the high 24 bits.
  55         */
  56        attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR);
  57        /* Merge in ATTR_VOLUME and ATTR_DIR */
  58        attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) |
  59                (is_dir ? ATTR_DIR : 0);
  60        oldattr = fat_make_attrs(inode);
  61
  62        /* Equivalent to a chmod() */
  63        ia.ia_valid = ATTR_MODE | ATTR_CTIME;
  64        ia.ia_ctime = current_fs_time(inode->i_sb);
  65        if (is_dir)
  66                ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO);
  67        else {
  68                ia.ia_mode = fat_make_mode(sbi, attr,
  69                        S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO));
  70        }
  71
  72        /* The root directory has no attributes */
  73        if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) {
  74                err = -EINVAL;
  75                goto out_drop_write;
  76        }
  77
  78        if (sbi->options.sys_immutable &&
  79            ((attr | oldattr) & ATTR_SYS) &&
  80            !capable(CAP_LINUX_IMMUTABLE)) {
  81                err = -EPERM;
  82                goto out_drop_write;
  83        }
  84
  85        /*
  86         * The security check is questionable...  We single
  87         * out the RO attribute for checking by the security
  88         * module, just because it maps to a file mode.
  89         */
  90        err = security_inode_setattr(file->f_path.dentry, &ia);
  91        if (err)
  92                goto out_drop_write;
  93
  94        /* This MUST be done before doing anything irreversible... */
  95        err = fat_setattr(file->f_path.dentry, &ia);
  96        if (err)
  97                goto out_drop_write;
  98
  99        fsnotify_change(file->f_path.dentry, ia.ia_valid);
 100        if (sbi->options.sys_immutable) {
 101                if (attr & ATTR_SYS)
 102                        inode->i_flags |= S_IMMUTABLE;
 103                else
 104                        inode->i_flags &= S_IMMUTABLE;
 105        }
 106
 107        fat_save_attrs(inode, attr);
 108        mark_inode_dirty(inode);
 109out_drop_write:
 110        mnt_drop_write(file->f_path.mnt);
 111out_unlock_inode:
 112        mutex_unlock(&inode->i_mutex);
 113out:
 114        return err;
 115}
 116
 117int fat_generic_ioctl(struct inode *inode, struct file *filp,
 118                      unsigned int cmd, unsigned long arg)
 119{
 120        u32 __user *user_attr = (u32 __user *)arg;
 121
 122        switch (cmd) {
 123        case FAT_IOCTL_GET_ATTRIBUTES:
 124                return fat_ioctl_get_attributes(inode, user_attr);
 125        case FAT_IOCTL_SET_ATTRIBUTES:
 126                return fat_ioctl_set_attributes(filp, user_attr);
 127        default:
 128                return -ENOTTY; /* Inappropriate ioctl for device */
 129        }
 130}
 131
 132static int fat_file_release(struct inode *inode, struct file *filp)
 133{
 134        if ((filp->f_mode & FMODE_WRITE) &&
 135             MSDOS_SB(inode->i_sb)->options.flush) {
 136                fat_flush_inodes(inode->i_sb, inode, NULL);
 137                congestion_wait(BLK_RW_ASYNC, HZ/10);
 138        }
 139        return 0;
 140}
 141
 142int fat_file_fsync(struct file *filp, struct dentry *dentry, int datasync)
 143{
 144        struct inode *inode = dentry->d_inode;
 145        int res, err;
 146
 147        res = simple_fsync(filp, dentry, datasync);
 148        err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping);
 149
 150        return res ? res : err;
 151}
 152
 153
 154const struct file_operations fat_file_operations = {
 155        .llseek         = generic_file_llseek,
 156        .read           = do_sync_read,
 157        .write          = do_sync_write,
 158        .aio_read       = generic_file_aio_read,
 159        .aio_write      = generic_file_aio_write,
 160        .mmap           = generic_file_mmap,
 161        .release        = fat_file_release,
 162        .ioctl          = fat_generic_ioctl,
 163        .fsync          = fat_file_fsync,
 164        .splice_read    = generic_file_splice_read,
 165};
 166
 167static int fat_cont_expand(struct inode *inode, loff_t size)
 168{
 169        struct address_space *mapping = inode->i_mapping;
 170        loff_t start = inode->i_size, count = size - inode->i_size;
 171        int err;
 172
 173        err = generic_cont_expand_simple(inode, size);
 174        if (err)
 175                goto out;
 176
 177        inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
 178        mark_inode_dirty(inode);
 179        if (IS_SYNC(inode)) {
 180                int err2;
 181
 182                /*
 183                 * Opencode syncing since we don't have a file open to use
 184                 * standard fsync path.
 185                 */
 186                err = filemap_fdatawrite_range(mapping, start,
 187                                               start + count - 1);
 188                err2 = sync_mapping_buffers(mapping);
 189                if (!err)
 190                        err = err2;
 191                err2 = write_inode_now(inode, 1);
 192                if (!err)
 193                        err = err2;
 194                if (!err) {
 195                        err =  filemap_fdatawait_range(mapping, start,
 196                                                       start + count - 1);
 197                }
 198        }
 199out:
 200        return err;
 201}
 202
 203/* Free all clusters after the skip'th cluster. */
 204static int fat_free(struct inode *inode, int skip)
 205{
 206        struct super_block *sb = inode->i_sb;
 207        int err, wait, free_start, i_start, i_logstart;
 208
 209        if (MSDOS_I(inode)->i_start == 0)
 210                return 0;
 211
 212        fat_cache_inval_inode(inode);
 213
 214        wait = IS_DIRSYNC(inode);
 215        i_start = free_start = MSDOS_I(inode)->i_start;
 216        i_logstart = MSDOS_I(inode)->i_logstart;
 217
 218        /* First, we write the new file size. */
 219        if (!skip) {
 220                MSDOS_I(inode)->i_start = 0;
 221                MSDOS_I(inode)->i_logstart = 0;
 222        }
 223        MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 224        inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
 225        if (wait) {
 226                err = fat_sync_inode(inode);
 227                if (err) {
 228                        MSDOS_I(inode)->i_start = i_start;
 229                        MSDOS_I(inode)->i_logstart = i_logstart;
 230                        return err;
 231                }
 232        } else
 233                mark_inode_dirty(inode);
 234
 235        /* Write a new EOF, and get the remaining cluster chain for freeing. */
 236        if (skip) {
 237                struct fat_entry fatent;
 238                int ret, fclus, dclus;
 239
 240                ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus);
 241                if (ret < 0)
 242                        return ret;
 243                else if (ret == FAT_ENT_EOF)
 244                        return 0;
 245
 246                fatent_init(&fatent);
 247                ret = fat_ent_read(inode, &fatent, dclus);
 248                if (ret == FAT_ENT_EOF) {
 249                        fatent_brelse(&fatent);
 250                        return 0;
 251                } else if (ret == FAT_ENT_FREE) {
 252                        fat_fs_error(sb,
 253                                     "%s: invalid cluster chain (i_pos %lld)",
 254                                     __func__, MSDOS_I(inode)->i_pos);
 255                        ret = -EIO;
 256                } else if (ret > 0) {
 257                        err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait);
 258                        if (err)
 259                                ret = err;
 260                }
 261                fatent_brelse(&fatent);
 262                if (ret < 0)
 263                        return ret;
 264
 265                free_start = ret;
 266        }
 267        inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);
 268
 269        /* Freeing the remained cluster chain */
 270        return fat_free_clusters(inode, free_start);
 271}
 272
 273void fat_truncate(struct inode *inode)
 274{
 275        struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
 276        const unsigned int cluster_size = sbi->cluster_size;
 277        int nr_clusters;
 278
 279        /*
 280         * This protects against truncating a file bigger than it was then
 281         * trying to write into the hole.
 282         */
 283        if (MSDOS_I(inode)->mmu_private > inode->i_size)
 284                MSDOS_I(inode)->mmu_private = inode->i_size;
 285
 286        nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits;
 287
 288        fat_free(inode, nr_clusters);
 289        fat_flush_inodes(inode->i_sb, inode, NULL);
 290}
 291
 292int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 293{
 294        struct inode *inode = dentry->d_inode;
 295        generic_fillattr(inode, stat);
 296        stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size;
 297        return 0;
 298}
 299EXPORT_SYMBOL_GPL(fat_getattr);
 300
 301static int fat_sanitize_mode(const struct msdos_sb_info *sbi,
 302                             struct inode *inode, umode_t *mode_ptr)
 303{
 304        mode_t mask, perm;
 305
 306        /*
 307         * Note, the basic check is already done by a caller of
 308         * (attr->ia_mode & ~FAT_VALID_MODE)
 309         */
 310
 311        if (S_ISREG(inode->i_mode))
 312                mask = sbi->options.fs_fmask;
 313        else
 314                mask = sbi->options.fs_dmask;
 315
 316        perm = *mode_ptr & ~(S_IFMT | mask);
 317
 318        /*
 319         * Of the r and x bits, all (subject to umask) must be present. Of the
 320         * w bits, either all (subject to umask) or none must be present.
 321         *
 322         * If fat_mode_can_hold_ro(inode) is false, can't change w bits.
 323         */
 324        if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))
 325                return -EPERM;
 326        if (fat_mode_can_hold_ro(inode)) {
 327                if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask)))
 328                        return -EPERM;
 329        } else {
 330                if ((perm & S_IWUGO) != (S_IWUGO & ~mask))
 331                        return -EPERM;
 332        }
 333
 334        *mode_ptr &= S_IFMT | perm;
 335
 336        return 0;
 337}
 338
 339static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
 340{
 341        mode_t allow_utime = sbi->options.allow_utime;
 342
 343        if (current_fsuid() != inode->i_uid) {
 344                if (in_group_p(inode->i_gid))
 345                        allow_utime >>= 3;
 346                if (allow_utime & MAY_WRITE)
 347                        return 1;
 348        }
 349
 350        /* use a default check */
 351        return 0;
 352}
 353
 354#define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)
 355/* valid file mode bits */
 356#define FAT_VALID_MODE  (S_IFREG | S_IFDIR | S_IRWXUGO)
 357
 358int fat_setattr(struct dentry *dentry, struct iattr *attr)
 359{
 360        struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
 361        struct inode *inode = dentry->d_inode;
 362        unsigned int ia_valid;
 363        int error;
 364
 365        /*
 366         * Expand the file. Since inode_setattr() updates ->i_size
 367         * before calling the ->truncate(), but FAT needs to fill the
 368         * hole before it.
 369         */
 370        if (attr->ia_valid & ATTR_SIZE) {
 371                if (attr->ia_size > inode->i_size) {
 372                        error = fat_cont_expand(inode, attr->ia_size);
 373                        if (error || attr->ia_valid == ATTR_SIZE)
 374                                goto out;
 375                        attr->ia_valid &= ~ATTR_SIZE;
 376                }
 377        }
 378
 379        /* Check for setting the inode time. */
 380        ia_valid = attr->ia_valid;
 381        if (ia_valid & TIMES_SET_FLAGS) {
 382                if (fat_allow_set_time(sbi, inode))
 383                        attr->ia_valid &= ~TIMES_SET_FLAGS;
 384        }
 385
 386        error = inode_change_ok(inode, attr);
 387        attr->ia_valid = ia_valid;
 388        if (error) {
 389                if (sbi->options.quiet)
 390                        error = 0;
 391                goto out;
 392        }
 393
 394        if (((attr->ia_valid & ATTR_UID) &&
 395             (attr->ia_uid != sbi->options.fs_uid)) ||
 396            ((attr->ia_valid & ATTR_GID) &&
 397             (attr->ia_gid != sbi->options.fs_gid)) ||
 398            ((attr->ia_valid & ATTR_MODE) &&
 399             (attr->ia_mode & ~FAT_VALID_MODE)))
 400                error = -EPERM;
 401
 402        if (error) {
 403                if (sbi->options.quiet)
 404                        error = 0;
 405                goto out;
 406        }
 407
 408        /*
 409         * We don't return -EPERM here. Yes, strange, but this is too
 410         * old behavior.
 411         */
 412        if (attr->ia_valid & ATTR_MODE) {
 413                if (fat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0)
 414                        attr->ia_valid &= ~ATTR_MODE;
 415        }
 416
 417        if (attr->ia_valid)
 418                error = inode_setattr(inode, attr);
 419out:
 420        return error;
 421}
 422EXPORT_SYMBOL_GPL(fat_setattr);
 423
 424const struct inode_operations fat_file_inode_operations = {
 425        .truncate       = fat_truncate,
 426        .setattr        = fat_setattr,
 427        .getattr        = fat_getattr,
 428};
 429