diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/fat |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/Makefile | 7 | ||||
-rw-r--r-- | fs/fat/cache.c | 324 | ||||
-rw-r--r-- | fs/fat/dir.c | 1271 | ||||
-rw-r--r-- | fs/fat/fatent.c | 612 | ||||
-rw-r--r-- | fs/fat/file.c | 308 | ||||
-rw-r--r-- | fs/fat/inode.c | 1351 | ||||
-rw-r--r-- | fs/fat/misc.c | 225 |
7 files changed, 4098 insertions, 0 deletions
diff --git a/fs/fat/Makefile b/fs/fat/Makefile new file mode 100644 index 000000000000..bfb5f06cf2c8 --- /dev/null +++ b/fs/fat/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for the Linux fat filesystem support. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_FAT_FS) += fat.o | ||
6 | |||
7 | fat-objs := cache.o dir.o fatent.o file.o inode.o misc.o | ||
diff --git a/fs/fat/cache.c b/fs/fat/cache.c new file mode 100644 index 000000000000..7c52e465a619 --- /dev/null +++ b/fs/fat/cache.c | |||
@@ -0,0 +1,324 @@ | |||
1 | /* | ||
2 | * linux/fs/fat/cache.c | ||
3 | * | ||
4 | * Written 1992,1993 by Werner Almesberger | ||
5 | * | ||
6 | * Mar 1999. AV. Changed cache, so that it uses the starting cluster instead | ||
7 | * of inode number. | ||
8 | * May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers. | ||
9 | */ | ||
10 | |||
11 | #include <linux/fs.h> | ||
12 | #include <linux/msdos_fs.h> | ||
13 | #include <linux/buffer_head.h> | ||
14 | |||
15 | /* this must be > 0. */ | ||
16 | #define FAT_MAX_CACHE 8 | ||
17 | |||
18 | struct fat_cache { | ||
19 | struct list_head cache_list; | ||
20 | int nr_contig; /* number of contiguous clusters */ | ||
21 | int fcluster; /* cluster number in the file. */ | ||
22 | int dcluster; /* cluster number on disk. */ | ||
23 | }; | ||
24 | |||
25 | struct fat_cache_id { | ||
26 | unsigned int id; | ||
27 | int nr_contig; | ||
28 | int fcluster; | ||
29 | int dcluster; | ||
30 | }; | ||
31 | |||
32 | static inline int fat_max_cache(struct inode *inode) | ||
33 | { | ||
34 | return FAT_MAX_CACHE; | ||
35 | } | ||
36 | |||
37 | static kmem_cache_t *fat_cache_cachep; | ||
38 | |||
39 | static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) | ||
40 | { | ||
41 | struct fat_cache *cache = (struct fat_cache *)foo; | ||
42 | |||
43 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | ||
44 | SLAB_CTOR_CONSTRUCTOR) | ||
45 | INIT_LIST_HEAD(&cache->cache_list); | ||
46 | } | ||
47 | |||
48 | int __init fat_cache_init(void) | ||
49 | { | ||
50 | fat_cache_cachep = kmem_cache_create("fat_cache", | ||
51 | sizeof(struct fat_cache), | ||
52 | 0, SLAB_RECLAIM_ACCOUNT, | ||
53 | init_once, NULL); | ||
54 | if (fat_cache_cachep == NULL) | ||
55 | return -ENOMEM; | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | void __exit fat_cache_destroy(void) | ||
60 | { | ||
61 | if (kmem_cache_destroy(fat_cache_cachep)) | ||
62 | printk(KERN_INFO "fat_cache: not all structures were freed\n"); | ||
63 | } | ||
64 | |||
65 | static inline struct fat_cache *fat_cache_alloc(struct inode *inode) | ||
66 | { | ||
67 | return kmem_cache_alloc(fat_cache_cachep, SLAB_KERNEL); | ||
68 | } | ||
69 | |||
70 | static inline void fat_cache_free(struct fat_cache *cache) | ||
71 | { | ||
72 | BUG_ON(!list_empty(&cache->cache_list)); | ||
73 | kmem_cache_free(fat_cache_cachep, cache); | ||
74 | } | ||
75 | |||
76 | static inline void fat_cache_update_lru(struct inode *inode, | ||
77 | struct fat_cache *cache) | ||
78 | { | ||
79 | if (MSDOS_I(inode)->cache_lru.next != &cache->cache_list) | ||
80 | list_move(&cache->cache_list, &MSDOS_I(inode)->cache_lru); | ||
81 | } | ||
82 | |||
83 | static int fat_cache_lookup(struct inode *inode, int fclus, | ||
84 | struct fat_cache_id *cid, | ||
85 | int *cached_fclus, int *cached_dclus) | ||
86 | { | ||
87 | static struct fat_cache nohit = { .fcluster = 0, }; | ||
88 | |||
89 | struct fat_cache *hit = &nohit, *p; | ||
90 | int offset = -1; | ||
91 | |||
92 | spin_lock(&MSDOS_I(inode)->cache_lru_lock); | ||
93 | list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) { | ||
94 | /* Find the cache of "fclus" or nearest cache. */ | ||
95 | if (p->fcluster <= fclus && hit->fcluster < p->fcluster) { | ||
96 | hit = p; | ||
97 | if ((hit->fcluster + hit->nr_contig) < fclus) { | ||
98 | offset = hit->nr_contig; | ||
99 | } else { | ||
100 | offset = fclus - hit->fcluster; | ||
101 | break; | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | if (hit != &nohit) { | ||
106 | fat_cache_update_lru(inode, hit); | ||
107 | |||
108 | cid->id = MSDOS_I(inode)->cache_valid_id; | ||
109 | cid->nr_contig = hit->nr_contig; | ||
110 | cid->fcluster = hit->fcluster; | ||
111 | cid->dcluster = hit->dcluster; | ||
112 | *cached_fclus = cid->fcluster + offset; | ||
113 | *cached_dclus = cid->dcluster + offset; | ||
114 | } | ||
115 | spin_unlock(&MSDOS_I(inode)->cache_lru_lock); | ||
116 | |||
117 | return offset; | ||
118 | } | ||
119 | |||
120 | static struct fat_cache *fat_cache_merge(struct inode *inode, | ||
121 | struct fat_cache_id *new) | ||
122 | { | ||
123 | struct fat_cache *p; | ||
124 | |||
125 | list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) { | ||
126 | /* Find the same part as "new" in cluster-chain. */ | ||
127 | if (p->fcluster == new->fcluster) { | ||
128 | BUG_ON(p->dcluster != new->dcluster); | ||
129 | if (new->nr_contig > p->nr_contig) | ||
130 | p->nr_contig = new->nr_contig; | ||
131 | return p; | ||
132 | } | ||
133 | } | ||
134 | return NULL; | ||
135 | } | ||
136 | |||
137 | static void fat_cache_add(struct inode *inode, struct fat_cache_id *new) | ||
138 | { | ||
139 | struct fat_cache *cache, *tmp; | ||
140 | |||
141 | if (new->fcluster == -1) /* dummy cache */ | ||
142 | return; | ||
143 | |||
144 | spin_lock(&MSDOS_I(inode)->cache_lru_lock); | ||
145 | if (new->id != FAT_CACHE_VALID && | ||
146 | new->id != MSDOS_I(inode)->cache_valid_id) | ||
147 | goto out; /* this cache was invalidated */ | ||
148 | |||
149 | cache = fat_cache_merge(inode, new); | ||
150 | if (cache == NULL) { | ||
151 | if (MSDOS_I(inode)->nr_caches < fat_max_cache(inode)) { | ||
152 | MSDOS_I(inode)->nr_caches++; | ||
153 | spin_unlock(&MSDOS_I(inode)->cache_lru_lock); | ||
154 | |||
155 | tmp = fat_cache_alloc(inode); | ||
156 | spin_lock(&MSDOS_I(inode)->cache_lru_lock); | ||
157 | cache = fat_cache_merge(inode, new); | ||
158 | if (cache != NULL) { | ||
159 | MSDOS_I(inode)->nr_caches--; | ||
160 | fat_cache_free(tmp); | ||
161 | goto out_update_lru; | ||
162 | } | ||
163 | cache = tmp; | ||
164 | } else { | ||
165 | struct list_head *p = MSDOS_I(inode)->cache_lru.prev; | ||
166 | cache = list_entry(p, struct fat_cache, cache_list); | ||
167 | } | ||
168 | cache->fcluster = new->fcluster; | ||
169 | cache->dcluster = new->dcluster; | ||
170 | cache->nr_contig = new->nr_contig; | ||
171 | } | ||
172 | out_update_lru: | ||
173 | fat_cache_update_lru(inode, cache); | ||
174 | out: | ||
175 | spin_unlock(&MSDOS_I(inode)->cache_lru_lock); | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * Cache invalidation occurs rarely, thus the LRU chain is not updated. It | ||
180 | * fixes itself after a while. | ||
181 | */ | ||
182 | static void __fat_cache_inval_inode(struct inode *inode) | ||
183 | { | ||
184 | struct msdos_inode_info *i = MSDOS_I(inode); | ||
185 | struct fat_cache *cache; | ||
186 | |||
187 | while (!list_empty(&i->cache_lru)) { | ||
188 | cache = list_entry(i->cache_lru.next, struct fat_cache, cache_list); | ||
189 | list_del_init(&cache->cache_list); | ||
190 | i->nr_caches--; | ||
191 | fat_cache_free(cache); | ||
192 | } | ||
193 | /* Update. The copy of caches before this id is discarded. */ | ||
194 | i->cache_valid_id++; | ||
195 | if (i->cache_valid_id == FAT_CACHE_VALID) | ||
196 | i->cache_valid_id++; | ||
197 | } | ||
198 | |||
199 | void fat_cache_inval_inode(struct inode *inode) | ||
200 | { | ||
201 | spin_lock(&MSDOS_I(inode)->cache_lru_lock); | ||
202 | __fat_cache_inval_inode(inode); | ||
203 | spin_unlock(&MSDOS_I(inode)->cache_lru_lock); | ||
204 | } | ||
205 | |||
206 | static inline int cache_contiguous(struct fat_cache_id *cid, int dclus) | ||
207 | { | ||
208 | cid->nr_contig++; | ||
209 | return ((cid->dcluster + cid->nr_contig) == dclus); | ||
210 | } | ||
211 | |||
212 | static inline void cache_init(struct fat_cache_id *cid, int fclus, int dclus) | ||
213 | { | ||
214 | cid->id = FAT_CACHE_VALID; | ||
215 | cid->fcluster = fclus; | ||
216 | cid->dcluster = dclus; | ||
217 | cid->nr_contig = 0; | ||
218 | } | ||
219 | |||
220 | int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) | ||
221 | { | ||
222 | struct super_block *sb = inode->i_sb; | ||
223 | const int limit = sb->s_maxbytes >> MSDOS_SB(sb)->cluster_bits; | ||
224 | struct fat_entry fatent; | ||
225 | struct fat_cache_id cid; | ||
226 | int nr; | ||
227 | |||
228 | BUG_ON(MSDOS_I(inode)->i_start == 0); | ||
229 | |||
230 | *fclus = 0; | ||
231 | *dclus = MSDOS_I(inode)->i_start; | ||
232 | if (cluster == 0) | ||
233 | return 0; | ||
234 | |||
235 | if (fat_cache_lookup(inode, cluster, &cid, fclus, dclus) < 0) { | ||
236 | /* | ||
237 | * dummy, always not contiguous | ||
238 | * This is reinitialized by cache_init(), later. | ||
239 | */ | ||
240 | cache_init(&cid, -1, -1); | ||
241 | } | ||
242 | |||
243 | fatent_init(&fatent); | ||
244 | while (*fclus < cluster) { | ||
245 | /* prevent the infinite loop of cluster chain */ | ||
246 | if (*fclus > limit) { | ||
247 | fat_fs_panic(sb, "%s: detected the cluster chain loop" | ||
248 | " (i_pos %lld)", __FUNCTION__, | ||
249 | MSDOS_I(inode)->i_pos); | ||
250 | nr = -EIO; | ||
251 | goto out; | ||
252 | } | ||
253 | |||
254 | nr = fat_ent_read(inode, &fatent, *dclus); | ||
255 | if (nr < 0) | ||
256 | goto out; | ||
257 | else if (nr == FAT_ENT_FREE) { | ||
258 | fat_fs_panic(sb, "%s: invalid cluster chain" | ||
259 | " (i_pos %lld)", __FUNCTION__, | ||
260 | MSDOS_I(inode)->i_pos); | ||
261 | nr = -EIO; | ||
262 | goto out; | ||
263 | } else if (nr == FAT_ENT_EOF) { | ||
264 | fat_cache_add(inode, &cid); | ||
265 | goto out; | ||
266 | } | ||
267 | (*fclus)++; | ||
268 | *dclus = nr; | ||
269 | if (!cache_contiguous(&cid, *dclus)) | ||
270 | cache_init(&cid, *fclus, *dclus); | ||
271 | } | ||
272 | nr = 0; | ||
273 | fat_cache_add(inode, &cid); | ||
274 | out: | ||
275 | fatent_brelse(&fatent); | ||
276 | return nr; | ||
277 | } | ||
278 | |||
279 | static int fat_bmap_cluster(struct inode *inode, int cluster) | ||
280 | { | ||
281 | struct super_block *sb = inode->i_sb; | ||
282 | int ret, fclus, dclus; | ||
283 | |||
284 | if (MSDOS_I(inode)->i_start == 0) | ||
285 | return 0; | ||
286 | |||
287 | ret = fat_get_cluster(inode, cluster, &fclus, &dclus); | ||
288 | if (ret < 0) | ||
289 | return ret; | ||
290 | else if (ret == FAT_ENT_EOF) { | ||
291 | fat_fs_panic(sb, "%s: request beyond EOF (i_pos %lld)", | ||
292 | __FUNCTION__, MSDOS_I(inode)->i_pos); | ||
293 | return -EIO; | ||
294 | } | ||
295 | return dclus; | ||
296 | } | ||
297 | |||
298 | int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys) | ||
299 | { | ||
300 | struct super_block *sb = inode->i_sb; | ||
301 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
302 | sector_t last_block; | ||
303 | int cluster, offset; | ||
304 | |||
305 | *phys = 0; | ||
306 | if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO)) { | ||
307 | if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) | ||
308 | *phys = sector + sbi->dir_start; | ||
309 | return 0; | ||
310 | } | ||
311 | last_block = (MSDOS_I(inode)->mmu_private + (sb->s_blocksize - 1)) | ||
312 | >> sb->s_blocksize_bits; | ||
313 | if (sector >= last_block) | ||
314 | return 0; | ||
315 | |||
316 | cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits); | ||
317 | offset = sector & (sbi->sec_per_clus - 1); | ||
318 | cluster = fat_bmap_cluster(inode, cluster); | ||
319 | if (cluster < 0) | ||
320 | return cluster; | ||
321 | else if (cluster) | ||
322 | *phys = fat_clus_to_blknr(sbi, cluster) + offset; | ||
323 | return 0; | ||
324 | } | ||
diff --git a/fs/fat/dir.c b/fs/fat/dir.c new file mode 100644 index 000000000000..e5ae1b720dde --- /dev/null +++ b/fs/fat/dir.c | |||
@@ -0,0 +1,1271 @@ | |||
1 | /* | ||
2 | * linux/fs/fat/dir.c | ||
3 | * | ||
4 | * directory handling functions for fat-based filesystems | ||
5 | * | ||
6 | * Written 1992,1993 by Werner Almesberger | ||
7 | * | ||
8 | * Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu> | ||
9 | * | ||
10 | * VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu> | ||
11 | * Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk> | ||
12 | * Rewritten for constant inumbers. Plugged buffer overrun in readdir(). AV | ||
13 | * Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de> | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/time.h> | ||
19 | #include <linux/msdos_fs.h> | ||
20 | #include <linux/dirent.h> | ||
21 | #include <linux/smp_lock.h> | ||
22 | #include <linux/buffer_head.h> | ||
23 | #include <asm/uaccess.h> | ||
24 | |||
25 | static inline loff_t fat_make_i_pos(struct super_block *sb, | ||
26 | struct buffer_head *bh, | ||
27 | struct msdos_dir_entry *de) | ||
28 | { | ||
29 | return ((loff_t)bh->b_blocknr << MSDOS_SB(sb)->dir_per_block_bits) | ||
30 | | (de - (struct msdos_dir_entry *)bh->b_data); | ||
31 | } | ||
32 | |||
33 | /* Returns the inode number of the directory entry at offset pos. If bh is | ||
34 | non-NULL, it is brelse'd before. Pos is incremented. The buffer header is | ||
35 | returned in bh. | ||
36 | AV. Most often we do it item-by-item. Makes sense to optimize. | ||
37 | AV. OK, there we go: if both bh and de are non-NULL we assume that we just | ||
38 | AV. want the next entry (took one explicit de=NULL in vfat/namei.c). | ||
39 | AV. It's done in fat_get_entry() (inlined), here the slow case lives. | ||
40 | AV. Additionally, when we return -1 (i.e. reached the end of directory) | ||
41 | AV. we make bh NULL. | ||
42 | */ | ||
43 | static int fat__get_entry(struct inode *dir, loff_t *pos, | ||
44 | struct buffer_head **bh, struct msdos_dir_entry **de) | ||
45 | { | ||
46 | struct super_block *sb = dir->i_sb; | ||
47 | sector_t phys, iblock; | ||
48 | int offset; | ||
49 | int err; | ||
50 | |||
51 | next: | ||
52 | if (*bh) | ||
53 | brelse(*bh); | ||
54 | |||
55 | *bh = NULL; | ||
56 | iblock = *pos >> sb->s_blocksize_bits; | ||
57 | err = fat_bmap(dir, iblock, &phys); | ||
58 | if (err || !phys) | ||
59 | return -1; /* beyond EOF or error */ | ||
60 | |||
61 | *bh = sb_bread(sb, phys); | ||
62 | if (*bh == NULL) { | ||
63 | printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n", | ||
64 | (unsigned long long)phys); | ||
65 | /* skip this block */ | ||
66 | *pos = (iblock + 1) << sb->s_blocksize_bits; | ||
67 | goto next; | ||
68 | } | ||
69 | |||
70 | offset = *pos & (sb->s_blocksize - 1); | ||
71 | *pos += sizeof(struct msdos_dir_entry); | ||
72 | *de = (struct msdos_dir_entry *)((*bh)->b_data + offset); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static inline int fat_get_entry(struct inode *dir, loff_t *pos, | ||
78 | struct buffer_head **bh, | ||
79 | struct msdos_dir_entry **de) | ||
80 | { | ||
81 | /* Fast stuff first */ | ||
82 | if (*bh && *de && | ||
83 | (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) { | ||
84 | *pos += sizeof(struct msdos_dir_entry); | ||
85 | (*de)++; | ||
86 | return 0; | ||
87 | } | ||
88 | return fat__get_entry(dir, pos, bh, de); | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Convert Unicode 16 to UTF8, translated Unicode, or ASCII. | ||
93 | * If uni_xlate is enabled and we can't get a 1:1 conversion, use a | ||
94 | * colon as an escape character since it is normally invalid on the vfat | ||
95 | * filesystem. The following four characters are the hexadecimal digits | ||
96 | * of Unicode value. This lets us do a full dump and restore of Unicode | ||
97 | * filenames. We could get into some trouble with long Unicode names, | ||
98 | * but ignore that right now. | ||
99 | * Ahem... Stack smashing in ring 0 isn't fun. Fixed. | ||
100 | */ | ||
101 | static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate, | ||
102 | struct nls_table *nls) | ||
103 | { | ||
104 | wchar_t *ip, ec; | ||
105 | unsigned char *op, nc; | ||
106 | int charlen; | ||
107 | int k; | ||
108 | |||
109 | ip = uni; | ||
110 | op = ascii; | ||
111 | |||
112 | while (*ip) { | ||
113 | ec = *ip++; | ||
114 | if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) { | ||
115 | op += charlen; | ||
116 | } else { | ||
117 | if (uni_xlate == 1) { | ||
118 | *op = ':'; | ||
119 | for (k = 4; k > 0; k--) { | ||
120 | nc = ec & 0xF; | ||
121 | op[k] = nc > 9 ? nc + ('a' - 10) | ||
122 | : nc + '0'; | ||
123 | ec >>= 4; | ||
124 | } | ||
125 | op += 5; | ||
126 | } else { | ||
127 | *op++ = '?'; | ||
128 | } | ||
129 | } | ||
130 | /* We have some slack there, so it's OK */ | ||
131 | if (op>ascii+256) { | ||
132 | op = ascii + 256; | ||
133 | break; | ||
134 | } | ||
135 | } | ||
136 | *op = 0; | ||
137 | return (op - ascii); | ||
138 | } | ||
139 | |||
140 | static inline int | ||
141 | fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) | ||
142 | { | ||
143 | int charlen; | ||
144 | |||
145 | charlen = t->char2uni(c, clen, uni); | ||
146 | if (charlen < 0) { | ||
147 | *uni = 0x003f; /* a question mark */ | ||
148 | charlen = 1; | ||
149 | } | ||
150 | return charlen; | ||
151 | } | ||
152 | |||
153 | static inline int | ||
154 | fat_short2lower_uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) | ||
155 | { | ||
156 | int charlen; | ||
157 | wchar_t wc; | ||
158 | |||
159 | charlen = t->char2uni(c, clen, &wc); | ||
160 | if (charlen < 0) { | ||
161 | *uni = 0x003f; /* a question mark */ | ||
162 | charlen = 1; | ||
163 | } else if (charlen <= 1) { | ||
164 | unsigned char nc = t->charset2lower[*c]; | ||
165 | |||
166 | if (!nc) | ||
167 | nc = *c; | ||
168 | |||
169 | if ( (charlen = t->char2uni(&nc, 1, uni)) < 0) { | ||
170 | *uni = 0x003f; /* a question mark */ | ||
171 | charlen = 1; | ||
172 | } | ||
173 | } else | ||
174 | *uni = wc; | ||
175 | |||
176 | return charlen; | ||
177 | } | ||
178 | |||
179 | static inline int | ||
180 | fat_shortname2uni(struct nls_table *nls, unsigned char *buf, int buf_size, | ||
181 | wchar_t *uni_buf, unsigned short opt, int lower) | ||
182 | { | ||
183 | int len = 0; | ||
184 | |||
185 | if (opt & VFAT_SFN_DISPLAY_LOWER) | ||
186 | len = fat_short2lower_uni(nls, buf, buf_size, uni_buf); | ||
187 | else if (opt & VFAT_SFN_DISPLAY_WIN95) | ||
188 | len = fat_short2uni(nls, buf, buf_size, uni_buf); | ||
189 | else if (opt & VFAT_SFN_DISPLAY_WINNT) { | ||
190 | if (lower) | ||
191 | len = fat_short2lower_uni(nls, buf, buf_size, uni_buf); | ||
192 | else | ||
193 | len = fat_short2uni(nls, buf, buf_size, uni_buf); | ||
194 | } else | ||
195 | len = fat_short2uni(nls, buf, buf_size, uni_buf); | ||
196 | |||
197 | return len; | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * Return values: negative -> error, 0 -> not found, positive -> found, | ||
202 | * value is the total amount of slots, including the shortname entry. | ||
203 | */ | ||
204 | int fat_search_long(struct inode *inode, const unsigned char *name, | ||
205 | int name_len, struct fat_slot_info *sinfo) | ||
206 | { | ||
207 | struct super_block *sb = inode->i_sb; | ||
208 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
209 | struct buffer_head *bh = NULL; | ||
210 | struct msdos_dir_entry *de; | ||
211 | struct nls_table *nls_io = sbi->nls_io; | ||
212 | struct nls_table *nls_disk = sbi->nls_disk; | ||
213 | wchar_t bufuname[14]; | ||
214 | unsigned char xlate_len, nr_slots; | ||
215 | wchar_t *unicode = NULL; | ||
216 | unsigned char work[8], bufname[260]; /* 256 + 4 */ | ||
217 | int uni_xlate = sbi->options.unicode_xlate; | ||
218 | int utf8 = sbi->options.utf8; | ||
219 | int anycase = (sbi->options.name_check != 's'); | ||
220 | unsigned short opt_shortname = sbi->options.shortname; | ||
221 | loff_t cpos = 0; | ||
222 | int chl, i, j, last_u, err; | ||
223 | |||
224 | err = -ENOENT; | ||
225 | while(1) { | ||
226 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) | ||
227 | goto EODir; | ||
228 | parse_record: | ||
229 | nr_slots = 0; | ||
230 | if (de->name[0] == DELETED_FLAG) | ||
231 | continue; | ||
232 | if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME)) | ||
233 | continue; | ||
234 | if (de->attr != ATTR_EXT && IS_FREE(de->name)) | ||
235 | continue; | ||
236 | if (de->attr == ATTR_EXT) { | ||
237 | struct msdos_dir_slot *ds; | ||
238 | unsigned char id; | ||
239 | unsigned char slot; | ||
240 | unsigned char slots; | ||
241 | unsigned char sum; | ||
242 | unsigned char alias_checksum; | ||
243 | |||
244 | if (!unicode) { | ||
245 | unicode = (wchar_t *) | ||
246 | __get_free_page(GFP_KERNEL); | ||
247 | if (!unicode) { | ||
248 | brelse(bh); | ||
249 | return -ENOMEM; | ||
250 | } | ||
251 | } | ||
252 | parse_long: | ||
253 | slots = 0; | ||
254 | ds = (struct msdos_dir_slot *) de; | ||
255 | id = ds->id; | ||
256 | if (!(id & 0x40)) | ||
257 | continue; | ||
258 | slots = id & ~0x40; | ||
259 | if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */ | ||
260 | continue; | ||
261 | nr_slots = slots; | ||
262 | alias_checksum = ds->alias_checksum; | ||
263 | |||
264 | slot = slots; | ||
265 | while (1) { | ||
266 | int offset; | ||
267 | |||
268 | slot--; | ||
269 | offset = slot * 13; | ||
270 | fat16_towchar(unicode + offset, ds->name0_4, 5); | ||
271 | fat16_towchar(unicode + offset + 5, ds->name5_10, 6); | ||
272 | fat16_towchar(unicode + offset + 11, ds->name11_12, 2); | ||
273 | |||
274 | if (ds->id & 0x40) { | ||
275 | unicode[offset + 13] = 0; | ||
276 | } | ||
277 | if (fat_get_entry(inode, &cpos, &bh, &de) < 0) | ||
278 | goto EODir; | ||
279 | if (slot == 0) | ||
280 | break; | ||
281 | ds = (struct msdos_dir_slot *) de; | ||
282 | if (ds->attr != ATTR_EXT) | ||
283 | goto parse_record; | ||
284 | if ((ds->id & ~0x40) != slot) | ||
285 | goto parse_long; | ||
286 | if (ds->alias_checksum != alias_checksum) | ||
287 | goto parse_long; | ||
288 | } | ||
289 | if (de->name[0] == DELETED_FLAG) | ||
290 | continue; | ||
291 | if (de->attr == ATTR_EXT) | ||
292 | goto parse_long; | ||
293 | if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME)) | ||
294 | continue; | ||
295 | for (sum = 0, i = 0; i < 11; i++) | ||
296 | sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i]; | ||
297 | if (sum != alias_checksum) | ||
298 | nr_slots = 0; | ||
299 | } | ||
300 | |||
301 | memcpy(work, de->name, sizeof(de->name)); | ||
302 | /* see namei.c, msdos_format_name */ | ||
303 | if (work[0] == 0x05) | ||
304 | work[0] = 0xE5; | ||
305 | for (i = 0, j = 0, last_u = 0; i < 8;) { | ||
306 | if (!work[i]) break; | ||
307 | chl = fat_shortname2uni(nls_disk, &work[i], 8 - i, | ||
308 | &bufuname[j++], opt_shortname, | ||
309 | de->lcase & CASE_LOWER_BASE); | ||
310 | if (chl <= 1) { | ||
311 | if (work[i] != ' ') | ||
312 | last_u = j; | ||
313 | } else { | ||
314 | last_u = j; | ||
315 | } | ||
316 | i += chl; | ||
317 | } | ||
318 | j = last_u; | ||
319 | fat_short2uni(nls_disk, ".", 1, &bufuname[j++]); | ||
320 | for (i = 0; i < 3;) { | ||
321 | if (!de->ext[i]) break; | ||
322 | chl = fat_shortname2uni(nls_disk, &de->ext[i], 3 - i, | ||
323 | &bufuname[j++], opt_shortname, | ||
324 | de->lcase & CASE_LOWER_EXT); | ||
325 | if (chl <= 1) { | ||
326 | if (de->ext[i] != ' ') | ||
327 | last_u = j; | ||
328 | } else { | ||
329 | last_u = j; | ||
330 | } | ||
331 | i += chl; | ||
332 | } | ||
333 | if (!last_u) | ||
334 | continue; | ||
335 | |||
336 | bufuname[last_u] = 0x0000; | ||
337 | xlate_len = utf8 | ||
338 | ?utf8_wcstombs(bufname, bufuname, sizeof(bufname)) | ||
339 | :uni16_to_x8(bufname, bufuname, uni_xlate, nls_io); | ||
340 | if (xlate_len == name_len) | ||
341 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || | ||
342 | (anycase && !nls_strnicmp(nls_io, name, bufname, | ||
343 | xlate_len))) | ||
344 | goto Found; | ||
345 | |||
346 | if (nr_slots) { | ||
347 | xlate_len = utf8 | ||
348 | ?utf8_wcstombs(bufname, unicode, sizeof(bufname)) | ||
349 | :uni16_to_x8(bufname, unicode, uni_xlate, nls_io); | ||
350 | if (xlate_len != name_len) | ||
351 | continue; | ||
352 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || | ||
353 | (anycase && !nls_strnicmp(nls_io, name, bufname, | ||
354 | xlate_len))) | ||
355 | goto Found; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | Found: | ||
360 | nr_slots++; /* include the de */ | ||
361 | sinfo->slot_off = cpos - nr_slots * sizeof(*de); | ||
362 | sinfo->nr_slots = nr_slots; | ||
363 | sinfo->de = de; | ||
364 | sinfo->bh = bh; | ||
365 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); | ||
366 | err = 0; | ||
367 | EODir: | ||
368 | if (unicode) | ||
369 | free_page((unsigned long)unicode); | ||
370 | |||
371 | return err; | ||
372 | } | ||
373 | |||
374 | EXPORT_SYMBOL(fat_search_long); | ||
375 | |||
376 | struct fat_ioctl_filldir_callback { | ||
377 | struct dirent __user *dirent; | ||
378 | int result; | ||
379 | /* for dir ioctl */ | ||
380 | const char *longname; | ||
381 | int long_len; | ||
382 | const char *shortname; | ||
383 | int short_len; | ||
384 | }; | ||
385 | |||
386 | static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent, | ||
387 | filldir_t filldir, int short_only, int both) | ||
388 | { | ||
389 | struct super_block *sb = inode->i_sb; | ||
390 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
391 | struct buffer_head *bh; | ||
392 | struct msdos_dir_entry *de; | ||
393 | struct nls_table *nls_io = sbi->nls_io; | ||
394 | struct nls_table *nls_disk = sbi->nls_disk; | ||
395 | unsigned char long_slots; | ||
396 | const char *fill_name; | ||
397 | int fill_len; | ||
398 | wchar_t bufuname[14]; | ||
399 | wchar_t *unicode = NULL; | ||
400 | unsigned char c, work[8], bufname[56], *ptname = bufname; | ||
401 | unsigned long lpos, dummy, *furrfu = &lpos; | ||
402 | int uni_xlate = sbi->options.unicode_xlate; | ||
403 | int isvfat = sbi->options.isvfat; | ||
404 | int utf8 = sbi->options.utf8; | ||
405 | int nocase = sbi->options.nocase; | ||
406 | unsigned short opt_shortname = sbi->options.shortname; | ||
407 | unsigned long inum; | ||
408 | int chi, chl, i, i2, j, last, last_u, dotoffset = 0; | ||
409 | loff_t cpos; | ||
410 | int ret = 0; | ||
411 | |||
412 | lock_kernel(); | ||
413 | |||
414 | cpos = filp->f_pos; | ||
415 | /* Fake . and .. for the root directory. */ | ||
416 | if (inode->i_ino == MSDOS_ROOT_INO) { | ||
417 | while (cpos < 2) { | ||
418 | if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO, DT_DIR) < 0) | ||
419 | goto out; | ||
420 | cpos++; | ||
421 | filp->f_pos++; | ||
422 | } | ||
423 | if (cpos == 2) { | ||
424 | dummy = 2; | ||
425 | furrfu = &dummy; | ||
426 | cpos = 0; | ||
427 | } | ||
428 | } | ||
429 | if (cpos & (sizeof(struct msdos_dir_entry)-1)) { | ||
430 | ret = -ENOENT; | ||
431 | goto out; | ||
432 | } | ||
433 | |||
434 | bh = NULL; | ||
435 | GetNew: | ||
436 | long_slots = 0; | ||
437 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) | ||
438 | goto EODir; | ||
439 | /* Check for long filename entry */ | ||
440 | if (isvfat) { | ||
441 | if (de->name[0] == DELETED_FLAG) | ||
442 | goto RecEnd; | ||
443 | if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME)) | ||
444 | goto RecEnd; | ||
445 | if (de->attr != ATTR_EXT && IS_FREE(de->name)) | ||
446 | goto RecEnd; | ||
447 | } else { | ||
448 | if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) | ||
449 | goto RecEnd; | ||
450 | } | ||
451 | |||
452 | if (isvfat && de->attr == ATTR_EXT) { | ||
453 | struct msdos_dir_slot *ds; | ||
454 | unsigned char id; | ||
455 | unsigned char slot; | ||
456 | unsigned char slots; | ||
457 | unsigned char sum; | ||
458 | unsigned char alias_checksum; | ||
459 | |||
460 | if (!unicode) { | ||
461 | unicode = (wchar_t *)__get_free_page(GFP_KERNEL); | ||
462 | if (!unicode) { | ||
463 | filp->f_pos = cpos; | ||
464 | brelse(bh); | ||
465 | ret = -ENOMEM; | ||
466 | goto out; | ||
467 | } | ||
468 | } | ||
469 | ParseLong: | ||
470 | slots = 0; | ||
471 | ds = (struct msdos_dir_slot *) de; | ||
472 | id = ds->id; | ||
473 | if (!(id & 0x40)) | ||
474 | goto RecEnd; | ||
475 | slots = id & ~0x40; | ||
476 | if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */ | ||
477 | goto RecEnd; | ||
478 | long_slots = slots; | ||
479 | alias_checksum = ds->alias_checksum; | ||
480 | |||
481 | slot = slots; | ||
482 | while (1) { | ||
483 | int offset; | ||
484 | |||
485 | slot--; | ||
486 | offset = slot * 13; | ||
487 | fat16_towchar(unicode + offset, ds->name0_4, 5); | ||
488 | fat16_towchar(unicode + offset + 5, ds->name5_10, 6); | ||
489 | fat16_towchar(unicode + offset + 11, ds->name11_12, 2); | ||
490 | |||
491 | if (ds->id & 0x40) { | ||
492 | unicode[offset + 13] = 0; | ||
493 | } | ||
494 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) | ||
495 | goto EODir; | ||
496 | if (slot == 0) | ||
497 | break; | ||
498 | ds = (struct msdos_dir_slot *) de; | ||
499 | if (ds->attr != ATTR_EXT) | ||
500 | goto RecEnd; /* XXX */ | ||
501 | if ((ds->id & ~0x40) != slot) | ||
502 | goto ParseLong; | ||
503 | if (ds->alias_checksum != alias_checksum) | ||
504 | goto ParseLong; | ||
505 | } | ||
506 | if (de->name[0] == DELETED_FLAG) | ||
507 | goto RecEnd; | ||
508 | if (de->attr == ATTR_EXT) | ||
509 | goto ParseLong; | ||
510 | if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME)) | ||
511 | goto RecEnd; | ||
512 | for (sum = 0, i = 0; i < 11; i++) | ||
513 | sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i]; | ||
514 | if (sum != alias_checksum) | ||
515 | long_slots = 0; | ||
516 | } | ||
517 | |||
518 | if (sbi->options.dotsOK) { | ||
519 | ptname = bufname; | ||
520 | dotoffset = 0; | ||
521 | if (de->attr & ATTR_HIDDEN) { | ||
522 | *ptname++ = '.'; | ||
523 | dotoffset = 1; | ||
524 | } | ||
525 | } | ||
526 | |||
527 | memcpy(work, de->name, sizeof(de->name)); | ||
528 | /* see namei.c, msdos_format_name */ | ||
529 | if (work[0] == 0x05) | ||
530 | work[0] = 0xE5; | ||
531 | for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) { | ||
532 | if (!(c = work[i])) break; | ||
533 | chl = fat_shortname2uni(nls_disk, &work[i], 8 - i, | ||
534 | &bufuname[j++], opt_shortname, | ||
535 | de->lcase & CASE_LOWER_BASE); | ||
536 | if (chl <= 1) { | ||
537 | ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c; | ||
538 | if (c != ' ') { | ||
539 | last = i; | ||
540 | last_u = j; | ||
541 | } | ||
542 | } else { | ||
543 | last_u = j; | ||
544 | for (chi = 0; chi < chl && i < 8; chi++) { | ||
545 | ptname[i] = work[i]; | ||
546 | i++; last = i; | ||
547 | } | ||
548 | } | ||
549 | } | ||
550 | i = last; | ||
551 | j = last_u; | ||
552 | fat_short2uni(nls_disk, ".", 1, &bufuname[j++]); | ||
553 | ptname[i++] = '.'; | ||
554 | for (i2 = 0; i2 < 3;) { | ||
555 | if (!(c = de->ext[i2])) break; | ||
556 | chl = fat_shortname2uni(nls_disk, &de->ext[i2], 3 - i2, | ||
557 | &bufuname[j++], opt_shortname, | ||
558 | de->lcase & CASE_LOWER_EXT); | ||
559 | if (chl <= 1) { | ||
560 | i2++; | ||
561 | ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c; | ||
562 | if (c != ' ') { | ||
563 | last = i; | ||
564 | last_u = j; | ||
565 | } | ||
566 | } else { | ||
567 | last_u = j; | ||
568 | for (chi = 0; chi < chl && i2 < 3; chi++) { | ||
569 | ptname[i++] = de->ext[i2++]; | ||
570 | last = i; | ||
571 | } | ||
572 | } | ||
573 | } | ||
574 | if (!last) | ||
575 | goto RecEnd; | ||
576 | |||
577 | i = last + dotoffset; | ||
578 | j = last_u; | ||
579 | |||
580 | lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry); | ||
581 | if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) | ||
582 | inum = inode->i_ino; | ||
583 | else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) { | ||
584 | inum = parent_ino(filp->f_dentry); | ||
585 | } else { | ||
586 | loff_t i_pos = fat_make_i_pos(sb, bh, de); | ||
587 | struct inode *tmp = fat_iget(sb, i_pos); | ||
588 | if (tmp) { | ||
589 | inum = tmp->i_ino; | ||
590 | iput(tmp); | ||
591 | } else | ||
592 | inum = iunique(sb, MSDOS_ROOT_INO); | ||
593 | } | ||
594 | |||
595 | if (isvfat) { | ||
596 | bufuname[j] = 0x0000; | ||
597 | i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname)) | ||
598 | : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io); | ||
599 | } | ||
600 | |||
601 | fill_name = bufname; | ||
602 | fill_len = i; | ||
603 | if (!short_only && long_slots) { | ||
604 | /* convert the unicode long name. 261 is maximum size | ||
605 | * of unicode buffer. (13 * slots + nul) */ | ||
606 | void *longname = unicode + 261; | ||
607 | int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0])); | ||
608 | int long_len = utf8 | ||
609 | ? utf8_wcstombs(longname, unicode, buf_size) | ||
610 | : uni16_to_x8(longname, unicode, uni_xlate, nls_io); | ||
611 | |||
612 | if (!both) { | ||
613 | fill_name = longname; | ||
614 | fill_len = long_len; | ||
615 | } else { | ||
616 | /* hack for fat_ioctl_filldir() */ | ||
617 | struct fat_ioctl_filldir_callback *p = dirent; | ||
618 | |||
619 | p->longname = longname; | ||
620 | p->long_len = long_len; | ||
621 | p->shortname = bufname; | ||
622 | p->short_len = i; | ||
623 | fill_name = NULL; | ||
624 | fill_len = 0; | ||
625 | } | ||
626 | } | ||
627 | if (filldir(dirent, fill_name, fill_len, *furrfu, inum, | ||
628 | (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0) | ||
629 | goto FillFailed; | ||
630 | |||
631 | RecEnd: | ||
632 | furrfu = &lpos; | ||
633 | filp->f_pos = cpos; | ||
634 | goto GetNew; | ||
635 | EODir: | ||
636 | filp->f_pos = cpos; | ||
637 | FillFailed: | ||
638 | if (bh) | ||
639 | brelse(bh); | ||
640 | if (unicode) | ||
641 | free_page((unsigned long)unicode); | ||
642 | out: | ||
643 | unlock_kernel(); | ||
644 | return ret; | ||
645 | } | ||
646 | |||
647 | static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir) | ||
648 | { | ||
649 | struct inode *inode = filp->f_dentry->d_inode; | ||
650 | return fat_readdirx(inode, filp, dirent, filldir, 0, 0); | ||
651 | } | ||
652 | |||
653 | static int fat_ioctl_filldir(void *__buf, const char *name, int name_len, | ||
654 | loff_t offset, ino_t ino, unsigned int d_type) | ||
655 | { | ||
656 | struct fat_ioctl_filldir_callback *buf = __buf; | ||
657 | struct dirent __user *d1 = buf->dirent; | ||
658 | struct dirent __user *d2 = d1 + 1; | ||
659 | |||
660 | if (buf->result) | ||
661 | return -EINVAL; | ||
662 | buf->result++; | ||
663 | |||
664 | if (name != NULL) { | ||
665 | /* dirent has only short name */ | ||
666 | if (name_len >= sizeof(d1->d_name)) | ||
667 | name_len = sizeof(d1->d_name) - 1; | ||
668 | |||
669 | if (put_user(0, d2->d_name) || | ||
670 | put_user(0, &d2->d_reclen) || | ||
671 | copy_to_user(d1->d_name, name, name_len) || | ||
672 | put_user(0, d1->d_name + name_len) || | ||
673 | put_user(name_len, &d1->d_reclen)) | ||
674 | goto efault; | ||
675 | } else { | ||
676 | /* dirent has short and long name */ | ||
677 | const char *longname = buf->longname; | ||
678 | int long_len = buf->long_len; | ||
679 | const char *shortname = buf->shortname; | ||
680 | int short_len = buf->short_len; | ||
681 | |||
682 | if (long_len >= sizeof(d1->d_name)) | ||
683 | long_len = sizeof(d1->d_name) - 1; | ||
684 | if (short_len >= sizeof(d1->d_name)) | ||
685 | short_len = sizeof(d1->d_name) - 1; | ||
686 | |||
687 | if (copy_to_user(d2->d_name, longname, long_len) || | ||
688 | put_user(0, d2->d_name + long_len) || | ||
689 | put_user(long_len, &d2->d_reclen) || | ||
690 | put_user(ino, &d2->d_ino) || | ||
691 | put_user(offset, &d2->d_off) || | ||
692 | copy_to_user(d1->d_name, shortname, short_len) || | ||
693 | put_user(0, d1->d_name + short_len) || | ||
694 | put_user(short_len, &d1->d_reclen)) | ||
695 | goto efault; | ||
696 | } | ||
697 | return 0; | ||
698 | efault: | ||
699 | buf->result = -EFAULT; | ||
700 | return -EFAULT; | ||
701 | } | ||
702 | |||
703 | static int fat_dir_ioctl(struct inode * inode, struct file * filp, | ||
704 | unsigned int cmd, unsigned long arg) | ||
705 | { | ||
706 | struct fat_ioctl_filldir_callback buf; | ||
707 | struct dirent __user *d1; | ||
708 | int ret, short_only, both; | ||
709 | |||
710 | switch (cmd) { | ||
711 | case VFAT_IOCTL_READDIR_SHORT: | ||
712 | short_only = 1; | ||
713 | both = 0; | ||
714 | break; | ||
715 | case VFAT_IOCTL_READDIR_BOTH: | ||
716 | short_only = 0; | ||
717 | both = 1; | ||
718 | break; | ||
719 | default: | ||
720 | return fat_generic_ioctl(inode, filp, cmd, arg); | ||
721 | } | ||
722 | |||
723 | d1 = (struct dirent __user *)arg; | ||
724 | if (!access_ok(VERIFY_WRITE, d1, sizeof(struct dirent[2]))) | ||
725 | return -EFAULT; | ||
726 | /* | ||
727 | * Yes, we don't need this put_user() absolutely. However old | ||
728 | * code didn't return the right value. So, app use this value, | ||
729 | * in order to check whether it is EOF. | ||
730 | */ | ||
731 | if (put_user(0, &d1->d_reclen)) | ||
732 | return -EFAULT; | ||
733 | |||
734 | buf.dirent = d1; | ||
735 | buf.result = 0; | ||
736 | down(&inode->i_sem); | ||
737 | ret = -ENOENT; | ||
738 | if (!IS_DEADDIR(inode)) { | ||
739 | ret = fat_readdirx(inode, filp, &buf, fat_ioctl_filldir, | ||
740 | short_only, both); | ||
741 | } | ||
742 | up(&inode->i_sem); | ||
743 | if (ret >= 0) | ||
744 | ret = buf.result; | ||
745 | return ret; | ||
746 | } | ||
747 | |||
748 | struct file_operations fat_dir_operations = { | ||
749 | .read = generic_read_dir, | ||
750 | .readdir = fat_readdir, | ||
751 | .ioctl = fat_dir_ioctl, | ||
752 | .fsync = file_fsync, | ||
753 | }; | ||
754 | |||
755 | static int fat_get_short_entry(struct inode *dir, loff_t *pos, | ||
756 | struct buffer_head **bh, | ||
757 | struct msdos_dir_entry **de) | ||
758 | { | ||
759 | while (fat_get_entry(dir, pos, bh, de) >= 0) { | ||
760 | /* free entry or long name entry or volume label */ | ||
761 | if (!IS_FREE((*de)->name) && !((*de)->attr & ATTR_VOLUME)) | ||
762 | return 0; | ||
763 | } | ||
764 | return -ENOENT; | ||
765 | } | ||
766 | |||
767 | /* | ||
768 | * The ".." entry can not provide the "struct fat_slot_info" informations | ||
769 | * for inode. So, this function provide the some informations only. | ||
770 | */ | ||
771 | int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh, | ||
772 | struct msdos_dir_entry **de, loff_t *i_pos) | ||
773 | { | ||
774 | loff_t offset; | ||
775 | |||
776 | offset = 0; | ||
777 | *bh = NULL; | ||
778 | while (fat_get_short_entry(dir, &offset, bh, de) >= 0) { | ||
779 | if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME)) { | ||
780 | *i_pos = fat_make_i_pos(dir->i_sb, *bh, *de); | ||
781 | return 0; | ||
782 | } | ||
783 | } | ||
784 | return -ENOENT; | ||
785 | } | ||
786 | |||
787 | EXPORT_SYMBOL(fat_get_dotdot_entry); | ||
788 | |||
789 | /* See if directory is empty */ | ||
790 | int fat_dir_empty(struct inode *dir) | ||
791 | { | ||
792 | struct buffer_head *bh; | ||
793 | struct msdos_dir_entry *de; | ||
794 | loff_t cpos; | ||
795 | int result = 0; | ||
796 | |||
797 | bh = NULL; | ||
798 | cpos = 0; | ||
799 | while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) { | ||
800 | if (strncmp(de->name, MSDOS_DOT , MSDOS_NAME) && | ||
801 | strncmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) { | ||
802 | result = -ENOTEMPTY; | ||
803 | break; | ||
804 | } | ||
805 | } | ||
806 | brelse(bh); | ||
807 | return result; | ||
808 | } | ||
809 | |||
810 | EXPORT_SYMBOL(fat_dir_empty); | ||
811 | |||
812 | /* | ||
813 | * fat_subdirs counts the number of sub-directories of dir. It can be run | ||
814 | * on directories being created. | ||
815 | */ | ||
816 | int fat_subdirs(struct inode *dir) | ||
817 | { | ||
818 | struct buffer_head *bh; | ||
819 | struct msdos_dir_entry *de; | ||
820 | loff_t cpos; | ||
821 | int count = 0; | ||
822 | |||
823 | bh = NULL; | ||
824 | cpos = 0; | ||
825 | while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) { | ||
826 | if (de->attr & ATTR_DIR) | ||
827 | count++; | ||
828 | } | ||
829 | brelse(bh); | ||
830 | return count; | ||
831 | } | ||
832 | |||
833 | /* | ||
834 | * Scans a directory for a given file (name points to its formatted name). | ||
835 | * Returns an error code or zero. | ||
836 | */ | ||
837 | int fat_scan(struct inode *dir, const unsigned char *name, | ||
838 | struct fat_slot_info *sinfo) | ||
839 | { | ||
840 | struct super_block *sb = dir->i_sb; | ||
841 | |||
842 | sinfo->slot_off = 0; | ||
843 | sinfo->bh = NULL; | ||
844 | while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh, | ||
845 | &sinfo->de) >= 0) { | ||
846 | if (!strncmp(sinfo->de->name, name, MSDOS_NAME)) { | ||
847 | sinfo->slot_off -= sizeof(*sinfo->de); | ||
848 | sinfo->nr_slots = 1; | ||
849 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); | ||
850 | return 0; | ||
851 | } | ||
852 | } | ||
853 | return -ENOENT; | ||
854 | } | ||
855 | |||
856 | EXPORT_SYMBOL(fat_scan); | ||
857 | |||
858 | static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots) | ||
859 | { | ||
860 | struct super_block *sb = dir->i_sb; | ||
861 | struct buffer_head *bh; | ||
862 | struct msdos_dir_entry *de, *endp; | ||
863 | int err = 0, orig_slots; | ||
864 | |||
865 | while (nr_slots) { | ||
866 | bh = NULL; | ||
867 | if (fat_get_entry(dir, &pos, &bh, &de) < 0) { | ||
868 | err = -EIO; | ||
869 | break; | ||
870 | } | ||
871 | |||
872 | orig_slots = nr_slots; | ||
873 | endp = (struct msdos_dir_entry *)(bh->b_data + sb->s_blocksize); | ||
874 | while (nr_slots && de < endp) { | ||
875 | de->name[0] = DELETED_FLAG; | ||
876 | de++; | ||
877 | nr_slots--; | ||
878 | } | ||
879 | mark_buffer_dirty(bh); | ||
880 | if (IS_DIRSYNC(dir)) | ||
881 | err = sync_dirty_buffer(bh); | ||
882 | brelse(bh); | ||
883 | if (err) | ||
884 | break; | ||
885 | |||
886 | /* pos is *next* de's position, so this does `- sizeof(de)' */ | ||
887 | pos += ((orig_slots - nr_slots) * sizeof(*de)) - sizeof(*de); | ||
888 | } | ||
889 | |||
890 | return err; | ||
891 | } | ||
892 | |||
893 | int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo) | ||
894 | { | ||
895 | struct msdos_dir_entry *de; | ||
896 | struct buffer_head *bh; | ||
897 | int err = 0, nr_slots; | ||
898 | |||
899 | /* | ||
900 | * First stage: Remove the shortname. By this, the directory | ||
901 | * entry is removed. | ||
902 | */ | ||
903 | nr_slots = sinfo->nr_slots; | ||
904 | de = sinfo->de; | ||
905 | sinfo->de = NULL; | ||
906 | bh = sinfo->bh; | ||
907 | sinfo->bh = NULL; | ||
908 | while (nr_slots && de >= (struct msdos_dir_entry *)bh->b_data) { | ||
909 | de->name[0] = DELETED_FLAG; | ||
910 | de--; | ||
911 | nr_slots--; | ||
912 | } | ||
913 | mark_buffer_dirty(bh); | ||
914 | if (IS_DIRSYNC(dir)) | ||
915 | err = sync_dirty_buffer(bh); | ||
916 | brelse(bh); | ||
917 | if (err) | ||
918 | return err; | ||
919 | dir->i_version++; | ||
920 | |||
921 | if (nr_slots) { | ||
922 | /* | ||
923 | * Second stage: remove the remaining longname slots. | ||
924 | * (This directory entry is already removed, and so return | ||
925 | * the success) | ||
926 | */ | ||
927 | err = __fat_remove_entries(dir, sinfo->slot_off, nr_slots); | ||
928 | if (err) { | ||
929 | printk(KERN_WARNING | ||
930 | "FAT: Couldn't remove the long name slots\n"); | ||
931 | } | ||
932 | } | ||
933 | |||
934 | dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC; | ||
935 | if (IS_DIRSYNC(dir)) | ||
936 | (void)fat_sync_inode(dir); | ||
937 | else | ||
938 | mark_inode_dirty(dir); | ||
939 | |||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | EXPORT_SYMBOL(fat_remove_entries); | ||
944 | |||
945 | static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used, | ||
946 | struct buffer_head **bhs, int nr_bhs) | ||
947 | { | ||
948 | struct super_block *sb = dir->i_sb; | ||
949 | sector_t last_blknr = blknr + MSDOS_SB(sb)->sec_per_clus; | ||
950 | int err, i, n; | ||
951 | |||
952 | /* Zeroing the unused blocks on this cluster */ | ||
953 | blknr += nr_used; | ||
954 | n = nr_used; | ||
955 | while (blknr < last_blknr) { | ||
956 | bhs[n] = sb_getblk(sb, blknr); | ||
957 | if (!bhs[n]) { | ||
958 | err = -ENOMEM; | ||
959 | goto error; | ||
960 | } | ||
961 | memset(bhs[n]->b_data, 0, sb->s_blocksize); | ||
962 | set_buffer_uptodate(bhs[n]); | ||
963 | mark_buffer_dirty(bhs[n]); | ||
964 | |||
965 | n++; | ||
966 | blknr++; | ||
967 | if (n == nr_bhs) { | ||
968 | if (IS_DIRSYNC(dir)) { | ||
969 | err = fat_sync_bhs(bhs, n); | ||
970 | if (err) | ||
971 | goto error; | ||
972 | } | ||
973 | for (i = 0; i < n; i++) | ||
974 | brelse(bhs[i]); | ||
975 | n = 0; | ||
976 | } | ||
977 | } | ||
978 | if (IS_DIRSYNC(dir)) { | ||
979 | err = fat_sync_bhs(bhs, n); | ||
980 | if (err) | ||
981 | goto error; | ||
982 | } | ||
983 | for (i = 0; i < n; i++) | ||
984 | brelse(bhs[i]); | ||
985 | |||
986 | return 0; | ||
987 | |||
988 | error: | ||
989 | for (i = 0; i < n; i++) | ||
990 | bforget(bhs[i]); | ||
991 | return err; | ||
992 | } | ||
993 | |||
994 | int fat_alloc_new_dir(struct inode *dir, struct timespec *ts) | ||
995 | { | ||
996 | struct super_block *sb = dir->i_sb; | ||
997 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
998 | struct buffer_head *bhs[MAX_BUF_PER_PAGE]; | ||
999 | struct msdos_dir_entry *de; | ||
1000 | sector_t blknr; | ||
1001 | __le16 date, time; | ||
1002 | int err, cluster; | ||
1003 | |||
1004 | err = fat_alloc_clusters(dir, &cluster, 1); | ||
1005 | if (err) | ||
1006 | goto error; | ||
1007 | |||
1008 | blknr = fat_clus_to_blknr(sbi, cluster); | ||
1009 | bhs[0] = sb_getblk(sb, blknr); | ||
1010 | if (!bhs[0]) { | ||
1011 | err = -ENOMEM; | ||
1012 | goto error_free; | ||
1013 | } | ||
1014 | |||
1015 | fat_date_unix2dos(ts->tv_sec, &time, &date); | ||
1016 | |||
1017 | de = (struct msdos_dir_entry *)bhs[0]->b_data; | ||
1018 | /* filling the new directory slots ("." and ".." entries) */ | ||
1019 | memcpy(de[0].name, MSDOS_DOT, MSDOS_NAME); | ||
1020 | memcpy(de[1].name, MSDOS_DOTDOT, MSDOS_NAME); | ||
1021 | de->attr = de[1].attr = ATTR_DIR; | ||
1022 | de[0].lcase = de[1].lcase = 0; | ||
1023 | de[0].time = de[1].time = time; | ||
1024 | de[0].date = de[1].date = date; | ||
1025 | de[0].ctime_cs = de[1].ctime_cs = 0; | ||
1026 | if (sbi->options.isvfat) { | ||
1027 | /* extra timestamps */ | ||
1028 | de[0].ctime = de[1].ctime = time; | ||
1029 | de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date; | ||
1030 | } else { | ||
1031 | de[0].ctime = de[1].ctime = 0; | ||
1032 | de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0; | ||
1033 | } | ||
1034 | de[0].start = cpu_to_le16(cluster); | ||
1035 | de[0].starthi = cpu_to_le16(cluster >> 16); | ||
1036 | de[1].start = cpu_to_le16(MSDOS_I(dir)->i_logstart); | ||
1037 | de[1].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart >> 16); | ||
1038 | de[0].size = de[1].size = 0; | ||
1039 | memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de)); | ||
1040 | set_buffer_uptodate(bhs[0]); | ||
1041 | mark_buffer_dirty(bhs[0]); | ||
1042 | |||
1043 | err = fat_zeroed_cluster(dir, blknr, 1, bhs, MAX_BUF_PER_PAGE); | ||
1044 | if (err) | ||
1045 | goto error_free; | ||
1046 | |||
1047 | return cluster; | ||
1048 | |||
1049 | error_free: | ||
1050 | fat_free_clusters(dir, cluster); | ||
1051 | error: | ||
1052 | return err; | ||
1053 | } | ||
1054 | |||
1055 | EXPORT_SYMBOL(fat_alloc_new_dir); | ||
1056 | |||
1057 | static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots, | ||
1058 | int *nr_cluster, struct msdos_dir_entry **de, | ||
1059 | struct buffer_head **bh, loff_t *i_pos) | ||
1060 | { | ||
1061 | struct super_block *sb = dir->i_sb; | ||
1062 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
1063 | struct buffer_head *bhs[MAX_BUF_PER_PAGE]; | ||
1064 | sector_t blknr, start_blknr, last_blknr; | ||
1065 | unsigned long size, copy; | ||
1066 | int err, i, n, offset, cluster[2]; | ||
1067 | |||
1068 | /* | ||
1069 | * The minimum cluster size is 512bytes, and maximum entry | ||
1070 | * size is 32*slots (672bytes). So, iff the cluster size is | ||
1071 | * 512bytes, we may need two clusters. | ||
1072 | */ | ||
1073 | size = nr_slots * sizeof(struct msdos_dir_entry); | ||
1074 | *nr_cluster = (size + (sbi->cluster_size - 1)) >> sbi->cluster_bits; | ||
1075 | BUG_ON(*nr_cluster > 2); | ||
1076 | |||
1077 | err = fat_alloc_clusters(dir, cluster, *nr_cluster); | ||
1078 | if (err) | ||
1079 | goto error; | ||
1080 | |||
1081 | /* | ||
1082 | * First stage: Fill the directory entry. NOTE: This cluster | ||
1083 | * is not referenced from any inode yet, so updates order is | ||
1084 | * not important. | ||
1085 | */ | ||
1086 | i = n = copy = 0; | ||
1087 | do { | ||
1088 | start_blknr = blknr = fat_clus_to_blknr(sbi, cluster[i]); | ||
1089 | last_blknr = start_blknr + sbi->sec_per_clus; | ||
1090 | while (blknr < last_blknr) { | ||
1091 | bhs[n] = sb_getblk(sb, blknr); | ||
1092 | if (!bhs[n]) { | ||
1093 | err = -ENOMEM; | ||
1094 | goto error_nomem; | ||
1095 | } | ||
1096 | |||
1097 | /* fill the directory entry */ | ||
1098 | copy = min(size, sb->s_blocksize); | ||
1099 | memcpy(bhs[n]->b_data, slots, copy); | ||
1100 | slots += copy; | ||
1101 | size -= copy; | ||
1102 | set_buffer_uptodate(bhs[n]); | ||
1103 | mark_buffer_dirty(bhs[n]); | ||
1104 | if (!size) | ||
1105 | break; | ||
1106 | n++; | ||
1107 | blknr++; | ||
1108 | } | ||
1109 | } while (++i < *nr_cluster); | ||
1110 | |||
1111 | memset(bhs[n]->b_data + copy, 0, sb->s_blocksize - copy); | ||
1112 | offset = copy - sizeof(struct msdos_dir_entry); | ||
1113 | get_bh(bhs[n]); | ||
1114 | *bh = bhs[n]; | ||
1115 | *de = (struct msdos_dir_entry *)((*bh)->b_data + offset); | ||
1116 | *i_pos = fat_make_i_pos(sb, *bh, *de); | ||
1117 | |||
1118 | /* Second stage: clear the rest of cluster, and write outs */ | ||
1119 | err = fat_zeroed_cluster(dir, start_blknr, ++n, bhs, MAX_BUF_PER_PAGE); | ||
1120 | if (err) | ||
1121 | goto error_free; | ||
1122 | |||
1123 | return cluster[0]; | ||
1124 | |||
1125 | error_free: | ||
1126 | brelse(*bh); | ||
1127 | *bh = NULL; | ||
1128 | n = 0; | ||
1129 | error_nomem: | ||
1130 | for (i = 0; i < n; i++) | ||
1131 | bforget(bhs[i]); | ||
1132 | fat_free_clusters(dir, cluster[0]); | ||
1133 | error: | ||
1134 | return err; | ||
1135 | } | ||
1136 | |||
1137 | int fat_add_entries(struct inode *dir, void *slots, int nr_slots, | ||
1138 | struct fat_slot_info *sinfo) | ||
1139 | { | ||
1140 | struct super_block *sb = dir->i_sb; | ||
1141 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
1142 | struct buffer_head *bh, *prev, *bhs[3]; /* 32*slots (672bytes) */ | ||
1143 | struct msdos_dir_entry *de; | ||
1144 | int err, free_slots, i, nr_bhs; | ||
1145 | loff_t pos, i_pos; | ||
1146 | |||
1147 | sinfo->nr_slots = nr_slots; | ||
1148 | |||
1149 | /* First stage: search free direcotry entries */ | ||
1150 | free_slots = nr_bhs = 0; | ||
1151 | bh = prev = NULL; | ||
1152 | pos = 0; | ||
1153 | err = -ENOSPC; | ||
1154 | while (fat_get_entry(dir, &pos, &bh, &de) > -1) { | ||
1155 | /* check the maximum size of directory */ | ||
1156 | if (pos >= FAT_MAX_DIR_SIZE) | ||
1157 | goto error; | ||
1158 | |||
1159 | if (IS_FREE(de->name)) { | ||
1160 | if (prev != bh) { | ||
1161 | get_bh(bh); | ||
1162 | bhs[nr_bhs] = prev = bh; | ||
1163 | nr_bhs++; | ||
1164 | } | ||
1165 | free_slots++; | ||
1166 | if (free_slots == nr_slots) | ||
1167 | goto found; | ||
1168 | } else { | ||
1169 | for (i = 0; i < nr_bhs; i++) | ||
1170 | brelse(bhs[i]); | ||
1171 | prev = NULL; | ||
1172 | free_slots = nr_bhs = 0; | ||
1173 | } | ||
1174 | } | ||
1175 | if (dir->i_ino == MSDOS_ROOT_INO) { | ||
1176 | if (sbi->fat_bits != 32) | ||
1177 | goto error; | ||
1178 | } else if (MSDOS_I(dir)->i_start == 0) { | ||
1179 | printk(KERN_ERR "FAT: Corrupted directory (i_pos %lld)\n", | ||
1180 | MSDOS_I(dir)->i_pos); | ||
1181 | err = -EIO; | ||
1182 | goto error; | ||
1183 | } | ||
1184 | |||
1185 | found: | ||
1186 | err = 0; | ||
1187 | pos -= free_slots * sizeof(*de); | ||
1188 | nr_slots -= free_slots; | ||
1189 | if (free_slots) { | ||
1190 | /* | ||
1191 | * Second stage: filling the free entries with new entries. | ||
1192 | * NOTE: If this slots has shortname, first, we write | ||
1193 | * the long name slots, then write the short name. | ||
1194 | */ | ||
1195 | int size = free_slots * sizeof(*de); | ||
1196 | int offset = pos & (sb->s_blocksize - 1); | ||
1197 | int long_bhs = nr_bhs - (nr_slots == 0); | ||
1198 | |||
1199 | /* Fill the long name slots. */ | ||
1200 | for (i = 0; i < long_bhs; i++) { | ||
1201 | int copy = min_t(int, sb->s_blocksize - offset, size); | ||
1202 | memcpy(bhs[i]->b_data + offset, slots, copy); | ||
1203 | mark_buffer_dirty(bhs[i]); | ||
1204 | offset = 0; | ||
1205 | slots += copy; | ||
1206 | size -= copy; | ||
1207 | } | ||
1208 | if (long_bhs && IS_DIRSYNC(dir)) | ||
1209 | err = fat_sync_bhs(bhs, long_bhs); | ||
1210 | if (!err && i < nr_bhs) { | ||
1211 | /* Fill the short name slot. */ | ||
1212 | int copy = min_t(int, sb->s_blocksize - offset, size); | ||
1213 | memcpy(bhs[i]->b_data + offset, slots, copy); | ||
1214 | mark_buffer_dirty(bhs[i]); | ||
1215 | if (IS_DIRSYNC(dir)) | ||
1216 | err = sync_dirty_buffer(bhs[i]); | ||
1217 | } | ||
1218 | for (i = 0; i < nr_bhs; i++) | ||
1219 | brelse(bhs[i]); | ||
1220 | if (err) | ||
1221 | goto error_remove; | ||
1222 | } | ||
1223 | |||
1224 | if (nr_slots) { | ||
1225 | int cluster, nr_cluster; | ||
1226 | |||
1227 | /* | ||
1228 | * Third stage: allocate the cluster for new entries. | ||
1229 | * And initialize the cluster with new entries, then | ||
1230 | * add the cluster to dir. | ||
1231 | */ | ||
1232 | cluster = fat_add_new_entries(dir, slots, nr_slots, &nr_cluster, | ||
1233 | &de, &bh, &i_pos); | ||
1234 | if (cluster < 0) { | ||
1235 | err = cluster; | ||
1236 | goto error_remove; | ||
1237 | } | ||
1238 | err = fat_chain_add(dir, cluster, nr_cluster); | ||
1239 | if (err) { | ||
1240 | fat_free_clusters(dir, cluster); | ||
1241 | goto error_remove; | ||
1242 | } | ||
1243 | if (dir->i_size & (sbi->cluster_size - 1)) { | ||
1244 | fat_fs_panic(sb, "Odd directory size"); | ||
1245 | dir->i_size = (dir->i_size + sbi->cluster_size - 1) | ||
1246 | & ~((loff_t)sbi->cluster_size - 1); | ||
1247 | } | ||
1248 | dir->i_size += nr_cluster << sbi->cluster_bits; | ||
1249 | MSDOS_I(dir)->mmu_private += nr_cluster << sbi->cluster_bits; | ||
1250 | } | ||
1251 | sinfo->slot_off = pos; | ||
1252 | sinfo->de = de; | ||
1253 | sinfo->bh = bh; | ||
1254 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); | ||
1255 | |||
1256 | return 0; | ||
1257 | |||
1258 | error: | ||
1259 | brelse(bh); | ||
1260 | for (i = 0; i < nr_bhs; i++) | ||
1261 | brelse(bhs[i]); | ||
1262 | return err; | ||
1263 | |||
1264 | error_remove: | ||
1265 | brelse(bh); | ||
1266 | if (free_slots) | ||
1267 | __fat_remove_entries(dir, pos, free_slots); | ||
1268 | return err; | ||
1269 | } | ||
1270 | |||
1271 | EXPORT_SYMBOL(fat_add_entries); | ||
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c new file mode 100644 index 000000000000..4164cd54c4d1 --- /dev/null +++ b/fs/fat/fatent.c | |||
@@ -0,0 +1,612 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004, OGAWA Hirofumi | ||
3 | * Released under GPL v2. | ||
4 | */ | ||
5 | |||
6 | #include <linux/module.h> | ||
7 | #include <linux/fs.h> | ||
8 | #include <linux/msdos_fs.h> | ||
9 | |||
10 | struct fatent_operations { | ||
11 | void (*ent_blocknr)(struct super_block *, int, int *, sector_t *); | ||
12 | void (*ent_set_ptr)(struct fat_entry *, int); | ||
13 | int (*ent_bread)(struct super_block *, struct fat_entry *, | ||
14 | int, sector_t); | ||
15 | int (*ent_get)(struct fat_entry *); | ||
16 | void (*ent_put)(struct fat_entry *, int); | ||
17 | int (*ent_next)(struct fat_entry *); | ||
18 | }; | ||
19 | |||
20 | static void fat12_ent_blocknr(struct super_block *sb, int entry, | ||
21 | int *offset, sector_t *blocknr) | ||
22 | { | ||
23 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
24 | int bytes = entry + (entry >> 1); | ||
25 | WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry); | ||
26 | *offset = bytes & (sb->s_blocksize - 1); | ||
27 | *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits); | ||
28 | } | ||
29 | |||
30 | static void fat_ent_blocknr(struct super_block *sb, int entry, | ||
31 | int *offset, sector_t *blocknr) | ||
32 | { | ||
33 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
34 | int bytes = (entry << sbi->fatent_shift); | ||
35 | WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry); | ||
36 | *offset = bytes & (sb->s_blocksize - 1); | ||
37 | *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits); | ||
38 | } | ||
39 | |||
40 | static void fat12_ent_set_ptr(struct fat_entry *fatent, int offset) | ||
41 | { | ||
42 | struct buffer_head **bhs = fatent->bhs; | ||
43 | if (fatent->nr_bhs == 1) { | ||
44 | WARN_ON(offset >= (bhs[0]->b_size - 1)); | ||
45 | fatent->u.ent12_p[0] = bhs[0]->b_data + offset; | ||
46 | fatent->u.ent12_p[1] = bhs[0]->b_data + (offset + 1); | ||
47 | } else { | ||
48 | WARN_ON(offset != (bhs[0]->b_size - 1)); | ||
49 | fatent->u.ent12_p[0] = bhs[0]->b_data + offset; | ||
50 | fatent->u.ent12_p[1] = bhs[1]->b_data; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | static void fat16_ent_set_ptr(struct fat_entry *fatent, int offset) | ||
55 | { | ||
56 | WARN_ON(offset & (2 - 1)); | ||
57 | fatent->u.ent16_p = (__le16 *)(fatent->bhs[0]->b_data + offset); | ||
58 | } | ||
59 | |||
60 | static void fat32_ent_set_ptr(struct fat_entry *fatent, int offset) | ||
61 | { | ||
62 | WARN_ON(offset & (4 - 1)); | ||
63 | fatent->u.ent32_p = (__le32 *)(fatent->bhs[0]->b_data + offset); | ||
64 | } | ||
65 | |||
66 | static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent, | ||
67 | int offset, sector_t blocknr) | ||
68 | { | ||
69 | struct buffer_head **bhs = fatent->bhs; | ||
70 | |||
71 | WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); | ||
72 | bhs[0] = sb_bread(sb, blocknr); | ||
73 | if (!bhs[0]) | ||
74 | goto err; | ||
75 | |||
76 | if ((offset + 1) < sb->s_blocksize) | ||
77 | fatent->nr_bhs = 1; | ||
78 | else { | ||
79 | /* This entry is block boundary, it needs the next block */ | ||
80 | blocknr++; | ||
81 | bhs[1] = sb_bread(sb, blocknr); | ||
82 | if (!bhs[1]) | ||
83 | goto err_brelse; | ||
84 | fatent->nr_bhs = 2; | ||
85 | } | ||
86 | fat12_ent_set_ptr(fatent, offset); | ||
87 | return 0; | ||
88 | |||
89 | err_brelse: | ||
90 | brelse(bhs[0]); | ||
91 | err: | ||
92 | printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n", | ||
93 | (unsigned long long)blocknr); | ||
94 | return -EIO; | ||
95 | } | ||
96 | |||
97 | static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent, | ||
98 | int offset, sector_t blocknr) | ||
99 | { | ||
100 | struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; | ||
101 | |||
102 | WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); | ||
103 | fatent->bhs[0] = sb_bread(sb, blocknr); | ||
104 | if (!fatent->bhs[0]) { | ||
105 | printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n", | ||
106 | (unsigned long long)blocknr); | ||
107 | return -EIO; | ||
108 | } | ||
109 | fatent->nr_bhs = 1; | ||
110 | ops->ent_set_ptr(fatent, offset); | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int fat12_ent_get(struct fat_entry *fatent) | ||
115 | { | ||
116 | u8 **ent12_p = fatent->u.ent12_p; | ||
117 | int next; | ||
118 | |||
119 | if (fatent->entry & 1) | ||
120 | next = (*ent12_p[0] >> 4) | (*ent12_p[1] << 4); | ||
121 | else | ||
122 | next = (*ent12_p[1] << 8) | *ent12_p[0]; | ||
123 | next &= 0x0fff; | ||
124 | if (next >= BAD_FAT12) | ||
125 | next = FAT_ENT_EOF; | ||
126 | return next; | ||
127 | } | ||
128 | |||
129 | static int fat16_ent_get(struct fat_entry *fatent) | ||
130 | { | ||
131 | int next = le16_to_cpu(*fatent->u.ent16_p); | ||
132 | WARN_ON((unsigned long)fatent->u.ent16_p & (2 - 1)); | ||
133 | if (next >= BAD_FAT16) | ||
134 | next = FAT_ENT_EOF; | ||
135 | return next; | ||
136 | } | ||
137 | |||
138 | static int fat32_ent_get(struct fat_entry *fatent) | ||
139 | { | ||
140 | int next = le32_to_cpu(*fatent->u.ent32_p) & 0x0fffffff; | ||
141 | WARN_ON((unsigned long)fatent->u.ent32_p & (4 - 1)); | ||
142 | if (next >= BAD_FAT32) | ||
143 | next = FAT_ENT_EOF; | ||
144 | return next; | ||
145 | } | ||
146 | |||
147 | static void fat12_ent_put(struct fat_entry *fatent, int new) | ||
148 | { | ||
149 | u8 **ent12_p = fatent->u.ent12_p; | ||
150 | |||
151 | if (new == FAT_ENT_EOF) | ||
152 | new = EOF_FAT12; | ||
153 | |||
154 | if (fatent->entry & 1) { | ||
155 | *ent12_p[0] = (new << 4) | (*ent12_p[0] & 0x0f); | ||
156 | *ent12_p[1] = new >> 4; | ||
157 | } else { | ||
158 | *ent12_p[0] = new & 0xff; | ||
159 | *ent12_p[1] = (*ent12_p[1] & 0xf0) | (new >> 8); | ||
160 | } | ||
161 | |||
162 | mark_buffer_dirty(fatent->bhs[0]); | ||
163 | if (fatent->nr_bhs == 2) | ||
164 | mark_buffer_dirty(fatent->bhs[1]); | ||
165 | } | ||
166 | |||
167 | static void fat16_ent_put(struct fat_entry *fatent, int new) | ||
168 | { | ||
169 | if (new == FAT_ENT_EOF) | ||
170 | new = EOF_FAT16; | ||
171 | |||
172 | *fatent->u.ent16_p = cpu_to_le16(new); | ||
173 | mark_buffer_dirty(fatent->bhs[0]); | ||
174 | } | ||
175 | |||
176 | static void fat32_ent_put(struct fat_entry *fatent, int new) | ||
177 | { | ||
178 | if (new == FAT_ENT_EOF) | ||
179 | new = EOF_FAT32; | ||
180 | |||
181 | WARN_ON(new & 0xf0000000); | ||
182 | new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff; | ||
183 | *fatent->u.ent32_p = cpu_to_le32(new); | ||
184 | mark_buffer_dirty(fatent->bhs[0]); | ||
185 | } | ||
186 | |||
187 | static int fat12_ent_next(struct fat_entry *fatent) | ||
188 | { | ||
189 | u8 **ent12_p = fatent->u.ent12_p; | ||
190 | struct buffer_head **bhs = fatent->bhs; | ||
191 | u8 *nextp = ent12_p[1] + 1 + (fatent->entry & 1); | ||
192 | |||
193 | fatent->entry++; | ||
194 | if (fatent->nr_bhs == 1) { | ||
195 | WARN_ON(ent12_p[0] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 2))); | ||
196 | WARN_ON(ent12_p[1] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))); | ||
197 | if (nextp < (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))) { | ||
198 | ent12_p[0] = nextp - 1; | ||
199 | ent12_p[1] = nextp; | ||
200 | return 1; | ||
201 | } | ||
202 | } else { | ||
203 | WARN_ON(ent12_p[0] != (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))); | ||
204 | WARN_ON(ent12_p[1] != (u8 *)bhs[1]->b_data); | ||
205 | ent12_p[0] = nextp - 1; | ||
206 | ent12_p[1] = nextp; | ||
207 | brelse(bhs[0]); | ||
208 | bhs[0] = bhs[1]; | ||
209 | fatent->nr_bhs = 1; | ||
210 | return 1; | ||
211 | } | ||
212 | ent12_p[0] = NULL; | ||
213 | ent12_p[1] = NULL; | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static int fat16_ent_next(struct fat_entry *fatent) | ||
218 | { | ||
219 | const struct buffer_head *bh = fatent->bhs[0]; | ||
220 | fatent->entry++; | ||
221 | if (fatent->u.ent16_p < (__le16 *)(bh->b_data + (bh->b_size - 2))) { | ||
222 | fatent->u.ent16_p++; | ||
223 | return 1; | ||
224 | } | ||
225 | fatent->u.ent16_p = NULL; | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int fat32_ent_next(struct fat_entry *fatent) | ||
230 | { | ||
231 | const struct buffer_head *bh = fatent->bhs[0]; | ||
232 | fatent->entry++; | ||
233 | if (fatent->u.ent32_p < (__le32 *)(bh->b_data + (bh->b_size - 4))) { | ||
234 | fatent->u.ent32_p++; | ||
235 | return 1; | ||
236 | } | ||
237 | fatent->u.ent32_p = NULL; | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static struct fatent_operations fat12_ops = { | ||
242 | .ent_blocknr = fat12_ent_blocknr, | ||
243 | .ent_set_ptr = fat12_ent_set_ptr, | ||
244 | .ent_bread = fat12_ent_bread, | ||
245 | .ent_get = fat12_ent_get, | ||
246 | .ent_put = fat12_ent_put, | ||
247 | .ent_next = fat12_ent_next, | ||
248 | }; | ||
249 | |||
250 | static struct fatent_operations fat16_ops = { | ||
251 | .ent_blocknr = fat_ent_blocknr, | ||
252 | .ent_set_ptr = fat16_ent_set_ptr, | ||
253 | .ent_bread = fat_ent_bread, | ||
254 | .ent_get = fat16_ent_get, | ||
255 | .ent_put = fat16_ent_put, | ||
256 | .ent_next = fat16_ent_next, | ||
257 | }; | ||
258 | |||
259 | static struct fatent_operations fat32_ops = { | ||
260 | .ent_blocknr = fat_ent_blocknr, | ||
261 | .ent_set_ptr = fat32_ent_set_ptr, | ||
262 | .ent_bread = fat_ent_bread, | ||
263 | .ent_get = fat32_ent_get, | ||
264 | .ent_put = fat32_ent_put, | ||
265 | .ent_next = fat32_ent_next, | ||
266 | }; | ||
267 | |||
268 | static inline void lock_fat(struct msdos_sb_info *sbi) | ||
269 | { | ||
270 | down(&sbi->fat_lock); | ||
271 | } | ||
272 | |||
273 | static inline void unlock_fat(struct msdos_sb_info *sbi) | ||
274 | { | ||
275 | up(&sbi->fat_lock); | ||
276 | } | ||
277 | |||
278 | void fat_ent_access_init(struct super_block *sb) | ||
279 | { | ||
280 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
281 | |||
282 | init_MUTEX(&sbi->fat_lock); | ||
283 | |||
284 | switch (sbi->fat_bits) { | ||
285 | case 32: | ||
286 | sbi->fatent_shift = 2; | ||
287 | sbi->fatent_ops = &fat32_ops; | ||
288 | break; | ||
289 | case 16: | ||
290 | sbi->fatent_shift = 1; | ||
291 | sbi->fatent_ops = &fat16_ops; | ||
292 | break; | ||
293 | case 12: | ||
294 | sbi->fatent_shift = -1; | ||
295 | sbi->fatent_ops = &fat12_ops; | ||
296 | break; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | static inline int fat_ent_update_ptr(struct super_block *sb, | ||
301 | struct fat_entry *fatent, | ||
302 | int offset, sector_t blocknr) | ||
303 | { | ||
304 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
305 | struct fatent_operations *ops = sbi->fatent_ops; | ||
306 | struct buffer_head **bhs = fatent->bhs; | ||
307 | |||
308 | /* Is this fatent's blocks including this entry? */ | ||
309 | if (!fatent->nr_bhs || bhs[0]->b_blocknr != blocknr) | ||
310 | return 0; | ||
311 | /* Does this entry need the next block? */ | ||
312 | if (sbi->fat_bits == 12 && (offset + 1) >= sb->s_blocksize) { | ||
313 | if (fatent->nr_bhs != 2 || bhs[1]->b_blocknr != (blocknr + 1)) | ||
314 | return 0; | ||
315 | } | ||
316 | ops->ent_set_ptr(fatent, offset); | ||
317 | return 1; | ||
318 | } | ||
319 | |||
320 | int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry) | ||
321 | { | ||
322 | struct super_block *sb = inode->i_sb; | ||
323 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
324 | struct fatent_operations *ops = sbi->fatent_ops; | ||
325 | int err, offset; | ||
326 | sector_t blocknr; | ||
327 | |||
328 | if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { | ||
329 | fatent_brelse(fatent); | ||
330 | fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", entry); | ||
331 | return -EIO; | ||
332 | } | ||
333 | |||
334 | fatent_set_entry(fatent, entry); | ||
335 | ops->ent_blocknr(sb, entry, &offset, &blocknr); | ||
336 | |||
337 | if (!fat_ent_update_ptr(sb, fatent, offset, blocknr)) { | ||
338 | fatent_brelse(fatent); | ||
339 | err = ops->ent_bread(sb, fatent, offset, blocknr); | ||
340 | if (err) | ||
341 | return err; | ||
342 | } | ||
343 | return ops->ent_get(fatent); | ||
344 | } | ||
345 | |||
346 | /* FIXME: We can write the blocks as more big chunk. */ | ||
347 | static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs, | ||
348 | int nr_bhs) | ||
349 | { | ||
350 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
351 | struct buffer_head *c_bh; | ||
352 | int err, n, copy; | ||
353 | |||
354 | err = 0; | ||
355 | for (copy = 1; copy < sbi->fats; copy++) { | ||
356 | sector_t backup_fat = sbi->fat_length * copy; | ||
357 | |||
358 | for (n = 0; n < nr_bhs; n++) { | ||
359 | c_bh = sb_getblk(sb, backup_fat + bhs[n]->b_blocknr); | ||
360 | if (!c_bh) { | ||
361 | err = -ENOMEM; | ||
362 | goto error; | ||
363 | } | ||
364 | memcpy(c_bh->b_data, bhs[n]->b_data, sb->s_blocksize); | ||
365 | set_buffer_uptodate(c_bh); | ||
366 | mark_buffer_dirty(c_bh); | ||
367 | if (sb->s_flags & MS_SYNCHRONOUS) | ||
368 | err = sync_dirty_buffer(c_bh); | ||
369 | brelse(c_bh); | ||
370 | if (err) | ||
371 | goto error; | ||
372 | } | ||
373 | } | ||
374 | error: | ||
375 | return err; | ||
376 | } | ||
377 | |||
378 | int fat_ent_write(struct inode *inode, struct fat_entry *fatent, | ||
379 | int new, int wait) | ||
380 | { | ||
381 | struct super_block *sb = inode->i_sb; | ||
382 | struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; | ||
383 | int err; | ||
384 | |||
385 | ops->ent_put(fatent, new); | ||
386 | if (wait) { | ||
387 | err = fat_sync_bhs(fatent->bhs, fatent->nr_bhs); | ||
388 | if (err) | ||
389 | return err; | ||
390 | } | ||
391 | return fat_mirror_bhs(sb, fatent->bhs, fatent->nr_bhs); | ||
392 | } | ||
393 | |||
394 | static inline int fat_ent_next(struct msdos_sb_info *sbi, | ||
395 | struct fat_entry *fatent) | ||
396 | { | ||
397 | if (sbi->fatent_ops->ent_next(fatent)) { | ||
398 | if (fatent->entry < sbi->max_cluster) | ||
399 | return 1; | ||
400 | } | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static inline int fat_ent_read_block(struct super_block *sb, | ||
405 | struct fat_entry *fatent) | ||
406 | { | ||
407 | struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; | ||
408 | sector_t blocknr; | ||
409 | int offset; | ||
410 | |||
411 | fatent_brelse(fatent); | ||
412 | ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr); | ||
413 | return ops->ent_bread(sb, fatent, offset, blocknr); | ||
414 | } | ||
415 | |||
416 | static void fat_collect_bhs(struct buffer_head **bhs, int *nr_bhs, | ||
417 | struct fat_entry *fatent) | ||
418 | { | ||
419 | int n, i; | ||
420 | |||
421 | for (n = 0; n < fatent->nr_bhs; n++) { | ||
422 | for (i = 0; i < *nr_bhs; i++) { | ||
423 | if (fatent->bhs[n] == bhs[i]) | ||
424 | break; | ||
425 | } | ||
426 | if (i == *nr_bhs) { | ||
427 | get_bh(fatent->bhs[n]); | ||
428 | bhs[i] = fatent->bhs[n]; | ||
429 | (*nr_bhs)++; | ||
430 | } | ||
431 | } | ||
432 | } | ||
433 | |||
434 | int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster) | ||
435 | { | ||
436 | struct super_block *sb = inode->i_sb; | ||
437 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
438 | struct fatent_operations *ops = sbi->fatent_ops; | ||
439 | struct fat_entry fatent, prev_ent; | ||
440 | struct buffer_head *bhs[MAX_BUF_PER_PAGE]; | ||
441 | int i, count, err, nr_bhs, idx_clus; | ||
442 | |||
443 | BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2)); /* fixed limit */ | ||
444 | |||
445 | lock_fat(sbi); | ||
446 | if (sbi->free_clusters != -1 && sbi->free_clusters < nr_cluster) { | ||
447 | unlock_fat(sbi); | ||
448 | return -ENOSPC; | ||
449 | } | ||
450 | |||
451 | err = nr_bhs = idx_clus = 0; | ||
452 | count = FAT_START_ENT; | ||
453 | fatent_init(&prev_ent); | ||
454 | fatent_init(&fatent); | ||
455 | fatent_set_entry(&fatent, sbi->prev_free + 1); | ||
456 | while (count < sbi->max_cluster) { | ||
457 | if (fatent.entry >= sbi->max_cluster) | ||
458 | fatent.entry = FAT_START_ENT; | ||
459 | fatent_set_entry(&fatent, fatent.entry); | ||
460 | err = fat_ent_read_block(sb, &fatent); | ||
461 | if (err) | ||
462 | goto out; | ||
463 | |||
464 | /* Find the free entries in a block */ | ||
465 | do { | ||
466 | if (ops->ent_get(&fatent) == FAT_ENT_FREE) { | ||
467 | int entry = fatent.entry; | ||
468 | |||
469 | /* make the cluster chain */ | ||
470 | ops->ent_put(&fatent, FAT_ENT_EOF); | ||
471 | if (prev_ent.nr_bhs) | ||
472 | ops->ent_put(&prev_ent, entry); | ||
473 | |||
474 | fat_collect_bhs(bhs, &nr_bhs, &fatent); | ||
475 | |||
476 | sbi->prev_free = entry; | ||
477 | if (sbi->free_clusters != -1) | ||
478 | sbi->free_clusters--; | ||
479 | |||
480 | cluster[idx_clus] = entry; | ||
481 | idx_clus++; | ||
482 | if (idx_clus == nr_cluster) | ||
483 | goto out; | ||
484 | |||
485 | /* | ||
486 | * fat_collect_bhs() gets ref-count of bhs, | ||
487 | * so we can still use the prev_ent. | ||
488 | */ | ||
489 | prev_ent = fatent; | ||
490 | } | ||
491 | count++; | ||
492 | if (count == sbi->max_cluster) | ||
493 | break; | ||
494 | } while (fat_ent_next(sbi, &fatent)); | ||
495 | } | ||
496 | |||
497 | /* Couldn't allocate the free entries */ | ||
498 | sbi->free_clusters = 0; | ||
499 | err = -ENOSPC; | ||
500 | |||
501 | out: | ||
502 | unlock_fat(sbi); | ||
503 | fatent_brelse(&fatent); | ||
504 | if (!err) { | ||
505 | if (inode_needs_sync(inode)) | ||
506 | err = fat_sync_bhs(bhs, nr_bhs); | ||
507 | if (!err) | ||
508 | err = fat_mirror_bhs(sb, bhs, nr_bhs); | ||
509 | } | ||
510 | for (i = 0; i < nr_bhs; i++) | ||
511 | brelse(bhs[i]); | ||
512 | fat_clusters_flush(sb); | ||
513 | |||
514 | if (err && idx_clus) | ||
515 | fat_free_clusters(inode, cluster[0]); | ||
516 | |||
517 | return err; | ||
518 | } | ||
519 | |||
520 | int fat_free_clusters(struct inode *inode, int cluster) | ||
521 | { | ||
522 | struct super_block *sb = inode->i_sb; | ||
523 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
524 | struct fatent_operations *ops = sbi->fatent_ops; | ||
525 | struct fat_entry fatent; | ||
526 | struct buffer_head *bhs[MAX_BUF_PER_PAGE]; | ||
527 | int i, err, nr_bhs; | ||
528 | |||
529 | nr_bhs = 0; | ||
530 | fatent_init(&fatent); | ||
531 | lock_fat(sbi); | ||
532 | do { | ||
533 | cluster = fat_ent_read(inode, &fatent, cluster); | ||
534 | if (cluster < 0) { | ||
535 | err = cluster; | ||
536 | goto error; | ||
537 | } else if (cluster == FAT_ENT_FREE) { | ||
538 | fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF", | ||
539 | __FUNCTION__); | ||
540 | err = -EIO; | ||
541 | goto error; | ||
542 | } | ||
543 | |||
544 | ops->ent_put(&fatent, FAT_ENT_FREE); | ||
545 | if (sbi->free_clusters != -1) | ||
546 | sbi->free_clusters++; | ||
547 | |||
548 | if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) { | ||
549 | if (sb->s_flags & MS_SYNCHRONOUS) { | ||
550 | err = fat_sync_bhs(bhs, nr_bhs); | ||
551 | if (err) | ||
552 | goto error; | ||
553 | } | ||
554 | err = fat_mirror_bhs(sb, bhs, nr_bhs); | ||
555 | if (err) | ||
556 | goto error; | ||
557 | for (i = 0; i < nr_bhs; i++) | ||
558 | brelse(bhs[i]); | ||
559 | nr_bhs = 0; | ||
560 | } | ||
561 | fat_collect_bhs(bhs, &nr_bhs, &fatent); | ||
562 | } while (cluster != FAT_ENT_EOF); | ||
563 | |||
564 | if (sb->s_flags & MS_SYNCHRONOUS) { | ||
565 | err = fat_sync_bhs(bhs, nr_bhs); | ||
566 | if (err) | ||
567 | goto error; | ||
568 | } | ||
569 | err = fat_mirror_bhs(sb, bhs, nr_bhs); | ||
570 | error: | ||
571 | fatent_brelse(&fatent); | ||
572 | for (i = 0; i < nr_bhs; i++) | ||
573 | brelse(bhs[i]); | ||
574 | unlock_fat(sbi); | ||
575 | |||
576 | fat_clusters_flush(sb); | ||
577 | |||
578 | return err; | ||
579 | } | ||
580 | |||
581 | EXPORT_SYMBOL(fat_free_clusters); | ||
582 | |||
583 | int fat_count_free_clusters(struct super_block *sb) | ||
584 | { | ||
585 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
586 | struct fatent_operations *ops = sbi->fatent_ops; | ||
587 | struct fat_entry fatent; | ||
588 | int err = 0, free; | ||
589 | |||
590 | lock_fat(sbi); | ||
591 | if (sbi->free_clusters != -1) | ||
592 | goto out; | ||
593 | |||
594 | free = 0; | ||
595 | fatent_init(&fatent); | ||
596 | fatent_set_entry(&fatent, FAT_START_ENT); | ||
597 | while (fatent.entry < sbi->max_cluster) { | ||
598 | err = fat_ent_read_block(sb, &fatent); | ||
599 | if (err) | ||
600 | goto out; | ||
601 | |||
602 | do { | ||
603 | if (ops->ent_get(&fatent) == FAT_ENT_FREE) | ||
604 | free++; | ||
605 | } while (fat_ent_next(sbi, &fatent)); | ||
606 | } | ||
607 | sbi->free_clusters = free; | ||
608 | fatent_brelse(&fatent); | ||
609 | out: | ||
610 | unlock_fat(sbi); | ||
611 | return err; | ||
612 | } | ||
diff --git a/fs/fat/file.c b/fs/fat/file.c new file mode 100644 index 000000000000..62ffa9139400 --- /dev/null +++ b/fs/fat/file.c | |||
@@ -0,0 +1,308 @@ | |||
1 | /* | ||
2 | * linux/fs/fat/file.c | ||
3 | * | ||
4 | * Written 1992,1993 by Werner Almesberger | ||
5 | * | ||
6 | * regular file handling primitives for fat-based filesystems | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/time.h> | ||
11 | #include <linux/msdos_fs.h> | ||
12 | #include <linux/smp_lock.h> | ||
13 | #include <linux/buffer_head.h> | ||
14 | |||
15 | static ssize_t fat_file_aio_write(struct kiocb *iocb, const char __user *buf, | ||
16 | size_t count, loff_t pos) | ||
17 | { | ||
18 | struct inode *inode = iocb->ki_filp->f_dentry->d_inode; | ||
19 | int retval; | ||
20 | |||
21 | retval = generic_file_aio_write(iocb, buf, count, pos); | ||
22 | if (retval > 0) { | ||
23 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; | ||
24 | MSDOS_I(inode)->i_attrs |= ATTR_ARCH; | ||
25 | mark_inode_dirty(inode); | ||
26 | // check the locking rules | ||
27 | // if (IS_SYNC(inode)) | ||
28 | // fat_sync_inode(inode); | ||
29 | } | ||
30 | return retval; | ||
31 | } | ||
32 | |||
33 | static ssize_t fat_file_writev(struct file *filp, const struct iovec *iov, | ||
34 | unsigned long nr_segs, loff_t *ppos) | ||
35 | { | ||
36 | struct inode *inode = filp->f_dentry->d_inode; | ||
37 | int retval; | ||
38 | |||
39 | retval = generic_file_writev(filp, iov, nr_segs, ppos); | ||
40 | if (retval > 0) { | ||
41 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; | ||
42 | MSDOS_I(inode)->i_attrs |= ATTR_ARCH; | ||
43 | mark_inode_dirty(inode); | ||
44 | } | ||
45 | return retval; | ||
46 | } | ||
47 | |||
48 | int fat_generic_ioctl(struct inode *inode, struct file *filp, | ||
49 | unsigned int cmd, unsigned long arg) | ||
50 | { | ||
51 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
52 | u32 __user *user_attr = (u32 __user *)arg; | ||
53 | |||
54 | switch (cmd) { | ||
55 | case FAT_IOCTL_GET_ATTRIBUTES: | ||
56 | { | ||
57 | u32 attr; | ||
58 | |||
59 | if (inode->i_ino == MSDOS_ROOT_INO) | ||
60 | attr = ATTR_DIR; | ||
61 | else | ||
62 | attr = fat_attr(inode); | ||
63 | |||
64 | return put_user(attr, user_attr); | ||
65 | } | ||
66 | case FAT_IOCTL_SET_ATTRIBUTES: | ||
67 | { | ||
68 | u32 attr, oldattr; | ||
69 | int err, is_dir = S_ISDIR(inode->i_mode); | ||
70 | struct iattr ia; | ||
71 | |||
72 | err = get_user(attr, user_attr); | ||
73 | if (err) | ||
74 | return err; | ||
75 | |||
76 | down(&inode->i_sem); | ||
77 | |||
78 | if (IS_RDONLY(inode)) { | ||
79 | err = -EROFS; | ||
80 | goto up; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * ATTR_VOLUME and ATTR_DIR cannot be changed; this also | ||
85 | * prevents the user from turning us into a VFAT | ||
86 | * longname entry. Also, we obviously can't set | ||
87 | * any of the NTFS attributes in the high 24 bits. | ||
88 | */ | ||
89 | attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); | ||
90 | /* Merge in ATTR_VOLUME and ATTR_DIR */ | ||
91 | attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | | ||
92 | (is_dir ? ATTR_DIR : 0); | ||
93 | oldattr = fat_attr(inode); | ||
94 | |||
95 | /* Equivalent to a chmod() */ | ||
96 | ia.ia_valid = ATTR_MODE | ATTR_CTIME; | ||
97 | if (is_dir) { | ||
98 | ia.ia_mode = MSDOS_MKMODE(attr, | ||
99 | S_IRWXUGO & ~sbi->options.fs_dmask) | ||
100 | | S_IFDIR; | ||
101 | } else { | ||
102 | ia.ia_mode = MSDOS_MKMODE(attr, | ||
103 | (S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)) | ||
104 | & ~sbi->options.fs_fmask) | ||
105 | | S_IFREG; | ||
106 | } | ||
107 | |||
108 | /* The root directory has no attributes */ | ||
109 | if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { | ||
110 | err = -EINVAL; | ||
111 | goto up; | ||
112 | } | ||
113 | |||
114 | if (sbi->options.sys_immutable) { | ||
115 | if ((attr | oldattr) & ATTR_SYS) { | ||
116 | if (!capable(CAP_LINUX_IMMUTABLE)) { | ||
117 | err = -EPERM; | ||
118 | goto up; | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /* This MUST be done before doing anything irreversible... */ | ||
124 | err = notify_change(filp->f_dentry, &ia); | ||
125 | if (err) | ||
126 | goto up; | ||
127 | |||
128 | if (sbi->options.sys_immutable) { | ||
129 | if (attr & ATTR_SYS) | ||
130 | inode->i_flags |= S_IMMUTABLE; | ||
131 | else | ||
132 | inode->i_flags &= S_IMMUTABLE; | ||
133 | } | ||
134 | |||
135 | MSDOS_I(inode)->i_attrs = attr & ATTR_UNUSED; | ||
136 | mark_inode_dirty(inode); | ||
137 | up: | ||
138 | up(&inode->i_sem); | ||
139 | return err; | ||
140 | } | ||
141 | default: | ||
142 | return -ENOTTY; /* Inappropriate ioctl for device */ | ||
143 | } | ||
144 | } | ||
145 | |||
146 | struct file_operations fat_file_operations = { | ||
147 | .llseek = generic_file_llseek, | ||
148 | .read = do_sync_read, | ||
149 | .write = do_sync_write, | ||
150 | .readv = generic_file_readv, | ||
151 | .writev = fat_file_writev, | ||
152 | .aio_read = generic_file_aio_read, | ||
153 | .aio_write = fat_file_aio_write, | ||
154 | .mmap = generic_file_mmap, | ||
155 | .ioctl = fat_generic_ioctl, | ||
156 | .fsync = file_fsync, | ||
157 | .sendfile = generic_file_sendfile, | ||
158 | }; | ||
159 | |||
160 | int fat_notify_change(struct dentry *dentry, struct iattr *attr) | ||
161 | { | ||
162 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | ||
163 | struct inode *inode = dentry->d_inode; | ||
164 | int mask, error = 0; | ||
165 | |||
166 | lock_kernel(); | ||
167 | |||
168 | /* FAT cannot truncate to a longer file */ | ||
169 | if (attr->ia_valid & ATTR_SIZE) { | ||
170 | if (attr->ia_size > inode->i_size) { | ||
171 | error = -EPERM; | ||
172 | goto out; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | error = inode_change_ok(inode, attr); | ||
177 | if (error) { | ||
178 | if (sbi->options.quiet) | ||
179 | error = 0; | ||
180 | goto out; | ||
181 | } | ||
182 | if (((attr->ia_valid & ATTR_UID) && | ||
183 | (attr->ia_uid != sbi->options.fs_uid)) || | ||
184 | ((attr->ia_valid & ATTR_GID) && | ||
185 | (attr->ia_gid != sbi->options.fs_gid)) || | ||
186 | ((attr->ia_valid & ATTR_MODE) && | ||
187 | (attr->ia_mode & ~MSDOS_VALID_MODE))) | ||
188 | error = -EPERM; | ||
189 | |||
190 | if (error) { | ||
191 | if (sbi->options.quiet) | ||
192 | error = 0; | ||
193 | goto out; | ||
194 | } | ||
195 | error = inode_setattr(inode, attr); | ||
196 | if (error) | ||
197 | goto out; | ||
198 | |||
199 | if (S_ISDIR(inode->i_mode)) | ||
200 | mask = sbi->options.fs_dmask; | ||
201 | else | ||
202 | mask = sbi->options.fs_fmask; | ||
203 | inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask); | ||
204 | out: | ||
205 | unlock_kernel(); | ||
206 | return error; | ||
207 | } | ||
208 | |||
209 | EXPORT_SYMBOL(fat_notify_change); | ||
210 | |||
211 | /* Free all clusters after the skip'th cluster. */ | ||
212 | static int fat_free(struct inode *inode, int skip) | ||
213 | { | ||
214 | struct super_block *sb = inode->i_sb; | ||
215 | int err, wait, free_start, i_start, i_logstart; | ||
216 | |||
217 | if (MSDOS_I(inode)->i_start == 0) | ||
218 | return 0; | ||
219 | |||
220 | /* | ||
221 | * Write a new EOF, and get the remaining cluster chain for freeing. | ||
222 | */ | ||
223 | wait = IS_DIRSYNC(inode); | ||
224 | if (skip) { | ||
225 | struct fat_entry fatent; | ||
226 | int ret, fclus, dclus; | ||
227 | |||
228 | ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus); | ||
229 | if (ret < 0) | ||
230 | return ret; | ||
231 | else if (ret == FAT_ENT_EOF) | ||
232 | return 0; | ||
233 | |||
234 | fatent_init(&fatent); | ||
235 | ret = fat_ent_read(inode, &fatent, dclus); | ||
236 | if (ret == FAT_ENT_EOF) { | ||
237 | fatent_brelse(&fatent); | ||
238 | return 0; | ||
239 | } else if (ret == FAT_ENT_FREE) { | ||
240 | fat_fs_panic(sb, | ||
241 | "%s: invalid cluster chain (i_pos %lld)", | ||
242 | __FUNCTION__, MSDOS_I(inode)->i_pos); | ||
243 | ret = -EIO; | ||
244 | } else if (ret > 0) { | ||
245 | err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait); | ||
246 | if (err) | ||
247 | ret = err; | ||
248 | } | ||
249 | fatent_brelse(&fatent); | ||
250 | if (ret < 0) | ||
251 | return ret; | ||
252 | |||
253 | free_start = ret; | ||
254 | i_start = i_logstart = 0; | ||
255 | fat_cache_inval_inode(inode); | ||
256 | } else { | ||
257 | fat_cache_inval_inode(inode); | ||
258 | |||
259 | i_start = free_start = MSDOS_I(inode)->i_start; | ||
260 | i_logstart = MSDOS_I(inode)->i_logstart; | ||
261 | MSDOS_I(inode)->i_start = 0; | ||
262 | MSDOS_I(inode)->i_logstart = 0; | ||
263 | } | ||
264 | MSDOS_I(inode)->i_attrs |= ATTR_ARCH; | ||
265 | inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; | ||
266 | if (wait) { | ||
267 | err = fat_sync_inode(inode); | ||
268 | if (err) | ||
269 | goto error; | ||
270 | } else | ||
271 | mark_inode_dirty(inode); | ||
272 | inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9); | ||
273 | |||
274 | /* Freeing the remained cluster chain */ | ||
275 | return fat_free_clusters(inode, free_start); | ||
276 | |||
277 | error: | ||
278 | if (i_start) { | ||
279 | MSDOS_I(inode)->i_start = i_start; | ||
280 | MSDOS_I(inode)->i_logstart = i_logstart; | ||
281 | } | ||
282 | return err; | ||
283 | } | ||
284 | |||
285 | void fat_truncate(struct inode *inode) | ||
286 | { | ||
287 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
288 | const unsigned int cluster_size = sbi->cluster_size; | ||
289 | int nr_clusters; | ||
290 | |||
291 | /* | ||
292 | * This protects against truncating a file bigger than it was then | ||
293 | * trying to write into the hole. | ||
294 | */ | ||
295 | if (MSDOS_I(inode)->mmu_private > inode->i_size) | ||
296 | MSDOS_I(inode)->mmu_private = inode->i_size; | ||
297 | |||
298 | nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits; | ||
299 | |||
300 | lock_kernel(); | ||
301 | fat_free(inode, nr_clusters); | ||
302 | unlock_kernel(); | ||
303 | } | ||
304 | |||
305 | struct inode_operations fat_file_inode_operations = { | ||
306 | .truncate = fat_truncate, | ||
307 | .setattr = fat_notify_change, | ||
308 | }; | ||
diff --git a/fs/fat/inode.c b/fs/fat/inode.c new file mode 100644 index 000000000000..8ccee8415488 --- /dev/null +++ b/fs/fat/inode.c | |||
@@ -0,0 +1,1351 @@ | |||
1 | /* | ||
2 | * linux/fs/fat/inode.c | ||
3 | * | ||
4 | * Written 1992,1993 by Werner Almesberger | ||
5 | * VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner | ||
6 | * Rewritten for the constant inumbers support by Al Viro | ||
7 | * | ||
8 | * Fixes: | ||
9 | * | ||
10 | * Max Cohan: Fixed invalid FSINFO offset when info_sector is 0 | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/time.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/smp_lock.h> | ||
18 | #include <linux/seq_file.h> | ||
19 | #include <linux/msdos_fs.h> | ||
20 | #include <linux/pagemap.h> | ||
21 | #include <linux/buffer_head.h> | ||
22 | #include <linux/mount.h> | ||
23 | #include <linux/vfs.h> | ||
24 | #include <linux/parser.h> | ||
25 | #include <asm/unaligned.h> | ||
26 | |||
27 | #ifndef CONFIG_FAT_DEFAULT_IOCHARSET | ||
28 | /* if user don't select VFAT, this is undefined. */ | ||
29 | #define CONFIG_FAT_DEFAULT_IOCHARSET "" | ||
30 | #endif | ||
31 | |||
32 | static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE; | ||
33 | static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET; | ||
34 | |||
35 | |||
36 | static int fat_add_cluster(struct inode *inode) | ||
37 | { | ||
38 | int err, cluster; | ||
39 | |||
40 | err = fat_alloc_clusters(inode, &cluster, 1); | ||
41 | if (err) | ||
42 | return err; | ||
43 | /* FIXME: this cluster should be added after data of this | ||
44 | * cluster is writed */ | ||
45 | err = fat_chain_add(inode, cluster, 1); | ||
46 | if (err) | ||
47 | fat_free_clusters(inode, cluster); | ||
48 | return err; | ||
49 | } | ||
50 | |||
51 | static int fat_get_block(struct inode *inode, sector_t iblock, | ||
52 | struct buffer_head *bh_result, int create) | ||
53 | { | ||
54 | struct super_block *sb = inode->i_sb; | ||
55 | sector_t phys; | ||
56 | int err; | ||
57 | |||
58 | err = fat_bmap(inode, iblock, &phys); | ||
59 | if (err) | ||
60 | return err; | ||
61 | if (phys) { | ||
62 | map_bh(bh_result, sb, phys); | ||
63 | return 0; | ||
64 | } | ||
65 | if (!create) | ||
66 | return 0; | ||
67 | if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) { | ||
68 | fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)", | ||
69 | MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private); | ||
70 | return -EIO; | ||
71 | } | ||
72 | if (!((unsigned long)iblock & (MSDOS_SB(sb)->sec_per_clus - 1))) { | ||
73 | err = fat_add_cluster(inode); | ||
74 | if (err) | ||
75 | return err; | ||
76 | } | ||
77 | MSDOS_I(inode)->mmu_private += sb->s_blocksize; | ||
78 | err = fat_bmap(inode, iblock, &phys); | ||
79 | if (err) | ||
80 | return err; | ||
81 | if (!phys) | ||
82 | BUG(); | ||
83 | set_buffer_new(bh_result); | ||
84 | map_bh(bh_result, sb, phys); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int fat_writepage(struct page *page, struct writeback_control *wbc) | ||
89 | { | ||
90 | return block_write_full_page(page, fat_get_block, wbc); | ||
91 | } | ||
92 | |||
93 | static int fat_readpage(struct file *file, struct page *page) | ||
94 | { | ||
95 | return block_read_full_page(page, fat_get_block); | ||
96 | } | ||
97 | |||
98 | static int fat_prepare_write(struct file *file, struct page *page, | ||
99 | unsigned from, unsigned to) | ||
100 | { | ||
101 | return cont_prepare_write(page, from, to, fat_get_block, | ||
102 | &MSDOS_I(page->mapping->host)->mmu_private); | ||
103 | } | ||
104 | |||
105 | static sector_t _fat_bmap(struct address_space *mapping, sector_t block) | ||
106 | { | ||
107 | return generic_block_bmap(mapping, block, fat_get_block); | ||
108 | } | ||
109 | |||
110 | static struct address_space_operations fat_aops = { | ||
111 | .readpage = fat_readpage, | ||
112 | .writepage = fat_writepage, | ||
113 | .sync_page = block_sync_page, | ||
114 | .prepare_write = fat_prepare_write, | ||
115 | .commit_write = generic_commit_write, | ||
116 | .bmap = _fat_bmap | ||
117 | }; | ||
118 | |||
119 | /* | ||
120 | * New FAT inode stuff. We do the following: | ||
121 | * a) i_ino is constant and has nothing with on-disk location. | ||
122 | * b) FAT manages its own cache of directory entries. | ||
123 | * c) *This* cache is indexed by on-disk location. | ||
124 | * d) inode has an associated directory entry, all right, but | ||
125 | * it may be unhashed. | ||
126 | * e) currently entries are stored within struct inode. That should | ||
127 | * change. | ||
128 | * f) we deal with races in the following way: | ||
129 | * 1. readdir() and lookup() do FAT-dir-cache lookup. | ||
130 | * 2. rename() unhashes the F-d-c entry and rehashes it in | ||
131 | * a new place. | ||
132 | * 3. unlink() and rmdir() unhash F-d-c entry. | ||
133 | * 4. fat_write_inode() checks whether the thing is unhashed. | ||
134 | * If it is we silently return. If it isn't we do bread(), | ||
135 | * check if the location is still valid and retry if it | ||
136 | * isn't. Otherwise we do changes. | ||
137 | * 5. Spinlock is used to protect hash/unhash/location check/lookup | ||
138 | * 6. fat_clear_inode() unhashes the F-d-c entry. | ||
139 | * 7. lookup() and readdir() do igrab() if they find a F-d-c entry | ||
140 | * and consider negative result as cache miss. | ||
141 | */ | ||
142 | |||
143 | static void fat_hash_init(struct super_block *sb) | ||
144 | { | ||
145 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
146 | int i; | ||
147 | |||
148 | spin_lock_init(&sbi->inode_hash_lock); | ||
149 | for (i = 0; i < FAT_HASH_SIZE; i++) | ||
150 | INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); | ||
151 | } | ||
152 | |||
153 | static inline unsigned long fat_hash(struct super_block *sb, loff_t i_pos) | ||
154 | { | ||
155 | unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb; | ||
156 | tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2); | ||
157 | return tmp & FAT_HASH_MASK; | ||
158 | } | ||
159 | |||
160 | void fat_attach(struct inode *inode, loff_t i_pos) | ||
161 | { | ||
162 | struct super_block *sb = inode->i_sb; | ||
163 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
164 | |||
165 | spin_lock(&sbi->inode_hash_lock); | ||
166 | MSDOS_I(inode)->i_pos = i_pos; | ||
167 | hlist_add_head(&MSDOS_I(inode)->i_fat_hash, | ||
168 | sbi->inode_hashtable + fat_hash(sb, i_pos)); | ||
169 | spin_unlock(&sbi->inode_hash_lock); | ||
170 | } | ||
171 | |||
172 | EXPORT_SYMBOL(fat_attach); | ||
173 | |||
174 | void fat_detach(struct inode *inode) | ||
175 | { | ||
176 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
177 | spin_lock(&sbi->inode_hash_lock); | ||
178 | MSDOS_I(inode)->i_pos = 0; | ||
179 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); | ||
180 | spin_unlock(&sbi->inode_hash_lock); | ||
181 | } | ||
182 | |||
183 | EXPORT_SYMBOL(fat_detach); | ||
184 | |||
185 | struct inode *fat_iget(struct super_block *sb, loff_t i_pos) | ||
186 | { | ||
187 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
188 | struct hlist_head *head = sbi->inode_hashtable + fat_hash(sb, i_pos); | ||
189 | struct hlist_node *_p; | ||
190 | struct msdos_inode_info *i; | ||
191 | struct inode *inode = NULL; | ||
192 | |||
193 | spin_lock(&sbi->inode_hash_lock); | ||
194 | hlist_for_each_entry(i, _p, head, i_fat_hash) { | ||
195 | BUG_ON(i->vfs_inode.i_sb != sb); | ||
196 | if (i->i_pos != i_pos) | ||
197 | continue; | ||
198 | inode = igrab(&i->vfs_inode); | ||
199 | if (inode) | ||
200 | break; | ||
201 | } | ||
202 | spin_unlock(&sbi->inode_hash_lock); | ||
203 | return inode; | ||
204 | } | ||
205 | |||
206 | static int is_exec(unsigned char *extension) | ||
207 | { | ||
208 | unsigned char *exe_extensions = "EXECOMBAT", *walk; | ||
209 | |||
210 | for (walk = exe_extensions; *walk; walk += 3) | ||
211 | if (!strncmp(extension, walk, 3)) | ||
212 | return 1; | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int fat_calc_dir_size(struct inode *inode) | ||
217 | { | ||
218 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
219 | int ret, fclus, dclus; | ||
220 | |||
221 | inode->i_size = 0; | ||
222 | if (MSDOS_I(inode)->i_start == 0) | ||
223 | return 0; | ||
224 | |||
225 | ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus); | ||
226 | if (ret < 0) | ||
227 | return ret; | ||
228 | inode->i_size = (fclus + 1) << sbi->cluster_bits; | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | /* doesn't deal with root inode */ | ||
234 | static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) | ||
235 | { | ||
236 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
237 | int error; | ||
238 | |||
239 | MSDOS_I(inode)->i_pos = 0; | ||
240 | inode->i_uid = sbi->options.fs_uid; | ||
241 | inode->i_gid = sbi->options.fs_gid; | ||
242 | inode->i_version++; | ||
243 | inode->i_generation = get_seconds(); | ||
244 | |||
245 | if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) { | ||
246 | inode->i_generation &= ~1; | ||
247 | inode->i_mode = MSDOS_MKMODE(de->attr, | ||
248 | S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR; | ||
249 | inode->i_op = sbi->dir_ops; | ||
250 | inode->i_fop = &fat_dir_operations; | ||
251 | |||
252 | MSDOS_I(inode)->i_start = le16_to_cpu(de->start); | ||
253 | if (sbi->fat_bits == 32) | ||
254 | MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16); | ||
255 | |||
256 | MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; | ||
257 | error = fat_calc_dir_size(inode); | ||
258 | if (error < 0) | ||
259 | return error; | ||
260 | MSDOS_I(inode)->mmu_private = inode->i_size; | ||
261 | |||
262 | inode->i_nlink = fat_subdirs(inode); | ||
263 | } else { /* not a directory */ | ||
264 | inode->i_generation |= 1; | ||
265 | inode->i_mode = MSDOS_MKMODE(de->attr, | ||
266 | ((sbi->options.showexec && | ||
267 | !is_exec(de->ext)) | ||
268 | ? S_IRUGO|S_IWUGO : S_IRWXUGO) | ||
269 | & ~sbi->options.fs_fmask) | S_IFREG; | ||
270 | MSDOS_I(inode)->i_start = le16_to_cpu(de->start); | ||
271 | if (sbi->fat_bits == 32) | ||
272 | MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16); | ||
273 | |||
274 | MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; | ||
275 | inode->i_size = le32_to_cpu(de->size); | ||
276 | inode->i_op = &fat_file_inode_operations; | ||
277 | inode->i_fop = &fat_file_operations; | ||
278 | inode->i_mapping->a_ops = &fat_aops; | ||
279 | MSDOS_I(inode)->mmu_private = inode->i_size; | ||
280 | } | ||
281 | if (de->attr & ATTR_SYS) { | ||
282 | if (sbi->options.sys_immutable) | ||
283 | inode->i_flags |= S_IMMUTABLE; | ||
284 | } | ||
285 | MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED; | ||
286 | /* this is as close to the truth as we can get ... */ | ||
287 | inode->i_blksize = sbi->cluster_size; | ||
288 | inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) | ||
289 | & ~((loff_t)sbi->cluster_size - 1)) >> 9; | ||
290 | inode->i_mtime.tv_sec = inode->i_atime.tv_sec = | ||
291 | date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date)); | ||
292 | inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = 0; | ||
293 | if (sbi->options.isvfat) { | ||
294 | int secs = de->ctime_cs / 100; | ||
295 | int csecs = de->ctime_cs % 100; | ||
296 | inode->i_ctime.tv_sec = | ||
297 | date_dos2unix(le16_to_cpu(de->ctime), | ||
298 | le16_to_cpu(de->cdate)) + secs; | ||
299 | inode->i_ctime.tv_nsec = csecs * 10000000; | ||
300 | } else | ||
301 | inode->i_ctime = inode->i_mtime; | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | struct inode *fat_build_inode(struct super_block *sb, | ||
307 | struct msdos_dir_entry *de, loff_t i_pos) | ||
308 | { | ||
309 | struct inode *inode; | ||
310 | int err; | ||
311 | |||
312 | inode = fat_iget(sb, i_pos); | ||
313 | if (inode) | ||
314 | goto out; | ||
315 | inode = new_inode(sb); | ||
316 | if (!inode) { | ||
317 | inode = ERR_PTR(-ENOMEM); | ||
318 | goto out; | ||
319 | } | ||
320 | inode->i_ino = iunique(sb, MSDOS_ROOT_INO); | ||
321 | inode->i_version = 1; | ||
322 | err = fat_fill_inode(inode, de); | ||
323 | if (err) { | ||
324 | iput(inode); | ||
325 | inode = ERR_PTR(err); | ||
326 | goto out; | ||
327 | } | ||
328 | fat_attach(inode, i_pos); | ||
329 | insert_inode_hash(inode); | ||
330 | out: | ||
331 | return inode; | ||
332 | } | ||
333 | |||
334 | EXPORT_SYMBOL(fat_build_inode); | ||
335 | |||
336 | static void fat_delete_inode(struct inode *inode) | ||
337 | { | ||
338 | if (!is_bad_inode(inode)) { | ||
339 | inode->i_size = 0; | ||
340 | fat_truncate(inode); | ||
341 | } | ||
342 | clear_inode(inode); | ||
343 | } | ||
344 | |||
345 | static void fat_clear_inode(struct inode *inode) | ||
346 | { | ||
347 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
348 | |||
349 | if (is_bad_inode(inode)) | ||
350 | return; | ||
351 | lock_kernel(); | ||
352 | spin_lock(&sbi->inode_hash_lock); | ||
353 | fat_cache_inval_inode(inode); | ||
354 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); | ||
355 | spin_unlock(&sbi->inode_hash_lock); | ||
356 | unlock_kernel(); | ||
357 | } | ||
358 | |||
359 | static void fat_put_super(struct super_block *sb) | ||
360 | { | ||
361 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
362 | |||
363 | if (!(sb->s_flags & MS_RDONLY)) | ||
364 | fat_clusters_flush(sb); | ||
365 | |||
366 | if (sbi->nls_disk) { | ||
367 | unload_nls(sbi->nls_disk); | ||
368 | sbi->nls_disk = NULL; | ||
369 | sbi->options.codepage = fat_default_codepage; | ||
370 | } | ||
371 | if (sbi->nls_io) { | ||
372 | unload_nls(sbi->nls_io); | ||
373 | sbi->nls_io = NULL; | ||
374 | } | ||
375 | if (sbi->options.iocharset != fat_default_iocharset) { | ||
376 | kfree(sbi->options.iocharset); | ||
377 | sbi->options.iocharset = fat_default_iocharset; | ||
378 | } | ||
379 | |||
380 | sb->s_fs_info = NULL; | ||
381 | kfree(sbi); | ||
382 | } | ||
383 | |||
384 | static kmem_cache_t *fat_inode_cachep; | ||
385 | |||
386 | static struct inode *fat_alloc_inode(struct super_block *sb) | ||
387 | { | ||
388 | struct msdos_inode_info *ei; | ||
389 | ei = kmem_cache_alloc(fat_inode_cachep, SLAB_KERNEL); | ||
390 | if (!ei) | ||
391 | return NULL; | ||
392 | return &ei->vfs_inode; | ||
393 | } | ||
394 | |||
395 | static void fat_destroy_inode(struct inode *inode) | ||
396 | { | ||
397 | kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); | ||
398 | } | ||
399 | |||
400 | static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | ||
401 | { | ||
402 | struct msdos_inode_info *ei = (struct msdos_inode_info *)foo; | ||
403 | |||
404 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | ||
405 | SLAB_CTOR_CONSTRUCTOR) { | ||
406 | spin_lock_init(&ei->cache_lru_lock); | ||
407 | ei->nr_caches = 0; | ||
408 | ei->cache_valid_id = FAT_CACHE_VALID + 1; | ||
409 | INIT_LIST_HEAD(&ei->cache_lru); | ||
410 | INIT_HLIST_NODE(&ei->i_fat_hash); | ||
411 | inode_init_once(&ei->vfs_inode); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | static int __init fat_init_inodecache(void) | ||
416 | { | ||
417 | fat_inode_cachep = kmem_cache_create("fat_inode_cache", | ||
418 | sizeof(struct msdos_inode_info), | ||
419 | 0, SLAB_RECLAIM_ACCOUNT, | ||
420 | init_once, NULL); | ||
421 | if (fat_inode_cachep == NULL) | ||
422 | return -ENOMEM; | ||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | static void __exit fat_destroy_inodecache(void) | ||
427 | { | ||
428 | if (kmem_cache_destroy(fat_inode_cachep)) | ||
429 | printk(KERN_INFO "fat_inode_cache: not all structures were freed\n"); | ||
430 | } | ||
431 | |||
432 | static int fat_remount(struct super_block *sb, int *flags, char *data) | ||
433 | { | ||
434 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
435 | *flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME); | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int fat_statfs(struct super_block *sb, struct kstatfs *buf) | ||
440 | { | ||
441 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
442 | |||
443 | /* If the count of free cluster is still unknown, counts it here. */ | ||
444 | if (sbi->free_clusters == -1) { | ||
445 | int err = fat_count_free_clusters(sb); | ||
446 | if (err) | ||
447 | return err; | ||
448 | } | ||
449 | |||
450 | buf->f_type = sb->s_magic; | ||
451 | buf->f_bsize = sbi->cluster_size; | ||
452 | buf->f_blocks = sbi->max_cluster - FAT_START_ENT; | ||
453 | buf->f_bfree = sbi->free_clusters; | ||
454 | buf->f_bavail = sbi->free_clusters; | ||
455 | buf->f_namelen = sbi->options.isvfat ? 260 : 12; | ||
456 | |||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static int fat_write_inode(struct inode *inode, int wait) | ||
461 | { | ||
462 | struct super_block *sb = inode->i_sb; | ||
463 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
464 | struct buffer_head *bh; | ||
465 | struct msdos_dir_entry *raw_entry; | ||
466 | loff_t i_pos; | ||
467 | int err = 0; | ||
468 | |||
469 | retry: | ||
470 | i_pos = MSDOS_I(inode)->i_pos; | ||
471 | if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) | ||
472 | return 0; | ||
473 | |||
474 | lock_kernel(); | ||
475 | bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits); | ||
476 | if (!bh) { | ||
477 | printk(KERN_ERR "FAT: unable to read inode block " | ||
478 | "for updating (i_pos %lld)\n", i_pos); | ||
479 | err = -EIO; | ||
480 | goto out; | ||
481 | } | ||
482 | spin_lock(&sbi->inode_hash_lock); | ||
483 | if (i_pos != MSDOS_I(inode)->i_pos) { | ||
484 | spin_unlock(&sbi->inode_hash_lock); | ||
485 | brelse(bh); | ||
486 | unlock_kernel(); | ||
487 | goto retry; | ||
488 | } | ||
489 | |||
490 | raw_entry = &((struct msdos_dir_entry *) (bh->b_data)) | ||
491 | [i_pos & (sbi->dir_per_block - 1)]; | ||
492 | if (S_ISDIR(inode->i_mode)) | ||
493 | raw_entry->size = 0; | ||
494 | else | ||
495 | raw_entry->size = cpu_to_le32(inode->i_size); | ||
496 | raw_entry->attr = fat_attr(inode); | ||
497 | raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart); | ||
498 | raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); | ||
499 | fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, &raw_entry->date); | ||
500 | if (sbi->options.isvfat) { | ||
501 | fat_date_unix2dos(inode->i_ctime.tv_sec,&raw_entry->ctime,&raw_entry->cdate); | ||
502 | raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 + | ||
503 | inode->i_ctime.tv_nsec / 10000000; | ||
504 | } | ||
505 | spin_unlock(&sbi->inode_hash_lock); | ||
506 | mark_buffer_dirty(bh); | ||
507 | if (wait) | ||
508 | err = sync_dirty_buffer(bh); | ||
509 | brelse(bh); | ||
510 | out: | ||
511 | unlock_kernel(); | ||
512 | return err; | ||
513 | } | ||
514 | |||
515 | int fat_sync_inode(struct inode *inode) | ||
516 | { | ||
517 | return fat_write_inode(inode, 1); | ||
518 | } | ||
519 | |||
520 | EXPORT_SYMBOL(fat_sync_inode); | ||
521 | |||
522 | static int fat_show_options(struct seq_file *m, struct vfsmount *mnt); | ||
523 | static struct super_operations fat_sops = { | ||
524 | .alloc_inode = fat_alloc_inode, | ||
525 | .destroy_inode = fat_destroy_inode, | ||
526 | .write_inode = fat_write_inode, | ||
527 | .delete_inode = fat_delete_inode, | ||
528 | .put_super = fat_put_super, | ||
529 | .statfs = fat_statfs, | ||
530 | .clear_inode = fat_clear_inode, | ||
531 | .remount_fs = fat_remount, | ||
532 | |||
533 | .read_inode = make_bad_inode, | ||
534 | |||
535 | .show_options = fat_show_options, | ||
536 | }; | ||
537 | |||
538 | /* | ||
539 | * a FAT file handle with fhtype 3 is | ||
540 | * 0/ i_ino - for fast, reliable lookup if still in the cache | ||
541 | * 1/ i_generation - to see if i_ino is still valid | ||
542 | * bit 0 == 0 iff directory | ||
543 | * 2/ i_pos(8-39) - if ino has changed, but still in cache | ||
544 | * 3/ i_pos(4-7)|i_logstart - to semi-verify inode found at i_pos | ||
545 | * 4/ i_pos(0-3)|parent->i_logstart - maybe used to hunt for the file on disc | ||
546 | * | ||
547 | * Hack for NFSv2: Maximum FAT entry number is 28bits and maximum | ||
548 | * i_pos is 40bits (blocknr(32) + dir offset(8)), so two 4bits | ||
549 | * of i_logstart is used to store the directory entry offset. | ||
550 | */ | ||
551 | |||
552 | static struct dentry * | ||
553 | fat_decode_fh(struct super_block *sb, __u32 *fh, int len, int fhtype, | ||
554 | int (*acceptable)(void *context, struct dentry *de), | ||
555 | void *context) | ||
556 | { | ||
557 | if (fhtype != 3) | ||
558 | return ERR_PTR(-ESTALE); | ||
559 | if (len < 5) | ||
560 | return ERR_PTR(-ESTALE); | ||
561 | |||
562 | return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable, context); | ||
563 | } | ||
564 | |||
565 | static struct dentry *fat_get_dentry(struct super_block *sb, void *inump) | ||
566 | { | ||
567 | struct inode *inode = NULL; | ||
568 | struct dentry *result; | ||
569 | __u32 *fh = inump; | ||
570 | |||
571 | inode = iget(sb, fh[0]); | ||
572 | if (!inode || is_bad_inode(inode) || inode->i_generation != fh[1]) { | ||
573 | if (inode) | ||
574 | iput(inode); | ||
575 | inode = NULL; | ||
576 | } | ||
577 | if (!inode) { | ||
578 | loff_t i_pos; | ||
579 | int i_logstart = fh[3] & 0x0fffffff; | ||
580 | |||
581 | i_pos = (loff_t)fh[2] << 8; | ||
582 | i_pos |= ((fh[3] >> 24) & 0xf0) | (fh[4] >> 28); | ||
583 | |||
584 | /* try 2 - see if i_pos is in F-d-c | ||
585 | * require i_logstart to be the same | ||
586 | * Will fail if you truncate and then re-write | ||
587 | */ | ||
588 | |||
589 | inode = fat_iget(sb, i_pos); | ||
590 | if (inode && MSDOS_I(inode)->i_logstart != i_logstart) { | ||
591 | iput(inode); | ||
592 | inode = NULL; | ||
593 | } | ||
594 | } | ||
595 | if (!inode) { | ||
596 | /* For now, do nothing | ||
597 | * What we could do is: | ||
598 | * follow the file starting at fh[4], and record | ||
599 | * the ".." entry, and the name of the fh[2] entry. | ||
600 | * The follow the ".." file finding the next step up. | ||
601 | * This way we build a path to the root of | ||
602 | * the tree. If this works, we lookup the path and so | ||
603 | * get this inode into the cache. | ||
604 | * Finally try the fat_iget lookup again | ||
605 | * If that fails, then weare totally out of luck | ||
606 | * But all that is for another day | ||
607 | */ | ||
608 | } | ||
609 | if (!inode) | ||
610 | return ERR_PTR(-ESTALE); | ||
611 | |||
612 | |||
613 | /* now to find a dentry. | ||
614 | * If possible, get a well-connected one | ||
615 | */ | ||
616 | result = d_alloc_anon(inode); | ||
617 | if (result == NULL) { | ||
618 | iput(inode); | ||
619 | return ERR_PTR(-ENOMEM); | ||
620 | } | ||
621 | result->d_op = sb->s_root->d_op; | ||
622 | return result; | ||
623 | } | ||
624 | |||
625 | static int | ||
626 | fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable) | ||
627 | { | ||
628 | int len = *lenp; | ||
629 | struct inode *inode = de->d_inode; | ||
630 | u32 ipos_h, ipos_m, ipos_l; | ||
631 | |||
632 | if (len < 5) | ||
633 | return 255; /* no room */ | ||
634 | |||
635 | ipos_h = MSDOS_I(inode)->i_pos >> 8; | ||
636 | ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24; | ||
637 | ipos_l = (MSDOS_I(inode)->i_pos & 0x0f) << 28; | ||
638 | *lenp = 5; | ||
639 | fh[0] = inode->i_ino; | ||
640 | fh[1] = inode->i_generation; | ||
641 | fh[2] = ipos_h; | ||
642 | fh[3] = ipos_m | MSDOS_I(inode)->i_logstart; | ||
643 | spin_lock(&de->d_lock); | ||
644 | fh[4] = ipos_l | MSDOS_I(de->d_parent->d_inode)->i_logstart; | ||
645 | spin_unlock(&de->d_lock); | ||
646 | return 3; | ||
647 | } | ||
648 | |||
649 | static struct dentry *fat_get_parent(struct dentry *child) | ||
650 | { | ||
651 | struct buffer_head *bh; | ||
652 | struct msdos_dir_entry *de; | ||
653 | loff_t i_pos; | ||
654 | struct dentry *parent; | ||
655 | struct inode *inode; | ||
656 | int err; | ||
657 | |||
658 | lock_kernel(); | ||
659 | |||
660 | err = fat_get_dotdot_entry(child->d_inode, &bh, &de, &i_pos); | ||
661 | if (err) { | ||
662 | parent = ERR_PTR(err); | ||
663 | goto out; | ||
664 | } | ||
665 | inode = fat_build_inode(child->d_sb, de, i_pos); | ||
666 | brelse(bh); | ||
667 | if (IS_ERR(inode)) { | ||
668 | parent = ERR_PTR(PTR_ERR(inode)); | ||
669 | goto out; | ||
670 | } | ||
671 | parent = d_alloc_anon(inode); | ||
672 | if (!parent) { | ||
673 | iput(inode); | ||
674 | parent = ERR_PTR(-ENOMEM); | ||
675 | } | ||
676 | out: | ||
677 | unlock_kernel(); | ||
678 | |||
679 | return parent; | ||
680 | } | ||
681 | |||
682 | static struct export_operations fat_export_ops = { | ||
683 | .decode_fh = fat_decode_fh, | ||
684 | .encode_fh = fat_encode_fh, | ||
685 | .get_dentry = fat_get_dentry, | ||
686 | .get_parent = fat_get_parent, | ||
687 | }; | ||
688 | |||
689 | static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) | ||
690 | { | ||
691 | struct msdos_sb_info *sbi = MSDOS_SB(mnt->mnt_sb); | ||
692 | struct fat_mount_options *opts = &sbi->options; | ||
693 | int isvfat = opts->isvfat; | ||
694 | |||
695 | if (opts->fs_uid != 0) | ||
696 | seq_printf(m, ",uid=%u", opts->fs_uid); | ||
697 | if (opts->fs_gid != 0) | ||
698 | seq_printf(m, ",gid=%u", opts->fs_gid); | ||
699 | seq_printf(m, ",fmask=%04o", opts->fs_fmask); | ||
700 | seq_printf(m, ",dmask=%04o", opts->fs_dmask); | ||
701 | if (sbi->nls_disk) | ||
702 | seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); | ||
703 | if (isvfat) { | ||
704 | if (sbi->nls_io) | ||
705 | seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); | ||
706 | |||
707 | switch (opts->shortname) { | ||
708 | case VFAT_SFN_DISPLAY_WIN95 | VFAT_SFN_CREATE_WIN95: | ||
709 | seq_puts(m, ",shortname=win95"); | ||
710 | break; | ||
711 | case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WINNT: | ||
712 | seq_puts(m, ",shortname=winnt"); | ||
713 | break; | ||
714 | case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WIN95: | ||
715 | seq_puts(m, ",shortname=mixed"); | ||
716 | break; | ||
717 | case VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95: | ||
718 | /* seq_puts(m, ",shortname=lower"); */ | ||
719 | break; | ||
720 | default: | ||
721 | seq_puts(m, ",shortname=unknown"); | ||
722 | break; | ||
723 | } | ||
724 | } | ||
725 | if (opts->name_check != 'n') | ||
726 | seq_printf(m, ",check=%c", opts->name_check); | ||
727 | if (opts->quiet) | ||
728 | seq_puts(m, ",quiet"); | ||
729 | if (opts->showexec) | ||
730 | seq_puts(m, ",showexec"); | ||
731 | if (opts->sys_immutable) | ||
732 | seq_puts(m, ",sys_immutable"); | ||
733 | if (!isvfat) { | ||
734 | if (opts->dotsOK) | ||
735 | seq_puts(m, ",dotsOK=yes"); | ||
736 | if (opts->nocase) | ||
737 | seq_puts(m, ",nocase"); | ||
738 | } else { | ||
739 | if (opts->utf8) | ||
740 | seq_puts(m, ",utf8"); | ||
741 | if (opts->unicode_xlate) | ||
742 | seq_puts(m, ",uni_xlate"); | ||
743 | if (!opts->numtail) | ||
744 | seq_puts(m, ",nonumtail"); | ||
745 | } | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | enum { | ||
751 | Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid, | ||
752 | Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_nocase, | ||
753 | Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable, | ||
754 | Opt_dots, Opt_nodots, | ||
755 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, | ||
756 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, | ||
757 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, | ||
758 | Opt_obsolate, Opt_err, | ||
759 | }; | ||
760 | |||
761 | static match_table_t fat_tokens = { | ||
762 | {Opt_check_r, "check=relaxed"}, | ||
763 | {Opt_check_s, "check=strict"}, | ||
764 | {Opt_check_n, "check=normal"}, | ||
765 | {Opt_check_r, "check=r"}, | ||
766 | {Opt_check_s, "check=s"}, | ||
767 | {Opt_check_n, "check=n"}, | ||
768 | {Opt_uid, "uid=%u"}, | ||
769 | {Opt_gid, "gid=%u"}, | ||
770 | {Opt_umask, "umask=%o"}, | ||
771 | {Opt_dmask, "dmask=%o"}, | ||
772 | {Opt_fmask, "fmask=%o"}, | ||
773 | {Opt_codepage, "codepage=%u"}, | ||
774 | {Opt_nocase, "nocase"}, | ||
775 | {Opt_quiet, "quiet"}, | ||
776 | {Opt_showexec, "showexec"}, | ||
777 | {Opt_debug, "debug"}, | ||
778 | {Opt_immutable, "sys_immutable"}, | ||
779 | {Opt_obsolate, "conv=binary"}, | ||
780 | {Opt_obsolate, "conv=text"}, | ||
781 | {Opt_obsolate, "conv=auto"}, | ||
782 | {Opt_obsolate, "conv=b"}, | ||
783 | {Opt_obsolate, "conv=t"}, | ||
784 | {Opt_obsolate, "conv=a"}, | ||
785 | {Opt_obsolate, "fat=%u"}, | ||
786 | {Opt_obsolate, "blocksize=%u"}, | ||
787 | {Opt_obsolate, "cvf_format=%20s"}, | ||
788 | {Opt_obsolate, "cvf_options=%100s"}, | ||
789 | {Opt_obsolate, "posix"}, | ||
790 | {Opt_err, NULL} | ||
791 | }; | ||
792 | static match_table_t msdos_tokens = { | ||
793 | {Opt_nodots, "nodots"}, | ||
794 | {Opt_nodots, "dotsOK=no"}, | ||
795 | {Opt_dots, "dots"}, | ||
796 | {Opt_dots, "dotsOK=yes"}, | ||
797 | {Opt_err, NULL} | ||
798 | }; | ||
799 | static match_table_t vfat_tokens = { | ||
800 | {Opt_charset, "iocharset=%s"}, | ||
801 | {Opt_shortname_lower, "shortname=lower"}, | ||
802 | {Opt_shortname_win95, "shortname=win95"}, | ||
803 | {Opt_shortname_winnt, "shortname=winnt"}, | ||
804 | {Opt_shortname_mixed, "shortname=mixed"}, | ||
805 | {Opt_utf8_no, "utf8=0"}, /* 0 or no or false */ | ||
806 | {Opt_utf8_no, "utf8=no"}, | ||
807 | {Opt_utf8_no, "utf8=false"}, | ||
808 | {Opt_utf8_yes, "utf8=1"}, /* empty or 1 or yes or true */ | ||
809 | {Opt_utf8_yes, "utf8=yes"}, | ||
810 | {Opt_utf8_yes, "utf8=true"}, | ||
811 | {Opt_utf8_yes, "utf8"}, | ||
812 | {Opt_uni_xl_no, "uni_xlate=0"}, /* 0 or no or false */ | ||
813 | {Opt_uni_xl_no, "uni_xlate=no"}, | ||
814 | {Opt_uni_xl_no, "uni_xlate=false"}, | ||
815 | {Opt_uni_xl_yes, "uni_xlate=1"}, /* empty or 1 or yes or true */ | ||
816 | {Opt_uni_xl_yes, "uni_xlate=yes"}, | ||
817 | {Opt_uni_xl_yes, "uni_xlate=true"}, | ||
818 | {Opt_uni_xl_yes, "uni_xlate"}, | ||
819 | {Opt_nonumtail_no, "nonumtail=0"}, /* 0 or no or false */ | ||
820 | {Opt_nonumtail_no, "nonumtail=no"}, | ||
821 | {Opt_nonumtail_no, "nonumtail=false"}, | ||
822 | {Opt_nonumtail_yes, "nonumtail=1"}, /* empty or 1 or yes or true */ | ||
823 | {Opt_nonumtail_yes, "nonumtail=yes"}, | ||
824 | {Opt_nonumtail_yes, "nonumtail=true"}, | ||
825 | {Opt_nonumtail_yes, "nonumtail"}, | ||
826 | {Opt_err, NULL} | ||
827 | }; | ||
828 | |||
829 | static int parse_options(char *options, int is_vfat, int *debug, | ||
830 | struct fat_mount_options *opts) | ||
831 | { | ||
832 | char *p; | ||
833 | substring_t args[MAX_OPT_ARGS]; | ||
834 | int option; | ||
835 | char *iocharset; | ||
836 | |||
837 | opts->isvfat = is_vfat; | ||
838 | |||
839 | opts->fs_uid = current->uid; | ||
840 | opts->fs_gid = current->gid; | ||
841 | opts->fs_fmask = opts->fs_dmask = current->fs->umask; | ||
842 | opts->codepage = fat_default_codepage; | ||
843 | opts->iocharset = fat_default_iocharset; | ||
844 | if (is_vfat) | ||
845 | opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95; | ||
846 | else | ||
847 | opts->shortname = 0; | ||
848 | opts->name_check = 'n'; | ||
849 | opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0; | ||
850 | opts->utf8 = opts->unicode_xlate = 0; | ||
851 | opts->numtail = 1; | ||
852 | opts->nocase = 0; | ||
853 | *debug = 0; | ||
854 | |||
855 | if (!options) | ||
856 | return 0; | ||
857 | |||
858 | while ((p = strsep(&options, ",")) != NULL) { | ||
859 | int token; | ||
860 | if (!*p) | ||
861 | continue; | ||
862 | |||
863 | token = match_token(p, fat_tokens, args); | ||
864 | if (token == Opt_err) { | ||
865 | if (is_vfat) | ||
866 | token = match_token(p, vfat_tokens, args); | ||
867 | else | ||
868 | token = match_token(p, msdos_tokens, args); | ||
869 | } | ||
870 | switch (token) { | ||
871 | case Opt_check_s: | ||
872 | opts->name_check = 's'; | ||
873 | break; | ||
874 | case Opt_check_r: | ||
875 | opts->name_check = 'r'; | ||
876 | break; | ||
877 | case Opt_check_n: | ||
878 | opts->name_check = 'n'; | ||
879 | break; | ||
880 | case Opt_nocase: | ||
881 | if (!is_vfat) | ||
882 | opts->nocase = 1; | ||
883 | else { | ||
884 | /* for backward compatibility */ | ||
885 | opts->shortname = VFAT_SFN_DISPLAY_WIN95 | ||
886 | | VFAT_SFN_CREATE_WIN95; | ||
887 | } | ||
888 | break; | ||
889 | case Opt_quiet: | ||
890 | opts->quiet = 1; | ||
891 | break; | ||
892 | case Opt_showexec: | ||
893 | opts->showexec = 1; | ||
894 | break; | ||
895 | case Opt_debug: | ||
896 | *debug = 1; | ||
897 | break; | ||
898 | case Opt_immutable: | ||
899 | opts->sys_immutable = 1; | ||
900 | break; | ||
901 | case Opt_uid: | ||
902 | if (match_int(&args[0], &option)) | ||
903 | return 0; | ||
904 | opts->fs_uid = option; | ||
905 | break; | ||
906 | case Opt_gid: | ||
907 | if (match_int(&args[0], &option)) | ||
908 | return 0; | ||
909 | opts->fs_gid = option; | ||
910 | break; | ||
911 | case Opt_umask: | ||
912 | if (match_octal(&args[0], &option)) | ||
913 | return 0; | ||
914 | opts->fs_fmask = opts->fs_dmask = option; | ||
915 | break; | ||
916 | case Opt_dmask: | ||
917 | if (match_octal(&args[0], &option)) | ||
918 | return 0; | ||
919 | opts->fs_dmask = option; | ||
920 | break; | ||
921 | case Opt_fmask: | ||
922 | if (match_octal(&args[0], &option)) | ||
923 | return 0; | ||
924 | opts->fs_fmask = option; | ||
925 | break; | ||
926 | case Opt_codepage: | ||
927 | if (match_int(&args[0], &option)) | ||
928 | return 0; | ||
929 | opts->codepage = option; | ||
930 | break; | ||
931 | |||
932 | /* msdos specific */ | ||
933 | case Opt_dots: | ||
934 | opts->dotsOK = 1; | ||
935 | break; | ||
936 | case Opt_nodots: | ||
937 | opts->dotsOK = 0; | ||
938 | break; | ||
939 | |||
940 | /* vfat specific */ | ||
941 | case Opt_charset: | ||
942 | if (opts->iocharset != fat_default_iocharset) | ||
943 | kfree(opts->iocharset); | ||
944 | iocharset = match_strdup(&args[0]); | ||
945 | if (!iocharset) | ||
946 | return -ENOMEM; | ||
947 | opts->iocharset = iocharset; | ||
948 | break; | ||
949 | case Opt_shortname_lower: | ||
950 | opts->shortname = VFAT_SFN_DISPLAY_LOWER | ||
951 | | VFAT_SFN_CREATE_WIN95; | ||
952 | break; | ||
953 | case Opt_shortname_win95: | ||
954 | opts->shortname = VFAT_SFN_DISPLAY_WIN95 | ||
955 | | VFAT_SFN_CREATE_WIN95; | ||
956 | break; | ||
957 | case Opt_shortname_winnt: | ||
958 | opts->shortname = VFAT_SFN_DISPLAY_WINNT | ||
959 | | VFAT_SFN_CREATE_WINNT; | ||
960 | break; | ||
961 | case Opt_shortname_mixed: | ||
962 | opts->shortname = VFAT_SFN_DISPLAY_WINNT | ||
963 | | VFAT_SFN_CREATE_WIN95; | ||
964 | break; | ||
965 | case Opt_utf8_no: /* 0 or no or false */ | ||
966 | opts->utf8 = 0; | ||
967 | break; | ||
968 | case Opt_utf8_yes: /* empty or 1 or yes or true */ | ||
969 | opts->utf8 = 1; | ||
970 | break; | ||
971 | case Opt_uni_xl_no: /* 0 or no or false */ | ||
972 | opts->unicode_xlate = 0; | ||
973 | break; | ||
974 | case Opt_uni_xl_yes: /* empty or 1 or yes or true */ | ||
975 | opts->unicode_xlate = 1; | ||
976 | break; | ||
977 | case Opt_nonumtail_no: /* 0 or no or false */ | ||
978 | opts->numtail = 1; /* negated option */ | ||
979 | break; | ||
980 | case Opt_nonumtail_yes: /* empty or 1 or yes or true */ | ||
981 | opts->numtail = 0; /* negated option */ | ||
982 | break; | ||
983 | |||
984 | /* obsolete mount options */ | ||
985 | case Opt_obsolate: | ||
986 | printk(KERN_INFO "FAT: \"%s\" option is obsolete, " | ||
987 | "not supported now\n", p); | ||
988 | break; | ||
989 | /* unknown option */ | ||
990 | default: | ||
991 | printk(KERN_ERR "FAT: Unrecognized mount option \"%s\" " | ||
992 | "or missing value\n", p); | ||
993 | return -EINVAL; | ||
994 | } | ||
995 | } | ||
996 | /* UTF8 doesn't provide FAT semantics */ | ||
997 | if (!strcmp(opts->iocharset, "utf8")) { | ||
998 | printk(KERN_ERR "FAT: utf8 is not a recommended IO charset" | ||
999 | " for FAT filesystems, filesystem will be case sensitive!\n"); | ||
1000 | } | ||
1001 | |||
1002 | if (opts->unicode_xlate) | ||
1003 | opts->utf8 = 0; | ||
1004 | |||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | static int fat_read_root(struct inode *inode) | ||
1009 | { | ||
1010 | struct super_block *sb = inode->i_sb; | ||
1011 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
1012 | int error; | ||
1013 | |||
1014 | MSDOS_I(inode)->i_pos = 0; | ||
1015 | inode->i_uid = sbi->options.fs_uid; | ||
1016 | inode->i_gid = sbi->options.fs_gid; | ||
1017 | inode->i_version++; | ||
1018 | inode->i_generation = 0; | ||
1019 | inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR; | ||
1020 | inode->i_op = sbi->dir_ops; | ||
1021 | inode->i_fop = &fat_dir_operations; | ||
1022 | if (sbi->fat_bits == 32) { | ||
1023 | MSDOS_I(inode)->i_start = sbi->root_cluster; | ||
1024 | error = fat_calc_dir_size(inode); | ||
1025 | if (error < 0) | ||
1026 | return error; | ||
1027 | } else { | ||
1028 | MSDOS_I(inode)->i_start = 0; | ||
1029 | inode->i_size = sbi->dir_entries * sizeof(struct msdos_dir_entry); | ||
1030 | } | ||
1031 | inode->i_blksize = sbi->cluster_size; | ||
1032 | inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) | ||
1033 | & ~((loff_t)sbi->cluster_size - 1)) >> 9; | ||
1034 | MSDOS_I(inode)->i_logstart = 0; | ||
1035 | MSDOS_I(inode)->mmu_private = inode->i_size; | ||
1036 | |||
1037 | MSDOS_I(inode)->i_attrs = ATTR_NONE; | ||
1038 | inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0; | ||
1039 | inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0; | ||
1040 | inode->i_nlink = fat_subdirs(inode)+2; | ||
1041 | |||
1042 | return 0; | ||
1043 | } | ||
1044 | |||
1045 | /* | ||
1046 | * Read the super block of an MS-DOS FS. | ||
1047 | */ | ||
1048 | int fat_fill_super(struct super_block *sb, void *data, int silent, | ||
1049 | struct inode_operations *fs_dir_inode_ops, int isvfat) | ||
1050 | { | ||
1051 | struct inode *root_inode = NULL; | ||
1052 | struct buffer_head *bh; | ||
1053 | struct fat_boot_sector *b; | ||
1054 | struct msdos_sb_info *sbi; | ||
1055 | u16 logical_sector_size; | ||
1056 | u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors; | ||
1057 | int debug; | ||
1058 | unsigned int media; | ||
1059 | long error; | ||
1060 | char buf[50]; | ||
1061 | |||
1062 | sbi = kmalloc(sizeof(struct msdos_sb_info), GFP_KERNEL); | ||
1063 | if (!sbi) | ||
1064 | return -ENOMEM; | ||
1065 | sb->s_fs_info = sbi; | ||
1066 | memset(sbi, 0, sizeof(struct msdos_sb_info)); | ||
1067 | |||
1068 | sb->s_flags |= MS_NODIRATIME; | ||
1069 | sb->s_magic = MSDOS_SUPER_MAGIC; | ||
1070 | sb->s_op = &fat_sops; | ||
1071 | sb->s_export_op = &fat_export_ops; | ||
1072 | sbi->dir_ops = fs_dir_inode_ops; | ||
1073 | |||
1074 | error = parse_options(data, isvfat, &debug, &sbi->options); | ||
1075 | if (error) | ||
1076 | goto out_fail; | ||
1077 | |||
1078 | error = -EIO; | ||
1079 | sb_min_blocksize(sb, 512); | ||
1080 | bh = sb_bread(sb, 0); | ||
1081 | if (bh == NULL) { | ||
1082 | printk(KERN_ERR "FAT: unable to read boot sector\n"); | ||
1083 | goto out_fail; | ||
1084 | } | ||
1085 | |||
1086 | b = (struct fat_boot_sector *) bh->b_data; | ||
1087 | if (!b->reserved) { | ||
1088 | if (!silent) | ||
1089 | printk(KERN_ERR "FAT: bogus number of reserved sectors\n"); | ||
1090 | brelse(bh); | ||
1091 | goto out_invalid; | ||
1092 | } | ||
1093 | if (!b->fats) { | ||
1094 | if (!silent) | ||
1095 | printk(KERN_ERR "FAT: bogus number of FAT structure\n"); | ||
1096 | brelse(bh); | ||
1097 | goto out_invalid; | ||
1098 | } | ||
1099 | |||
1100 | /* | ||
1101 | * Earlier we checked here that b->secs_track and b->head are nonzero, | ||
1102 | * but it turns out valid FAT filesystems can have zero there. | ||
1103 | */ | ||
1104 | |||
1105 | media = b->media; | ||
1106 | if (!FAT_VALID_MEDIA(media)) { | ||
1107 | if (!silent) | ||
1108 | printk(KERN_ERR "FAT: invalid media value (0x%02x)\n", | ||
1109 | media); | ||
1110 | brelse(bh); | ||
1111 | goto out_invalid; | ||
1112 | } | ||
1113 | logical_sector_size = | ||
1114 | le16_to_cpu(get_unaligned((__le16 *)&b->sector_size)); | ||
1115 | if (!logical_sector_size | ||
1116 | || (logical_sector_size & (logical_sector_size - 1)) | ||
1117 | || (logical_sector_size < 512) | ||
1118 | || (PAGE_CACHE_SIZE < logical_sector_size)) { | ||
1119 | if (!silent) | ||
1120 | printk(KERN_ERR "FAT: bogus logical sector size %u\n", | ||
1121 | logical_sector_size); | ||
1122 | brelse(bh); | ||
1123 | goto out_invalid; | ||
1124 | } | ||
1125 | sbi->sec_per_clus = b->sec_per_clus; | ||
1126 | if (!sbi->sec_per_clus | ||
1127 | || (sbi->sec_per_clus & (sbi->sec_per_clus - 1))) { | ||
1128 | if (!silent) | ||
1129 | printk(KERN_ERR "FAT: bogus sectors per cluster %u\n", | ||
1130 | sbi->sec_per_clus); | ||
1131 | brelse(bh); | ||
1132 | goto out_invalid; | ||
1133 | } | ||
1134 | |||
1135 | if (logical_sector_size < sb->s_blocksize) { | ||
1136 | printk(KERN_ERR "FAT: logical sector size too small for device" | ||
1137 | " (logical sector size = %u)\n", logical_sector_size); | ||
1138 | brelse(bh); | ||
1139 | goto out_fail; | ||
1140 | } | ||
1141 | if (logical_sector_size > sb->s_blocksize) { | ||
1142 | brelse(bh); | ||
1143 | |||
1144 | if (!sb_set_blocksize(sb, logical_sector_size)) { | ||
1145 | printk(KERN_ERR "FAT: unable to set blocksize %u\n", | ||
1146 | logical_sector_size); | ||
1147 | goto out_fail; | ||
1148 | } | ||
1149 | bh = sb_bread(sb, 0); | ||
1150 | if (bh == NULL) { | ||
1151 | printk(KERN_ERR "FAT: unable to read boot sector" | ||
1152 | " (logical sector size = %lu)\n", | ||
1153 | sb->s_blocksize); | ||
1154 | goto out_fail; | ||
1155 | } | ||
1156 | b = (struct fat_boot_sector *) bh->b_data; | ||
1157 | } | ||
1158 | |||
1159 | sbi->cluster_size = sb->s_blocksize * sbi->sec_per_clus; | ||
1160 | sbi->cluster_bits = ffs(sbi->cluster_size) - 1; | ||
1161 | sbi->fats = b->fats; | ||
1162 | sbi->fat_bits = 0; /* Don't know yet */ | ||
1163 | sbi->fat_start = le16_to_cpu(b->reserved); | ||
1164 | sbi->fat_length = le16_to_cpu(b->fat_length); | ||
1165 | sbi->root_cluster = 0; | ||
1166 | sbi->free_clusters = -1; /* Don't know yet */ | ||
1167 | sbi->prev_free = FAT_START_ENT; | ||
1168 | |||
1169 | if (!sbi->fat_length && b->fat32_length) { | ||
1170 | struct fat_boot_fsinfo *fsinfo; | ||
1171 | struct buffer_head *fsinfo_bh; | ||
1172 | |||
1173 | /* Must be FAT32 */ | ||
1174 | sbi->fat_bits = 32; | ||
1175 | sbi->fat_length = le32_to_cpu(b->fat32_length); | ||
1176 | sbi->root_cluster = le32_to_cpu(b->root_cluster); | ||
1177 | |||
1178 | sb->s_maxbytes = 0xffffffff; | ||
1179 | |||
1180 | /* MC - if info_sector is 0, don't multiply by 0 */ | ||
1181 | sbi->fsinfo_sector = le16_to_cpu(b->info_sector); | ||
1182 | if (sbi->fsinfo_sector == 0) | ||
1183 | sbi->fsinfo_sector = 1; | ||
1184 | |||
1185 | fsinfo_bh = sb_bread(sb, sbi->fsinfo_sector); | ||
1186 | if (fsinfo_bh == NULL) { | ||
1187 | printk(KERN_ERR "FAT: bread failed, FSINFO block" | ||
1188 | " (sector = %lu)\n", sbi->fsinfo_sector); | ||
1189 | brelse(bh); | ||
1190 | goto out_fail; | ||
1191 | } | ||
1192 | |||
1193 | fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data; | ||
1194 | if (!IS_FSINFO(fsinfo)) { | ||
1195 | printk(KERN_WARNING | ||
1196 | "FAT: Did not find valid FSINFO signature.\n" | ||
1197 | " Found signature1 0x%08x signature2 0x%08x" | ||
1198 | " (sector = %lu)\n", | ||
1199 | le32_to_cpu(fsinfo->signature1), | ||
1200 | le32_to_cpu(fsinfo->signature2), | ||
1201 | sbi->fsinfo_sector); | ||
1202 | } else { | ||
1203 | sbi->free_clusters = le32_to_cpu(fsinfo->free_clusters); | ||
1204 | sbi->prev_free = le32_to_cpu(fsinfo->next_cluster); | ||
1205 | } | ||
1206 | |||
1207 | brelse(fsinfo_bh); | ||
1208 | } | ||
1209 | |||
1210 | sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry); | ||
1211 | sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1; | ||
1212 | |||
1213 | sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length; | ||
1214 | sbi->dir_entries = | ||
1215 | le16_to_cpu(get_unaligned((__le16 *)&b->dir_entries)); | ||
1216 | if (sbi->dir_entries & (sbi->dir_per_block - 1)) { | ||
1217 | if (!silent) | ||
1218 | printk(KERN_ERR "FAT: bogus directroy-entries per block" | ||
1219 | " (%u)\n", sbi->dir_entries); | ||
1220 | brelse(bh); | ||
1221 | goto out_invalid; | ||
1222 | } | ||
1223 | |||
1224 | rootdir_sectors = sbi->dir_entries | ||
1225 | * sizeof(struct msdos_dir_entry) / sb->s_blocksize; | ||
1226 | sbi->data_start = sbi->dir_start + rootdir_sectors; | ||
1227 | total_sectors = le16_to_cpu(get_unaligned((__le16 *)&b->sectors)); | ||
1228 | if (total_sectors == 0) | ||
1229 | total_sectors = le32_to_cpu(b->total_sect); | ||
1230 | |||
1231 | total_clusters = (total_sectors - sbi->data_start) / sbi->sec_per_clus; | ||
1232 | |||
1233 | if (sbi->fat_bits != 32) | ||
1234 | sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12; | ||
1235 | |||
1236 | /* check that FAT table does not overflow */ | ||
1237 | fat_clusters = sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits; | ||
1238 | total_clusters = min(total_clusters, fat_clusters - FAT_START_ENT); | ||
1239 | if (total_clusters > MAX_FAT(sb)) { | ||
1240 | if (!silent) | ||
1241 | printk(KERN_ERR "FAT: count of clusters too big (%u)\n", | ||
1242 | total_clusters); | ||
1243 | brelse(bh); | ||
1244 | goto out_invalid; | ||
1245 | } | ||
1246 | |||
1247 | sbi->max_cluster = total_clusters + FAT_START_ENT; | ||
1248 | /* check the free_clusters, it's not necessarily correct */ | ||
1249 | if (sbi->free_clusters != -1 && sbi->free_clusters > total_clusters) | ||
1250 | sbi->free_clusters = -1; | ||
1251 | /* check the prev_free, it's not necessarily correct */ | ||
1252 | sbi->prev_free %= sbi->max_cluster; | ||
1253 | if (sbi->prev_free < FAT_START_ENT) | ||
1254 | sbi->prev_free = FAT_START_ENT; | ||
1255 | |||
1256 | brelse(bh); | ||
1257 | |||
1258 | /* set up enough so that it can read an inode */ | ||
1259 | fat_hash_init(sb); | ||
1260 | fat_ent_access_init(sb); | ||
1261 | |||
1262 | /* | ||
1263 | * The low byte of FAT's first entry must have same value with | ||
1264 | * media-field. But in real world, too many devices is | ||
1265 | * writing wrong value. So, removed that validity check. | ||
1266 | * | ||
1267 | * if (FAT_FIRST_ENT(sb, media) != first) | ||
1268 | */ | ||
1269 | |||
1270 | error = -EINVAL; | ||
1271 | sprintf(buf, "cp%d", sbi->options.codepage); | ||
1272 | sbi->nls_disk = load_nls(buf); | ||
1273 | if (!sbi->nls_disk) { | ||
1274 | printk(KERN_ERR "FAT: codepage %s not found\n", buf); | ||
1275 | goto out_fail; | ||
1276 | } | ||
1277 | |||
1278 | /* FIXME: utf8 is using iocharset for upper/lower conversion */ | ||
1279 | if (sbi->options.isvfat) { | ||
1280 | sbi->nls_io = load_nls(sbi->options.iocharset); | ||
1281 | if (!sbi->nls_io) { | ||
1282 | printk(KERN_ERR "FAT: IO charset %s not found\n", | ||
1283 | sbi->options.iocharset); | ||
1284 | goto out_fail; | ||
1285 | } | ||
1286 | } | ||
1287 | |||
1288 | error = -ENOMEM; | ||
1289 | root_inode = new_inode(sb); | ||
1290 | if (!root_inode) | ||
1291 | goto out_fail; | ||
1292 | root_inode->i_ino = MSDOS_ROOT_INO; | ||
1293 | root_inode->i_version = 1; | ||
1294 | error = fat_read_root(root_inode); | ||
1295 | if (error < 0) | ||
1296 | goto out_fail; | ||
1297 | error = -ENOMEM; | ||
1298 | insert_inode_hash(root_inode); | ||
1299 | sb->s_root = d_alloc_root(root_inode); | ||
1300 | if (!sb->s_root) { | ||
1301 | printk(KERN_ERR "FAT: get root inode failed\n"); | ||
1302 | goto out_fail; | ||
1303 | } | ||
1304 | |||
1305 | return 0; | ||
1306 | |||
1307 | out_invalid: | ||
1308 | error = -EINVAL; | ||
1309 | if (!silent) | ||
1310 | printk(KERN_INFO "VFS: Can't find a valid FAT filesystem" | ||
1311 | " on dev %s.\n", sb->s_id); | ||
1312 | |||
1313 | out_fail: | ||
1314 | if (root_inode) | ||
1315 | iput(root_inode); | ||
1316 | if (sbi->nls_io) | ||
1317 | unload_nls(sbi->nls_io); | ||
1318 | if (sbi->nls_disk) | ||
1319 | unload_nls(sbi->nls_disk); | ||
1320 | if (sbi->options.iocharset != fat_default_iocharset) | ||
1321 | kfree(sbi->options.iocharset); | ||
1322 | sb->s_fs_info = NULL; | ||
1323 | kfree(sbi); | ||
1324 | return error; | ||
1325 | } | ||
1326 | |||
1327 | EXPORT_SYMBOL(fat_fill_super); | ||
1328 | |||
1329 | int __init fat_cache_init(void); | ||
1330 | void __exit fat_cache_destroy(void); | ||
1331 | |||
1332 | static int __init init_fat_fs(void) | ||
1333 | { | ||
1334 | int ret; | ||
1335 | |||
1336 | ret = fat_cache_init(); | ||
1337 | if (ret < 0) | ||
1338 | return ret; | ||
1339 | return fat_init_inodecache(); | ||
1340 | } | ||
1341 | |||
1342 | static void __exit exit_fat_fs(void) | ||
1343 | { | ||
1344 | fat_cache_destroy(); | ||
1345 | fat_destroy_inodecache(); | ||
1346 | } | ||
1347 | |||
1348 | module_init(init_fat_fs) | ||
1349 | module_exit(exit_fat_fs) | ||
1350 | |||
1351 | MODULE_LICENSE("GPL"); | ||
diff --git a/fs/fat/misc.c b/fs/fat/misc.c new file mode 100644 index 000000000000..2a0df2122f5d --- /dev/null +++ b/fs/fat/misc.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * linux/fs/fat/misc.c | ||
3 | * | ||
4 | * Written 1992,1993 by Werner Almesberger | ||
5 | * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 | ||
6 | * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/fs.h> | ||
11 | #include <linux/msdos_fs.h> | ||
12 | #include <linux/buffer_head.h> | ||
13 | |||
14 | /* | ||
15 | * fat_fs_panic reports a severe file system problem and sets the file system | ||
16 | * read-only. The file system can be made writable again by remounting it. | ||
17 | */ | ||
18 | void fat_fs_panic(struct super_block *s, const char *fmt, ...) | ||
19 | { | ||
20 | va_list args; | ||
21 | |||
22 | printk(KERN_ERR "FAT: Filesystem panic (dev %s)\n", s->s_id); | ||
23 | |||
24 | printk(KERN_ERR " "); | ||
25 | va_start(args, fmt); | ||
26 | vprintk(fmt, args); | ||
27 | va_end(args); | ||
28 | printk("\n"); | ||
29 | |||
30 | if (!(s->s_flags & MS_RDONLY)) { | ||
31 | s->s_flags |= MS_RDONLY; | ||
32 | printk(KERN_ERR " File system has been set read-only\n"); | ||
33 | } | ||
34 | } | ||
35 | |||
36 | EXPORT_SYMBOL(fat_fs_panic); | ||
37 | |||
38 | /* Flushes the number of free clusters on FAT32 */ | ||
39 | /* XXX: Need to write one per FSINFO block. Currently only writes 1 */ | ||
40 | void fat_clusters_flush(struct super_block *sb) | ||
41 | { | ||
42 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
43 | struct buffer_head *bh; | ||
44 | struct fat_boot_fsinfo *fsinfo; | ||
45 | |||
46 | if (sbi->fat_bits != 32) | ||
47 | return; | ||
48 | |||
49 | bh = sb_bread(sb, sbi->fsinfo_sector); | ||
50 | if (bh == NULL) { | ||
51 | printk(KERN_ERR "FAT: bread failed in fat_clusters_flush\n"); | ||
52 | return; | ||
53 | } | ||
54 | |||
55 | fsinfo = (struct fat_boot_fsinfo *)bh->b_data; | ||
56 | /* Sanity check */ | ||
57 | if (!IS_FSINFO(fsinfo)) { | ||
58 | printk(KERN_ERR "FAT: Did not find valid FSINFO signature.\n" | ||
59 | " Found signature1 0x%08x signature2 0x%08x" | ||
60 | " (sector = %lu)\n", | ||
61 | le32_to_cpu(fsinfo->signature1), | ||
62 | le32_to_cpu(fsinfo->signature2), | ||
63 | sbi->fsinfo_sector); | ||
64 | } else { | ||
65 | if (sbi->free_clusters != -1) | ||
66 | fsinfo->free_clusters = cpu_to_le32(sbi->free_clusters); | ||
67 | if (sbi->prev_free != -1) | ||
68 | fsinfo->next_cluster = cpu_to_le32(sbi->prev_free); | ||
69 | mark_buffer_dirty(bh); | ||
70 | if (sb->s_flags & MS_SYNCHRONOUS) | ||
71 | sync_dirty_buffer(bh); | ||
72 | } | ||
73 | brelse(bh); | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * fat_chain_add() adds a new cluster to the chain of clusters represented | ||
78 | * by inode. | ||
79 | */ | ||
80 | int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) | ||
81 | { | ||
82 | struct super_block *sb = inode->i_sb; | ||
83 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
84 | int ret, new_fclus, last; | ||
85 | |||
86 | /* | ||
87 | * We must locate the last cluster of the file to add this new | ||
88 | * one (new_dclus) to the end of the link list (the FAT). | ||
89 | */ | ||
90 | last = new_fclus = 0; | ||
91 | if (MSDOS_I(inode)->i_start) { | ||
92 | int fclus, dclus; | ||
93 | |||
94 | ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus); | ||
95 | if (ret < 0) | ||
96 | return ret; | ||
97 | new_fclus = fclus + 1; | ||
98 | last = dclus; | ||
99 | } | ||
100 | |||
101 | /* add new one to the last of the cluster chain */ | ||
102 | if (last) { | ||
103 | struct fat_entry fatent; | ||
104 | |||
105 | fatent_init(&fatent); | ||
106 | ret = fat_ent_read(inode, &fatent, last); | ||
107 | if (ret >= 0) { | ||
108 | int wait = inode_needs_sync(inode); | ||
109 | ret = fat_ent_write(inode, &fatent, new_dclus, wait); | ||
110 | fatent_brelse(&fatent); | ||
111 | } | ||
112 | if (ret < 0) | ||
113 | return ret; | ||
114 | // fat_cache_add(inode, new_fclus, new_dclus); | ||
115 | } else { | ||
116 | MSDOS_I(inode)->i_start = new_dclus; | ||
117 | MSDOS_I(inode)->i_logstart = new_dclus; | ||
118 | /* | ||
119 | * Since generic_osync_inode() synchronize later if | ||
120 | * this is not directory, we don't here. | ||
121 | */ | ||
122 | if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) { | ||
123 | ret = fat_sync_inode(inode); | ||
124 | if (ret) | ||
125 | return ret; | ||
126 | } else | ||
127 | mark_inode_dirty(inode); | ||
128 | } | ||
129 | if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { | ||
130 | fat_fs_panic(sb, "clusters badly computed (%d != %lu)", | ||
131 | new_fclus, inode->i_blocks >> (sbi->cluster_bits - 9)); | ||
132 | fat_cache_inval_inode(inode); | ||
133 | } | ||
134 | inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | extern struct timezone sys_tz; | ||
140 | |||
141 | /* Linear day numbers of the respective 1sts in non-leap years. */ | ||
142 | static int day_n[] = { | ||
143 | /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ | ||
144 | 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 | ||
145 | }; | ||
146 | |||
147 | /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ | ||
148 | int date_dos2unix(unsigned short time, unsigned short date) | ||
149 | { | ||
150 | int month, year, secs; | ||
151 | |||
152 | /* | ||
153 | * first subtract and mask after that... Otherwise, if | ||
154 | * date == 0, bad things happen | ||
155 | */ | ||
156 | month = ((date >> 5) - 1) & 15; | ||
157 | year = date >> 9; | ||
158 | secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* | ||
159 | ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && | ||
160 | month < 2 ? 1 : 0)+3653); | ||
161 | /* days since 1.1.70 plus 80's leap day */ | ||
162 | secs += sys_tz.tz_minuteswest*60; | ||
163 | return secs; | ||
164 | } | ||
165 | |||
166 | /* Convert linear UNIX date to a MS-DOS time/date pair. */ | ||
167 | void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date) | ||
168 | { | ||
169 | int day, year, nl_day, month; | ||
170 | |||
171 | unix_date -= sys_tz.tz_minuteswest*60; | ||
172 | |||
173 | /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ | ||
174 | if (unix_date < 315532800) | ||
175 | unix_date = 315532800; | ||
176 | |||
177 | *time = cpu_to_le16((unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ | ||
178 | (((unix_date/3600) % 24) << 11)); | ||
179 | day = unix_date/86400-3652; | ||
180 | year = day/365; | ||
181 | if ((year+3)/4+365*year > day) | ||
182 | year--; | ||
183 | day -= (year+3)/4+365*year; | ||
184 | if (day == 59 && !(year & 3)) { | ||
185 | nl_day = day; | ||
186 | month = 2; | ||
187 | } else { | ||
188 | nl_day = (year & 3) || day <= 59 ? day : day-1; | ||
189 | for (month = 0; month < 12; month++) { | ||
190 | if (day_n[month] > nl_day) | ||
191 | break; | ||
192 | } | ||
193 | } | ||
194 | *date = cpu_to_le16(nl_day-day_n[month-1]+1+(month << 5)+(year << 9)); | ||
195 | } | ||
196 | |||
197 | EXPORT_SYMBOL(fat_date_unix2dos); | ||
198 | |||
199 | int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) | ||
200 | { | ||
201 | int i, e, err = 0; | ||
202 | |||
203 | for (i = 0; i < nr_bhs; i++) { | ||
204 | lock_buffer(bhs[i]); | ||
205 | if (test_clear_buffer_dirty(bhs[i])) { | ||
206 | get_bh(bhs[i]); | ||
207 | bhs[i]->b_end_io = end_buffer_write_sync; | ||
208 | e = submit_bh(WRITE, bhs[i]); | ||
209 | if (!err && e) | ||
210 | err = e; | ||
211 | } else | ||
212 | unlock_buffer(bhs[i]); | ||
213 | } | ||
214 | for (i = 0; i < nr_bhs; i++) { | ||
215 | wait_on_buffer(bhs[i]); | ||
216 | if (buffer_eopnotsupp(bhs[i])) { | ||
217 | clear_buffer_eopnotsupp(bhs[i]); | ||
218 | err = -EOPNOTSUPP; | ||
219 | } else if (!err && !buffer_uptodate(bhs[i])) | ||
220 | err = -EIO; | ||
221 | } | ||
222 | return err; | ||
223 | } | ||
224 | |||
225 | EXPORT_SYMBOL(fat_sync_bhs); | ||