patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / fs / fat / file.c
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/time.h>
10 #include <linux/msdos_fs.h>
11 #include <linux/smp_lock.h>
12 #include <linux/buffer_head.h>
13
14 static ssize_t fat_file_write(struct file *filp, const char __user *buf,
15                               size_t count, loff_t *ppos);
16
17 struct file_operations fat_file_operations = {
18         .llseek         = generic_file_llseek,
19         .read           = generic_file_read,
20         .write          = fat_file_write,
21         .mmap           = generic_file_mmap,
22         .fsync          = file_fsync,
23         .readv          = generic_file_readv,
24         .writev         = generic_file_writev,
25         .sendfile       = generic_file_sendfile,
26 };
27
28 struct inode_operations fat_file_inode_operations = {
29         .truncate       = fat_truncate,
30         .setattr        = fat_notify_change,
31 };
32
33 int fat_get_block(struct inode *inode, sector_t iblock,
34                   struct buffer_head *bh_result, int create)
35 {
36         struct super_block *sb = inode->i_sb;
37         sector_t phys;
38         int err;
39
40         err = fat_bmap(inode, iblock, &phys);
41         if (err)
42                 return err;
43         if (phys) {
44                 map_bh(bh_result, sb, phys);
45                 return 0;
46         }
47         if (!create)
48                 return 0;
49         if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {
50                 fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)",
51                              MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
52                 return -EIO;
53         }
54         if (!((unsigned long)iblock & (MSDOS_SB(sb)->sec_per_clus - 1))) {
55                 int error;
56
57                 error = fat_add_cluster(inode);
58                 if (error < 0)
59                         return error;
60         }
61         MSDOS_I(inode)->mmu_private += sb->s_blocksize;
62         err = fat_bmap(inode, iblock, &phys);
63         if (err)
64                 return err;
65         if (!phys)
66                 BUG();
67         set_buffer_new(bh_result);
68         map_bh(bh_result, sb, phys);
69         return 0;
70 }
71
72 static ssize_t fat_file_write(struct file *filp, const char __user *buf,
73                               size_t count, loff_t *ppos)
74 {
75         struct inode *inode = filp->f_dentry->d_inode;
76         int retval;
77
78         retval = generic_file_write(filp, buf, count, ppos);
79         if (retval > 0) {
80                 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
81                 MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
82                 mark_inode_dirty(inode);
83         }
84         return retval;
85 }
86
87 void fat_truncate(struct inode *inode)
88 {
89         struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
90         const unsigned int cluster_size = sbi->cluster_size;
91         int nr_clusters;
92
93         /* Why no return value?  Surely the disk could fail... */
94         if (IS_RDONLY (inode))
95                 return /* -EPERM */;
96         if (IS_IMMUTABLE(inode))
97                 return /* -EPERM */;
98
99         /* 
100          * This protects against truncating a file bigger than it was then
101          * trying to write into the hole.
102          */
103         if (MSDOS_I(inode)->mmu_private > inode->i_size)
104                 MSDOS_I(inode)->mmu_private = inode->i_size;
105
106         nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits;
107
108         lock_kernel();
109         fat_free(inode, nr_clusters);
110         MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
111         unlock_kernel();
112         inode->i_ctime = inode->i_mtime = CURRENT_TIME;
113         mark_inode_dirty(inode);
114 }