aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fat')
-rw-r--r--fs/fat/Makefile6
-rw-r--r--fs/fat/cache.c25
-rw-r--r--fs/fat/dir.c20
-rw-r--r--fs/fat/fat.h329
-rw-r--r--fs/fat/fatent.c24
-rw-r--r--fs/fat/file.c49
-rw-r--r--fs/fat/inode.c133
-rw-r--r--fs/fat/misc.c155
-rw-r--r--fs/fat/namei_msdos.c706
-rw-r--r--fs/fat/namei_vfat.c1098
10 files changed, 2396 insertions, 149 deletions
diff --git a/fs/fat/Makefile b/fs/fat/Makefile
index bfb5f06cf2c8..e06190322c1c 100644
--- a/fs/fat/Makefile
+++ b/fs/fat/Makefile
@@ -3,5 +3,9 @@
3# 3#
4 4
5obj-$(CONFIG_FAT_FS) += fat.o 5obj-$(CONFIG_FAT_FS) += fat.o
6obj-$(CONFIG_VFAT_FS) += vfat.o
7obj-$(CONFIG_MSDOS_FS) += msdos.o
6 8
7fat-objs := cache.o dir.o fatent.o file.o inode.o misc.o 9fat-y := cache.o dir.o fatent.o file.o inode.o misc.o
10vfat-y := namei_vfat.o
11msdos-y := namei_msdos.o
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 3222f51c41cf..b42602298087 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -9,8 +9,8 @@
9 */ 9 */
10 10
11#include <linux/fs.h> 11#include <linux/fs.h>
12#include <linux/msdos_fs.h>
13#include <linux/buffer_head.h> 12#include <linux/buffer_head.h>
13#include "fat.h"
14 14
15/* this must be > 0. */ 15/* this must be > 0. */
16#define FAT_MAX_CACHE 8 16#define FAT_MAX_CACHE 8
@@ -293,10 +293,12 @@ static int fat_bmap_cluster(struct inode *inode, int cluster)
293} 293}
294 294
295int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, 295int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
296 unsigned long *mapped_blocks) 296 unsigned long *mapped_blocks, int create)
297{ 297{
298 struct super_block *sb = inode->i_sb; 298 struct super_block *sb = inode->i_sb;
299 struct msdos_sb_info *sbi = MSDOS_SB(sb); 299 struct msdos_sb_info *sbi = MSDOS_SB(sb);
300 const unsigned long blocksize = sb->s_blocksize;
301 const unsigned char blocksize_bits = sb->s_blocksize_bits;
300 sector_t last_block; 302 sector_t last_block;
301 int cluster, offset; 303 int cluster, offset;
302 304
@@ -309,10 +311,21 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
309 } 311 }
310 return 0; 312 return 0;
311 } 313 }
312 last_block = (MSDOS_I(inode)->mmu_private + (sb->s_blocksize - 1)) 314
313 >> sb->s_blocksize_bits; 315 last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
314 if (sector >= last_block) 316 if (sector >= last_block) {
315 return 0; 317 if (!create)
318 return 0;
319
320 /*
321 * ->mmu_private can access on only allocation path.
322 * (caller must hold ->i_mutex)
323 */
324 last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1))
325 >> blocksize_bits;
326 if (sector >= last_block)
327 return 0;
328 }
316 329
317 cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits); 330 cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
318 offset = sector & (sbi->sec_per_clus - 1); 331 offset = sector & (sbi->sec_per_clus - 1);
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index bae1c3292522..67e058357098 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -16,11 +16,11 @@
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/slab.h> 17#include <linux/slab.h>
18#include <linux/time.h> 18#include <linux/time.h>
19#include <linux/msdos_fs.h>
20#include <linux/smp_lock.h> 19#include <linux/smp_lock.h>
21#include <linux/buffer_head.h> 20#include <linux/buffer_head.h>
22#include <linux/compat.h> 21#include <linux/compat.h>
23#include <asm/uaccess.h> 22#include <asm/uaccess.h>
23#include "fat.h"
24 24
25static inline loff_t fat_make_i_pos(struct super_block *sb, 25static inline loff_t fat_make_i_pos(struct super_block *sb,
26 struct buffer_head *bh, 26 struct buffer_head *bh,
@@ -77,7 +77,7 @@ next:
77 77
78 *bh = NULL; 78 *bh = NULL;
79 iblock = *pos >> sb->s_blocksize_bits; 79 iblock = *pos >> sb->s_blocksize_bits;
80 err = fat_bmap(dir, iblock, &phys, &mapped_blocks); 80 err = fat_bmap(dir, iblock, &phys, &mapped_blocks, 0);
81 if (err || !phys) 81 if (err || !phys)
82 return -1; /* beyond EOF or error */ 82 return -1; /* beyond EOF or error */
83 83
@@ -86,7 +86,7 @@ next:
86 *bh = sb_bread(sb, phys); 86 *bh = sb_bread(sb, phys);
87 if (*bh == NULL) { 87 if (*bh == NULL) {
88 printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n", 88 printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
89 (unsigned long long)phys); 89 (llu)phys);
90 /* skip this block */ 90 /* skip this block */
91 *pos = (iblock + 1) << sb->s_blocksize_bits; 91 *pos = (iblock + 1) << sb->s_blocksize_bits;
92 goto next; 92 goto next;
@@ -373,9 +373,10 @@ parse_record:
373 if (de->attr == ATTR_EXT) { 373 if (de->attr == ATTR_EXT) {
374 int status = fat_parse_long(inode, &cpos, &bh, &de, 374 int status = fat_parse_long(inode, &cpos, &bh, &de,
375 &unicode, &nr_slots); 375 &unicode, &nr_slots);
376 if (status < 0) 376 if (status < 0) {
377 return status; 377 err = status;
378 else if (status == PARSE_INVALID) 378 goto end_of_dir;
379 } else if (status == PARSE_INVALID)
379 continue; 380 continue;
380 else if (status == PARSE_NOT_LONGNAME) 381 else if (status == PARSE_NOT_LONGNAME)
381 goto parse_record; 382 goto parse_record;
@@ -832,6 +833,7 @@ static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd,
832#endif /* CONFIG_COMPAT */ 833#endif /* CONFIG_COMPAT */
833 834
834const struct file_operations fat_dir_operations = { 835const struct file_operations fat_dir_operations = {
836 .llseek = generic_file_llseek,
835 .read = generic_read_dir, 837 .read = generic_read_dir,
836 .readdir = fat_readdir, 838 .readdir = fat_readdir,
837 .ioctl = fat_dir_ioctl, 839 .ioctl = fat_dir_ioctl,
@@ -1089,6 +1091,7 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts)
1089 struct msdos_dir_entry *de; 1091 struct msdos_dir_entry *de;
1090 sector_t blknr; 1092 sector_t blknr;
1091 __le16 date, time; 1093 __le16 date, time;
1094 u8 time_cs;
1092 int err, cluster; 1095 int err, cluster;
1093 1096
1094 err = fat_alloc_clusters(dir, &cluster, 1); 1097 err = fat_alloc_clusters(dir, &cluster, 1);
@@ -1102,7 +1105,7 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts)
1102 goto error_free; 1105 goto error_free;
1103 } 1106 }
1104 1107
1105 fat_date_unix2dos(ts->tv_sec, &time, &date, sbi->options.tz_utc); 1108 fat_time_unix2fat(sbi, ts, &time, &date, &time_cs);
1106 1109
1107 de = (struct msdos_dir_entry *)bhs[0]->b_data; 1110 de = (struct msdos_dir_entry *)bhs[0]->b_data;
1108 /* filling the new directory slots ("." and ".." entries) */ 1111 /* filling the new directory slots ("." and ".." entries) */
@@ -1112,13 +1115,14 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts)
1112 de[0].lcase = de[1].lcase = 0; 1115 de[0].lcase = de[1].lcase = 0;
1113 de[0].time = de[1].time = time; 1116 de[0].time = de[1].time = time;
1114 de[0].date = de[1].date = date; 1117 de[0].date = de[1].date = date;
1115 de[0].ctime_cs = de[1].ctime_cs = 0;
1116 if (sbi->options.isvfat) { 1118 if (sbi->options.isvfat) {
1117 /* extra timestamps */ 1119 /* extra timestamps */
1118 de[0].ctime = de[1].ctime = time; 1120 de[0].ctime = de[1].ctime = time;
1121 de[0].ctime_cs = de[1].ctime_cs = time_cs;
1119 de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date; 1122 de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date;
1120 } else { 1123 } else {
1121 de[0].ctime = de[1].ctime = 0; 1124 de[0].ctime = de[1].ctime = 0;
1125 de[0].ctime_cs = de[1].ctime_cs = 0;
1122 de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0; 1126 de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0;
1123 } 1127 }
1124 de[0].start = cpu_to_le16(cluster); 1128 de[0].start = cpu_to_le16(cluster);
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
new file mode 100644
index 000000000000..ea440d65819c
--- /dev/null
+++ b/fs/fat/fat.h
@@ -0,0 +1,329 @@
1#ifndef _FAT_H
2#define _FAT_H
3
4#include <linux/buffer_head.h>
5#include <linux/string.h>
6#include <linux/nls.h>
7#include <linux/fs.h>
8#include <linux/mutex.h>
9#include <linux/msdos_fs.h>
10
11/*
12 * vfat shortname flags
13 */
14#define VFAT_SFN_DISPLAY_LOWER 0x0001 /* convert to lowercase for display */
15#define VFAT_SFN_DISPLAY_WIN95 0x0002 /* emulate win95 rule for display */
16#define VFAT_SFN_DISPLAY_WINNT 0x0004 /* emulate winnt rule for display */
17#define VFAT_SFN_CREATE_WIN95 0x0100 /* emulate win95 rule for create */
18#define VFAT_SFN_CREATE_WINNT 0x0200 /* emulate winnt rule for create */
19
20struct fat_mount_options {
21 uid_t fs_uid;
22 gid_t fs_gid;
23 unsigned short fs_fmask;
24 unsigned short fs_dmask;
25 unsigned short codepage; /* Codepage for shortname conversions */
26 char *iocharset; /* Charset used for filename input/display */
27 unsigned short shortname; /* flags for shortname display/create rule */
28 unsigned char name_check; /* r = relaxed, n = normal, s = strict */
29 unsigned short allow_utime;/* permission for setting the [am]time */
30 unsigned quiet:1, /* set = fake successful chmods and chowns */
31 showexec:1, /* set = only set x bit for com/exe/bat */
32 sys_immutable:1, /* set = system files are immutable */
33 dotsOK:1, /* set = hidden and system files are named '.filename' */
34 isvfat:1, /* 0=no vfat long filename support, 1=vfat support */
35 utf8:1, /* Use of UTF-8 character set (Default) */
36 unicode_xlate:1, /* create escape sequences for unhandled Unicode */
37 numtail:1, /* Does first alias have a numeric '~1' type tail? */
38 flush:1, /* write things quickly */
39 nocase:1, /* Does this need case conversion? 0=need case conversion*/
40 usefree:1, /* Use free_clusters for FAT32 */
41 tz_utc:1, /* Filesystem timestamps are in UTC */
42 rodir:1; /* allow ATTR_RO for directory */
43};
44
45#define FAT_HASH_BITS 8
46#define FAT_HASH_SIZE (1UL << FAT_HASH_BITS)
47
48/*
49 * MS-DOS file system in-core superblock data
50 */
51struct msdos_sb_info {
52 unsigned short sec_per_clus; /* sectors/cluster */
53 unsigned short cluster_bits; /* log2(cluster_size) */
54 unsigned int cluster_size; /* cluster size */
55 unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */
56 unsigned short fat_start;
57 unsigned long fat_length; /* FAT start & length (sec.) */
58 unsigned long dir_start;
59 unsigned short dir_entries; /* root dir start & entries */
60 unsigned long data_start; /* first data sector */
61 unsigned long max_cluster; /* maximum cluster number */
62 unsigned long root_cluster; /* first cluster of the root directory */
63 unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */
64 struct mutex fat_lock;
65 unsigned int prev_free; /* previously allocated cluster number */
66 unsigned int free_clusters; /* -1 if undefined */
67 unsigned int free_clus_valid; /* is free_clusters valid? */
68 struct fat_mount_options options;
69 struct nls_table *nls_disk; /* Codepage used on disk */
70 struct nls_table *nls_io; /* Charset used for input and display */
71 const void *dir_ops; /* Opaque; default directory operations */
72 int dir_per_block; /* dir entries per block */
73 int dir_per_block_bits; /* log2(dir_per_block) */
74
75 int fatent_shift;
76 struct fatent_operations *fatent_ops;
77
78 spinlock_t inode_hash_lock;
79 struct hlist_head inode_hashtable[FAT_HASH_SIZE];
80};
81
82#define FAT_CACHE_VALID 0 /* special case for valid cache */
83
84/*
85 * MS-DOS file system inode data in memory
86 */
87struct msdos_inode_info {
88 spinlock_t cache_lru_lock;
89 struct list_head cache_lru;
90 int nr_caches;
91 /* for avoiding the race between fat_free() and fat_get_cluster() */
92 unsigned int cache_valid_id;
93
94 /* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */
95 loff_t mmu_private; /* physically allocated size */
96
97 int i_start; /* first cluster or 0 */
98 int i_logstart; /* logical first cluster */
99 int i_attrs; /* unused attribute bits */
100 loff_t i_pos; /* on-disk position of directory entry or 0 */
101 struct hlist_node i_fat_hash; /* hash by i_location */
102 struct inode vfs_inode;
103};
104
105struct fat_slot_info {
106 loff_t i_pos; /* on-disk position of directory entry */
107 loff_t slot_off; /* offset for slot or de start */
108 int nr_slots; /* number of slots + 1(de) in filename */
109 struct msdos_dir_entry *de;
110 struct buffer_head *bh;
111};
112
113static inline struct msdos_sb_info *MSDOS_SB(struct super_block *sb)
114{
115 return sb->s_fs_info;
116}
117
118static inline struct msdos_inode_info *MSDOS_I(struct inode *inode)
119{
120 return container_of(inode, struct msdos_inode_info, vfs_inode);
121}
122
123/*
124 * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to
125 * save ATTR_RO instead of ->i_mode.
126 *
127 * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only
128 * bit, it's just used as flag for app.
129 */
130static inline int fat_mode_can_hold_ro(struct inode *inode)
131{
132 struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
133 mode_t mask;
134
135 if (S_ISDIR(inode->i_mode)) {
136 if (!sbi->options.rodir)
137 return 0;
138 mask = ~sbi->options.fs_dmask;
139 } else
140 mask = ~sbi->options.fs_fmask;
141
142 if (!(mask & S_IWUGO))
143 return 0;
144 return 1;
145}
146
147/* Convert attribute bits and a mask to the UNIX mode. */
148static inline mode_t fat_make_mode(struct msdos_sb_info *sbi,
149 u8 attrs, mode_t mode)
150{
151 if (attrs & ATTR_RO && !((attrs & ATTR_DIR) && !sbi->options.rodir))
152 mode &= ~S_IWUGO;
153
154 if (attrs & ATTR_DIR)
155 return (mode & ~sbi->options.fs_dmask) | S_IFDIR;
156 else
157 return (mode & ~sbi->options.fs_fmask) | S_IFREG;
158}
159
160/* Return the FAT attribute byte for this inode */
161static inline u8 fat_make_attrs(struct inode *inode)
162{
163 u8 attrs = MSDOS_I(inode)->i_attrs;
164 if (S_ISDIR(inode->i_mode))
165 attrs |= ATTR_DIR;
166 if (fat_mode_can_hold_ro(inode) && !(inode->i_mode & S_IWUGO))
167 attrs |= ATTR_RO;
168 return attrs;
169}
170
171static inline void fat_save_attrs(struct inode *inode, u8 attrs)
172{
173 if (fat_mode_can_hold_ro(inode))
174 MSDOS_I(inode)->i_attrs = attrs & ATTR_UNUSED;
175 else
176 MSDOS_I(inode)->i_attrs = attrs & (ATTR_UNUSED | ATTR_RO);
177}
178
179static inline unsigned char fat_checksum(const __u8 *name)
180{
181 unsigned char s = name[0];
182 s = (s<<7) + (s>>1) + name[1]; s = (s<<7) + (s>>1) + name[2];
183 s = (s<<7) + (s>>1) + name[3]; s = (s<<7) + (s>>1) + name[4];
184 s = (s<<7) + (s>>1) + name[5]; s = (s<<7) + (s>>1) + name[6];
185 s = (s<<7) + (s>>1) + name[7]; s = (s<<7) + (s>>1) + name[8];
186 s = (s<<7) + (s>>1) + name[9]; s = (s<<7) + (s>>1) + name[10];
187 return s;
188}
189
190static inline sector_t fat_clus_to_blknr(struct msdos_sb_info *sbi, int clus)
191{
192 return ((sector_t)clus - FAT_START_ENT) * sbi->sec_per_clus
193 + sbi->data_start;
194}
195
196static inline void fat16_towchar(wchar_t *dst, const __u8 *src, size_t len)
197{
198#ifdef __BIG_ENDIAN
199 while (len--) {
200 *dst++ = src[0] | (src[1] << 8);
201 src += 2;
202 }
203#else
204 memcpy(dst, src, len * 2);
205#endif
206}
207
208static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len)
209{
210#ifdef __BIG_ENDIAN
211 while (len--) {
212 dst[0] = *src & 0x00FF;
213 dst[1] = (*src & 0xFF00) >> 8;
214 dst += 2;
215 src++;
216 }
217#else
218 memcpy(dst, src, len * 2);
219#endif
220}
221
222/* fat/cache.c */
223extern void fat_cache_inval_inode(struct inode *inode);
224extern int fat_get_cluster(struct inode *inode, int cluster,
225 int *fclus, int *dclus);
226extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
227 unsigned long *mapped_blocks, int create);
228
229/* fat/dir.c */
230extern const struct file_operations fat_dir_operations;
231extern int fat_search_long(struct inode *inode, const unsigned char *name,
232 int name_len, struct fat_slot_info *sinfo);
233extern int fat_dir_empty(struct inode *dir);
234extern int fat_subdirs(struct inode *dir);
235extern int fat_scan(struct inode *dir, const unsigned char *name,
236 struct fat_slot_info *sinfo);
237extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
238 struct msdos_dir_entry **de, loff_t *i_pos);
239extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts);
240extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
241 struct fat_slot_info *sinfo);
242extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
243
244/* fat/fatent.c */
245struct fat_entry {
246 int entry;
247 union {
248 u8 *ent12_p[2];
249 __le16 *ent16_p;
250 __le32 *ent32_p;
251 } u;
252 int nr_bhs;
253 struct buffer_head *bhs[2];
254};
255
256static inline void fatent_init(struct fat_entry *fatent)
257{
258 fatent->nr_bhs = 0;
259 fatent->entry = 0;
260 fatent->u.ent32_p = NULL;
261 fatent->bhs[0] = fatent->bhs[1] = NULL;
262}
263
264static inline void fatent_set_entry(struct fat_entry *fatent, int entry)
265{
266 fatent->entry = entry;
267 fatent->u.ent32_p = NULL;
268}
269
270static inline void fatent_brelse(struct fat_entry *fatent)
271{
272 int i;
273 fatent->u.ent32_p = NULL;
274 for (i = 0; i < fatent->nr_bhs; i++)
275 brelse(fatent->bhs[i]);
276 fatent->nr_bhs = 0;
277 fatent->bhs[0] = fatent->bhs[1] = NULL;
278}
279
280extern void fat_ent_access_init(struct super_block *sb);
281extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent,
282 int entry);
283extern int fat_ent_write(struct inode *inode, struct fat_entry *fatent,
284 int new, int wait);
285extern int fat_alloc_clusters(struct inode *inode, int *cluster,
286 int nr_cluster);
287extern int fat_free_clusters(struct inode *inode, int cluster);
288extern int fat_count_free_clusters(struct super_block *sb);
289
290/* fat/file.c */
291extern int fat_generic_ioctl(struct inode *inode, struct file *filp,
292 unsigned int cmd, unsigned long arg);
293extern const struct file_operations fat_file_operations;
294extern const struct inode_operations fat_file_inode_operations;
295extern int fat_setattr(struct dentry * dentry, struct iattr * attr);
296extern void fat_truncate(struct inode *inode);
297extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry,
298 struct kstat *stat);
299
300/* fat/inode.c */
301extern void fat_attach(struct inode *inode, loff_t i_pos);
302extern void fat_detach(struct inode *inode);
303extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos);
304extern struct inode *fat_build_inode(struct super_block *sb,
305 struct msdos_dir_entry *de, loff_t i_pos);
306extern int fat_sync_inode(struct inode *inode);
307extern int fat_fill_super(struct super_block *sb, void *data, int silent,
308 const struct inode_operations *fs_dir_inode_ops, int isvfat);
309
310extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
311 struct inode *i2);
312/* fat/misc.c */
313extern void fat_fs_panic(struct super_block *s, const char *fmt, ...)
314 __attribute__ ((format (printf, 2, 3))) __cold;
315extern void fat_clusters_flush(struct super_block *sb);
316extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
317extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
318 __le16 __time, __le16 __date, u8 time_cs);
319extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts,
320 __le16 *time, __le16 *date, u8 *time_cs);
321extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
322
323int fat_cache_init(void);
324void fat_cache_destroy(void);
325
326/* helper for printk */
327typedef unsigned long long llu;
328
329#endif /* !_FAT_H */
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
index fb98b3d847ed..da6eea47872f 100644
--- a/fs/fat/fatent.c
+++ b/fs/fat/fatent.c
@@ -7,6 +7,7 @@
7#include <linux/fs.h> 7#include <linux/fs.h>
8#include <linux/msdos_fs.h> 8#include <linux/msdos_fs.h>
9#include <linux/blkdev.h> 9#include <linux/blkdev.h>
10#include "fat.h"
10 11
11struct fatent_operations { 12struct fatent_operations {
12 void (*ent_blocknr)(struct super_block *, int, int *, sector_t *); 13 void (*ent_blocknr)(struct super_block *, int, int *, sector_t *);
@@ -92,8 +93,7 @@ static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent,
92err_brelse: 93err_brelse:
93 brelse(bhs[0]); 94 brelse(bhs[0]);
94err: 95err:
95 printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n", 96 printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n", (llu)blocknr);
96 (unsigned long long)blocknr);
97 return -EIO; 97 return -EIO;
98} 98}
99 99
@@ -106,7 +106,7 @@ static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent,
106 fatent->bhs[0] = sb_bread(sb, blocknr); 106 fatent->bhs[0] = sb_bread(sb, blocknr);
107 if (!fatent->bhs[0]) { 107 if (!fatent->bhs[0]) {
108 printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n", 108 printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n",
109 (unsigned long long)blocknr); 109 (llu)blocknr);
110 return -EIO; 110 return -EIO;
111 } 111 }
112 fatent->nr_bhs = 1; 112 fatent->nr_bhs = 1;
@@ -316,10 +316,20 @@ static inline int fat_ent_update_ptr(struct super_block *sb,
316 /* Is this fatent's blocks including this entry? */ 316 /* Is this fatent's blocks including this entry? */
317 if (!fatent->nr_bhs || bhs[0]->b_blocknr != blocknr) 317 if (!fatent->nr_bhs || bhs[0]->b_blocknr != blocknr)
318 return 0; 318 return 0;
319 /* Does this entry need the next block? */ 319 if (sbi->fat_bits == 12) {
320 if (sbi->fat_bits == 12 && (offset + 1) >= sb->s_blocksize) { 320 if ((offset + 1) < sb->s_blocksize) {
321 if (fatent->nr_bhs != 2 || bhs[1]->b_blocknr != (blocknr + 1)) 321 /* This entry is on bhs[0]. */
322 return 0; 322 if (fatent->nr_bhs == 2) {
323 brelse(bhs[1]);
324 fatent->nr_bhs = 1;
325 }
326 } else {
327 /* This entry needs the next block. */
328 if (fatent->nr_bhs != 2)
329 return 0;
330 if (bhs[1]->b_blocknr != (blocknr + 1))
331 return 0;
332 }
323 } 333 }
324 ops->ent_set_ptr(fatent, offset); 334 ops->ent_set_ptr(fatent, offset);
325 return 1; 335 return 1;
diff --git a/fs/fat/file.c b/fs/fat/file.c
index ddde37025ca6..f06a4e525ece 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -10,13 +10,13 @@
10#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/mount.h> 11#include <linux/mount.h>
12#include <linux/time.h> 12#include <linux/time.h>
13#include <linux/msdos_fs.h>
14#include <linux/buffer_head.h> 13#include <linux/buffer_head.h>
15#include <linux/writeback.h> 14#include <linux/writeback.h>
16#include <linux/backing-dev.h> 15#include <linux/backing-dev.h>
17#include <linux/blkdev.h> 16#include <linux/blkdev.h>
18#include <linux/fsnotify.h> 17#include <linux/fsnotify.h>
19#include <linux/security.h> 18#include <linux/security.h>
19#include "fat.h"
20 20
21int fat_generic_ioctl(struct inode *inode, struct file *filp, 21int fat_generic_ioctl(struct inode *inode, struct file *filp,
22 unsigned int cmd, unsigned long arg) 22 unsigned int cmd, unsigned long arg)
@@ -29,10 +29,9 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
29 { 29 {
30 u32 attr; 30 u32 attr;
31 31
32 if (inode->i_ino == MSDOS_ROOT_INO) 32 mutex_lock(&inode->i_mutex);
33 attr = ATTR_DIR; 33 attr = fat_make_attrs(inode);
34 else 34 mutex_unlock(&inode->i_mutex);
35 attr = fat_attr(inode);
36 35
37 return put_user(attr, user_attr); 36 return put_user(attr, user_attr);
38 } 37 }
@@ -62,20 +61,16 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
62 /* Merge in ATTR_VOLUME and ATTR_DIR */ 61 /* Merge in ATTR_VOLUME and ATTR_DIR */
63 attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | 62 attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) |
64 (is_dir ? ATTR_DIR : 0); 63 (is_dir ? ATTR_DIR : 0);
65 oldattr = fat_attr(inode); 64 oldattr = fat_make_attrs(inode);
66 65
67 /* Equivalent to a chmod() */ 66 /* Equivalent to a chmod() */
68 ia.ia_valid = ATTR_MODE | ATTR_CTIME; 67 ia.ia_valid = ATTR_MODE | ATTR_CTIME;
69 ia.ia_ctime = current_fs_time(inode->i_sb); 68 ia.ia_ctime = current_fs_time(inode->i_sb);
70 if (is_dir) { 69 if (is_dir)
71 ia.ia_mode = MSDOS_MKMODE(attr, 70 ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO);
72 S_IRWXUGO & ~sbi->options.fs_dmask) 71 else {
73 | S_IFDIR; 72 ia.ia_mode = fat_make_mode(sbi, attr,
74 } else { 73 S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO));
75 ia.ia_mode = MSDOS_MKMODE(attr,
76 (S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO))
77 & ~sbi->options.fs_fmask)
78 | S_IFREG;
79 } 74 }
80 75
81 /* The root directory has no attributes */ 76 /* The root directory has no attributes */
@@ -115,7 +110,7 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
115 inode->i_flags &= S_IMMUTABLE; 110 inode->i_flags &= S_IMMUTABLE;
116 } 111 }
117 112
118 MSDOS_I(inode)->i_attrs = attr & ATTR_UNUSED; 113 fat_save_attrs(inode, attr);
119 mark_inode_dirty(inode); 114 mark_inode_dirty(inode);
120up: 115up:
121 mnt_drop_write(filp->f_path.mnt); 116 mnt_drop_write(filp->f_path.mnt);
@@ -274,7 +269,7 @@ static int fat_sanitize_mode(const struct msdos_sb_info *sbi,
274 269
275 /* 270 /*
276 * Note, the basic check is already done by a caller of 271 * Note, the basic check is already done by a caller of
277 * (attr->ia_mode & ~MSDOS_VALID_MODE) 272 * (attr->ia_mode & ~FAT_VALID_MODE)
278 */ 273 */
279 274
280 if (S_ISREG(inode->i_mode)) 275 if (S_ISREG(inode->i_mode))
@@ -287,11 +282,18 @@ static int fat_sanitize_mode(const struct msdos_sb_info *sbi,
287 /* 282 /*
288 * Of the r and x bits, all (subject to umask) must be present. Of the 283 * Of the r and x bits, all (subject to umask) must be present. Of the
289 * w bits, either all (subject to umask) or none must be present. 284 * w bits, either all (subject to umask) or none must be present.
285 *
286 * If fat_mode_can_hold_ro(inode) is false, can't change w bits.
290 */ 287 */
291 if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) 288 if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))
292 return -EPERM; 289 return -EPERM;
293 if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) 290 if (fat_mode_can_hold_ro(inode)) {
294 return -EPERM; 291 if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask)))
292 return -EPERM;
293 } else {
294 if ((perm & S_IWUGO) != (S_IWUGO & ~mask))
295 return -EPERM;
296 }
295 297
296 *mode_ptr &= S_IFMT | perm; 298 *mode_ptr &= S_IFMT | perm;
297 299
@@ -314,13 +316,15 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
314} 316}
315 317
316#define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) 318#define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)
319/* valid file mode bits */
320#define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO)
317 321
318int fat_setattr(struct dentry *dentry, struct iattr *attr) 322int fat_setattr(struct dentry *dentry, struct iattr *attr)
319{ 323{
320 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); 324 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
321 struct inode *inode = dentry->d_inode; 325 struct inode *inode = dentry->d_inode;
322 int error = 0;
323 unsigned int ia_valid; 326 unsigned int ia_valid;
327 int error;
324 328
325 /* 329 /*
326 * Expand the file. Since inode_setattr() updates ->i_size 330 * Expand the file. Since inode_setattr() updates ->i_size
@@ -356,7 +360,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
356 ((attr->ia_valid & ATTR_GID) && 360 ((attr->ia_valid & ATTR_GID) &&
357 (attr->ia_gid != sbi->options.fs_gid)) || 361 (attr->ia_gid != sbi->options.fs_gid)) ||
358 ((attr->ia_valid & ATTR_MODE) && 362 ((attr->ia_valid & ATTR_MODE) &&
359 (attr->ia_mode & ~MSDOS_VALID_MODE))) 363 (attr->ia_mode & ~FAT_VALID_MODE)))
360 error = -EPERM; 364 error = -EPERM;
361 365
362 if (error) { 366 if (error) {
@@ -374,7 +378,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
374 attr->ia_valid &= ~ATTR_MODE; 378 attr->ia_valid &= ~ATTR_MODE;
375 } 379 }
376 380
377 error = inode_setattr(inode, attr); 381 if (attr->ia_valid)
382 error = inode_setattr(inode, attr);
378out: 383out:
379 return error; 384 return error;
380} 385}
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 19eafbe3c379..bdd8fb7be2ca 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -16,7 +16,6 @@
16#include <linux/slab.h> 16#include <linux/slab.h>
17#include <linux/smp_lock.h> 17#include <linux/smp_lock.h>
18#include <linux/seq_file.h> 18#include <linux/seq_file.h>
19#include <linux/msdos_fs.h>
20#include <linux/pagemap.h> 19#include <linux/pagemap.h>
21#include <linux/mpage.h> 20#include <linux/mpage.h>
22#include <linux/buffer_head.h> 21#include <linux/buffer_head.h>
@@ -27,7 +26,9 @@
27#include <linux/uio.h> 26#include <linux/uio.h>
28#include <linux/writeback.h> 27#include <linux/writeback.h>
29#include <linux/log2.h> 28#include <linux/log2.h>
29#include <linux/hash.h>
30#include <asm/unaligned.h> 30#include <asm/unaligned.h>
31#include "fat.h"
31 32
32#ifndef CONFIG_FAT_DEFAULT_IOCHARSET 33#ifndef CONFIG_FAT_DEFAULT_IOCHARSET
33/* if user don't select VFAT, this is undefined. */ 34/* if user don't select VFAT, this is undefined. */
@@ -63,7 +64,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
63 sector_t phys; 64 sector_t phys;
64 int err, offset; 65 int err, offset;
65 66
66 err = fat_bmap(inode, iblock, &phys, &mapped_blocks); 67 err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);
67 if (err) 68 if (err)
68 return err; 69 return err;
69 if (phys) { 70 if (phys) {
@@ -93,7 +94,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
93 *max_blocks = min(mapped_blocks, *max_blocks); 94 *max_blocks = min(mapped_blocks, *max_blocks);
94 MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits; 95 MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits;
95 96
96 err = fat_bmap(inode, iblock, &phys, &mapped_blocks); 97 err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);
97 if (err) 98 if (err)
98 return err; 99 return err;
99 100
@@ -175,7 +176,7 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
175 176
176 if (rw == WRITE) { 177 if (rw == WRITE) {
177 /* 178 /*
178 * FIXME: blockdev_direct_IO() doesn't use ->prepare_write(), 179 * FIXME: blockdev_direct_IO() doesn't use ->write_begin(),
179 * so we need to update the ->mmu_private to block boundary. 180 * so we need to update the ->mmu_private to block boundary.
180 * 181 *
181 * But we must fill the remaining area or hole by nul for 182 * But we must fill the remaining area or hole by nul for
@@ -198,7 +199,14 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
198 199
199static sector_t _fat_bmap(struct address_space *mapping, sector_t block) 200static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
200{ 201{
201 return generic_block_bmap(mapping, block, fat_get_block); 202 sector_t blocknr;
203
204 /* fat_get_cluster() assumes the requested blocknr isn't truncated. */
205 mutex_lock(&mapping->host->i_mutex);
206 blocknr = generic_block_bmap(mapping, block, fat_get_block);
207 mutex_unlock(&mapping->host->i_mutex);
208
209 return blocknr;
202} 210}
203 211
204static const struct address_space_operations fat_aops = { 212static const struct address_space_operations fat_aops = {
@@ -247,25 +255,21 @@ static void fat_hash_init(struct super_block *sb)
247 INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); 255 INIT_HLIST_HEAD(&sbi->inode_hashtable[i]);
248} 256}
249 257
250static inline unsigned long fat_hash(struct super_block *sb, loff_t i_pos) 258static inline unsigned long fat_hash(loff_t i_pos)
251{ 259{
252 unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb; 260 return hash_32(i_pos, FAT_HASH_BITS);
253 tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2);
254 return tmp & FAT_HASH_MASK;
255} 261}
256 262
257void fat_attach(struct inode *inode, loff_t i_pos) 263void fat_attach(struct inode *inode, loff_t i_pos)
258{ 264{
259 struct super_block *sb = inode->i_sb; 265 struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
260 struct msdos_sb_info *sbi = MSDOS_SB(sb); 266 struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos);
261 267
262 spin_lock(&sbi->inode_hash_lock); 268 spin_lock(&sbi->inode_hash_lock);
263 MSDOS_I(inode)->i_pos = i_pos; 269 MSDOS_I(inode)->i_pos = i_pos;
264 hlist_add_head(&MSDOS_I(inode)->i_fat_hash, 270 hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head);
265 sbi->inode_hashtable + fat_hash(sb, i_pos));
266 spin_unlock(&sbi->inode_hash_lock); 271 spin_unlock(&sbi->inode_hash_lock);
267} 272}
268
269EXPORT_SYMBOL_GPL(fat_attach); 273EXPORT_SYMBOL_GPL(fat_attach);
270 274
271void fat_detach(struct inode *inode) 275void fat_detach(struct inode *inode)
@@ -276,13 +280,12 @@ void fat_detach(struct inode *inode)
276 hlist_del_init(&MSDOS_I(inode)->i_fat_hash); 280 hlist_del_init(&MSDOS_I(inode)->i_fat_hash);
277 spin_unlock(&sbi->inode_hash_lock); 281 spin_unlock(&sbi->inode_hash_lock);
278} 282}
279
280EXPORT_SYMBOL_GPL(fat_detach); 283EXPORT_SYMBOL_GPL(fat_detach);
281 284
282struct inode *fat_iget(struct super_block *sb, loff_t i_pos) 285struct inode *fat_iget(struct super_block *sb, loff_t i_pos)
283{ 286{
284 struct msdos_sb_info *sbi = MSDOS_SB(sb); 287 struct msdos_sb_info *sbi = MSDOS_SB(sb);
285 struct hlist_head *head = sbi->inode_hashtable + fat_hash(sb, i_pos); 288 struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos);
286 struct hlist_node *_p; 289 struct hlist_node *_p;
287 struct msdos_inode_info *i; 290 struct msdos_inode_info *i;
288 struct inode *inode = NULL; 291 struct inode *inode = NULL;
@@ -341,8 +344,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
341 344
342 if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) { 345 if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
343 inode->i_generation &= ~1; 346 inode->i_generation &= ~1;
344 inode->i_mode = MSDOS_MKMODE(de->attr, 347 inode->i_mode = fat_make_mode(sbi, de->attr, S_IRWXUGO);
345 S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR;
346 inode->i_op = sbi->dir_ops; 348 inode->i_op = sbi->dir_ops;
347 inode->i_fop = &fat_dir_operations; 349 inode->i_fop = &fat_dir_operations;
348 350
@@ -359,10 +361,9 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
359 inode->i_nlink = fat_subdirs(inode); 361 inode->i_nlink = fat_subdirs(inode);
360 } else { /* not a directory */ 362 } else { /* not a directory */
361 inode->i_generation |= 1; 363 inode->i_generation |= 1;
362 inode->i_mode = MSDOS_MKMODE(de->attr, 364 inode->i_mode = fat_make_mode(sbi, de->attr,
363 ((sbi->options.showexec && !is_exec(de->name + 8)) 365 ((sbi->options.showexec && !is_exec(de->name + 8))
364 ? S_IRUGO|S_IWUGO : S_IRWXUGO) 366 ? S_IRUGO|S_IWUGO : S_IRWXUGO));
365 & ~sbi->options.fs_fmask) | S_IFREG;
366 MSDOS_I(inode)->i_start = le16_to_cpu(de->start); 367 MSDOS_I(inode)->i_start = le16_to_cpu(de->start);
367 if (sbi->fat_bits == 32) 368 if (sbi->fat_bits == 32)
368 MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16); 369 MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16);
@@ -378,25 +379,16 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
378 if (sbi->options.sys_immutable) 379 if (sbi->options.sys_immutable)
379 inode->i_flags |= S_IMMUTABLE; 380 inode->i_flags |= S_IMMUTABLE;
380 } 381 }
381 MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED; 382 fat_save_attrs(inode, de->attr);
383
382 inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) 384 inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
383 & ~((loff_t)sbi->cluster_size - 1)) >> 9; 385 & ~((loff_t)sbi->cluster_size - 1)) >> 9;
384 inode->i_mtime.tv_sec = 386
385 date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date), 387 fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0);
386 sbi->options.tz_utc);
387 inode->i_mtime.tv_nsec = 0;
388 if (sbi->options.isvfat) { 388 if (sbi->options.isvfat) {
389 int secs = de->ctime_cs / 100; 389 fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime,
390 int csecs = de->ctime_cs % 100; 390 de->cdate, de->ctime_cs);
391 inode->i_ctime.tv_sec = 391 fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0);
392 date_dos2unix(le16_to_cpu(de->ctime),
393 le16_to_cpu(de->cdate),
394 sbi->options.tz_utc) + secs;
395 inode->i_ctime.tv_nsec = csecs * 10000000;
396 inode->i_atime.tv_sec =
397 date_dos2unix(0, le16_to_cpu(de->adate),
398 sbi->options.tz_utc);
399 inode->i_atime.tv_nsec = 0;
400 } else 392 } else
401 inode->i_ctime = inode->i_atime = inode->i_mtime; 393 inode->i_ctime = inode->i_atime = inode->i_mtime;
402 394
@@ -443,13 +435,8 @@ static void fat_delete_inode(struct inode *inode)
443 435
444static void fat_clear_inode(struct inode *inode) 436static void fat_clear_inode(struct inode *inode)
445{ 437{
446 struct super_block *sb = inode->i_sb;
447 struct msdos_sb_info *sbi = MSDOS_SB(sb);
448
449 spin_lock(&sbi->inode_hash_lock);
450 fat_cache_inval_inode(inode); 438 fat_cache_inval_inode(inode);
451 hlist_del_init(&MSDOS_I(inode)->i_fat_hash); 439 fat_detach(inode);
452 spin_unlock(&sbi->inode_hash_lock);
453} 440}
454 441
455static void fat_write_super(struct super_block *sb) 442static void fat_write_super(struct super_block *sb)
@@ -555,6 +542,20 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
555 return 0; 542 return 0;
556} 543}
557 544
545static inline loff_t fat_i_pos_read(struct msdos_sb_info *sbi,
546 struct inode *inode)
547{
548 loff_t i_pos;
549#if BITS_PER_LONG == 32
550 spin_lock(&sbi->inode_hash_lock);
551#endif
552 i_pos = MSDOS_I(inode)->i_pos;
553#if BITS_PER_LONG == 32
554 spin_unlock(&sbi->inode_hash_lock);
555#endif
556 return i_pos;
557}
558
558static int fat_write_inode(struct inode *inode, int wait) 559static int fat_write_inode(struct inode *inode, int wait)
559{ 560{
560 struct super_block *sb = inode->i_sb; 561 struct super_block *sb = inode->i_sb;
@@ -564,9 +565,12 @@ static int fat_write_inode(struct inode *inode, int wait)
564 loff_t i_pos; 565 loff_t i_pos;
565 int err; 566 int err;
566 567
568 if (inode->i_ino == MSDOS_ROOT_INO)
569 return 0;
570
567retry: 571retry:
568 i_pos = MSDOS_I(inode)->i_pos; 572 i_pos = fat_i_pos_read(sbi, inode);
569 if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) 573 if (!i_pos)
570 return 0; 574 return 0;
571 575
572 bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits); 576 bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits);
@@ -588,19 +592,17 @@ retry:
588 raw_entry->size = 0; 592 raw_entry->size = 0;
589 else 593 else
590 raw_entry->size = cpu_to_le32(inode->i_size); 594 raw_entry->size = cpu_to_le32(inode->i_size);
591 raw_entry->attr = fat_attr(inode); 595 raw_entry->attr = fat_make_attrs(inode);
592 raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart); 596 raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart);
593 raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); 597 raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16);
594 fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, 598 fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time,
595 &raw_entry->date, sbi->options.tz_utc); 599 &raw_entry->date, NULL);
596 if (sbi->options.isvfat) { 600 if (sbi->options.isvfat) {
597 __le16 atime; 601 __le16 atime;
598 fat_date_unix2dos(inode->i_ctime.tv_sec, &raw_entry->ctime, 602 fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime,
599 &raw_entry->cdate, sbi->options.tz_utc); 603 &raw_entry->cdate, &raw_entry->ctime_cs);
600 fat_date_unix2dos(inode->i_atime.tv_sec, &atime, 604 fat_time_unix2fat(sbi, &inode->i_atime, &atime,
601 &raw_entry->adate, sbi->options.tz_utc); 605 &raw_entry->adate, NULL);
602 raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 +
603 inode->i_ctime.tv_nsec / 10000000;
604 } 606 }
605 spin_unlock(&sbi->inode_hash_lock); 607 spin_unlock(&sbi->inode_hash_lock);
606 mark_buffer_dirty(bh); 608 mark_buffer_dirty(bh);
@@ -819,8 +821,10 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
819 seq_puts(m, ",uni_xlate"); 821 seq_puts(m, ",uni_xlate");
820 if (!opts->numtail) 822 if (!opts->numtail)
821 seq_puts(m, ",nonumtail"); 823 seq_puts(m, ",nonumtail");
824 if (opts->rodir)
825 seq_puts(m, ",rodir");
822 } 826 }
823 if (sbi->options.flush) 827 if (opts->flush)
824 seq_puts(m, ",flush"); 828 seq_puts(m, ",flush");
825 if (opts->tz_utc) 829 if (opts->tz_utc)
826 seq_puts(m, ",tz=UTC"); 830 seq_puts(m, ",tz=UTC");
@@ -836,7 +840,7 @@ enum {
836 Opt_charset, Opt_shortname_lower, Opt_shortname_win95, 840 Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
837 Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, 841 Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
838 Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, 842 Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
839 Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_err, 843 Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err,
840}; 844};
841 845
842static const match_table_t fat_tokens = { 846static const match_table_t fat_tokens = {
@@ -908,6 +912,7 @@ static const match_table_t vfat_tokens = {
908 {Opt_nonumtail_yes, "nonumtail=yes"}, 912 {Opt_nonumtail_yes, "nonumtail=yes"},
909 {Opt_nonumtail_yes, "nonumtail=true"}, 913 {Opt_nonumtail_yes, "nonumtail=true"},
910 {Opt_nonumtail_yes, "nonumtail"}, 914 {Opt_nonumtail_yes, "nonumtail"},
915 {Opt_rodir, "rodir"},
911 {Opt_err, NULL} 916 {Opt_err, NULL}
912}; 917};
913 918
@@ -927,10 +932,13 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
927 opts->allow_utime = -1; 932 opts->allow_utime = -1;
928 opts->codepage = fat_default_codepage; 933 opts->codepage = fat_default_codepage;
929 opts->iocharset = fat_default_iocharset; 934 opts->iocharset = fat_default_iocharset;
930 if (is_vfat) 935 if (is_vfat) {
931 opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95; 936 opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95;
932 else 937 opts->rodir = 0;
938 } else {
933 opts->shortname = 0; 939 opts->shortname = 0;
940 opts->rodir = 1;
941 }
934 opts->name_check = 'n'; 942 opts->name_check = 'n';
935 opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0; 943 opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0;
936 opts->utf8 = opts->unicode_xlate = 0; 944 opts->utf8 = opts->unicode_xlate = 0;
@@ -1081,6 +1089,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
1081 case Opt_nonumtail_yes: /* empty or 1 or yes or true */ 1089 case Opt_nonumtail_yes: /* empty or 1 or yes or true */
1082 opts->numtail = 0; /* negated option */ 1090 opts->numtail = 0; /* negated option */
1083 break; 1091 break;
1092 case Opt_rodir:
1093 opts->rodir = 1;
1094 break;
1084 1095
1085 /* obsolete mount options */ 1096 /* obsolete mount options */
1086 case Opt_obsolate: 1097 case Opt_obsolate:
@@ -1126,7 +1137,7 @@ static int fat_read_root(struct inode *inode)
1126 inode->i_gid = sbi->options.fs_gid; 1137 inode->i_gid = sbi->options.fs_gid;
1127 inode->i_version++; 1138 inode->i_version++;
1128 inode->i_generation = 0; 1139 inode->i_generation = 0;
1129 inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR; 1140 inode->i_mode = fat_make_mode(sbi, ATTR_DIR, S_IRWXUGO);
1130 inode->i_op = sbi->dir_ops; 1141 inode->i_op = sbi->dir_ops;
1131 inode->i_fop = &fat_dir_operations; 1142 inode->i_fop = &fat_dir_operations;
1132 if (sbi->fat_bits == 32) { 1143 if (sbi->fat_bits == 32) {
@@ -1143,7 +1154,7 @@ static int fat_read_root(struct inode *inode)
1143 MSDOS_I(inode)->i_logstart = 0; 1154 MSDOS_I(inode)->i_logstart = 0;
1144 MSDOS_I(inode)->mmu_private = inode->i_size; 1155 MSDOS_I(inode)->mmu_private = inode->i_size;
1145 1156
1146 MSDOS_I(inode)->i_attrs = ATTR_NONE; 1157 fat_save_attrs(inode, ATTR_DIR);
1147 inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0; 1158 inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0;
1148 inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0; 1159 inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0;
1149 inode->i_nlink = fat_subdirs(inode)+2; 1160 inode->i_nlink = fat_subdirs(inode)+2;
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 79fb98ad36d4..ac39ebcc1496 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -8,8 +8,8 @@
8 8
9#include <linux/module.h> 9#include <linux/module.h>
10#include <linux/fs.h> 10#include <linux/fs.h>
11#include <linux/msdos_fs.h>
12#include <linux/buffer_head.h> 11#include <linux/buffer_head.h>
12#include "fat.h"
13 13
14/* 14/*
15 * fat_fs_panic reports a severe file system problem and sets the file system 15 * fat_fs_panic reports a severe file system problem and sets the file system
@@ -124,8 +124,9 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
124 mark_inode_dirty(inode); 124 mark_inode_dirty(inode);
125 } 125 }
126 if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { 126 if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) {
127 fat_fs_panic(sb, "clusters badly computed (%d != %lu)", 127 fat_fs_panic(sb, "clusters badly computed (%d != %llu)",
128 new_fclus, inode->i_blocks >> (sbi->cluster_bits - 9)); 128 new_fclus,
129 (llu)(inode->i_blocks >> (sbi->cluster_bits - 9)));
129 fat_cache_inval_inode(inode); 130 fat_cache_inval_inode(inode);
130 } 131 }
131 inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9); 132 inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9);
@@ -135,65 +136,131 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
135 136
136extern struct timezone sys_tz; 137extern struct timezone sys_tz;
137 138
139/*
140 * The epoch of FAT timestamp is 1980.
141 * : bits : value
142 * date: 0 - 4: day (1 - 31)
143 * date: 5 - 8: month (1 - 12)
144 * date: 9 - 15: year (0 - 127) from 1980
145 * time: 0 - 4: sec (0 - 29) 2sec counts
146 * time: 5 - 10: min (0 - 59)
147 * time: 11 - 15: hour (0 - 23)
148 */
149#define SECS_PER_MIN 60
150#define SECS_PER_HOUR (60 * 60)
151#define SECS_PER_DAY (SECS_PER_HOUR * 24)
152#define UNIX_SECS_1980 315532800L
153#if BITS_PER_LONG == 64
154#define UNIX_SECS_2108 4354819200L
155#endif
156/* days between 1.1.70 and 1.1.80 (2 leap days) */
157#define DAYS_DELTA (365 * 10 + 2)
158/* 120 (2100 - 1980) isn't leap year */
159#define YEAR_2100 120
160#define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != YEAR_2100)
161
138/* Linear day numbers of the respective 1sts in non-leap years. */ 162/* Linear day numbers of the respective 1sts in non-leap years. */
139static int day_n[] = { 163static time_t days_in_year[] = {
140 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ 164 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
141 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 165 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
142}; 166};
143 167
144/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ 168/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
145int date_dos2unix(unsigned short time, unsigned short date, int tz_utc) 169void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
170 __le16 __time, __le16 __date, u8 time_cs)
146{ 171{
147 int month, year, secs; 172 u16 time = le16_to_cpu(__time), date = le16_to_cpu(__date);
173 time_t second, day, leap_day, month, year;
148 174
149 /* 175 year = date >> 9;
150 * first subtract and mask after that... Otherwise, if 176 month = max(1, (date >> 5) & 0xf);
151 * date == 0, bad things happen 177 day = max(1, date & 0x1f) - 1;
152 */ 178
153 month = ((date >> 5) - 1) & 15; 179 leap_day = (year + 3) / 4;
154 year = date >> 9; 180 if (year > YEAR_2100) /* 2100 isn't leap year */
155 secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* 181 leap_day--;
156 ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && 182 if (IS_LEAP_YEAR(year) && month > 2)
157 month < 2 ? 1 : 0)+3653); 183 leap_day++;
158 /* days since 1.1.70 plus 80's leap day */ 184
159 if (!tz_utc) 185 second = (time & 0x1f) << 1;
160 secs += sys_tz.tz_minuteswest*60; 186 second += ((time >> 5) & 0x3f) * SECS_PER_MIN;
161 return secs; 187 second += (time >> 11) * SECS_PER_HOUR;
188 second += (year * 365 + leap_day
189 + days_in_year[month] + day
190 + DAYS_DELTA) * SECS_PER_DAY;
191
192 if (!sbi->options.tz_utc)
193 second += sys_tz.tz_minuteswest * SECS_PER_MIN;
194
195 if (time_cs) {
196 ts->tv_sec = second + (time_cs / 100);
197 ts->tv_nsec = (time_cs % 100) * 10000000;
198 } else {
199 ts->tv_sec = second;
200 ts->tv_nsec = 0;
201 }
162} 202}
163 203
164/* Convert linear UNIX date to a MS-DOS time/date pair. */ 204/* Convert linear UNIX date to a FAT time/date pair. */
165void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date, int tz_utc) 205void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts,
206 __le16 *time, __le16 *date, u8 *time_cs)
166{ 207{
167 int day, year, nl_day, month; 208 time_t second = ts->tv_sec;
209 time_t day, leap_day, month, year;
168 210
169 if (!tz_utc) 211 if (!sbi->options.tz_utc)
170 unix_date -= sys_tz.tz_minuteswest*60; 212 second -= sys_tz.tz_minuteswest * SECS_PER_MIN;
171 213
172 /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ 214 /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
173 if (unix_date < 315532800) 215 if (second < UNIX_SECS_1980) {
174 unix_date = 315532800; 216 *time = 0;
175 217 *date = cpu_to_le16((0 << 9) | (1 << 5) | 1);
176 *time = cpu_to_le16((unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ 218 if (time_cs)
177 (((unix_date/3600) % 24) << 11)); 219 *time_cs = 0;
178 day = unix_date/86400-3652; 220 return;
179 year = day/365; 221 }
180 if ((year+3)/4+365*year > day) 222#if BITS_PER_LONG == 64
223 if (second >= UNIX_SECS_2108) {
224 *time = cpu_to_le16((23 << 11) | (59 << 5) | 29);
225 *date = cpu_to_le16((127 << 9) | (12 << 5) | 31);
226 if (time_cs)
227 *time_cs = 199;
228 return;
229 }
230#endif
231
232 day = second / SECS_PER_DAY - DAYS_DELTA;
233 year = day / 365;
234 leap_day = (year + 3) / 4;
235 if (year > YEAR_2100) /* 2100 isn't leap year */
236 leap_day--;
237 if (year * 365 + leap_day > day)
181 year--; 238 year--;
182 day -= (year+3)/4+365*year; 239 leap_day = (year + 3) / 4;
183 if (day == 59 && !(year & 3)) { 240 if (year > YEAR_2100) /* 2100 isn't leap year */
184 nl_day = day; 241 leap_day--;
242 day -= year * 365 + leap_day;
243
244 if (IS_LEAP_YEAR(year) && day == days_in_year[3]) {
185 month = 2; 245 month = 2;
186 } else { 246 } else {
187 nl_day = (year & 3) || day <= 59 ? day : day-1; 247 if (IS_LEAP_YEAR(year) && day > days_in_year[3])
188 for (month = 0; month < 12; month++) { 248 day--;
189 if (day_n[month] > nl_day) 249 for (month = 1; month < 12; month++) {
250 if (days_in_year[month + 1] > day)
190 break; 251 break;
191 } 252 }
192 } 253 }
193 *date = cpu_to_le16(nl_day-day_n[month-1]+1+(month << 5)+(year << 9)); 254 day -= days_in_year[month];
194}
195 255
196EXPORT_SYMBOL_GPL(fat_date_unix2dos); 256 *time = cpu_to_le16(((second / SECS_PER_HOUR) % 24) << 11
257 | ((second / SECS_PER_MIN) % 60) << 5
258 | (second % SECS_PER_MIN) >> 1);
259 *date = cpu_to_le16((year << 9) | (month << 5) | (day + 1));
260 if (time_cs)
261 *time_cs = (ts->tv_sec & 1) * 100 + ts->tv_nsec / 10000000;
262}
263EXPORT_SYMBOL_GPL(fat_time_unix2fat);
197 264
198int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) 265int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
199{ 266{
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
new file mode 100644
index 000000000000..7ba03a4acbe0
--- /dev/null
+++ b/fs/fat/namei_msdos.c
@@ -0,0 +1,706 @@
1/*
2 * linux/fs/msdos/namei.c
3 *
4 * Written 1992,1993 by Werner Almesberger
5 * Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
6 * Rewritten for constant inumbers 1999 by Al Viro
7 */
8
9#include <linux/module.h>
10#include <linux/time.h>
11#include <linux/buffer_head.h>
12#include <linux/smp_lock.h>
13#include "fat.h"
14
15/* Characters that are undesirable in an MS-DOS file name */
16static unsigned char bad_chars[] = "*?<>|\"";
17static unsigned char bad_if_strict[] = "+=,; ";
18
19/***** Formats an MS-DOS file name. Rejects invalid names. */
20static int msdos_format_name(const unsigned char *name, int len,
21 unsigned char *res, struct fat_mount_options *opts)
22 /*
23 * name is the proposed name, len is its length, res is
24 * the resulting name, opts->name_check is either (r)elaxed,
25 * (n)ormal or (s)trict, opts->dotsOK allows dots at the
26 * beginning of name (for hidden files)
27 */
28{
29 unsigned char *walk;
30 unsigned char c;
31 int space;
32
33 if (name[0] == '.') { /* dotfile because . and .. already done */
34 if (opts->dotsOK) {
35 /* Get rid of dot - test for it elsewhere */
36 name++;
37 len--;
38 } else
39 return -EINVAL;
40 }
41 /*
42 * disallow names that _really_ start with a dot
43 */
44 space = 1;
45 c = 0;
46 for (walk = res; len && walk - res < 8; walk++) {
47 c = *name++;
48 len--;
49 if (opts->name_check != 'r' && strchr(bad_chars, c))
50 return -EINVAL;
51 if (opts->name_check == 's' && strchr(bad_if_strict, c))
52 return -EINVAL;
53 if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
54 return -EINVAL;
55 if (c < ' ' || c == ':' || c == '\\')
56 return -EINVAL;
57 /*
58 * 0xE5 is legal as a first character, but we must substitute
59 * 0x05 because 0xE5 marks deleted files. Yes, DOS really
60 * does this.
61 * It seems that Microsoft hacked DOS to support non-US
62 * characters after the 0xE5 character was already in use to
63 * mark deleted files.
64 */
65 if ((res == walk) && (c == 0xE5))
66 c = 0x05;
67 if (c == '.')
68 break;
69 space = (c == ' ');
70 *walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c - 32 : c;
71 }
72 if (space)
73 return -EINVAL;
74 if (opts->name_check == 's' && len && c != '.') {
75 c = *name++;
76 len--;
77 if (c != '.')
78 return -EINVAL;
79 }
80 while (c != '.' && len--)
81 c = *name++;
82 if (c == '.') {
83 while (walk - res < 8)
84 *walk++ = ' ';
85 while (len > 0 && walk - res < MSDOS_NAME) {
86 c = *name++;
87 len--;
88 if (opts->name_check != 'r' && strchr(bad_chars, c))
89 return -EINVAL;
90 if (opts->name_check == 's' &&
91 strchr(bad_if_strict, c))
92 return -EINVAL;
93 if (c < ' ' || c == ':' || c == '\\')
94 return -EINVAL;
95 if (c == '.') {
96 if (opts->name_check == 's')
97 return -EINVAL;
98 break;
99 }
100 if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
101 return -EINVAL;
102 space = c == ' ';
103 if (!opts->nocase && c >= 'a' && c <= 'z')
104 *walk++ = c - 32;
105 else
106 *walk++ = c;
107 }
108 if (space)
109 return -EINVAL;
110 if (opts->name_check == 's' && len)
111 return -EINVAL;
112 }
113 while (walk - res < MSDOS_NAME)
114 *walk++ = ' ';
115
116 return 0;
117}
118
119/***** Locates a directory entry. Uses unformatted name. */
120static int msdos_find(struct inode *dir, const unsigned char *name, int len,
121 struct fat_slot_info *sinfo)
122{
123 struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
124 unsigned char msdos_name[MSDOS_NAME];
125 int err;
126
127 err = msdos_format_name(name, len, msdos_name, &sbi->options);
128 if (err)
129 return -ENOENT;
130
131 err = fat_scan(dir, msdos_name, sinfo);
132 if (!err && sbi->options.dotsOK) {
133 if (name[0] == '.') {
134 if (!(sinfo->de->attr & ATTR_HIDDEN))
135 err = -ENOENT;
136 } else {
137 if (sinfo->de->attr & ATTR_HIDDEN)
138 err = -ENOENT;
139 }
140 if (err)
141 brelse(sinfo->bh);
142 }
143 return err;
144}
145
146/*
147 * Compute the hash for the msdos name corresponding to the dentry.
148 * Note: if the name is invalid, we leave the hash code unchanged so
149 * that the existing dentry can be used. The msdos fs routines will
150 * return ENOENT or EINVAL as appropriate.
151 */
152static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
153{
154 struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
155 unsigned char msdos_name[MSDOS_NAME];
156 int error;
157
158 error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
159 if (!error)
160 qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
161 return 0;
162}
163
164/*
165 * Compare two msdos names. If either of the names are invalid,
166 * we fall back to doing the standard name comparison.
167 */
168static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
169{
170 struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
171 unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
172 int error;
173
174 error = msdos_format_name(a->name, a->len, a_msdos_name, options);
175 if (error)
176 goto old_compare;
177 error = msdos_format_name(b->name, b->len, b_msdos_name, options);
178 if (error)
179 goto old_compare;
180 error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
181out:
182 return error;
183
184old_compare:
185 error = 1;
186 if (a->len == b->len)
187 error = memcmp(a->name, b->name, a->len);
188 goto out;
189}
190
191static struct dentry_operations msdos_dentry_operations = {
192 .d_hash = msdos_hash,
193 .d_compare = msdos_cmp,
194};
195
196/*
197 * AV. Wrappers for FAT sb operations. Is it wise?
198 */
199
200/***** Get inode using directory and name */
201static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
202 struct nameidata *nd)
203{
204 struct super_block *sb = dir->i_sb;
205 struct fat_slot_info sinfo;
206 struct inode *inode;
207 int err;
208
209 lock_super(sb);
210
211 err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
212 if (err) {
213 if (err == -ENOENT) {
214 inode = NULL;
215 goto out;
216 }
217 goto error;
218 }
219
220 inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
221 brelse(sinfo.bh);
222 if (IS_ERR(inode)) {
223 err = PTR_ERR(inode);
224 goto error;
225 }
226out:
227 unlock_super(sb);
228 dentry->d_op = &msdos_dentry_operations;
229 dentry = d_splice_alias(inode, dentry);
230 if (dentry)
231 dentry->d_op = &msdos_dentry_operations;
232 return dentry;
233
234error:
235 unlock_super(sb);
236 return ERR_PTR(err);
237}
238
239/***** Creates a directory entry (name is already formatted). */
240static int msdos_add_entry(struct inode *dir, const unsigned char *name,
241 int is_dir, int is_hid, int cluster,
242 struct timespec *ts, struct fat_slot_info *sinfo)
243{
244 struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
245 struct msdos_dir_entry de;
246 __le16 time, date;
247 int err;
248
249 memcpy(de.name, name, MSDOS_NAME);
250 de.attr = is_dir ? ATTR_DIR : ATTR_ARCH;
251 if (is_hid)
252 de.attr |= ATTR_HIDDEN;
253 de.lcase = 0;
254 fat_time_unix2fat(sbi, ts, &time, &date, NULL);
255 de.cdate = de.adate = 0;
256 de.ctime = 0;
257 de.ctime_cs = 0;
258 de.time = time;
259 de.date = date;
260 de.start = cpu_to_le16(cluster);
261 de.starthi = cpu_to_le16(cluster >> 16);
262 de.size = 0;
263
264 err = fat_add_entries(dir, &de, 1, sinfo);
265 if (err)
266 return err;
267
268 dir->i_ctime = dir->i_mtime = *ts;
269 if (IS_DIRSYNC(dir))
270 (void)fat_sync_inode(dir);
271 else
272 mark_inode_dirty(dir);
273
274 return 0;
275}
276
277/***** Create a file */
278static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
279 struct nameidata *nd)
280{
281 struct super_block *sb = dir->i_sb;
282 struct inode *inode = NULL;
283 struct fat_slot_info sinfo;
284 struct timespec ts;
285 unsigned char msdos_name[MSDOS_NAME];
286 int err, is_hid;
287
288 lock_super(sb);
289
290 err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
291 msdos_name, &MSDOS_SB(sb)->options);
292 if (err)
293 goto out;
294 is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
295 /* Have to do it due to foo vs. .foo conflicts */
296 if (!fat_scan(dir, msdos_name, &sinfo)) {
297 brelse(sinfo.bh);
298 err = -EINVAL;
299 goto out;
300 }
301
302 ts = CURRENT_TIME_SEC;
303 err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo);
304 if (err)
305 goto out;
306 inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
307 brelse(sinfo.bh);
308 if (IS_ERR(inode)) {
309 err = PTR_ERR(inode);
310 goto out;
311 }
312 inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
313 /* timestamp is already written, so mark_inode_dirty() is unneeded. */
314
315 d_instantiate(dentry, inode);
316out:
317 unlock_super(sb);
318 if (!err)
319 err = fat_flush_inodes(sb, dir, inode);
320 return err;
321}
322
323/***** Remove a directory */
324static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
325{
326 struct super_block *sb = dir->i_sb;
327 struct inode *inode = dentry->d_inode;
328 struct fat_slot_info sinfo;
329 int err;
330
331 lock_super(sb);
332 /*
333 * Check whether the directory is not in use, then check
334 * whether it is empty.
335 */
336 err = fat_dir_empty(inode);
337 if (err)
338 goto out;
339 err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
340 if (err)
341 goto out;
342
343 err = fat_remove_entries(dir, &sinfo); /* and releases bh */
344 if (err)
345 goto out;
346 drop_nlink(dir);
347
348 clear_nlink(inode);
349 inode->i_ctime = CURRENT_TIME_SEC;
350 fat_detach(inode);
351out:
352 unlock_super(sb);
353 if (!err)
354 err = fat_flush_inodes(sb, dir, inode);
355
356 return err;
357}
358
359/***** Make a directory */
360static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
361{
362 struct super_block *sb = dir->i_sb;
363 struct fat_slot_info sinfo;
364 struct inode *inode;
365 unsigned char msdos_name[MSDOS_NAME];
366 struct timespec ts;
367 int err, is_hid, cluster;
368
369 lock_super(sb);
370
371 err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
372 msdos_name, &MSDOS_SB(sb)->options);
373 if (err)
374 goto out;
375 is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
376 /* foo vs .foo situation */
377 if (!fat_scan(dir, msdos_name, &sinfo)) {
378 brelse(sinfo.bh);
379 err = -EINVAL;
380 goto out;
381 }
382
383 ts = CURRENT_TIME_SEC;
384 cluster = fat_alloc_new_dir(dir, &ts);
385 if (cluster < 0) {
386 err = cluster;
387 goto out;
388 }
389 err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
390 if (err)
391 goto out_free;
392 inc_nlink(dir);
393
394 inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
395 brelse(sinfo.bh);
396 if (IS_ERR(inode)) {
397 err = PTR_ERR(inode);
398 /* the directory was completed, just return a error */
399 goto out;
400 }
401 inode->i_nlink = 2;
402 inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
403 /* timestamp is already written, so mark_inode_dirty() is unneeded. */
404
405 d_instantiate(dentry, inode);
406
407 unlock_super(sb);
408 fat_flush_inodes(sb, dir, inode);
409 return 0;
410
411out_free:
412 fat_free_clusters(dir, cluster);
413out:
414 unlock_super(sb);
415 return err;
416}
417
418/***** Unlink a file */
419static int msdos_unlink(struct inode *dir, struct dentry *dentry)
420{
421 struct inode *inode = dentry->d_inode;
422 struct super_block *sb= inode->i_sb;
423 struct fat_slot_info sinfo;
424 int err;
425
426 lock_super(sb);
427 err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
428 if (err)
429 goto out;
430
431 err = fat_remove_entries(dir, &sinfo); /* and releases bh */
432 if (err)
433 goto out;
434 clear_nlink(inode);
435 inode->i_ctime = CURRENT_TIME_SEC;
436 fat_detach(inode);
437out:
438 unlock_super(sb);
439 if (!err)
440 err = fat_flush_inodes(sb, dir, inode);
441
442 return err;
443}
444
445static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
446 struct dentry *old_dentry,
447 struct inode *new_dir, unsigned char *new_name,
448 struct dentry *new_dentry, int is_hid)
449{
450 struct buffer_head *dotdot_bh;
451 struct msdos_dir_entry *dotdot_de;
452 struct inode *old_inode, *new_inode;
453 struct fat_slot_info old_sinfo, sinfo;
454 struct timespec ts;
455 loff_t dotdot_i_pos, new_i_pos;
456 int err, old_attrs, is_dir, update_dotdot, corrupt = 0;
457
458 old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
459 old_inode = old_dentry->d_inode;
460 new_inode = new_dentry->d_inode;
461
462 err = fat_scan(old_dir, old_name, &old_sinfo);
463 if (err) {
464 err = -EIO;
465 goto out;
466 }
467
468 is_dir = S_ISDIR(old_inode->i_mode);
469 update_dotdot = (is_dir && old_dir != new_dir);
470 if (update_dotdot) {
471 if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
472 &dotdot_i_pos) < 0) {
473 err = -EIO;
474 goto out;
475 }
476 }
477
478 old_attrs = MSDOS_I(old_inode)->i_attrs;
479 err = fat_scan(new_dir, new_name, &sinfo);
480 if (!err) {
481 if (!new_inode) {
482 /* "foo" -> ".foo" case. just change the ATTR_HIDDEN */
483 if (sinfo.de != old_sinfo.de) {
484 err = -EINVAL;
485 goto out;
486 }
487 if (is_hid)
488 MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
489 else
490 MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
491 if (IS_DIRSYNC(old_dir)) {
492 err = fat_sync_inode(old_inode);
493 if (err) {
494 MSDOS_I(old_inode)->i_attrs = old_attrs;
495 goto out;
496 }
497 } else
498 mark_inode_dirty(old_inode);
499
500 old_dir->i_version++;
501 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
502 if (IS_DIRSYNC(old_dir))
503 (void)fat_sync_inode(old_dir);
504 else
505 mark_inode_dirty(old_dir);
506 goto out;
507 }
508 }
509
510 ts = CURRENT_TIME_SEC;
511 if (new_inode) {
512 if (err)
513 goto out;
514 if (is_dir) {
515 err = fat_dir_empty(new_inode);
516 if (err)
517 goto out;
518 }
519 new_i_pos = MSDOS_I(new_inode)->i_pos;
520 fat_detach(new_inode);
521 } else {
522 err = msdos_add_entry(new_dir, new_name, is_dir, is_hid, 0,
523 &ts, &sinfo);
524 if (err)
525 goto out;
526 new_i_pos = sinfo.i_pos;
527 }
528 new_dir->i_version++;
529
530 fat_detach(old_inode);
531 fat_attach(old_inode, new_i_pos);
532 if (is_hid)
533 MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
534 else
535 MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
536 if (IS_DIRSYNC(new_dir)) {
537 err = fat_sync_inode(old_inode);
538 if (err)
539 goto error_inode;
540 } else
541 mark_inode_dirty(old_inode);
542
543 if (update_dotdot) {
544 int start = MSDOS_I(new_dir)->i_logstart;
545 dotdot_de->start = cpu_to_le16(start);
546 dotdot_de->starthi = cpu_to_le16(start >> 16);
547 mark_buffer_dirty(dotdot_bh);
548 if (IS_DIRSYNC(new_dir)) {
549 err = sync_dirty_buffer(dotdot_bh);
550 if (err)
551 goto error_dotdot;
552 }
553 drop_nlink(old_dir);
554 if (!new_inode)
555 inc_nlink(new_dir);
556 }
557
558 err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
559 old_sinfo.bh = NULL;
560 if (err)
561 goto error_dotdot;
562 old_dir->i_version++;
563 old_dir->i_ctime = old_dir->i_mtime = ts;
564 if (IS_DIRSYNC(old_dir))
565 (void)fat_sync_inode(old_dir);
566 else
567 mark_inode_dirty(old_dir);
568
569 if (new_inode) {
570 drop_nlink(new_inode);
571 if (is_dir)
572 drop_nlink(new_inode);
573 new_inode->i_ctime = ts;
574 }
575out:
576 brelse(sinfo.bh);
577 brelse(dotdot_bh);
578 brelse(old_sinfo.bh);
579 return err;
580
581error_dotdot:
582 /* data cluster is shared, serious corruption */
583 corrupt = 1;
584
585 if (update_dotdot) {
586 int start = MSDOS_I(old_dir)->i_logstart;
587 dotdot_de->start = cpu_to_le16(start);
588 dotdot_de->starthi = cpu_to_le16(start >> 16);
589 mark_buffer_dirty(dotdot_bh);
590 corrupt |= sync_dirty_buffer(dotdot_bh);
591 }
592error_inode:
593 fat_detach(old_inode);
594 fat_attach(old_inode, old_sinfo.i_pos);
595 MSDOS_I(old_inode)->i_attrs = old_attrs;
596 if (new_inode) {
597 fat_attach(new_inode, new_i_pos);
598 if (corrupt)
599 corrupt |= fat_sync_inode(new_inode);
600 } else {
601 /*
602 * If new entry was not sharing the data cluster, it
603 * shouldn't be serious corruption.
604 */
605 int err2 = fat_remove_entries(new_dir, &sinfo);
606 if (corrupt)
607 corrupt |= err2;
608 sinfo.bh = NULL;
609 }
610 if (corrupt < 0) {
611 fat_fs_panic(new_dir->i_sb,
612 "%s: Filesystem corrupted (i_pos %lld)",
613 __func__, sinfo.i_pos);
614 }
615 goto out;
616}
617
618/***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
619static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
620 struct inode *new_dir, struct dentry *new_dentry)
621{
622 struct super_block *sb = old_dir->i_sb;
623 unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
624 int err, is_hid;
625
626 lock_super(sb);
627
628 err = msdos_format_name(old_dentry->d_name.name,
629 old_dentry->d_name.len, old_msdos_name,
630 &MSDOS_SB(old_dir->i_sb)->options);
631 if (err)
632 goto out;
633 err = msdos_format_name(new_dentry->d_name.name,
634 new_dentry->d_name.len, new_msdos_name,
635 &MSDOS_SB(new_dir->i_sb)->options);
636 if (err)
637 goto out;
638
639 is_hid =
640 (new_dentry->d_name.name[0] == '.') && (new_msdos_name[0] != '.');
641
642 err = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
643 new_dir, new_msdos_name, new_dentry, is_hid);
644out:
645 unlock_super(sb);
646 if (!err)
647 err = fat_flush_inodes(sb, old_dir, new_dir);
648 return err;
649}
650
651static const struct inode_operations msdos_dir_inode_operations = {
652 .create = msdos_create,
653 .lookup = msdos_lookup,
654 .unlink = msdos_unlink,
655 .mkdir = msdos_mkdir,
656 .rmdir = msdos_rmdir,
657 .rename = msdos_rename,
658 .setattr = fat_setattr,
659 .getattr = fat_getattr,
660};
661
662static int msdos_fill_super(struct super_block *sb, void *data, int silent)
663{
664 int res;
665
666 res = fat_fill_super(sb, data, silent, &msdos_dir_inode_operations, 0);
667 if (res)
668 return res;
669
670 sb->s_flags |= MS_NOATIME;
671 sb->s_root->d_op = &msdos_dentry_operations;
672 return 0;
673}
674
675static int msdos_get_sb(struct file_system_type *fs_type,
676 int flags, const char *dev_name,
677 void *data, struct vfsmount *mnt)
678{
679 return get_sb_bdev(fs_type, flags, dev_name, data, msdos_fill_super,
680 mnt);
681}
682
683static struct file_system_type msdos_fs_type = {
684 .owner = THIS_MODULE,
685 .name = "msdos",
686 .get_sb = msdos_get_sb,
687 .kill_sb = kill_block_super,
688 .fs_flags = FS_REQUIRES_DEV,
689};
690
691static int __init init_msdos_fs(void)
692{
693 return register_filesystem(&msdos_fs_type);
694}
695
696static void __exit exit_msdos_fs(void)
697{
698 unregister_filesystem(&msdos_fs_type);
699}
700
701MODULE_LICENSE("GPL");
702MODULE_AUTHOR("Werner Almesberger");
703MODULE_DESCRIPTION("MS-DOS filesystem support");
704
705module_init(init_msdos_fs)
706module_exit(exit_msdos_fs)
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
new file mode 100644
index 000000000000..bf326d4356a3
--- /dev/null
+++ b/fs/fat/namei_vfat.c
@@ -0,0 +1,1098 @@
1/*
2 * linux/fs/vfat/namei.c
3 *
4 * Written 1992,1993 by Werner Almesberger
5 *
6 * Windows95/Windows NT compatible extended MSDOS filesystem
7 * by Gordon Chaffee Copyright (C) 1995. Send bug reports for the
8 * VFAT filesystem to <chaffee@cs.berkeley.edu>. Specify
9 * what file operation caused you trouble and if you can duplicate
10 * the problem, send a script that demonstrates it.
11 *
12 * Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de>
13 *
14 * Support Multibyte characters and cleanup by
15 * OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
16 */
17
18#include <linux/module.h>
19#include <linux/jiffies.h>
20#include <linux/ctype.h>
21#include <linux/slab.h>
22#include <linux/smp_lock.h>
23#include <linux/buffer_head.h>
24#include <linux/namei.h>
25#include "fat.h"
26
27/*
28 * If new entry was created in the parent, it could create the 8.3
29 * alias (the shortname of logname). So, the parent may have the
30 * negative-dentry which matches the created 8.3 alias.
31 *
32 * If it happened, the negative dentry isn't actually negative
33 * anymore. So, drop it.
34 */
35static int vfat_revalidate_shortname(struct dentry *dentry)
36{
37 int ret = 1;
38 spin_lock(&dentry->d_lock);
39 if (dentry->d_time != dentry->d_parent->d_inode->i_version)
40 ret = 0;
41 spin_unlock(&dentry->d_lock);
42 return ret;
43}
44
45static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
46{
47 /* This is not negative dentry. Always valid. */
48 if (dentry->d_inode)
49 return 1;
50 return vfat_revalidate_shortname(dentry);
51}
52
53static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
54{
55 /*
56 * This is not negative dentry. Always valid.
57 *
58 * Note, rename() to existing directory entry will have ->d_inode,
59 * and will use existing name which isn't specified name by user.
60 *
61 * We may be able to drop this positive dentry here. But dropping
62 * positive dentry isn't good idea. So it's unsupported like
63 * rename("filename", "FILENAME") for now.
64 */
65 if (dentry->d_inode)
66 return 1;
67
68 /*
69 * This may be nfsd (or something), anyway, we can't see the
70 * intent of this. So, since this can be for creation, drop it.
71 */
72 if (!nd)
73 return 0;
74
75 /*
76 * Drop the negative dentry, in order to make sure to use the
77 * case sensitive name which is specified by user if this is
78 * for creation.
79 */
80 if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) {
81 if (nd->flags & LOOKUP_CREATE)
82 return 0;
83 }
84
85 return vfat_revalidate_shortname(dentry);
86}
87
88/* returns the length of a struct qstr, ignoring trailing dots */
89static unsigned int vfat_striptail_len(struct qstr *qstr)
90{
91 unsigned int len = qstr->len;
92
93 while (len && qstr->name[len - 1] == '.')
94 len--;
95 return len;
96}
97
98/*
99 * Compute the hash for the vfat name corresponding to the dentry.
100 * Note: if the name is invalid, we leave the hash code unchanged so
101 * that the existing dentry can be used. The vfat fs routines will
102 * return ENOENT or EINVAL as appropriate.
103 */
104static int vfat_hash(struct dentry *dentry, struct qstr *qstr)
105{
106 qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr));
107 return 0;
108}
109
110/*
111 * Compute the hash for the vfat name corresponding to the dentry.
112 * Note: if the name is invalid, we leave the hash code unchanged so
113 * that the existing dentry can be used. The vfat fs routines will
114 * return ENOENT or EINVAL as appropriate.
115 */
116static int vfat_hashi(struct dentry *dentry, struct qstr *qstr)
117{
118 struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io;
119 const unsigned char *name;
120 unsigned int len;
121 unsigned long hash;
122
123 name = qstr->name;
124 len = vfat_striptail_len(qstr);
125
126 hash = init_name_hash();
127 while (len--)
128 hash = partial_name_hash(nls_tolower(t, *name++), hash);
129 qstr->hash = end_name_hash(hash);
130
131 return 0;
132}
133
134/*
135 * Case insensitive compare of two vfat names.
136 */
137static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b)
138{
139 struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io;
140 unsigned int alen, blen;
141
142 /* A filename cannot end in '.' or we treat it like it has none */
143 alen = vfat_striptail_len(a);
144 blen = vfat_striptail_len(b);
145 if (alen == blen) {
146 if (nls_strnicmp(t, a->name, b->name, alen) == 0)
147 return 0;
148 }
149 return 1;
150}
151
152/*
153 * Case sensitive compare of two vfat names.
154 */
155static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
156{
157 unsigned int alen, blen;
158
159 /* A filename cannot end in '.' or we treat it like it has none */
160 alen = vfat_striptail_len(a);
161 blen = vfat_striptail_len(b);
162 if (alen == blen) {
163 if (strncmp(a->name, b->name, alen) == 0)
164 return 0;
165 }
166 return 1;
167}
168
169static struct dentry_operations vfat_ci_dentry_ops = {
170 .d_revalidate = vfat_revalidate_ci,
171 .d_hash = vfat_hashi,
172 .d_compare = vfat_cmpi,
173};
174
175static struct dentry_operations vfat_dentry_ops = {
176 .d_revalidate = vfat_revalidate,
177 .d_hash = vfat_hash,
178 .d_compare = vfat_cmp,
179};
180
181/* Characters that are undesirable in an MS-DOS file name */
182
183static inline wchar_t vfat_bad_char(wchar_t w)
184{
185 return (w < 0x0020)
186 || (w == '*') || (w == '?') || (w == '<') || (w == '>')
187 || (w == '|') || (w == '"') || (w == ':') || (w == '/')
188 || (w == '\\');
189}
190
191static inline wchar_t vfat_replace_char(wchar_t w)
192{
193 return (w == '[') || (w == ']') || (w == ';') || (w == ',')
194 || (w == '+') || (w == '=');
195}
196
197static wchar_t vfat_skip_char(wchar_t w)
198{
199 return (w == '.') || (w == ' ');
200}
201
202static inline int vfat_is_used_badchars(const wchar_t *s, int len)
203{
204 int i;
205
206 for (i = 0; i < len; i++)
207 if (vfat_bad_char(s[i]))
208 return -EINVAL;
209
210 if (s[i - 1] == ' ') /* last character cannot be space */
211 return -EINVAL;
212
213 return 0;
214}
215
216static int vfat_find_form(struct inode *dir, unsigned char *name)
217{
218 struct fat_slot_info sinfo;
219 int err = fat_scan(dir, name, &sinfo);
220 if (err)
221 return -ENOENT;
222 brelse(sinfo.bh);
223 return 0;
224}
225
226/*
227 * 1) Valid characters for the 8.3 format alias are any combination of
228 * letters, uppercase alphabets, digits, any of the
229 * following special characters:
230 * $ % ' ` - @ { } ~ ! # ( ) & _ ^
231 * In this case Longfilename is not stored in disk.
232 *
233 * WinNT's Extension:
234 * File name and extension name is contain uppercase/lowercase
235 * only. And it is expressed by CASE_LOWER_BASE and CASE_LOWER_EXT.
236 *
237 * 2) File name is 8.3 format, but it contain the uppercase and
238 * lowercase char, muliti bytes char, etc. In this case numtail is not
239 * added, but Longfilename is stored.
240 *
241 * 3) When the one except for the above, or the following special
242 * character are contained:
243 * . [ ] ; , + =
244 * numtail is added, and Longfilename must be stored in disk .
245 */
246struct shortname_info {
247 unsigned char lower:1,
248 upper:1,
249 valid:1;
250};
251#define INIT_SHORTNAME_INFO(x) do { \
252 (x)->lower = 1; \
253 (x)->upper = 1; \
254 (x)->valid = 1; \
255} while (0)
256
257static inline int to_shortname_char(struct nls_table *nls,
258 unsigned char *buf, int buf_size,
259 wchar_t *src, struct shortname_info *info)
260{
261 int len;
262
263 if (vfat_skip_char(*src)) {
264 info->valid = 0;
265 return 0;
266 }
267 if (vfat_replace_char(*src)) {
268 info->valid = 0;
269 buf[0] = '_';
270 return 1;
271 }
272
273 len = nls->uni2char(*src, buf, buf_size);
274 if (len <= 0) {
275 info->valid = 0;
276 buf[0] = '_';
277 len = 1;
278 } else if (len == 1) {
279 unsigned char prev = buf[0];
280
281 if (buf[0] >= 0x7F) {
282 info->lower = 0;
283 info->upper = 0;
284 }
285
286 buf[0] = nls_toupper(nls, buf[0]);
287 if (isalpha(buf[0])) {
288 if (buf[0] == prev)
289 info->lower = 0;
290 else
291 info->upper = 0;
292 }
293 } else {
294 info->lower = 0;
295 info->upper = 0;
296 }
297
298 return len;
299}
300
301/*
302 * Given a valid longname, create a unique shortname. Make sure the
303 * shortname does not exist
304 * Returns negative number on error, 0 for a normal
305 * return, and 1 for valid shortname
306 */
307static int vfat_create_shortname(struct inode *dir, struct nls_table *nls,
308 wchar_t *uname, int ulen,
309 unsigned char *name_res, unsigned char *lcase)
310{
311 struct fat_mount_options *opts = &MSDOS_SB(dir->i_sb)->options;
312 wchar_t *ip, *ext_start, *end, *name_start;
313 unsigned char base[9], ext[4], buf[8], *p;
314 unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
315 int chl, chi;
316 int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen;
317 int is_shortname;
318 struct shortname_info base_info, ext_info;
319
320 is_shortname = 1;
321 INIT_SHORTNAME_INFO(&base_info);
322 INIT_SHORTNAME_INFO(&ext_info);
323
324 /* Now, we need to create a shortname from the long name */
325 ext_start = end = &uname[ulen];
326 while (--ext_start >= uname) {
327 if (*ext_start == 0x002E) { /* is `.' */
328 if (ext_start == end - 1) {
329 sz = ulen;
330 ext_start = NULL;
331 }
332 break;
333 }
334 }
335
336 if (ext_start == uname - 1) {
337 sz = ulen;
338 ext_start = NULL;
339 } else if (ext_start) {
340 /*
341 * Names which start with a dot could be just
342 * an extension eg. "...test". In this case Win95
343 * uses the extension as the name and sets no extension.
344 */
345 name_start = &uname[0];
346 while (name_start < ext_start) {
347 if (!vfat_skip_char(*name_start))
348 break;
349 name_start++;
350 }
351 if (name_start != ext_start) {
352 sz = ext_start - uname;
353 ext_start++;
354 } else {
355 sz = ulen;
356 ext_start = NULL;
357 }
358 }
359
360 numtail_baselen = 6;
361 numtail2_baselen = 2;
362 for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++) {
363 chl = to_shortname_char(nls, charbuf, sizeof(charbuf),
364 ip, &base_info);
365 if (chl == 0)
366 continue;
367
368 if (baselen < 2 && (baselen + chl) > 2)
369 numtail2_baselen = baselen;
370 if (baselen < 6 && (baselen + chl) > 6)
371 numtail_baselen = baselen;
372 for (chi = 0; chi < chl; chi++) {
373 *p++ = charbuf[chi];
374 baselen++;
375 if (baselen >= 8)
376 break;
377 }
378 if (baselen >= 8) {
379 if ((chi < chl - 1) || (ip + 1) - uname < sz)
380 is_shortname = 0;
381 break;
382 }
383 }
384 if (baselen == 0) {
385 return -EINVAL;
386 }
387
388 extlen = 0;
389 if (ext_start) {
390 for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
391 chl = to_shortname_char(nls, charbuf, sizeof(charbuf),
392 ip, &ext_info);
393 if (chl == 0)
394 continue;
395
396 if ((extlen + chl) > 3) {
397 is_shortname = 0;
398 break;
399 }
400 for (chi = 0; chi < chl; chi++) {
401 *p++ = charbuf[chi];
402 extlen++;
403 }
404 if (extlen >= 3) {
405 if (ip + 1 != end)
406 is_shortname = 0;
407 break;
408 }
409 }
410 }
411 ext[extlen] = '\0';
412 base[baselen] = '\0';
413
414 /* Yes, it can happen. ".\xe5" would do it. */
415 if (base[0] == DELETED_FLAG)
416 base[0] = 0x05;
417
418 /* OK, at this point we know that base is not longer than 8 symbols,
419 * ext is not longer than 3, base is nonempty, both don't contain
420 * any bad symbols (lowercase transformed to uppercase).
421 */
422
423 memset(name_res, ' ', MSDOS_NAME);
424 memcpy(name_res, base, baselen);
425 memcpy(name_res + 8, ext, extlen);
426 *lcase = 0;
427 if (is_shortname && base_info.valid && ext_info.valid) {
428 if (vfat_find_form(dir, name_res) == 0)
429 return -EEXIST;
430
431 if (opts->shortname & VFAT_SFN_CREATE_WIN95) {
432 return (base_info.upper && ext_info.upper);
433 } else if (opts->shortname & VFAT_SFN_CREATE_WINNT) {
434 if ((base_info.upper || base_info.lower) &&
435 (ext_info.upper || ext_info.lower)) {
436 if (!base_info.upper && base_info.lower)
437 *lcase |= CASE_LOWER_BASE;
438 if (!ext_info.upper && ext_info.lower)
439 *lcase |= CASE_LOWER_EXT;
440 return 1;
441 }
442 return 0;
443 } else {
444 BUG();
445 }
446 }
447
448 if (opts->numtail == 0)
449 if (vfat_find_form(dir, name_res) < 0)
450 return 0;
451
452 /*
453 * Try to find a unique extension. This used to
454 * iterate through all possibilities sequentially,
455 * but that gave extremely bad performance. Windows
456 * only tries a few cases before using random
457 * values for part of the base.
458 */
459
460 if (baselen > 6) {
461 baselen = numtail_baselen;
462 name_res[7] = ' ';
463 }
464 name_res[baselen] = '~';
465 for (i = 1; i < 10; i++) {
466 name_res[baselen + 1] = i + '0';
467 if (vfat_find_form(dir, name_res) < 0)
468 return 0;
469 }
470
471 i = jiffies & 0xffff;
472 sz = (jiffies >> 16) & 0x7;
473 if (baselen > 2) {
474 baselen = numtail2_baselen;
475 name_res[7] = ' ';
476 }
477 name_res[baselen + 4] = '~';
478 name_res[baselen + 5] = '1' + sz;
479 while (1) {
480 sprintf(buf, "%04X", i);
481 memcpy(&name_res[baselen], buf, 4);
482 if (vfat_find_form(dir, name_res) < 0)
483 break;
484 i -= 11;
485 }
486 return 0;
487}
488
489/* Translate a string, including coded sequences into Unicode */
490static int
491xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
492 int *longlen, int *outlen, int escape, int utf8,
493 struct nls_table *nls)
494{
495 const unsigned char *ip;
496 unsigned char nc;
497 unsigned char *op;
498 unsigned int ec;
499 int i, k, fill;
500 int charlen;
501
502 if (utf8) {
503 int name_len = strlen(name);
504
505 *outlen = utf8_mbstowcs((wchar_t *)outname, name, PATH_MAX);
506
507 /*
508 * We stripped '.'s before and set len appropriately,
509 * but utf8_mbstowcs doesn't care about len
510 */
511 *outlen -= (name_len - len);
512
513 if (*outlen > 255)
514 return -ENAMETOOLONG;
515
516 op = &outname[*outlen * sizeof(wchar_t)];
517 } else {
518 if (nls) {
519 for (i = 0, ip = name, op = outname, *outlen = 0;
520 i < len && *outlen <= 255;
521 *outlen += 1)
522 {
523 if (escape && (*ip == ':')) {
524 if (i > len - 5)
525 return -EINVAL;
526 ec = 0;
527 for (k = 1; k < 5; k++) {
528 nc = ip[k];
529 ec <<= 4;
530 if (nc >= '0' && nc <= '9') {
531 ec |= nc - '0';
532 continue;
533 }
534 if (nc >= 'a' && nc <= 'f') {
535 ec |= nc - ('a' - 10);
536 continue;
537 }
538 if (nc >= 'A' && nc <= 'F') {
539 ec |= nc - ('A' - 10);
540 continue;
541 }
542 return -EINVAL;
543 }
544 *op++ = ec & 0xFF;
545 *op++ = ec >> 8;
546 ip += 5;
547 i += 5;
548 } else {
549 if ((charlen = nls->char2uni(ip, len - i, (wchar_t *)op)) < 0)
550 return -EINVAL;
551 ip += charlen;
552 i += charlen;
553 op += 2;
554 }
555 }
556 if (i < len)
557 return -ENAMETOOLONG;
558 } else {
559 for (i = 0, ip = name, op = outname, *outlen = 0;
560 i < len && *outlen <= 255;
561 i++, *outlen += 1)
562 {
563 *op++ = *ip++;
564 *op++ = 0;
565 }
566 if (i < len)
567 return -ENAMETOOLONG;
568 }
569 }
570
571 *longlen = *outlen;
572 if (*outlen % 13) {
573 *op++ = 0;
574 *op++ = 0;
575 *outlen += 1;
576 if (*outlen % 13) {
577 fill = 13 - (*outlen % 13);
578 for (i = 0; i < fill; i++) {
579 *op++ = 0xff;
580 *op++ = 0xff;
581 }
582 *outlen += fill;
583 }
584 }
585
586 return 0;
587}
588
589static int vfat_build_slots(struct inode *dir, const unsigned char *name,
590 int len, int is_dir, int cluster,
591 struct timespec *ts,
592 struct msdos_dir_slot *slots, int *nr_slots)
593{
594 struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
595 struct fat_mount_options *opts = &sbi->options;
596 struct msdos_dir_slot *ps;
597 struct msdos_dir_entry *de;
598 unsigned char cksum, lcase;
599 unsigned char msdos_name[MSDOS_NAME];
600 wchar_t *uname;
601 __le16 time, date;
602 u8 time_cs;
603 int err, ulen, usize, i;
604 loff_t offset;
605
606 *nr_slots = 0;
607
608 uname = __getname();
609 if (!uname)
610 return -ENOMEM;
611
612 err = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,
613 opts->unicode_xlate, opts->utf8, sbi->nls_io);
614 if (err)
615 goto out_free;
616
617 err = vfat_is_used_badchars(uname, ulen);
618 if (err)
619 goto out_free;
620
621 err = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen,
622 msdos_name, &lcase);
623 if (err < 0)
624 goto out_free;
625 else if (err == 1) {
626 de = (struct msdos_dir_entry *)slots;
627 err = 0;
628 goto shortname;
629 }
630
631 /* build the entry of long file name */
632 cksum = fat_checksum(msdos_name);
633
634 *nr_slots = usize / 13;
635 for (ps = slots, i = *nr_slots; i > 0; i--, ps++) {
636 ps->id = i;
637 ps->attr = ATTR_EXT;
638 ps->reserved = 0;
639 ps->alias_checksum = cksum;
640 ps->start = 0;
641 offset = (i - 1) * 13;
642 fatwchar_to16(ps->name0_4, uname + offset, 5);
643 fatwchar_to16(ps->name5_10, uname + offset + 5, 6);
644 fatwchar_to16(ps->name11_12, uname + offset + 11, 2);
645 }
646 slots[0].id |= 0x40;
647 de = (struct msdos_dir_entry *)ps;
648
649shortname:
650 /* build the entry of 8.3 alias name */
651 (*nr_slots)++;
652 memcpy(de->name, msdos_name, MSDOS_NAME);
653 de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
654 de->lcase = lcase;
655 fat_time_unix2fat(sbi, ts, &time, &date, &time_cs);
656 de->time = de->ctime = time;
657 de->date = de->cdate = de->adate = date;
658 de->ctime_cs = time_cs;
659 de->start = cpu_to_le16(cluster);
660 de->starthi = cpu_to_le16(cluster >> 16);
661 de->size = 0;
662out_free:
663 __putname(uname);
664 return err;
665}
666
667static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,
668 int cluster, struct timespec *ts,
669 struct fat_slot_info *sinfo)
670{
671 struct msdos_dir_slot *slots;
672 unsigned int len;
673 int err, nr_slots;
674
675 len = vfat_striptail_len(qname);
676 if (len == 0)
677 return -ENOENT;
678
679 slots = kmalloc(sizeof(*slots) * MSDOS_SLOTS, GFP_NOFS);
680 if (slots == NULL)
681 return -ENOMEM;
682
683 err = vfat_build_slots(dir, qname->name, len, is_dir, cluster, ts,
684 slots, &nr_slots);
685 if (err)
686 goto cleanup;
687
688 err = fat_add_entries(dir, slots, nr_slots, sinfo);
689 if (err)
690 goto cleanup;
691
692 /* update timestamp */
693 dir->i_ctime = dir->i_mtime = dir->i_atime = *ts;
694 if (IS_DIRSYNC(dir))
695 (void)fat_sync_inode(dir);
696 else
697 mark_inode_dirty(dir);
698cleanup:
699 kfree(slots);
700 return err;
701}
702
703static int vfat_find(struct inode *dir, struct qstr *qname,
704 struct fat_slot_info *sinfo)
705{
706 unsigned int len = vfat_striptail_len(qname);
707 if (len == 0)
708 return -ENOENT;
709 return fat_search_long(dir, qname->name, len, sinfo);
710}
711
712static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
713 struct nameidata *nd)
714{
715 struct super_block *sb = dir->i_sb;
716 struct fat_slot_info sinfo;
717 struct inode *inode;
718 struct dentry *alias;
719 int err;
720
721 lock_super(sb);
722
723 err = vfat_find(dir, &dentry->d_name, &sinfo);
724 if (err) {
725 if (err == -ENOENT) {
726 inode = NULL;
727 goto out;
728 }
729 goto error;
730 }
731
732 inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
733 brelse(sinfo.bh);
734 if (IS_ERR(inode)) {
735 err = PTR_ERR(inode);
736 goto error;
737 }
738
739 alias = d_find_alias(inode);
740 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
741 /*
742 * This inode has non DCACHE_DISCONNECTED dentry. This
743 * means, the user did ->lookup() by an another name
744 * (longname vs 8.3 alias of it) in past.
745 *
746 * Switch to new one for reason of locality if possible.
747 */
748 BUG_ON(d_unhashed(alias));
749 if (!S_ISDIR(inode->i_mode))
750 d_move(alias, dentry);
751 iput(inode);
752 unlock_super(sb);
753 return alias;
754 }
755out:
756 unlock_super(sb);
757 dentry->d_op = sb->s_root->d_op;
758 dentry->d_time = dentry->d_parent->d_inode->i_version;
759 dentry = d_splice_alias(inode, dentry);
760 if (dentry) {
761 dentry->d_op = sb->s_root->d_op;
762 dentry->d_time = dentry->d_parent->d_inode->i_version;
763 }
764 return dentry;
765
766error:
767 unlock_super(sb);
768 return ERR_PTR(err);
769}
770
771static int vfat_create(struct inode *dir, struct dentry *dentry, int mode,
772 struct nameidata *nd)
773{
774 struct super_block *sb = dir->i_sb;
775 struct inode *inode;
776 struct fat_slot_info sinfo;
777 struct timespec ts;
778 int err;
779
780 lock_super(sb);
781
782 ts = CURRENT_TIME_SEC;
783 err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo);
784 if (err)
785 goto out;
786 dir->i_version++;
787
788 inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
789 brelse(sinfo.bh);
790 if (IS_ERR(inode)) {
791 err = PTR_ERR(inode);
792 goto out;
793 }
794 inode->i_version++;
795 inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
796 /* timestamp is already written, so mark_inode_dirty() is unneeded. */
797
798 dentry->d_time = dentry->d_parent->d_inode->i_version;
799 d_instantiate(dentry, inode);
800out:
801 unlock_super(sb);
802 return err;
803}
804
805static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
806{
807 struct inode *inode = dentry->d_inode;
808 struct super_block *sb = dir->i_sb;
809 struct fat_slot_info sinfo;
810 int err;
811
812 lock_super(sb);
813
814 err = fat_dir_empty(inode);
815 if (err)
816 goto out;
817 err = vfat_find(dir, &dentry->d_name, &sinfo);
818 if (err)
819 goto out;
820
821 err = fat_remove_entries(dir, &sinfo); /* and releases bh */
822 if (err)
823 goto out;
824 drop_nlink(dir);
825
826 clear_nlink(inode);
827 inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
828 fat_detach(inode);
829out:
830 unlock_super(sb);
831
832 return err;
833}
834
835static int vfat_unlink(struct inode *dir, struct dentry *dentry)
836{
837 struct inode *inode = dentry->d_inode;
838 struct super_block *sb = dir->i_sb;
839 struct fat_slot_info sinfo;
840 int err;
841
842 lock_super(sb);
843
844 err = vfat_find(dir, &dentry->d_name, &sinfo);
845 if (err)
846 goto out;
847
848 err = fat_remove_entries(dir, &sinfo); /* and releases bh */
849 if (err)
850 goto out;
851 clear_nlink(inode);
852 inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
853 fat_detach(inode);
854out:
855 unlock_super(sb);
856
857 return err;
858}
859
860static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
861{
862 struct super_block *sb = dir->i_sb;
863 struct inode *inode;
864 struct fat_slot_info sinfo;
865 struct timespec ts;
866 int err, cluster;
867
868 lock_super(sb);
869
870 ts = CURRENT_TIME_SEC;
871 cluster = fat_alloc_new_dir(dir, &ts);
872 if (cluster < 0) {
873 err = cluster;
874 goto out;
875 }
876 err = vfat_add_entry(dir, &dentry->d_name, 1, cluster, &ts, &sinfo);
877 if (err)
878 goto out_free;
879 dir->i_version++;
880 inc_nlink(dir);
881
882 inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
883 brelse(sinfo.bh);
884 if (IS_ERR(inode)) {
885 err = PTR_ERR(inode);
886 /* the directory was completed, just return a error */
887 goto out;
888 }
889 inode->i_version++;
890 inode->i_nlink = 2;
891 inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
892 /* timestamp is already written, so mark_inode_dirty() is unneeded. */
893
894 dentry->d_time = dentry->d_parent->d_inode->i_version;
895 d_instantiate(dentry, inode);
896
897 unlock_super(sb);
898 return 0;
899
900out_free:
901 fat_free_clusters(dir, cluster);
902out:
903 unlock_super(sb);
904 return err;
905}
906
907static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
908 struct inode *new_dir, struct dentry *new_dentry)
909{
910 struct buffer_head *dotdot_bh;
911 struct msdos_dir_entry *dotdot_de;
912 struct inode *old_inode, *new_inode;
913 struct fat_slot_info old_sinfo, sinfo;
914 struct timespec ts;
915 loff_t dotdot_i_pos, new_i_pos;
916 int err, is_dir, update_dotdot, corrupt = 0;
917 struct super_block *sb = old_dir->i_sb;
918
919 old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
920 old_inode = old_dentry->d_inode;
921 new_inode = new_dentry->d_inode;
922 lock_super(sb);
923 err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
924 if (err)
925 goto out;
926
927 is_dir = S_ISDIR(old_inode->i_mode);
928 update_dotdot = (is_dir && old_dir != new_dir);
929 if (update_dotdot) {
930 if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
931 &dotdot_i_pos) < 0) {
932 err = -EIO;
933 goto out;
934 }
935 }
936
937 ts = CURRENT_TIME_SEC;
938 if (new_inode) {
939 if (is_dir) {
940 err = fat_dir_empty(new_inode);
941 if (err)
942 goto out;
943 }
944 new_i_pos = MSDOS_I(new_inode)->i_pos;
945 fat_detach(new_inode);
946 } else {
947 err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, 0,
948 &ts, &sinfo);
949 if (err)
950 goto out;
951 new_i_pos = sinfo.i_pos;
952 }
953 new_dir->i_version++;
954
955 fat_detach(old_inode);
956 fat_attach(old_inode, new_i_pos);
957 if (IS_DIRSYNC(new_dir)) {
958 err = fat_sync_inode(old_inode);
959 if (err)
960 goto error_inode;
961 } else
962 mark_inode_dirty(old_inode);
963
964 if (update_dotdot) {
965 int start = MSDOS_I(new_dir)->i_logstart;
966 dotdot_de->start = cpu_to_le16(start);
967 dotdot_de->starthi = cpu_to_le16(start >> 16);
968 mark_buffer_dirty(dotdot_bh);
969 if (IS_DIRSYNC(new_dir)) {
970 err = sync_dirty_buffer(dotdot_bh);
971 if (err)
972 goto error_dotdot;
973 }
974 drop_nlink(old_dir);
975 if (!new_inode)
976 inc_nlink(new_dir);
977 }
978
979 err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
980 old_sinfo.bh = NULL;
981 if (err)
982 goto error_dotdot;
983 old_dir->i_version++;
984 old_dir->i_ctime = old_dir->i_mtime = ts;
985 if (IS_DIRSYNC(old_dir))
986 (void)fat_sync_inode(old_dir);
987 else
988 mark_inode_dirty(old_dir);
989
990 if (new_inode) {
991 drop_nlink(new_inode);
992 if (is_dir)
993 drop_nlink(new_inode);
994 new_inode->i_ctime = ts;
995 }
996out:
997 brelse(sinfo.bh);
998 brelse(dotdot_bh);
999 brelse(old_sinfo.bh);
1000 unlock_super(sb);
1001
1002 return err;
1003
1004error_dotdot:
1005 /* data cluster is shared, serious corruption */
1006 corrupt = 1;
1007
1008 if (update_dotdot) {
1009 int start = MSDOS_I(old_dir)->i_logstart;
1010 dotdot_de->start = cpu_to_le16(start);
1011 dotdot_de->starthi = cpu_to_le16(start >> 16);
1012 mark_buffer_dirty(dotdot_bh);
1013 corrupt |= sync_dirty_buffer(dotdot_bh);
1014 }
1015error_inode:
1016 fat_detach(old_inode);
1017 fat_attach(old_inode, old_sinfo.i_pos);
1018 if (new_inode) {
1019 fat_attach(new_inode, new_i_pos);
1020 if (corrupt)
1021 corrupt |= fat_sync_inode(new_inode);
1022 } else {
1023 /*
1024 * If new entry was not sharing the data cluster, it
1025 * shouldn't be serious corruption.
1026 */
1027 int err2 = fat_remove_entries(new_dir, &sinfo);
1028 if (corrupt)
1029 corrupt |= err2;
1030 sinfo.bh = NULL;
1031 }
1032 if (corrupt < 0) {
1033 fat_fs_panic(new_dir->i_sb,
1034 "%s: Filesystem corrupted (i_pos %lld)",
1035 __func__, sinfo.i_pos);
1036 }
1037 goto out;
1038}
1039
1040static const struct inode_operations vfat_dir_inode_operations = {
1041 .create = vfat_create,
1042 .lookup = vfat_lookup,
1043 .unlink = vfat_unlink,
1044 .mkdir = vfat_mkdir,
1045 .rmdir = vfat_rmdir,
1046 .rename = vfat_rename,
1047 .setattr = fat_setattr,
1048 .getattr = fat_getattr,
1049};
1050
1051static int vfat_fill_super(struct super_block *sb, void *data, int silent)
1052{
1053 int res;
1054
1055 res = fat_fill_super(sb, data, silent, &vfat_dir_inode_operations, 1);
1056 if (res)
1057 return res;
1058
1059 if (MSDOS_SB(sb)->options.name_check != 's')
1060 sb->s_root->d_op = &vfat_ci_dentry_ops;
1061 else
1062 sb->s_root->d_op = &vfat_dentry_ops;
1063
1064 return 0;
1065}
1066
1067static int vfat_get_sb(struct file_system_type *fs_type,
1068 int flags, const char *dev_name,
1069 void *data, struct vfsmount *mnt)
1070{
1071 return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super,
1072 mnt);
1073}
1074
1075static struct file_system_type vfat_fs_type = {
1076 .owner = THIS_MODULE,
1077 .name = "vfat",
1078 .get_sb = vfat_get_sb,
1079 .kill_sb = kill_block_super,
1080 .fs_flags = FS_REQUIRES_DEV,
1081};
1082
1083static int __init init_vfat_fs(void)
1084{
1085 return register_filesystem(&vfat_fs_type);
1086}
1087
1088static void __exit exit_vfat_fs(void)
1089{
1090 unregister_filesystem(&vfat_fs_type);
1091}
1092
1093MODULE_LICENSE("GPL");
1094MODULE_DESCRIPTION("VFAT filesystem support");
1095MODULE_AUTHOR("Gordon Chaffee");
1096
1097module_init(init_vfat_fs)
1098module_exit(exit_vfat_fs)