ufs: permit mounting of BorderWare filesystems
[safe/jmp/linux-2.6] / fs / udf / file.c
index eb91f3b..baae3a7 100644 (file)
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
 #include <linux/pagemap.h>
+#include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/aio.h>
+#include <linux/smp_lock.h>
 
 #include "udf_i.h"
 #include "udf_sb.h"
@@ -143,59 +145,72 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        return retval;
 }
 
-int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
-             unsigned long arg)
+long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
+       struct inode *inode = filp->f_dentry->d_inode;
        long old_block, new_block;
        int result = -EINVAL;
 
+       lock_kernel();
+
        if (file_permission(filp, MAY_READ) != 0) {
-               udf_debug("no permission to access inode %lu\n",
-                         inode->i_ino);
-               return -EPERM;
+               udf_debug("no permission to access inode %lu\n", inode->i_ino);
+               result = -EPERM;
+               goto out;
        }
 
        if (!arg) {
                udf_debug("invalid argument to udf_ioctl\n");
-               return -EINVAL;
+               result = -EINVAL;
+               goto out;
        }
 
        switch (cmd) {
        case UDF_GETVOLIDENT:
                if (copy_to_user((char __user *)arg,
                                 UDF_SB(inode->i_sb)->s_volume_ident, 32))
-                       return -EFAULT;
+                       result = -EFAULT;
                else
-                       return 0;
+                       result = 0;
+               goto out;
        case UDF_RELOCATE_BLOCKS:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EACCES;
-               if (get_user(old_block, (long __user *)arg))
-                       return -EFAULT;
+               if (!capable(CAP_SYS_ADMIN)) {
+                       result = -EACCES;
+                       goto out;
+               }
+               if (get_user(old_block, (long __user *)arg)) {
+                       result = -EFAULT;
+                       goto out;
+               }
                result = udf_relocate_blocks(inode->i_sb,
                                                old_block, &new_block);
                if (result == 0)
                        result = put_user(new_block, (long __user *)arg);
-               return result;
+               goto out;
        case UDF_GETEASIZE:
                result = put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg);
-               break;
+               goto out;
        case UDF_GETEABLOCK:
                result = copy_to_user((char __user *)arg,
                                      UDF_I(inode)->i_ext.i_data,
                                      UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0;
-               break;
+               goto out;
        }
 
+out:
+       unlock_kernel();
        return result;
 }
 
 static int udf_release_file(struct inode *inode, struct file *filp)
 {
        if (filp->f_mode & FMODE_WRITE) {
+               mutex_lock(&inode->i_mutex);
                lock_kernel();
                udf_discard_prealloc(inode);
+               udf_truncate_tail_extent(inode);
                unlock_kernel();
+               mutex_unlock(&inode->i_mutex);
        }
        return 0;
 }
@@ -203,17 +218,40 @@ static int udf_release_file(struct inode *inode, struct file *filp)
 const struct file_operations udf_file_operations = {
        .read                   = do_sync_read,
        .aio_read               = generic_file_aio_read,
-       .ioctl                  = udf_ioctl,
-       .open                   = generic_file_open,
+       .unlocked_ioctl         = udf_ioctl,
+       .open                   = dquot_file_open,
        .mmap                   = generic_file_mmap,
        .write                  = do_sync_write,
        .aio_write              = udf_file_aio_write,
        .release                = udf_release_file,
-       .fsync                  = udf_fsync_file,
+       .fsync                  = simple_fsync,
        .splice_read            = generic_file_splice_read,
        .llseek                 = generic_file_llseek,
 };
 
+int udf_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+       struct inode *inode = dentry->d_inode;
+       int error;
+
+       error = inode_change_ok(inode, iattr);
+       if (error)
+               return error;
+
+       if (is_quota_modification(inode, iattr))
+               dquot_initialize(inode);
+
+       if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
+            (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
+               error = dquot_transfer(inode, iattr);
+               if (error)
+                       return error;
+       }
+
+       return inode_setattr(inode, iattr);
+}
+
 const struct inode_operations udf_file_inode_operations = {
-       .truncate = udf_truncate,
+       .truncate               = udf_truncate,
+       .setattr                = udf_setattr,
 };