diff options
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/dir.c | 52 | ||||
-rw-r--r-- | fs/fat/fatent.c | 9 | ||||
-rw-r--r-- | fs/fat/file.c | 204 | ||||
-rw-r--r-- | fs/fat/inode.c | 38 |
4 files changed, 165 insertions, 138 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 72cbcd61bd95..486725ee99ae 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
@@ -124,8 +124,8 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos, | |||
124 | * but ignore that right now. | 124 | * but ignore that right now. |
125 | * Ahem... Stack smashing in ring 0 isn't fun. Fixed. | 125 | * Ahem... Stack smashing in ring 0 isn't fun. Fixed. |
126 | */ | 126 | */ |
127 | static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate, | 127 | static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len, |
128 | struct nls_table *nls) | 128 | int uni_xlate, struct nls_table *nls) |
129 | { | 129 | { |
130 | wchar_t *ip, ec; | 130 | wchar_t *ip, ec; |
131 | unsigned char *op, nc; | 131 | unsigned char *op, nc; |
@@ -135,10 +135,11 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate, | |||
135 | ip = uni; | 135 | ip = uni; |
136 | op = ascii; | 136 | op = ascii; |
137 | 137 | ||
138 | while (*ip) { | 138 | while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) { |
139 | ec = *ip++; | 139 | ec = *ip++; |
140 | if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) { | 140 | if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) { |
141 | op += charlen; | 141 | op += charlen; |
142 | len -= charlen; | ||
142 | } else { | 143 | } else { |
143 | if (uni_xlate == 1) { | 144 | if (uni_xlate == 1) { |
144 | *op = ':'; | 145 | *op = ':'; |
@@ -149,16 +150,19 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate, | |||
149 | ec >>= 4; | 150 | ec >>= 4; |
150 | } | 151 | } |
151 | op += 5; | 152 | op += 5; |
153 | len -= 5; | ||
152 | } else { | 154 | } else { |
153 | *op++ = '?'; | 155 | *op++ = '?'; |
156 | len--; | ||
154 | } | 157 | } |
155 | } | 158 | } |
156 | /* We have some slack there, so it's OK */ | ||
157 | if (op>ascii+256) { | ||
158 | op = ascii + 256; | ||
159 | break; | ||
160 | } | ||
161 | } | 159 | } |
160 | |||
161 | if (unlikely(*ip)) { | ||
162 | printk(KERN_WARNING "FAT: filename was truncated while " | ||
163 | "converting."); | ||
164 | } | ||
165 | |||
162 | *op = 0; | 166 | *op = 0; |
163 | return (op - ascii); | 167 | return (op - ascii); |
164 | } | 168 | } |
@@ -243,7 +247,7 @@ static int fat_parse_long(struct inode *dir, loff_t *pos, | |||
243 | unsigned char id, slot, slots, alias_checksum; | 247 | unsigned char id, slot, slots, alias_checksum; |
244 | 248 | ||
245 | if (!*unicode) { | 249 | if (!*unicode) { |
246 | *unicode = (wchar_t *)__get_free_page(GFP_KERNEL); | 250 | *unicode = __getname(); |
247 | if (!*unicode) { | 251 | if (!*unicode) { |
248 | brelse(*bh); | 252 | brelse(*bh); |
249 | return -ENOMEM; | 253 | return -ENOMEM; |
@@ -311,9 +315,11 @@ int fat_search_long(struct inode *inode, const unsigned char *name, | |||
311 | struct nls_table *nls_io = sbi->nls_io; | 315 | struct nls_table *nls_io = sbi->nls_io; |
312 | struct nls_table *nls_disk = sbi->nls_disk; | 316 | struct nls_table *nls_disk = sbi->nls_disk; |
313 | wchar_t bufuname[14]; | 317 | wchar_t bufuname[14]; |
314 | unsigned char xlate_len, nr_slots; | 318 | unsigned char nr_slots; |
319 | int xlate_len; | ||
315 | wchar_t *unicode = NULL; | 320 | wchar_t *unicode = NULL; |
316 | unsigned char work[MSDOS_NAME], bufname[260]; /* 256 + 4 */ | 321 | unsigned char work[MSDOS_NAME]; |
322 | unsigned char *bufname = NULL; | ||
317 | int uni_xlate = sbi->options.unicode_xlate; | 323 | int uni_xlate = sbi->options.unicode_xlate; |
318 | int utf8 = sbi->options.utf8; | 324 | int utf8 = sbi->options.utf8; |
319 | int anycase = (sbi->options.name_check != 's'); | 325 | int anycase = (sbi->options.name_check != 's'); |
@@ -321,6 +327,10 @@ int fat_search_long(struct inode *inode, const unsigned char *name, | |||
321 | loff_t cpos = 0; | 327 | loff_t cpos = 0; |
322 | int chl, i, j, last_u, err; | 328 | int chl, i, j, last_u, err; |
323 | 329 | ||
330 | bufname = __getname(); | ||
331 | if (!bufname) | ||
332 | return -ENOMEM; | ||
333 | |||
324 | err = -ENOENT; | 334 | err = -ENOENT; |
325 | while(1) { | 335 | while(1) { |
326 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) | 336 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) |
@@ -386,8 +396,8 @@ parse_record: | |||
386 | 396 | ||
387 | bufuname[last_u] = 0x0000; | 397 | bufuname[last_u] = 0x0000; |
388 | xlate_len = utf8 | 398 | xlate_len = utf8 |
389 | ?utf8_wcstombs(bufname, bufuname, sizeof(bufname)) | 399 | ?utf8_wcstombs(bufname, bufuname, PATH_MAX) |
390 | :uni16_to_x8(bufname, bufuname, uni_xlate, nls_io); | 400 | :uni16_to_x8(bufname, bufuname, PATH_MAX, uni_xlate, nls_io); |
391 | if (xlate_len == name_len) | 401 | if (xlate_len == name_len) |
392 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || | 402 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || |
393 | (anycase && !nls_strnicmp(nls_io, name, bufname, | 403 | (anycase && !nls_strnicmp(nls_io, name, bufname, |
@@ -396,8 +406,8 @@ parse_record: | |||
396 | 406 | ||
397 | if (nr_slots) { | 407 | if (nr_slots) { |
398 | xlate_len = utf8 | 408 | xlate_len = utf8 |
399 | ?utf8_wcstombs(bufname, unicode, sizeof(bufname)) | 409 | ?utf8_wcstombs(bufname, unicode, PATH_MAX) |
400 | :uni16_to_x8(bufname, unicode, uni_xlate, nls_io); | 410 | :uni16_to_x8(bufname, unicode, PATH_MAX, uni_xlate, nls_io); |
401 | if (xlate_len != name_len) | 411 | if (xlate_len != name_len) |
402 | continue; | 412 | continue; |
403 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || | 413 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || |
@@ -416,8 +426,10 @@ Found: | |||
416 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); | 426 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); |
417 | err = 0; | 427 | err = 0; |
418 | EODir: | 428 | EODir: |
429 | if (bufname) | ||
430 | __putname(bufname); | ||
419 | if (unicode) | 431 | if (unicode) |
420 | free_page((unsigned long)unicode); | 432 | __putname(unicode); |
421 | 433 | ||
422 | return err; | 434 | return err; |
423 | } | 435 | } |
@@ -598,7 +610,7 @@ parse_record: | |||
598 | if (isvfat) { | 610 | if (isvfat) { |
599 | bufuname[j] = 0x0000; | 611 | bufuname[j] = 0x0000; |
600 | i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname)) | 612 | i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname)) |
601 | : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io); | 613 | : uni16_to_x8(bufname, bufuname, sizeof(bufname), uni_xlate, nls_io); |
602 | } | 614 | } |
603 | 615 | ||
604 | fill_name = bufname; | 616 | fill_name = bufname; |
@@ -607,10 +619,10 @@ parse_record: | |||
607 | /* convert the unicode long name. 261 is maximum size | 619 | /* convert the unicode long name. 261 is maximum size |
608 | * of unicode buffer. (13 * slots + nul) */ | 620 | * of unicode buffer. (13 * slots + nul) */ |
609 | void *longname = unicode + 261; | 621 | void *longname = unicode + 261; |
610 | int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0])); | 622 | int buf_size = PATH_MAX - (261 * sizeof(unicode[0])); |
611 | int long_len = utf8 | 623 | int long_len = utf8 |
612 | ? utf8_wcstombs(longname, unicode, buf_size) | 624 | ? utf8_wcstombs(longname, unicode, buf_size) |
613 | : uni16_to_x8(longname, unicode, uni_xlate, nls_io); | 625 | : uni16_to_x8(longname, unicode, buf_size, uni_xlate, nls_io); |
614 | 626 | ||
615 | if (!both) { | 627 | if (!both) { |
616 | fill_name = longname; | 628 | fill_name = longname; |
@@ -640,7 +652,7 @@ EODir: | |||
640 | FillFailed: | 652 | FillFailed: |
641 | brelse(bh); | 653 | brelse(bh); |
642 | if (unicode) | 654 | if (unicode) |
643 | free_page((unsigned long)unicode); | 655 | __putname(unicode); |
644 | out: | 656 | out: |
645 | unlock_kernel(); | 657 | unlock_kernel(); |
646 | return ret; | 658 | return ret; |
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 5fb366992b73..13ab763cc510 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c | |||
@@ -450,7 +450,8 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster) | |||
450 | BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2)); /* fixed limit */ | 450 | BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2)); /* fixed limit */ |
451 | 451 | ||
452 | lock_fat(sbi); | 452 | lock_fat(sbi); |
453 | if (sbi->free_clusters != -1 && sbi->free_clusters < nr_cluster) { | 453 | if (sbi->free_clusters != -1 && sbi->free_clus_valid && |
454 | sbi->free_clusters < nr_cluster) { | ||
454 | unlock_fat(sbi); | 455 | unlock_fat(sbi); |
455 | return -ENOSPC; | 456 | return -ENOSPC; |
456 | } | 457 | } |
@@ -504,6 +505,7 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster) | |||
504 | 505 | ||
505 | /* Couldn't allocate the free entries */ | 506 | /* Couldn't allocate the free entries */ |
506 | sbi->free_clusters = 0; | 507 | sbi->free_clusters = 0; |
508 | sbi->free_clus_valid = 1; | ||
507 | sb->s_dirt = 1; | 509 | sb->s_dirt = 1; |
508 | err = -ENOSPC; | 510 | err = -ENOSPC; |
509 | 511 | ||
@@ -583,8 +585,6 @@ error: | |||
583 | brelse(bhs[i]); | 585 | brelse(bhs[i]); |
584 | unlock_fat(sbi); | 586 | unlock_fat(sbi); |
585 | 587 | ||
586 | fat_clusters_flush(sb); | ||
587 | |||
588 | return err; | 588 | return err; |
589 | } | 589 | } |
590 | 590 | ||
@@ -615,7 +615,7 @@ int fat_count_free_clusters(struct super_block *sb) | |||
615 | int err = 0, free; | 615 | int err = 0, free; |
616 | 616 | ||
617 | lock_fat(sbi); | 617 | lock_fat(sbi); |
618 | if (sbi->free_clusters != -1) | 618 | if (sbi->free_clusters != -1 && sbi->free_clus_valid) |
619 | goto out; | 619 | goto out; |
620 | 620 | ||
621 | reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits; | 621 | reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits; |
@@ -643,6 +643,7 @@ int fat_count_free_clusters(struct super_block *sb) | |||
643 | } while (fat_ent_next(sbi, &fatent)); | 643 | } while (fat_ent_next(sbi, &fatent)); |
644 | } | 644 | } |
645 | sbi->free_clusters = free; | 645 | sbi->free_clusters = free; |
646 | sbi->free_clus_valid = 1; | ||
646 | sb->s_dirt = 1; | 647 | sb->s_dirt = 1; |
647 | fatent_brelse(&fatent); | 648 | fatent_brelse(&fatent); |
648 | out: | 649 | out: |
diff --git a/fs/fat/file.c b/fs/fat/file.c index 2a3bed967041..d604bb132422 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -157,104 +157,6 @@ out: | |||
157 | return err; | 157 | return err; |
158 | } | 158 | } |
159 | 159 | ||
160 | static int check_mode(const struct msdos_sb_info *sbi, mode_t mode) | ||
161 | { | ||
162 | mode_t req = mode & ~S_IFMT; | ||
163 | |||
164 | /* | ||
165 | * Of the r and x bits, all (subject to umask) must be present. Of the | ||
166 | * w bits, either all (subject to umask) or none must be present. | ||
167 | */ | ||
168 | |||
169 | if (S_ISREG(mode)) { | ||
170 | req &= ~sbi->options.fs_fmask; | ||
171 | |||
172 | if ((req & (S_IRUGO | S_IXUGO)) != | ||
173 | ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask)) | ||
174 | return -EPERM; | ||
175 | |||
176 | if ((req & S_IWUGO) != 0 && | ||
177 | (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask)) | ||
178 | return -EPERM; | ||
179 | } else if (S_ISDIR(mode)) { | ||
180 | req &= ~sbi->options.fs_dmask; | ||
181 | |||
182 | if ((req & (S_IRUGO | S_IXUGO)) != | ||
183 | ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask)) | ||
184 | return -EPERM; | ||
185 | |||
186 | if ((req & S_IWUGO) != 0 && | ||
187 | (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask)) | ||
188 | return -EPERM; | ||
189 | } else { | ||
190 | return -EPERM; | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | int fat_notify_change(struct dentry *dentry, struct iattr *attr) | ||
197 | { | ||
198 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | ||
199 | struct inode *inode = dentry->d_inode; | ||
200 | int mask, error = 0; | ||
201 | |||
202 | lock_kernel(); | ||
203 | |||
204 | /* | ||
205 | * Expand the file. Since inode_setattr() updates ->i_size | ||
206 | * before calling the ->truncate(), but FAT needs to fill the | ||
207 | * hole before it. | ||
208 | */ | ||
209 | if (attr->ia_valid & ATTR_SIZE) { | ||
210 | if (attr->ia_size > inode->i_size) { | ||
211 | error = fat_cont_expand(inode, attr->ia_size); | ||
212 | if (error || attr->ia_valid == ATTR_SIZE) | ||
213 | goto out; | ||
214 | attr->ia_valid &= ~ATTR_SIZE; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | error = inode_change_ok(inode, attr); | ||
219 | if (error) { | ||
220 | if (sbi->options.quiet) | ||
221 | error = 0; | ||
222 | goto out; | ||
223 | } | ||
224 | if (((attr->ia_valid & ATTR_UID) && | ||
225 | (attr->ia_uid != sbi->options.fs_uid)) || | ||
226 | ((attr->ia_valid & ATTR_GID) && | ||
227 | (attr->ia_gid != sbi->options.fs_gid))) | ||
228 | error = -EPERM; | ||
229 | |||
230 | if (error) { | ||
231 | if (sbi->options.quiet) | ||
232 | error = 0; | ||
233 | goto out; | ||
234 | } | ||
235 | |||
236 | if (attr->ia_valid & ATTR_MODE) { | ||
237 | error = check_mode(sbi, attr->ia_mode); | ||
238 | if (error != 0 && !sbi->options.quiet) | ||
239 | goto out; | ||
240 | } | ||
241 | |||
242 | error = inode_setattr(inode, attr); | ||
243 | if (error) | ||
244 | goto out; | ||
245 | |||
246 | if (S_ISDIR(inode->i_mode)) | ||
247 | mask = sbi->options.fs_dmask; | ||
248 | else | ||
249 | mask = sbi->options.fs_fmask; | ||
250 | inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask); | ||
251 | out: | ||
252 | unlock_kernel(); | ||
253 | return error; | ||
254 | } | ||
255 | |||
256 | EXPORT_SYMBOL_GPL(fat_notify_change); | ||
257 | |||
258 | /* Free all clusters after the skip'th cluster. */ | 160 | /* Free all clusters after the skip'th cluster. */ |
259 | static int fat_free(struct inode *inode, int skip) | 161 | static int fat_free(struct inode *inode, int skip) |
260 | { | 162 | { |
@@ -355,8 +257,112 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
355 | } | 257 | } |
356 | EXPORT_SYMBOL_GPL(fat_getattr); | 258 | EXPORT_SYMBOL_GPL(fat_getattr); |
357 | 259 | ||
260 | static int fat_check_mode(const struct msdos_sb_info *sbi, struct inode *inode, | ||
261 | mode_t mode) | ||
262 | { | ||
263 | mode_t mask, req = mode & ~S_IFMT; | ||
264 | |||
265 | if (S_ISREG(mode)) | ||
266 | mask = sbi->options.fs_fmask; | ||
267 | else | ||
268 | mask = sbi->options.fs_dmask; | ||
269 | |||
270 | /* | ||
271 | * Of the r and x bits, all (subject to umask) must be present. Of the | ||
272 | * w bits, either all (subject to umask) or none must be present. | ||
273 | */ | ||
274 | req &= ~mask; | ||
275 | if ((req & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) | ||
276 | return -EPERM; | ||
277 | if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask))) | ||
278 | return -EPERM; | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) | ||
284 | { | ||
285 | mode_t allow_utime = sbi->options.allow_utime; | ||
286 | |||
287 | if (current->fsuid != inode->i_uid) { | ||
288 | if (in_group_p(inode->i_gid)) | ||
289 | allow_utime >>= 3; | ||
290 | if (allow_utime & MAY_WRITE) | ||
291 | return 1; | ||
292 | } | ||
293 | |||
294 | /* use a default check */ | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | int fat_setattr(struct dentry *dentry, struct iattr *attr) | ||
299 | { | ||
300 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | ||
301 | struct inode *inode = dentry->d_inode; | ||
302 | int mask, error = 0; | ||
303 | unsigned int ia_valid; | ||
304 | |||
305 | lock_kernel(); | ||
306 | |||
307 | /* | ||
308 | * Expand the file. Since inode_setattr() updates ->i_size | ||
309 | * before calling the ->truncate(), but FAT needs to fill the | ||
310 | * hole before it. | ||
311 | */ | ||
312 | if (attr->ia_valid & ATTR_SIZE) { | ||
313 | if (attr->ia_size > inode->i_size) { | ||
314 | error = fat_cont_expand(inode, attr->ia_size); | ||
315 | if (error || attr->ia_valid == ATTR_SIZE) | ||
316 | goto out; | ||
317 | attr->ia_valid &= ~ATTR_SIZE; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | /* Check for setting the inode time. */ | ||
322 | ia_valid = attr->ia_valid; | ||
323 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { | ||
324 | if (fat_allow_set_time(sbi, inode)) | ||
325 | attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET); | ||
326 | } | ||
327 | |||
328 | error = inode_change_ok(inode, attr); | ||
329 | attr->ia_valid = ia_valid; | ||
330 | if (error) { | ||
331 | if (sbi->options.quiet) | ||
332 | error = 0; | ||
333 | goto out; | ||
334 | } | ||
335 | if (((attr->ia_valid & ATTR_UID) && | ||
336 | (attr->ia_uid != sbi->options.fs_uid)) || | ||
337 | ((attr->ia_valid & ATTR_GID) && | ||
338 | (attr->ia_gid != sbi->options.fs_gid)) || | ||
339 | ((attr->ia_valid & ATTR_MODE) && | ||
340 | fat_check_mode(sbi, inode, attr->ia_mode) < 0)) | ||
341 | error = -EPERM; | ||
342 | |||
343 | if (error) { | ||
344 | if (sbi->options.quiet) | ||
345 | error = 0; | ||
346 | goto out; | ||
347 | } | ||
348 | |||
349 | error = inode_setattr(inode, attr); | ||
350 | if (error) | ||
351 | goto out; | ||
352 | |||
353 | if (S_ISDIR(inode->i_mode)) | ||
354 | mask = sbi->options.fs_dmask; | ||
355 | else | ||
356 | mask = sbi->options.fs_fmask; | ||
357 | inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask); | ||
358 | out: | ||
359 | unlock_kernel(); | ||
360 | return error; | ||
361 | } | ||
362 | EXPORT_SYMBOL_GPL(fat_setattr); | ||
363 | |||
358 | const struct inode_operations fat_file_inode_operations = { | 364 | const struct inode_operations fat_file_inode_operations = { |
359 | .truncate = fat_truncate, | 365 | .truncate = fat_truncate, |
360 | .setattr = fat_notify_change, | 366 | .setattr = fat_setattr, |
361 | .getattr = fat_getattr, | 367 | .getattr = fat_getattr, |
362 | }; | 368 | }; |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 53f3cf62b7c1..5f522a55b596 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -433,11 +433,8 @@ EXPORT_SYMBOL_GPL(fat_build_inode); | |||
433 | static void fat_delete_inode(struct inode *inode) | 433 | static void fat_delete_inode(struct inode *inode) |
434 | { | 434 | { |
435 | truncate_inode_pages(&inode->i_data, 0); | 435 | truncate_inode_pages(&inode->i_data, 0); |
436 | 436 | inode->i_size = 0; | |
437 | if (!is_bad_inode(inode)) { | 437 | fat_truncate(inode); |
438 | inode->i_size = 0; | ||
439 | fat_truncate(inode); | ||
440 | } | ||
441 | clear_inode(inode); | 438 | clear_inode(inode); |
442 | } | 439 | } |
443 | 440 | ||
@@ -445,8 +442,6 @@ static void fat_clear_inode(struct inode *inode) | |||
445 | { | 442 | { |
446 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | 443 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
447 | 444 | ||
448 | if (is_bad_inode(inode)) | ||
449 | return; | ||
450 | lock_kernel(); | 445 | lock_kernel(); |
451 | spin_lock(&sbi->inode_hash_lock); | 446 | spin_lock(&sbi->inode_hash_lock); |
452 | fat_cache_inval_inode(inode); | 447 | fat_cache_inval_inode(inode); |
@@ -542,7 +537,7 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
542 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | 537 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); |
543 | 538 | ||
544 | /* If the count of free cluster is still unknown, counts it here. */ | 539 | /* If the count of free cluster is still unknown, counts it here. */ |
545 | if (sbi->free_clusters == -1) { | 540 | if (sbi->free_clusters == -1 || !sbi->free_clus_valid) { |
546 | int err = fat_count_free_clusters(dentry->d_sb); | 541 | int err = fat_count_free_clusters(dentry->d_sb); |
547 | if (err) | 542 | if (err) |
548 | return err; | 543 | return err; |
@@ -790,6 +785,8 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
790 | seq_printf(m, ",gid=%u", opts->fs_gid); | 785 | seq_printf(m, ",gid=%u", opts->fs_gid); |
791 | seq_printf(m, ",fmask=%04o", opts->fs_fmask); | 786 | seq_printf(m, ",fmask=%04o", opts->fs_fmask); |
792 | seq_printf(m, ",dmask=%04o", opts->fs_dmask); | 787 | seq_printf(m, ",dmask=%04o", opts->fs_dmask); |
788 | if (opts->allow_utime) | ||
789 | seq_printf(m, ",allow_utime=%04o", opts->allow_utime); | ||
793 | if (sbi->nls_disk) | 790 | if (sbi->nls_disk) |
794 | seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); | 791 | seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); |
795 | if (isvfat) { | 792 | if (isvfat) { |
@@ -845,9 +842,9 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
845 | 842 | ||
846 | enum { | 843 | enum { |
847 | Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid, | 844 | Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid, |
848 | Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_usefree, Opt_nocase, | 845 | Opt_umask, Opt_dmask, Opt_fmask, Opt_allow_utime, Opt_codepage, |
849 | Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable, | 846 | Opt_usefree, Opt_nocase, Opt_quiet, Opt_showexec, Opt_debug, |
850 | Opt_dots, Opt_nodots, | 847 | Opt_immutable, Opt_dots, Opt_nodots, |
851 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, | 848 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, |
852 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, | 849 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, |
853 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, | 850 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, |
@@ -866,6 +863,7 @@ static match_table_t fat_tokens = { | |||
866 | {Opt_umask, "umask=%o"}, | 863 | {Opt_umask, "umask=%o"}, |
867 | {Opt_dmask, "dmask=%o"}, | 864 | {Opt_dmask, "dmask=%o"}, |
868 | {Opt_fmask, "fmask=%o"}, | 865 | {Opt_fmask, "fmask=%o"}, |
866 | {Opt_allow_utime, "allow_utime=%o"}, | ||
869 | {Opt_codepage, "codepage=%u"}, | 867 | {Opt_codepage, "codepage=%u"}, |
870 | {Opt_usefree, "usefree"}, | 868 | {Opt_usefree, "usefree"}, |
871 | {Opt_nocase, "nocase"}, | 869 | {Opt_nocase, "nocase"}, |
@@ -937,6 +935,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
937 | opts->fs_uid = current->uid; | 935 | opts->fs_uid = current->uid; |
938 | opts->fs_gid = current->gid; | 936 | opts->fs_gid = current->gid; |
939 | opts->fs_fmask = opts->fs_dmask = current->fs->umask; | 937 | opts->fs_fmask = opts->fs_dmask = current->fs->umask; |
938 | opts->allow_utime = -1; | ||
940 | opts->codepage = fat_default_codepage; | 939 | opts->codepage = fat_default_codepage; |
941 | opts->iocharset = fat_default_iocharset; | 940 | opts->iocharset = fat_default_iocharset; |
942 | if (is_vfat) | 941 | if (is_vfat) |
@@ -1024,6 +1023,11 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
1024 | return 0; | 1023 | return 0; |
1025 | opts->fs_fmask = option; | 1024 | opts->fs_fmask = option; |
1026 | break; | 1025 | break; |
1026 | case Opt_allow_utime: | ||
1027 | if (match_octal(&args[0], &option)) | ||
1028 | return 0; | ||
1029 | opts->allow_utime = option & (S_IWGRP | S_IWOTH); | ||
1030 | break; | ||
1027 | case Opt_codepage: | 1031 | case Opt_codepage: |
1028 | if (match_int(&args[0], &option)) | 1032 | if (match_int(&args[0], &option)) |
1029 | return 0; | 1033 | return 0; |
@@ -1106,6 +1110,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
1106 | " for FAT filesystems, filesystem will be case sensitive!\n"); | 1110 | " for FAT filesystems, filesystem will be case sensitive!\n"); |
1107 | } | 1111 | } |
1108 | 1112 | ||
1113 | /* If user doesn't specify allow_utime, it's initialized from dmask. */ | ||
1114 | if (opts->allow_utime == (unsigned short)-1) | ||
1115 | opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH); | ||
1109 | if (opts->unicode_xlate) | 1116 | if (opts->unicode_xlate) |
1110 | opts->utf8 = 0; | 1117 | opts->utf8 = 0; |
1111 | 1118 | ||
@@ -1208,7 +1215,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, | |||
1208 | */ | 1215 | */ |
1209 | 1216 | ||
1210 | media = b->media; | 1217 | media = b->media; |
1211 | if (!FAT_VALID_MEDIA(media)) { | 1218 | if (!fat_valid_media(media)) { |
1212 | if (!silent) | 1219 | if (!silent) |
1213 | printk(KERN_ERR "FAT: invalid media value (0x%02x)\n", | 1220 | printk(KERN_ERR "FAT: invalid media value (0x%02x)\n", |
1214 | media); | 1221 | media); |
@@ -1219,7 +1226,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, | |||
1219 | le16_to_cpu(get_unaligned((__le16 *)&b->sector_size)); | 1226 | le16_to_cpu(get_unaligned((__le16 *)&b->sector_size)); |
1220 | if (!is_power_of_2(logical_sector_size) | 1227 | if (!is_power_of_2(logical_sector_size) |
1221 | || (logical_sector_size < 512) | 1228 | || (logical_sector_size < 512) |
1222 | || (PAGE_CACHE_SIZE < logical_sector_size)) { | 1229 | || (logical_sector_size > 4096)) { |
1223 | if (!silent) | 1230 | if (!silent) |
1224 | printk(KERN_ERR "FAT: bogus logical sector size %u\n", | 1231 | printk(KERN_ERR "FAT: bogus logical sector size %u\n", |
1225 | logical_sector_size); | 1232 | logical_sector_size); |
@@ -1267,6 +1274,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, | |||
1267 | sbi->fat_length = le16_to_cpu(b->fat_length); | 1274 | sbi->fat_length = le16_to_cpu(b->fat_length); |
1268 | sbi->root_cluster = 0; | 1275 | sbi->root_cluster = 0; |
1269 | sbi->free_clusters = -1; /* Don't know yet */ | 1276 | sbi->free_clusters = -1; /* Don't know yet */ |
1277 | sbi->free_clus_valid = 0; | ||
1270 | sbi->prev_free = FAT_START_ENT; | 1278 | sbi->prev_free = FAT_START_ENT; |
1271 | 1279 | ||
1272 | if (!sbi->fat_length && b->fat32_length) { | 1280 | if (!sbi->fat_length && b->fat32_length) { |
@@ -1302,8 +1310,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, | |||
1302 | sbi->fsinfo_sector); | 1310 | sbi->fsinfo_sector); |
1303 | } else { | 1311 | } else { |
1304 | if (sbi->options.usefree) | 1312 | if (sbi->options.usefree) |
1305 | sbi->free_clusters = | 1313 | sbi->free_clus_valid = 1; |
1306 | le32_to_cpu(fsinfo->free_clusters); | 1314 | sbi->free_clusters = le32_to_cpu(fsinfo->free_clusters); |
1307 | sbi->prev_free = le32_to_cpu(fsinfo->next_cluster); | 1315 | sbi->prev_free = le32_to_cpu(fsinfo->next_cluster); |
1308 | } | 1316 | } |
1309 | 1317 | ||