2 * linux/fs/vfat/namei.c
4 * Written 1992,1993 by Werner Almesberger
6 * Windows95/Windows NT compatible extended MSDOS filesystem
7 * by Gordon Chaffee Copyright (C) 1995. Send bug reports for the
8 * VFAT filesystem to <chaffee@cs.berkeley.edu>. Specify
9 * what file operation caused you trouble and if you can duplicate
10 * the problem, send a script that demonstrates it.
13 #define __NO_VERSION__
14 #include <linux/module.h>
16 #include <linux/sched.h>
17 #include <linux/msdos_fs.h>
18 #include <linux/nls.h>
19 #include <linux/kernel.h>
20 #include <linux/errno.h>
21 #include <linux/string.h>
22 #include <linux/ctype.h>
23 #include <linux/stat.h>
25 #include <linux/malloc.h>
27 #include "../fat/msbuffer.h"
30 #if (DEBUG_LEVEL >= 1)
31 # define PRINTK1(x) printk x
35 #if (DEBUG_LEVEL >= 2)
36 # define PRINTK2(x) printk x
40 #if (DEBUG_LEVEL >= 3)
41 # define PRINTK3(x) printk x
49 # define CHECK_STACK check_stack(__FILE__, __LINE__)
52 static int vfat_hashi(struct dentry
*parent
, struct qstr
*qstr
);
53 static int vfat_hash(struct dentry
*parent
, struct qstr
*qstr
);
54 static int vfat_cmpi(struct dentry
*dentry
, struct qstr
*a
, struct qstr
*b
);
55 static int vfat_cmp(struct dentry
*dentry
, struct qstr
*a
, struct qstr
*b
);
56 static int vfat_revalidate(struct dentry
*dentry
, int);
58 static struct dentry_operations vfat_dentry_ops
[4] = {
60 NULL
, /* d_revalidate */
72 NULL
, /* d_revalidate */
85 static void vfat_put_super_callback(struct super_block
*sb
)
90 static int vfat_revalidate(struct dentry
*dentry
, int flags
)
92 PRINTK1(("vfat_revalidate: %s\n", dentry
->d_name
.name
));
93 if (dentry
->d_time
== dentry
->d_parent
->d_inode
->i_version
) {
99 static int simple_getbool(char *s
, int *setval
)
102 if (!strcmp(s
,"1") || !strcmp(s
,"yes") || !strcmp(s
,"true")) {
104 } else if (!strcmp(s
,"0") || !strcmp(s
,"no") || !strcmp(s
,"false")) {
115 static int parse_options(char *options
, struct fat_mount_options
*opts
)
117 char *this_char
,*value
,save
,*savep
;
120 opts
->unicode_xlate
= opts
->posixfs
= 0;
124 if (!options
) return 1;
128 for (this_char
= strtok(options
,","); this_char
; this_char
= strtok(NULL
,",")) {
129 if ((value
= strchr(this_char
,'=')) != NULL
) {
134 if (!strcmp(this_char
,"utf8")) {
135 ret
= simple_getbool(value
, &val
);
136 if (ret
) opts
->utf8
= val
;
137 } else if (!strcmp(this_char
,"uni_xlate")) {
138 ret
= simple_getbool(value
, &val
);
139 if (ret
) opts
->unicode_xlate
= val
;
140 } else if (!strcmp(this_char
,"posix")) {
141 ret
= simple_getbool(value
, &val
);
142 if (ret
) opts
->posixfs
= val
;
143 } else if (!strcmp(this_char
,"nonumtail")) {
144 ret
= simple_getbool(value
, &val
);
146 opts
->numtail
= !val
;
149 if (this_char
!= options
)
150 *(this_char
-1) = ',';
158 if (opts
->unicode_xlate
) {
165 * Compute the hash for the vfat name corresponding to the dentry.
166 * Note: if the name is invalid, we leave the hash code unchanged so
167 * that the existing dentry can be used. The vfat fs routines will
168 * return ENOENT or EINVAL as appropriate.
170 static int vfat_hash(struct dentry
*dentry
, struct qstr
*qstr
)
177 while (len
&& name
[len
-1] == '.')
180 qstr
->hash
= full_name_hash(name
, len
);
186 * Compute the hash for the vfat name corresponding to the dentry.
187 * Note: if the name is invalid, we leave the hash code unchanged so
188 * that the existing dentry can be used. The vfat fs routines will
189 * return ENOENT or EINVAL as appropriate.
191 static int vfat_hashi(struct dentry
*dentry
, struct qstr
*qstr
)
200 while (len
&& name
[len
-1] == '.')
203 hash
= init_name_hash();
205 c
= tolower(*name
++);
206 hash
= partial_name_hash(tolower(c
), hash
);
208 qstr
->hash
= end_name_hash(hash
);
214 * Case insensitive compare of two vfat names.
216 static int vfat_cmpi(struct dentry
*dentry
, struct qstr
*a
, struct qstr
*b
)
220 /* A filename cannot end in '.' or we treat it like it has none */
223 while (alen
&& a
->name
[alen
-1] == '.')
225 while (blen
&& b
->name
[blen
-1] == '.')
228 if (strnicmp(a
->name
, b
->name
, alen
) == 0)
235 * Case sensitive compare of two vfat names.
237 static int vfat_cmp(struct dentry
*dentry
, struct qstr
*a
, struct qstr
*b
)
241 /* A filename cannot end in '.' or we treat it like it has none */
244 while (alen
&& a
->name
[alen
-1] == '.')
246 while (blen
&& b
->name
[blen
-1] == '.')
249 if (strncmp(a
->name
, b
->name
, alen
) == 0)
258 check_stack(const char *fname
, int lineno
)
263 stack_level
= (long)(&pg_dir
)-current
->kernel_stack_page
;
265 printk("*-*-*-* vfat kstack overflow in %s line %d: SL=%d\n",
266 fname
, lineno
, stack_level
);
267 else if (stack_level
< 500)
268 printk("*-*-*-* vfat kstack low in %s line %d: SL=%d\n",
269 fname
, lineno
, stack_level
);
272 printk("------- vfat kstack ok in %s line %d: SL=%d\n",
273 fname
, lineno
, stack_level
);
276 if (*(unsigned long *) current
->kernel_stack_page
!= STACK_MAGIC
) {
277 printk("******* vfat stack corruption detected in %s at line %d\n",
283 static int debug
= 0;
284 static void dump_fat(struct super_block
*sb
,int start
)
289 start
= fat_access(sb
,start
,-1);
294 if (start
== -1) break;
299 static void dump_de(struct msdos_dir_entry
*de
)
302 unsigned char *p
= (unsigned char *) de
;
305 for (i
= 0; i
< 32; i
++, p
++) {
313 /* MS-DOS "device special files" */
315 static const char *reserved3_names
[] = {
316 "con ", "prn ", "nul ", "aux ", NULL
319 static const char *reserved4_names
[] = {
320 "com1 ", "com2 ", "com3 ", "com4 ", "com5 ",
321 "com6 ", "com7 ", "com8 ", "com9 ",
322 "lpt1 ", "lpt2 ", "lpt3 ", "lpt4 ", "lpt5 ",
323 "lpt6 ", "lpt7 ", "lpt8 ", "lpt9 ",
327 /* Characters that are undesirable in an MS-DOS file name */
329 static char bad_chars
[] = "*?<>|\":/\\";
330 static char replace_chars
[] = "[];,+=";
332 /* Checks the validity of a long MS-DOS filename */
333 /* Returns negative number on error, 0 for a normal
334 * return, and 1 for . or .. */
336 static int vfat_valid_longname(const char *name
, int len
, int xlate
)
338 const char **reserved
, *walk
;
342 if (IS_FREE(name
)) return -EINVAL
;
344 if (len
&& name
[len
-1] == ' ') return -EINVAL
;
345 if (len
>= 256) return -EINVAL
;
346 for (i
= 0; i
< len
; i
++) {
348 if (xlate
&& c
== ':') continue;
349 if (strchr(bad_chars
,c
)) {
353 if (len
< 3) return 0;
355 for (walk
= name
; *walk
!= 0 && *walk
!= '.'; walk
++);
356 baselen
= walk
- name
;
359 for (reserved
= reserved3_names
; *reserved
; reserved
++) {
360 if (!strnicmp(name
,*reserved
,baselen
))
363 } else if (baselen
== 4) {
364 for (reserved
= reserved4_names
; *reserved
; reserved
++) {
365 if (!strnicmp(name
,*reserved
,baselen
))
372 static int vfat_valid_shortname(const char *name
,int len
,int utf8
)
379 space
= 1; /* disallow names starting with a dot */
381 for (walk
= name
; len
&& walk
-name
< 8;) {
384 if (utf8
&& (c
& 0x80)) return -EINVAL
;
385 if (strchr(replace_chars
,c
)) return -EINVAL
;
386 if (c
>= 'A' && c
<= 'Z') return -EINVAL
;
387 if (c
< ' '|| c
==':') return -EINVAL
;
391 if (space
) return -EINVAL
;
392 if (len
&& c
!= '.') {
395 if (c
!= '.') return -EINVAL
;
397 baselen
= walk
- name
;
400 if (len
>= 4) return -EINVAL
;
404 if (utf8
&& (c
& 0x80)) return -EINVAL
;
405 if (strchr(replace_chars
,c
))
407 if (c
< ' ' || c
== '.'|| c
==':')
409 if (c
>= 'A' && c
<= 'Z') return -EINVAL
;
412 if (space
) return -EINVAL
;
418 static int vfat_find_form(struct inode
*dir
,char *name
)
420 struct msdos_dir_entry
*de
;
421 struct buffer_head
*bh
= NULL
;
424 res
=fat_scan(dir
,name
,&bh
,&de
,&ino
);
425 fat_brelse(dir
->i_sb
, bh
);
431 static int vfat_format_name(const char *name
,int len
,char *res
,int utf8
)
437 space
= 1; /* disallow names starting with a dot */
438 for (walk
= res
; len
-- && (c
=*name
++)!='.' ; walk
++) {
439 if (walk
-res
== 8) return -EINVAL
;
440 if (utf8
&& (c
& 0x80)) return -EINVAL
;
441 if (strchr(replace_chars
,c
)) return -EINVAL
;
442 if (c
>= 'A' && c
<= 'Z') return -EINVAL
;
443 if (c
< ' '|| c
==':') return -EINVAL
;
445 *walk
= c
>= 'a' && c
<= 'z' ? c
-32 : c
;
447 if (space
) return -EINVAL
;
449 while (walk
-res
< 8) *walk
++ = ' ';
450 while (len
> 0 && walk
-res
< MSDOS_NAME
) {
453 if (utf8
&& (c
& 0x80)) return -EINVAL
;
454 if (strchr(replace_chars
,c
))
456 if (c
< ' ' || c
== '.'|| c
==':')
458 if (c
>= 'A' && c
<= 'Z') return -EINVAL
;
460 *walk
++ = c
>= 'a' && c
<= 'z' ? c
-32 : c
;
462 if (space
) return -EINVAL
;
463 if (len
) return -EINVAL
;
465 while (walk
-res
< MSDOS_NAME
) *walk
++ = ' ';
470 static char skip_chars
[] = ".:\"?<>| ";
472 /* Given a valid longname, create a unique shortname. Make sure the
473 * shortname does not exist
475 static int vfat_create_shortname(struct inode
*dir
, const char *name
,
476 int len
, char *name_res
, int utf8
)
478 const char *ip
, *ext_start
, *end
;
480 int sz
, extlen
, baselen
;
482 char base
[9], ext
[4];
485 const char *name_start
;
487 PRINTK2(("Entering vfat_create_shortname: name=%s, len=%d\n", name
, len
));
488 sz
= 0; /* Make compiler happy */
489 if (len
&& name
[len
-1]==' ') return -EINVAL
;
491 /* Do a case insensitive search if the name would be a valid
492 * shortname if is were all capitalized. However, do not
493 * allow spaces in short names because Win95 scandisk does
495 for (i
= 0, p
= msdos_name
, ip
= name
; ; i
++, p
++, ip
++) {
497 if (vfat_format_name(msdos_name
,
498 len
, name_res
, utf8
) < 0)
500 PRINTK3(("vfat_create_shortname 1\n"));
501 if (vfat_find_form(dir
, name_res
) < 0)
508 if (*ip
>= 'A' && *ip
<= 'Z') {
516 PRINTK3(("vfat_create_shortname 3\n"));
517 /* Now, we need to create a shortname from the long name */
518 ext_start
= end
= &name
[len
];
519 while (--ext_start
>= name
) {
520 if (*ext_start
== '.') {
521 if (ext_start
== end
- 1) {
528 if (ext_start
== name
- 1) {
531 } else if (ext_start
) {
533 * Names which start with a dot could be just
534 * an extension eg. "...test". In this case Win95
535 * uses the extension as the name and sets no extension.
537 name_start
= &name
[0];
538 while (name_start
< ext_start
)
540 if (!strchr(skip_chars
,*name_start
)) break;
543 if (name_start
!= ext_start
) {
544 sz
= ext_start
- name
;
552 for (baselen
= i
= 0, p
= base
, ip
= name
; i
< sz
&& baselen
< 8; i
++)
554 if (utf8
&& (*ip
& 0x80)) {
557 } else if (!strchr(skip_chars
, *ip
)) {
558 if (*ip
>= 'a' && *ip
<= 'z') {
563 if (strchr(replace_chars
, *p
)) *p
='_';
574 for (p
= ext
, ip
= ext_start
; extlen
< 3 && ip
< end
; ip
++) {
575 if (utf8
&& (*ip
& 0x80)) {
578 } else if (!strchr(skip_chars
, *ip
)) {
579 if (*ip
>= 'a' && *ip
<= 'z') {
584 if (strchr(replace_chars
, *p
)) *p
='_';
591 base
[baselen
] = '\0';
593 /* Yes, it can happen. ".\xe5" would do it. */
597 /* OK, at this point we know that base is not longer than 8 symbols,
598 * ext is not longer than 3, base is nonempty, both don't contain
599 * any bad symbols (lowercase transformed to uppercase).
602 memset(name_res
, ' ', MSDOS_NAME
);
603 memcpy(name_res
,base
,baselen
);
604 memcpy(name_res
+8,ext
,extlen
);
605 if (MSDOS_SB(dir
->i_sb
)->options
.numtail
== 0)
606 if (vfat_find_form(dir
, name_res
) < 0)
610 * Try to find a unique extension. This used to
611 * iterate through all possibilities sequentially,
612 * but that gave extremely bad performance. Windows
613 * only tries a few cases before using random
614 * values for part of the base.
619 name_res
[baselen
] = '~';
620 for (i
= 1; i
< 10; i
++) {
621 name_res
[baselen
+1] = i
+ '0';
622 if (vfat_find_form(dir
, name_res
) < 0)
626 i
= jiffies
& 0xffff;
627 sz
= (jiffies
>> 16) & 0x7;
630 name_res
[baselen
+4] = '~';
631 name_res
[baselen
+5] = '1' + sz
;
633 sprintf(buf
, "%04X", i
);
634 memcpy(&name_res
[baselen
], buf
, 4);
635 if (vfat_find_form(dir
, name_res
) < 0)
642 /* Translate a string, including coded sequences into Unicode */
644 xlate_to_uni(const char *name
, int len
, char *outname
, int *outlen
,
645 int escape
, int utf8
, struct nls_table
*nls
)
648 const unsigned char *ip
;
651 unsigned char c1
, c2
, c3
;
654 *outlen
= utf8_mbstowcs((__u16
*) outname
, name
, PAGE_SIZE
);
655 if (name
[len
-1] == '.')
657 op
= &outname
[*outlen
* sizeof(__u16
)];
659 if (name
[len
-1] == '.')
663 for (i
= 0, ip
= name
, op
= outname
, *outlen
= 0;
664 i
< len
&& *outlen
<= 260; i
++, *outlen
+= 1)
666 if (escape
&& (*ip
== ':')) {
667 if (i
> len
- 4) return -EINVAL
;
668 c1
= fat_esc2uni
[ip
[1]];
669 c2
= fat_esc2uni
[ip
[2]];
670 c3
= fat_esc2uni
[ip
[3]];
671 if (c1
== 255 || c2
== 255 || c3
== 255)
673 *op
++ = (c1
<< 4) + (c2
>> 2);
674 *op
++ = ((c2
& 0x3) << 6) + c3
;
677 *op
++ = nls
->charset2uni
[*ip
].uni1
;
678 *op
++ = nls
->charset2uni
[*ip
].uni2
;
683 for (i
= 0, ip
= name
, op
= outname
, *outlen
= 0;
684 i
< len
&& *outlen
<= 260; i
++, *outlen
+= 1)
692 return -ENAMETOOLONG
;
699 fill
= 13 - (*outlen
% 13);
700 for (i
= 0; i
< fill
; i
++) {
712 vfat_fill_long_slots(struct msdos_dir_slot
*ds
, const char *name
, int len
,
713 char *msdos_name
, int *slots
,
714 int uni_xlate
, int utf8
, struct nls_table
*nls
)
716 struct msdos_dir_slot
*ps
;
717 struct msdos_dir_entry
*de
;
728 if (name
[len
-1] == '.') len
--;
729 if(!(page
= __get_free_page(GFP_KERNEL
)))
731 uniname
= (char *) page
;
732 res
= xlate_to_uni(name
, len
, uniname
, &unilen
, uni_xlate
, utf8
, nls
);
738 *slots
= unilen
/ 13;
739 for (cksum
= i
= 0; i
< 11; i
++) {
740 cksum
= (((cksum
&1)<<7)|((cksum
&0xfe)>>1)) + msdos_name
[i
];
742 PRINTK3(("vfat_fill_long_slots 3: slots=%d\n",*slots
));
744 for (ps
= ds
, slot
= *slots
; slot
> 0; slot
--, ps
++) {
748 ps
->alias_checksum
= cksum
;
750 offset
= (slot
- 1) * 26;
751 ip
= &uniname
[offset
];
752 memcpy(ps
->name0_4
, ip
, 10);
753 memcpy(ps
->name5_10
, ip
+10, 12);
754 memcpy(ps
->name11_12
, ip
+22, 4);
758 de
= (struct msdos_dir_entry
*) ps
;
759 PRINTK3(("vfat_fill_long_slots 9\n"));
760 strncpy(de
->name
, msdos_name
, MSDOS_NAME
);
767 /* We can't get "." or ".." here - VFS takes care of those cases */
769 static int vfat_build_slots(struct inode
*dir
,const char *name
,int len
,
770 struct msdos_dir_slot
*ds
, int *slots
)
772 struct msdos_dir_entry
*de
;
773 char msdos_name
[MSDOS_NAME
];
774 int res
, xlate
, utf8
;
775 struct nls_table
*nls
;
777 de
= (struct msdos_dir_entry
*) ds
;
778 xlate
= MSDOS_SB(dir
->i_sb
)->options
.unicode_xlate
;
779 utf8
= MSDOS_SB(dir
->i_sb
)->options
.utf8
;
780 nls
= MSDOS_SB(dir
->i_sb
)->nls_io
;
783 res
= vfat_valid_longname(name
, len
, xlate
);
786 if (vfat_valid_shortname(name
, len
, utf8
) >= 0) {
787 vfat_format_name(name
, len
, de
->name
, utf8
);
790 res
= vfat_create_shortname(dir
, name
, len
, msdos_name
, utf8
);
793 return vfat_fill_long_slots(ds
, name
, len
, msdos_name
, slots
, xlate
,
797 static int vfat_add_entry(struct inode
*dir
,struct qstr
* qname
,
798 int is_dir
,struct vfat_slot_info
*sinfo_out
,
799 struct buffer_head
**bh
, struct msdos_dir_entry
**de
)
801 struct super_block
*sb
= dir
->i_sb
;
802 struct msdos_dir_slot
*ps
;
804 struct msdos_dir_slot
*ds
;
807 struct msdos_dir_entry
*de1
;
808 struct buffer_head
*bh1
;
813 ds
= (struct msdos_dir_slot
*)
814 kmalloc(sizeof(struct msdos_dir_slot
)*MSDOS_SLOTS
, GFP_KERNEL
);
815 if (ds
== NULL
) return -ENOMEM
;
818 while (len
&& qname
->name
[len
-1] == '.')
820 res
= fat_search_long(dir
, qname
->name
, len
,
821 (MSDOS_SB(sb
)->options
.name_check
!= 's') ||
822 !MSDOS_SB(sb
)->options
.posixfs
,
824 if (res
> 0) /* found */
829 res
= vfat_build_slots(dir
, qname
->name
, len
, ds
, &slots
);
830 if (res
< 0) goto cleanup
;
832 offset
= fat_add_entries(dir
, slots
, &bh1
, &de1
, &ino
);
839 /* Now create the new entry */
841 for (slot
= 0, ps
= ds
; slot
< slots
; slot
++, ps
++) {
842 if (fat_get_entry(dir
,&offset
,bh
,de
, &sinfo_out
->ino
) < 0) {
846 memcpy(*de
, ps
, sizeof(struct msdos_dir_slot
));
847 fat_mark_buffer_dirty(sb
, *bh
, 1);
850 dir
->i_ctime
= dir
->i_mtime
= dir
->i_atime
= CURRENT_TIME
;
851 mark_inode_dirty(dir
);
853 fat_date_unix2dos(dir
->i_mtime
,&(*de
)->time
,&(*de
)->date
);
855 (*de
)->ctime
= (*de
)->time
;
856 (*de
)->adate
= (*de
)->cdate
= (*de
)->date
;
860 (*de
)->attr
= is_dir
? ATTR_DIR
: ATTR_ARCH
;
861 (*de
)->lcase
= CASE_LOWER_BASE
| CASE_LOWER_EXT
;
864 fat_mark_buffer_dirty(sb
, *bh
, 1);
866 /* slots can't be less than 1 */
867 sinfo_out
->long_slots
= slots
- 1;
868 sinfo_out
->longname_offset
= offset
- sizeof(struct msdos_dir_slot
) * slots
;
876 static int vfat_find(struct inode
*dir
,struct qstr
* qname
,
877 struct vfat_slot_info
*sinfo
, struct buffer_head
**last_bh
,
878 struct msdos_dir_entry
**last_de
)
880 struct super_block
*sb
= dir
->i_sb
;
885 while (len
&& qname
->name
[len
-1] == '.')
887 res
= fat_search_long(dir
, qname
->name
, len
,
888 (MSDOS_SB(sb
)->options
.name_check
!= 's'),
889 &offset
,&sinfo
->longname_offset
);
891 sinfo
->long_slots
= res
-1;
892 if (fat_get_entry(dir
,&offset
,last_bh
,last_de
,&sinfo
->ino
)>=0)
896 return res
? res
: -ENOENT
;
899 /* Find a hashed dentry for inode; NULL if there are none */
900 static struct dentry
*find_alias(struct inode
*inode
)
902 struct list_head
*head
, *next
, *tmp
;
903 struct dentry
*alias
;
905 head
= &inode
->i_dentry
;
906 next
= inode
->i_dentry
.next
;
907 while (next
!= head
) {
910 alias
= list_entry(tmp
, struct dentry
, d_alias
);
911 if (!list_empty(&alias
->d_hash
))
917 struct dentry
*vfat_lookup(struct inode
*dir
,struct dentry
*dentry
)
920 struct vfat_slot_info sinfo
;
922 struct dentry
*alias
;
923 struct buffer_head
*bh
= NULL
;
924 struct msdos_dir_entry
*de
;
927 PRINTK2(("vfat_lookup: name=%s, len=%d\n",
928 dentry
->d_name
.name
, dentry
->d_name
.len
));
930 table
= (MSDOS_SB(dir
->i_sb
)->options
.name_check
== 's') ? 2 : 0;
931 dentry
->d_op
= &vfat_dentry_ops
[table
];
934 res
= vfat_find(dir
,&dentry
->d_name
,&sinfo
,&bh
,&de
);
939 inode
= fat_build_inode(dir
->i_sb
, de
, sinfo
.ino
, &res
);
940 fat_brelse(dir
->i_sb
, bh
);
943 alias
= find_alias(inode
);
945 if (d_invalidate(alias
)==0)
954 dentry
->d_op
= &vfat_dentry_ops
[table
];
955 dentry
->d_time
= dentry
->d_parent
->d_inode
->i_version
;
960 int vfat_create(struct inode
*dir
,struct dentry
* dentry
,int mode
)
962 struct super_block
*sb
= dir
->i_sb
;
963 struct inode
*inode
= NULL
;
964 struct buffer_head
*bh
= NULL
;
965 struct msdos_dir_entry
*de
;
966 struct vfat_slot_info sinfo
;
969 res
= vfat_add_entry(dir
, &dentry
->d_name
, 0, &sinfo
, &bh
, &de
);
972 inode
= fat_build_inode(sb
, de
, sinfo
.ino
, &res
);
976 inode
->i_mtime
= inode
->i_atime
= inode
->i_ctime
= CURRENT_TIME
;
977 mark_inode_dirty(inode
);
978 inode
->i_version
= ++event
;
979 dir
->i_version
= event
;
980 dentry
->d_time
= dentry
->d_parent
->d_inode
->i_version
;
981 d_instantiate(dentry
,inode
);
985 static void vfat_remove_entry(struct inode
*dir
,struct vfat_slot_info
*sinfo
,
986 struct buffer_head
*bh
, struct msdos_dir_entry
*de
)
988 struct super_block
*sb
= dir
->i_sb
;
992 /* remove the shortname */
993 dir
->i_mtime
= CURRENT_TIME
;
994 dir
->i_atime
= CURRENT_TIME
;
995 dir
->i_version
= ++event
;
996 mark_inode_dirty(dir
);
997 de
->name
[0] = DELETED_FLAG
;
998 fat_mark_buffer_dirty(sb
, bh
, 1);
999 /* remove the longname */
1000 offset
= sinfo
->longname_offset
; de
= NULL
;
1001 for (i
= sinfo
->long_slots
; i
> 0; --i
) {
1002 if (fat_get_entry(dir
, &offset
, &bh
, &de
, &ino
) < 0)
1004 de
->name
[0] = DELETED_FLAG
;
1006 fat_mark_buffer_dirty(sb
, bh
, 1);
1008 if (bh
) fat_brelse(sb
, bh
);
1011 int vfat_rmdir(struct inode
*dir
,struct dentry
* dentry
)
1014 struct vfat_slot_info sinfo
;
1015 struct buffer_head
*bh
= NULL
;
1016 struct msdos_dir_entry
*de
;
1018 if (!list_empty(&dentry
->d_hash
))
1021 res
= fat_dir_empty(dentry
->d_inode
);
1025 res
= vfat_find(dir
,&dentry
->d_name
,&sinfo
, &bh
, &de
);
1028 dentry
->d_inode
->i_nlink
= 0;
1029 dentry
->d_inode
->i_mtime
= CURRENT_TIME
;
1030 dentry
->d_inode
->i_atime
= CURRENT_TIME
;
1031 fat_detach(dentry
->d_inode
);
1032 mark_inode_dirty(dentry
->d_inode
);
1034 vfat_remove_entry(dir
,&sinfo
,bh
,de
);
1039 int vfat_unlink(struct inode
*dir
, struct dentry
* dentry
)
1042 struct vfat_slot_info sinfo
;
1043 struct buffer_head
*bh
= NULL
;
1044 struct msdos_dir_entry
*de
;
1046 PRINTK1(("vfat_unlink: %s\n", dentry
->d_name
.name
));
1047 res
= vfat_find(dir
,&dentry
->d_name
,&sinfo
,&bh
,&de
);
1050 dentry
->d_inode
->i_nlink
= 0;
1051 dentry
->d_inode
->i_mtime
= CURRENT_TIME
;
1052 dentry
->d_inode
->i_atime
= CURRENT_TIME
;
1053 fat_detach(dentry
->d_inode
);
1054 mark_inode_dirty(dentry
->d_inode
);
1056 vfat_remove_entry(dir
,&sinfo
,bh
,de
);
1063 int vfat_mkdir(struct inode
*dir
,struct dentry
* dentry
,int mode
)
1065 struct super_block
*sb
= dir
->i_sb
;
1066 struct inode
*inode
= NULL
;
1067 struct vfat_slot_info sinfo
;
1068 struct buffer_head
*bh
= NULL
;
1069 struct msdos_dir_entry
*de
;
1072 res
= vfat_add_entry(dir
, &dentry
->d_name
, 1, &sinfo
, &bh
, &de
);
1075 inode
= fat_build_inode(sb
, de
, sinfo
.ino
, &res
);
1078 inode
->i_mtime
= inode
->i_atime
= inode
->i_ctime
= CURRENT_TIME
;
1079 mark_inode_dirty(inode
);
1080 inode
->i_version
= ++event
;
1081 dir
->i_version
= event
;
1083 inode
->i_nlink
= 2; /* no need to mark them dirty */
1084 res
= fat_new_dir(inode
, dir
, 1);
1087 dentry
->d_time
= dentry
->d_parent
->d_inode
->i_version
;
1088 d_instantiate(dentry
,inode
);
1095 inode
->i_mtime
= CURRENT_TIME
;
1096 inode
->i_atime
= CURRENT_TIME
;
1098 mark_inode_dirty(inode
);
1100 vfat_remove_entry(dir
,&sinfo
,bh
,de
);
1106 int vfat_rename(struct inode
*old_dir
,struct dentry
*old_dentry
,
1107 struct inode
*new_dir
,struct dentry
*new_dentry
)
1109 struct super_block
*sb
= old_dir
->i_sb
;
1110 struct buffer_head
*old_bh
,*new_bh
,*dotdot_bh
;
1111 struct msdos_dir_entry
*old_de
,*new_de
,*dotdot_de
;
1113 struct inode
*old_inode
, *new_inode
;
1115 struct vfat_slot_info old_sinfo
,sinfo
;
1117 old_bh
= new_bh
= dotdot_bh
= NULL
;
1118 old_inode
= old_dentry
->d_inode
;
1119 new_inode
= new_dentry
->d_inode
;
1120 res
= vfat_find(old_dir
,&old_dentry
->d_name
,&old_sinfo
,&old_bh
,&old_de
);
1121 PRINTK3(("vfat_rename 2\n"));
1122 if (res
< 0) goto rename_done
;
1124 is_dir
= S_ISDIR(old_inode
->i_mode
);
1126 if (is_dir
&& (res
= fat_scan(old_inode
,MSDOS_DOTDOT
,&dotdot_bh
,
1127 &dotdot_de
,&dotdot_ino
)) < 0)
1130 if (new_dentry
->d_inode
) {
1131 res
= vfat_find(new_dir
,&new_dentry
->d_name
,&sinfo
,&new_bh
,
1133 if (res
< 0 || MSDOS_I(new_inode
)->i_location
!= sinfo
.ino
) {
1134 /* WTF??? Cry and fail. */
1135 printk(KERN_WARNING
"vfat_rename: fs corrupted\n");
1140 res
= fat_dir_empty(new_inode
);
1144 fat_detach(new_inode
);
1146 res
= vfat_add_entry(new_dir
,&new_dentry
->d_name
,is_dir
,&sinfo
,
1148 if (res
< 0) goto rename_done
;
1151 new_dir
->i_version
= ++event
;
1153 /* releases old_bh */
1154 vfat_remove_entry(old_dir
,&old_sinfo
,old_bh
,old_de
);
1156 fat_detach(old_inode
);
1157 fat_attach(old_inode
, sinfo
.ino
);
1158 mark_inode_dirty(old_inode
);
1160 old_dir
->i_version
= ++event
;
1161 old_dir
->i_ctime
= old_dir
->i_mtime
= CURRENT_TIME
;
1162 mark_inode_dirty(old_dir
);
1164 new_inode
->i_nlink
--;
1165 new_inode
->i_ctime
=CURRENT_TIME
;
1169 int start
= MSDOS_I(new_dir
)->i_logstart
;
1170 dotdot_de
->start
= CT_LE_W(start
);
1171 dotdot_de
->starthi
= CT_LE_W(start
>>16);
1172 fat_mark_buffer_dirty(sb
, dotdot_bh
, 1);
1175 new_inode
->i_nlink
--;
1178 mark_inode_dirty(new_dir
);
1183 fat_brelse(sb
, dotdot_bh
);
1184 fat_brelse(sb
, old_bh
);
1185 fat_brelse(sb
, new_bh
);
1191 /* Public inode operations for the VFAT fs */
1192 struct inode_operations vfat_dir_inode_operations
= {
1193 &fat_dir_operations
, /* default directory file-ops */
1194 vfat_create
, /* create */
1195 vfat_lookup
, /* lookup */
1197 vfat_unlink
, /* unlink */
1199 vfat_mkdir
, /* mkdir */
1200 vfat_rmdir
, /* rmdir */
1202 vfat_rename
, /* rename */
1203 NULL
, /* readlink */
1204 NULL
, /* followlink */
1205 NULL
, /* get_block */
1206 NULL
, /* readpage */
1207 NULL
, /* writepage */
1208 NULL
, /* flushpage */
1209 NULL
, /* truncate */
1210 NULL
, /* permission */
1212 NULL
/* revalidate */
1215 struct super_block
*vfat_read_super(struct super_block
*sb
,void *data
,
1218 struct super_block
*res
;
1222 MSDOS_SB(sb
)->options
.isvfat
= 1;
1224 res
= fat_read_super(sb
, data
, silent
, &vfat_dir_inode_operations
);
1231 if (!parse_options((char *) data
, &(MSDOS_SB(sb
)->options
))) {
1234 MSDOS_SB(sb
)->put_super_callback
=vfat_put_super_callback
;
1235 MSDOS_SB(sb
)->options
.dotsOK
= 0;
1236 if (MSDOS_SB(sb
)->options
.posixfs
) {
1237 MSDOS_SB(sb
)->options
.name_check
= 's';
1239 if (MSDOS_SB(sb
)->options
.name_check
!= 's') {
1240 sb
->s_root
->d_op
= &vfat_dentry_ops
[0];
1242 sb
->s_root
->d_op
= &vfat_dentry_ops
[2];
1250 int init_module(void)
1252 return init_vfat_fs();
1255 void cleanup_module(void)
1257 unregister_filesystem(&vfat_fs_type
);
1260 #endif /* ifdef MODULE */