]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/fat/file.c
[SCSI] zfcp: Simplify usage of hex dump output function for debug trace.
[linux-2.6-omap-h63xx.git] / fs / fat / file.c
index 55d3c7461c5b9acb50b851fae64df4a68dcd3d01..c614175876e09316ea0a36566dc072fe6819169c 100644 (file)
@@ -134,7 +134,7 @@ const struct file_operations fat_file_operations = {
        .release        = fat_file_release,
        .ioctl          = fat_generic_ioctl,
        .fsync          = file_fsync,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
 };
 
 static int fat_cont_expand(struct inode *inode, loff_t size)
@@ -155,6 +155,42 @@ out:
        return err;
 }
 
+static int check_mode(const struct msdos_sb_info *sbi, mode_t mode)
+{
+       mode_t req = mode & ~S_IFMT;
+
+       /*
+        * Of the r and x bits, all (subject to umask) must be present. Of the
+        * w bits, either all (subject to umask) or none must be present.
+        */
+
+       if (S_ISREG(mode)) {
+               req &= ~sbi->options.fs_fmask;
+
+               if ((req & (S_IRUGO | S_IXUGO)) !=
+                   ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask))
+                       return -EPERM;
+
+               if ((req & S_IWUGO) != 0 &&
+                   (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask))
+                       return -EPERM;
+       } else if (S_ISDIR(mode)) {
+               req &= ~sbi->options.fs_dmask;
+
+               if ((req & (S_IRUGO | S_IXUGO)) !=
+                   ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask))
+                       return -EPERM;
+
+               if ((req & S_IWUGO) != 0 &&
+                   (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask))
+                       return -EPERM;
+       } else {
+               return -EPERM;
+       }
+
+       return 0;
+}
+
 int fat_notify_change(struct dentry *dentry, struct iattr *attr)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
@@ -186,9 +222,7 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
        if (((attr->ia_valid & ATTR_UID) &&
             (attr->ia_uid != sbi->options.fs_uid)) ||
            ((attr->ia_valid & ATTR_GID) &&
-            (attr->ia_gid != sbi->options.fs_gid)) ||
-           ((attr->ia_valid & ATTR_MODE) &&
-            (attr->ia_mode & ~MSDOS_VALID_MODE)))
+            (attr->ia_gid != sbi->options.fs_gid)))
                error = -EPERM;
 
        if (error) {
@@ -196,6 +230,13 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
                        error = 0;
                goto out;
        }
+
+       if (attr->ia_valid & ATTR_MODE) {
+               error = check_mode(sbi, attr->ia_mode);
+               if (error != 0 && !sbi->options.quiet)
+                       goto out;
+       }
+
        error = inode_setattr(inode, attr);
        if (error)
                goto out;