4 * Written 1992,1993 by Werner Almesberger
6 * regular file handling primitives for fat-based filesystems
9 #include <linux/module.h>
10 #include <linux/time.h>
11 #include <linux/msdos_fs.h>
12 #include <linux/smp_lock.h>
13 #include <linux/buffer_head.h>
15 static ssize_t fat_file_write(struct file *filp, const char __user *buf,
16 size_t count, loff_t *ppos)
18 struct inode *inode = filp->f_dentry->d_inode;
21 retval = generic_file_write(filp, buf, count, ppos);
23 inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
24 MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
25 mark_inode_dirty(inode);
30 struct file_operations fat_file_operations = {
31 .llseek = generic_file_llseek,
32 .read = generic_file_read,
33 .write = fat_file_write,
34 .mmap = generic_file_mmap,
36 .readv = generic_file_readv,
37 .writev = generic_file_writev,
38 .sendfile = generic_file_sendfile,
41 int fat_notify_change(struct dentry *dentry, struct iattr *attr)
43 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
44 struct inode *inode = dentry->d_inode;
49 /* FAT cannot truncate to a longer file */
50 if (attr->ia_valid & ATTR_SIZE) {
51 if (attr->ia_size > inode->i_size) {
57 error = inode_change_ok(inode, attr);
59 if (sbi->options.quiet)
63 if (((attr->ia_valid & ATTR_UID) &&
64 (attr->ia_uid != sbi->options.fs_uid)) ||
65 ((attr->ia_valid & ATTR_GID) &&
66 (attr->ia_gid != sbi->options.fs_gid)) ||
67 ((attr->ia_valid & ATTR_MODE) &&
68 (attr->ia_mode & ~MSDOS_VALID_MODE)))
72 if (sbi->options.quiet)
76 error = inode_setattr(inode, attr);
80 if (S_ISDIR(inode->i_mode))
81 mask = sbi->options.fs_dmask;
83 mask = sbi->options.fs_fmask;
84 inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
90 EXPORT_SYMBOL(fat_notify_change);
92 /* Free all clusters after the skip'th cluster. */
93 static int fat_free(struct inode *inode, int skip)
95 struct super_block *sb = inode->i_sb;
96 int nr, ret, fclus, dclus;
98 if (MSDOS_I(inode)->i_start == 0)
102 ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus);
105 else if (ret == FAT_ENT_EOF)
108 nr = fat_access(sb, dclus, -1);
109 if (nr == FAT_ENT_EOF)
113 * write a new EOF, and get the remaining cluster
116 nr = fat_access(sb, dclus, FAT_ENT_EOF);
121 fat_cache_inval_inode(inode);
123 fat_cache_inval_inode(inode);
125 nr = MSDOS_I(inode)->i_start;
126 MSDOS_I(inode)->i_start = 0;
127 MSDOS_I(inode)->i_logstart = 0;
128 mark_inode_dirty(inode);
133 nr = fat_access(sb, nr, FAT_ENT_FREE);
136 else if (nr == FAT_ENT_FREE) {
137 fat_fs_panic(sb, "%s: deleting beyond EOF (i_pos %lld)",
138 __FUNCTION__, MSDOS_I(inode)->i_pos);
142 if (MSDOS_SB(sb)->free_clusters != -1)
143 MSDOS_SB(sb)->free_clusters++;
144 inode->i_blocks -= MSDOS_SB(sb)->cluster_size >> 9;
145 } while (nr != FAT_ENT_EOF);
146 fat_clusters_flush(sb);
154 void fat_truncate(struct inode *inode)
156 struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
157 const unsigned int cluster_size = sbi->cluster_size;
161 * This protects against truncating a file bigger than it was then
162 * trying to write into the hole.
164 if (MSDOS_I(inode)->mmu_private > inode->i_size)
165 MSDOS_I(inode)->mmu_private = inode->i_size;
167 nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits;
170 fat_free(inode, nr_clusters);
171 MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
173 inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
174 mark_inode_dirty(inode);
177 struct inode_operations fat_file_inode_operations = {
178 .truncate = fat_truncate,
179 .setattr = fat_notify_change,