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.
12 * Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de>
14 * Support Multibyte character and cleanup by
15 * OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
18 #include <linux/module.h>
20 #include <linux/jiffies.h>
21 #include <linux/msdos_fs.h>
22 #include <linux/ctype.h>
23 #include <linux/slab.h>
24 #include <linux/smp_lock.h>
25 #include <linux/buffer_head.h>
26 #include <linux/namei.h>
28 static int vfat_hashi(struct dentry
*parent
, struct qstr
*qstr
);
29 static int vfat_hash(struct dentry
*parent
, struct qstr
*qstr
);
30 static int vfat_cmpi(struct dentry
*dentry
, struct qstr
*a
, struct qstr
*b
);
31 static int vfat_cmp(struct dentry
*dentry
, struct qstr
*a
, struct qstr
*b
);
32 static int vfat_revalidate(struct dentry
*dentry
, struct nameidata
*nd
);
34 static struct dentry_operations vfat_dentry_ops
[4] = {
37 .d_compare
= vfat_cmpi
,
40 .d_revalidate
= vfat_revalidate
,
42 .d_compare
= vfat_cmpi
,
46 .d_compare
= vfat_cmp
,
49 .d_revalidate
= vfat_revalidate
,
51 .d_compare
= vfat_cmp
,
55 static int vfat_revalidate(struct dentry
*dentry
, struct nameidata
*nd
)
59 if (!dentry
->d_inode
&&
60 nd
&& !(nd
->flags
& LOOKUP_CONTINUE
) && (nd
->flags
& LOOKUP_CREATE
))
62 * negative dentry is dropped, in order to make sure
63 * to use the name which a user desires if this is
68 spin_lock(&dentry
->d_lock
);
69 if (dentry
->d_time
!= dentry
->d_parent
->d_inode
->i_version
)
71 spin_unlock(&dentry
->d_lock
);
76 /* returns the length of a struct qstr, ignoring trailing dots */
77 static unsigned int vfat_striptail_len(struct qstr
*qstr
)
79 unsigned int len
= qstr
->len
;
81 while (len
&& qstr
->name
[len
-1] == '.')
88 * Compute the hash for the vfat name corresponding to the dentry.
89 * Note: if the name is invalid, we leave the hash code unchanged so
90 * that the existing dentry can be used. The vfat fs routines will
91 * return ENOENT or EINVAL as appropriate.
93 static int vfat_hash(struct dentry
*dentry
, struct qstr
*qstr
)
95 qstr
->hash
= full_name_hash(qstr
->name
, vfat_striptail_len(qstr
));
101 * Compute the hash for the vfat name corresponding to the dentry.
102 * Note: if the name is invalid, we leave the hash code unchanged so
103 * that the existing dentry can be used. The vfat fs routines will
104 * return ENOENT or EINVAL as appropriate.
106 static int vfat_hashi(struct dentry
*dentry
, struct qstr
*qstr
)
108 struct nls_table
*t
= MSDOS_SB(dentry
->d_inode
->i_sb
)->nls_io
;
109 const unsigned char *name
;
114 len
= vfat_striptail_len(qstr
);
116 hash
= init_name_hash();
118 hash
= partial_name_hash(nls_tolower(t
, *name
++), hash
);
119 qstr
->hash
= end_name_hash(hash
);
125 * Case insensitive compare of two vfat names.
127 static int vfat_cmpi(struct dentry
*dentry
, struct qstr
*a
, struct qstr
*b
)
129 struct nls_table
*t
= MSDOS_SB(dentry
->d_inode
->i_sb
)->nls_io
;
130 unsigned int alen
, blen
;
132 /* A filename cannot end in '.' or we treat it like it has none */
133 alen
= vfat_striptail_len(a
);
134 blen
= vfat_striptail_len(b
);
136 if (nls_strnicmp(t
, a
->name
, b
->name
, alen
) == 0)
143 * Case sensitive compare of two vfat names.
145 static int vfat_cmp(struct dentry
*dentry
, struct qstr
*a
, struct qstr
*b
)
147 unsigned int alen
, blen
;
149 /* A filename cannot end in '.' or we treat it like it has none */
150 alen
= vfat_striptail_len(a
);
151 blen
= vfat_striptail_len(b
);
153 if (strncmp(a
->name
, b
->name
, alen
) == 0)
159 /* Characters that are undesirable in an MS-DOS file name */
161 static wchar_t bad_chars
[] = {
162 /* `*' `?' `<' `>' `|' `"' `:' `/' */
163 0x002A, 0x003F, 0x003C, 0x003E, 0x007C, 0x0022, 0x003A, 0x002F,
167 #define IS_BADCHAR(uni) (vfat_unistrchr(bad_chars, (uni)) != NULL)
169 static wchar_t replace_chars
[] = {
170 /* `[' `]' `;' `,' `+' `=' */
171 0x005B, 0x005D, 0x003B, 0x002C, 0x002B, 0x003D, 0,
173 #define IS_REPLACECHAR(uni) (vfat_unistrchr(replace_chars, (uni)) != NULL)
175 static wchar_t skip_chars
[] = {
179 #define IS_SKIPCHAR(uni) \
180 ((wchar_t)(uni) == skip_chars[0] || (wchar_t)(uni) == skip_chars[1])
182 static inline wchar_t *vfat_unistrchr(const wchar_t *s
, const wchar_t c
)
187 return (wchar_t *) s
;
190 static inline int vfat_is_used_badchars(const wchar_t *s
, int len
)
194 for (i
= 0; i
< len
; i
++)
195 if (s
[i
] < 0x0020 || IS_BADCHAR(s
[i
]))
200 static int vfat_valid_longname(const unsigned char *name
, unsigned int len
)
202 if (len
&& name
[len
-1] == ' ')
207 /* MS-DOS "device special files" */
208 if (len
== 3 || (len
> 3 && name
[3] == '.')) { /* basename == 3 */
209 if (!strnicmp(name
, "aux", 3) ||
210 !strnicmp(name
, "con", 3) ||
211 !strnicmp(name
, "nul", 3) ||
212 !strnicmp(name
, "prn", 3))
215 if (len
== 4 || (len
> 4 && name
[4] == '.')) { /* basename == 4 */
216 /* "com1", "com2", ... */
217 if ('1' <= name
[3] && name
[3] <= '9') {
218 if (!strnicmp(name
, "com", 3) ||
219 !strnicmp(name
, "lpt", 3))
227 static int vfat_find_form(struct inode
*dir
, unsigned char *name
)
229 struct msdos_dir_entry
*de
;
230 struct buffer_head
*bh
= NULL
;
234 res
= fat_scan(dir
, name
, &bh
, &de
, &i_pos
);
242 * 1) Valid characters for the 8.3 format alias are any combination of
243 * letters, uppercase alphabets, digits, any of the
244 * following special characters:
245 * $ % ' ` - @ { } ~ ! # ( ) & _ ^
246 * In this case Longfilename is not stored in disk.
249 * File name and extension name is contain uppercase/lowercase
250 * only. And it is expressed by CASE_LOWER_BASE and CASE_LOWER_EXT.
252 * 2) File name is 8.3 format, but it contain the uppercase and
253 * lowercase char, muliti bytes char, etc. In this case numtail is not
254 * added, but Longfilename is stored.
256 * 3) When the one except for the above, or the following special
257 * character are contained:
259 * numtail is added, and Longfilename must be stored in disk .
261 struct shortname_info
{
262 unsigned char lower
:1,
266 #define INIT_SHORTNAME_INFO(x) do { \
272 static inline unsigned char
273 shortname_info_to_lcase(struct shortname_info
*base
,
274 struct shortname_info
*ext
)
276 unsigned char lcase
= 0;
278 if (base
->valid
&& ext
->valid
) {
279 if (!base
->upper
&& base
->lower
&& (ext
->lower
|| ext
->upper
))
280 lcase
|= CASE_LOWER_BASE
;
281 if (!ext
->upper
&& ext
->lower
&& (base
->lower
|| base
->upper
))
282 lcase
|= CASE_LOWER_EXT
;
288 static inline int to_shortname_char(struct nls_table
*nls
,
289 unsigned char *buf
, int buf_size
, wchar_t *src
,
290 struct shortname_info
*info
)
294 if (IS_SKIPCHAR(*src
)) {
298 if (IS_REPLACECHAR(*src
)) {
304 len
= nls
->uni2char(*src
, buf
, buf_size
);
309 } else if (len
== 1) {
310 unsigned char prev
= buf
[0];
312 if (buf
[0] >= 0x7F) {
317 buf
[0] = nls_toupper(nls
, buf
[0]);
318 if (isalpha(buf
[0])) {
333 * Given a valid longname, create a unique shortname. Make sure the
334 * shortname does not exist
335 * Returns negative number on error, 0 for a normal
336 * return, and 1 for valid shortname
338 static int vfat_create_shortname(struct inode
*dir
, struct nls_table
*nls
,
339 wchar_t *uname
, int ulen
,
340 unsigned char *name_res
, unsigned char *lcase
)
342 wchar_t *ip
, *ext_start
, *end
, *name_start
;
343 unsigned char base
[9], ext
[4], buf
[8], *p
;
344 unsigned char charbuf
[NLS_MAX_CHARSET_SIZE
];
346 int sz
= 0, extlen
, baselen
, i
, numtail_baselen
, numtail2_baselen
;
348 struct shortname_info base_info
, ext_info
;
349 unsigned short opt_shortname
= MSDOS_SB(dir
->i_sb
)->options
.shortname
;
352 INIT_SHORTNAME_INFO(&base_info
);
353 INIT_SHORTNAME_INFO(&ext_info
);
355 /* Now, we need to create a shortname from the long name */
356 ext_start
= end
= &uname
[ulen
];
357 while (--ext_start
>= uname
) {
358 if (*ext_start
== 0x002E) { /* is `.' */
359 if (ext_start
== end
- 1) {
367 if (ext_start
== uname
- 1) {
370 } else if (ext_start
) {
372 * Names which start with a dot could be just
373 * an extension eg. "...test". In this case Win95
374 * uses the extension as the name and sets no extension.
376 name_start
= &uname
[0];
377 while (name_start
< ext_start
) {
378 if (!IS_SKIPCHAR(*name_start
))
382 if (name_start
!= ext_start
) {
383 sz
= ext_start
- uname
;
392 numtail2_baselen
= 2;
393 for (baselen
= i
= 0, p
= base
, ip
= uname
; i
< sz
; i
++, ip
++) {
394 chl
= to_shortname_char(nls
, charbuf
, sizeof(charbuf
),
399 if (baselen
< 2 && (baselen
+ chl
) > 2)
400 numtail2_baselen
= baselen
;
401 if (baselen
< 6 && (baselen
+ chl
) > 6)
402 numtail_baselen
= baselen
;
403 for (chi
= 0; chi
< chl
; chi
++){
410 if ((chi
< chl
- 1) || (ip
+ 1) - uname
< sz
)
421 for (p
= ext
, ip
= ext_start
; extlen
< 3 && ip
< end
; ip
++) {
422 chl
= to_shortname_char(nls
, charbuf
, sizeof(charbuf
),
427 if ((extlen
+ chl
) > 3) {
431 for (chi
= 0; chi
< chl
; chi
++) {
443 base
[baselen
] = '\0';
445 /* Yes, it can happen. ".\xe5" would do it. */
446 if (base
[0] == DELETED_FLAG
)
449 /* OK, at this point we know that base is not longer than 8 symbols,
450 * ext is not longer than 3, base is nonempty, both don't contain
451 * any bad symbols (lowercase transformed to uppercase).
454 memset(name_res
, ' ', MSDOS_NAME
);
455 memcpy(name_res
, base
, baselen
);
456 memcpy(name_res
+ 8, ext
, extlen
);
458 if (is_shortname
&& base_info
.valid
&& ext_info
.valid
) {
459 if (vfat_find_form(dir
, name_res
) == 0)
462 if (opt_shortname
& VFAT_SFN_CREATE_WIN95
) {
463 return (base_info
.upper
&& ext_info
.upper
);
464 } else if (opt_shortname
& VFAT_SFN_CREATE_WINNT
) {
465 if ((base_info
.upper
|| base_info
.lower
)
466 && (ext_info
.upper
|| ext_info
.lower
)) {
467 *lcase
= shortname_info_to_lcase(&base_info
,
477 if (MSDOS_SB(dir
->i_sb
)->options
.numtail
== 0)
478 if (vfat_find_form(dir
, name_res
) < 0)
482 * Try to find a unique extension. This used to
483 * iterate through all possibilities sequentially,
484 * but that gave extremely bad performance. Windows
485 * only tries a few cases before using random
486 * values for part of the base.
490 baselen
= numtail_baselen
;
493 name_res
[baselen
] = '~';
494 for (i
= 1; i
< 10; i
++) {
495 name_res
[baselen
+1] = i
+ '0';
496 if (vfat_find_form(dir
, name_res
) < 0)
500 i
= jiffies
& 0xffff;
501 sz
= (jiffies
>> 16) & 0x7;
503 baselen
= numtail2_baselen
;
506 name_res
[baselen
+4] = '~';
507 name_res
[baselen
+5] = '1' + sz
;
509 sprintf(buf
, "%04X", i
);
510 memcpy(&name_res
[baselen
], buf
, 4);
511 if (vfat_find_form(dir
, name_res
) < 0)
518 /* Translate a string, including coded sequences into Unicode */
520 xlate_to_uni(const unsigned char *name
, int len
, unsigned char *outname
,
521 int *longlen
, int *outlen
, int escape
, int utf8
,
522 struct nls_table
*nls
)
524 const unsigned char *ip
;
532 int name_len
= strlen(name
);
534 *outlen
= utf8_mbstowcs((wchar_t *)outname
, name
, PAGE_SIZE
);
537 * We stripped '.'s before and set len appropriately,
538 * but utf8_mbstowcs doesn't care about len
540 *outlen
-= (name_len
-len
);
542 op
= &outname
[*outlen
* sizeof(wchar_t)];
545 for (i
= 0, ip
= name
, op
= outname
, *outlen
= 0;
546 i
< len
&& *outlen
<= 260; *outlen
+= 1)
548 if (escape
&& (*ip
== ':')) {
552 for (k
= 1; k
< 5; k
++) {
555 if (nc
>= '0' && nc
<= '9') {
559 if (nc
>= 'a' && nc
<= 'f') {
560 ec
|= nc
- ('a' - 10);
563 if (nc
>= 'A' && nc
<= 'F') {
564 ec
|= nc
- ('A' - 10);
574 if ((charlen
= nls
->char2uni(ip
, len
-i
, (wchar_t *)op
)) < 0)
582 for (i
= 0, ip
= name
, op
= outname
, *outlen
= 0;
583 i
< len
&& *outlen
<= 260; i
++, *outlen
+= 1)
591 return -ENAMETOOLONG
;
599 fill
= 13 - (*outlen
% 13);
600 for (i
= 0; i
< fill
; i
++) {
611 static int vfat_build_slots(struct inode
*dir
, const unsigned char *name
,
612 int len
, struct msdos_dir_slot
*ds
,
613 int *slots
, int is_dir
)
615 struct msdos_sb_info
*sbi
= MSDOS_SB(dir
->i_sb
);
616 struct fat_mount_options
*opts
= &sbi
->options
;
617 struct msdos_dir_slot
*ps
;
618 struct msdos_dir_entry
*de
;
620 unsigned char cksum
, lcase
;
621 unsigned char msdos_name
[MSDOS_NAME
];
623 int res
, slot
, ulen
, usize
, i
;
627 if (!vfat_valid_longname(name
, len
))
630 if(!(page
= __get_free_page(GFP_KERNEL
)))
633 uname
= (wchar_t *)page
;
634 res
= xlate_to_uni(name
, len
, (unsigned char *)uname
, &ulen
, &usize
,
635 opts
->unicode_xlate
, opts
->utf8
, sbi
->nls_io
);
639 res
= vfat_is_used_badchars(uname
, ulen
);
643 res
= vfat_create_shortname(dir
, sbi
->nls_disk
, uname
, ulen
,
648 de
= (struct msdos_dir_entry
*)ds
;
653 /* build the entry of long file name */
655 for (cksum
= i
= 0; i
< 11; i
++) {
656 cksum
= (((cksum
&1)<<7)|((cksum
&0xfe)>>1)) + msdos_name
[i
];
659 for (ps
= ds
, slot
= *slots
; slot
> 0; slot
--, ps
++) {
663 ps
->alias_checksum
= cksum
;
665 offset
= (slot
- 1) * 13;
666 fatwchar_to16(ps
->name0_4
, uname
+ offset
, 5);
667 fatwchar_to16(ps
->name5_10
, uname
+ offset
+ 5, 6);
668 fatwchar_to16(ps
->name11_12
, uname
+ offset
+ 11, 2);
671 de
= (struct msdos_dir_entry
*) ps
;
674 /* build the entry of 8.3 alias name */
676 memcpy(de
->name
, msdos_name
, MSDOS_NAME
);
677 de
->attr
= is_dir
? ATTR_DIR
: ATTR_ARCH
;
679 de
->adate
= de
->cdate
= de
->date
= 0;
680 de
->ctime
= de
->time
= 0;
691 static int vfat_add_entry(struct inode
*dir
,struct qstr
* qname
,
692 int is_dir
, struct vfat_slot_info
*sinfo_out
,
693 struct buffer_head
**bh
, struct msdos_dir_entry
**de
)
695 struct msdos_dir_slot
*dir_slots
;
697 int res
, slots
, slot
;
699 struct msdos_dir_entry
*dummy_de
;
700 struct buffer_head
*dummy_bh
;
703 len
= vfat_striptail_len(qname
);
708 kmalloc(sizeof(struct msdos_dir_slot
) * MSDOS_SLOTS
, GFP_KERNEL
);
709 if (dir_slots
== NULL
)
712 res
= vfat_build_slots(dir
, qname
->name
, len
,
713 dir_slots
, &slots
, is_dir
);
717 /* build the empty directory entry of number of slots */
718 offset
= fat_add_entries(dir
, slots
, &dummy_bh
, &dummy_de
, &dummy_i_pos
);
725 /* Now create the new entry */
727 for (slot
= 0; slot
< slots
; slot
++) {
728 if (fat_get_entry(dir
, &offset
, bh
, de
, &sinfo_out
->i_pos
) < 0) {
732 memcpy(*de
, dir_slots
+ slot
, sizeof(struct msdos_dir_slot
));
733 mark_buffer_dirty(*bh
);
737 /* update timestamp */
738 dir
->i_ctime
= dir
->i_mtime
= dir
->i_atime
= CURRENT_TIME
;
739 mark_inode_dirty(dir
);
741 fat_date_unix2dos(dir
->i_mtime
.tv_sec
, &(*de
)->time
, &(*de
)->date
);
742 (*de
)->ctime
= (*de
)->time
;
743 (*de
)->adate
= (*de
)->cdate
= (*de
)->date
;
745 mark_buffer_dirty(*bh
);
747 /* slots can't be less than 1 */
748 sinfo_out
->long_slots
= slots
- 1;
749 sinfo_out
->longname_offset
=
750 offset
- sizeof(struct msdos_dir_slot
) * slots
;
757 static int vfat_find(struct inode
*dir
,struct qstr
* qname
,
758 struct vfat_slot_info
*sinfo
, struct buffer_head
**last_bh
,
759 struct msdos_dir_entry
**last_de
)
761 struct super_block
*sb
= dir
->i_sb
;
766 len
= vfat_striptail_len(qname
);
770 res
= fat_search_long(dir
, qname
->name
, len
,
771 (MSDOS_SB(sb
)->options
.name_check
!= 's'),
772 &offset
, &sinfo
->longname_offset
);
774 sinfo
->long_slots
= res
-1;
775 if (fat_get_entry(dir
,&offset
,last_bh
,last_de
,&sinfo
->i_pos
)>=0)
779 return res
? res
: -ENOENT
;
782 static struct dentry
*vfat_lookup(struct inode
*dir
, struct dentry
*dentry
,
783 struct nameidata
*nd
)
786 struct vfat_slot_info sinfo
;
788 struct dentry
*alias
;
789 struct buffer_head
*bh
= NULL
;
790 struct msdos_dir_entry
*de
;
794 table
= (MSDOS_SB(dir
->i_sb
)->options
.name_check
== 's') ? 2 : 0;
795 dentry
->d_op
= &vfat_dentry_ops
[table
];
798 res
= vfat_find(dir
,&dentry
->d_name
,&sinfo
,&bh
,&de
);
803 inode
= fat_build_inode(dir
->i_sb
, de
, sinfo
.i_pos
, &res
);
809 alias
= d_find_alias(inode
);
811 if (d_invalidate(alias
)==0)
822 dentry
->d_op
= &vfat_dentry_ops
[table
];
823 dentry
->d_time
= dentry
->d_parent
->d_inode
->i_version
;
824 dentry
= d_splice_alias(inode
, dentry
);
826 dentry
->d_op
= &vfat_dentry_ops
[table
];
827 dentry
->d_time
= dentry
->d_parent
->d_inode
->i_version
;
832 static int vfat_create(struct inode
*dir
, struct dentry
* dentry
, int mode
,
833 struct nameidata
*nd
)
835 struct super_block
*sb
= dir
->i_sb
;
836 struct inode
*inode
= NULL
;
837 struct buffer_head
*bh
= NULL
;
838 struct msdos_dir_entry
*de
;
839 struct vfat_slot_info sinfo
;
843 res
= vfat_add_entry(dir
, &dentry
->d_name
, 0, &sinfo
, &bh
, &de
);
846 inode
= fat_build_inode(sb
, de
, sinfo
.i_pos
, &res
);
851 inode
->i_mtime
= inode
->i_atime
= inode
->i_ctime
= CURRENT_TIME
;
852 mark_inode_dirty(inode
);
855 dentry
->d_time
= dentry
->d_parent
->d_inode
->i_version
;
856 d_instantiate(dentry
,inode
);
862 static void vfat_remove_entry(struct inode
*dir
,struct vfat_slot_info
*sinfo
,
863 struct buffer_head
*bh
, struct msdos_dir_entry
*de
)
865 loff_t offset
, i_pos
;
868 /* remove the shortname */
869 dir
->i_mtime
= dir
->i_atime
= CURRENT_TIME
;
871 mark_inode_dirty(dir
);
872 de
->name
[0] = DELETED_FLAG
;
873 mark_buffer_dirty(bh
);
874 /* remove the longname */
875 offset
= sinfo
->longname_offset
; de
= NULL
;
876 for (i
= sinfo
->long_slots
; i
> 0; --i
) {
877 if (fat_get_entry(dir
, &offset
, &bh
, &de
, &i_pos
) < 0)
879 de
->name
[0] = DELETED_FLAG
;
880 de
->attr
= ATTR_NONE
;
881 mark_buffer_dirty(bh
);
886 static int vfat_rmdir(struct inode
*dir
, struct dentry
* dentry
)
889 struct vfat_slot_info sinfo
;
890 struct buffer_head
*bh
= NULL
;
891 struct msdos_dir_entry
*de
;
894 res
= fat_dir_empty(dentry
->d_inode
);
898 res
= vfat_find(dir
,&dentry
->d_name
,&sinfo
, &bh
, &de
);
902 dentry
->d_inode
->i_nlink
= 0;
903 dentry
->d_inode
->i_mtime
= dentry
->d_inode
->i_atime
= CURRENT_TIME
;
904 fat_detach(dentry
->d_inode
);
905 mark_inode_dirty(dentry
->d_inode
);
907 vfat_remove_entry(dir
,&sinfo
,bh
,de
);
914 static int vfat_unlink(struct inode
*dir
, struct dentry
*dentry
)
917 struct vfat_slot_info sinfo
;
918 struct buffer_head
*bh
= NULL
;
919 struct msdos_dir_entry
*de
;
922 res
= vfat_find(dir
,&dentry
->d_name
,&sinfo
,&bh
,&de
);
925 dentry
->d_inode
->i_nlink
= 0;
926 dentry
->d_inode
->i_mtime
= dentry
->d_inode
->i_atime
= CURRENT_TIME
;
927 fat_detach(dentry
->d_inode
);
928 mark_inode_dirty(dentry
->d_inode
);
930 vfat_remove_entry(dir
,&sinfo
,bh
,de
);
937 static int vfat_mkdir(struct inode
*dir
,struct dentry
* dentry
,int mode
)
939 struct super_block
*sb
= dir
->i_sb
;
940 struct inode
*inode
= NULL
;
941 struct vfat_slot_info sinfo
;
942 struct buffer_head
*bh
= NULL
;
943 struct msdos_dir_entry
*de
;
947 res
= vfat_add_entry(dir
, &dentry
->d_name
, 1, &sinfo
, &bh
, &de
);
950 inode
= fat_build_inode(sb
, de
, sinfo
.i_pos
, &res
);
953 inode
->i_mtime
= inode
->i_atime
= inode
->i_ctime
= CURRENT_TIME
;
954 mark_inode_dirty(inode
);
958 inode
->i_nlink
= 2; /* no need to mark them dirty */
959 res
= fat_new_dir(inode
, dir
, 1);
962 dentry
->d_time
= dentry
->d_parent
->d_inode
->i_version
;
963 d_instantiate(dentry
,inode
);
972 inode
->i_mtime
= inode
->i_atime
= CURRENT_TIME
;
974 mark_inode_dirty(inode
);
976 vfat_remove_entry(dir
,&sinfo
,bh
,de
);
982 static int vfat_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
983 struct inode
*new_dir
, struct dentry
*new_dentry
)
985 struct buffer_head
*old_bh
,*new_bh
,*dotdot_bh
;
986 struct msdos_dir_entry
*old_de
,*new_de
,*dotdot_de
;
988 struct inode
*old_inode
, *new_inode
;
990 struct vfat_slot_info old_sinfo
,sinfo
;
992 old_bh
= new_bh
= dotdot_bh
= NULL
;
993 old_inode
= old_dentry
->d_inode
;
994 new_inode
= new_dentry
->d_inode
;
996 res
= vfat_find(old_dir
,&old_dentry
->d_name
,&old_sinfo
,&old_bh
,&old_de
);
1000 is_dir
= S_ISDIR(old_inode
->i_mode
);
1003 if (fat_scan(old_inode
, MSDOS_DOTDOT
, &dotdot_bh
,
1004 &dotdot_de
, &dotdot_i_pos
) < 0) {
1010 if (new_dentry
->d_inode
) {
1011 res
= vfat_find(new_dir
,&new_dentry
->d_name
,&sinfo
,&new_bh
,
1013 if (res
< 0 || MSDOS_I(new_inode
)->i_pos
!= sinfo
.i_pos
) {
1014 /* WTF??? Cry and fail. */
1015 printk(KERN_WARNING
"vfat_rename: fs corrupted\n");
1020 res
= fat_dir_empty(new_inode
);
1024 fat_detach(new_inode
);
1026 res
= vfat_add_entry(new_dir
,&new_dentry
->d_name
,is_dir
,&sinfo
,
1028 if (res
< 0) goto rename_done
;
1031 new_dir
->i_version
++;
1033 /* releases old_bh */
1034 vfat_remove_entry(old_dir
,&old_sinfo
,old_bh
,old_de
);
1036 fat_detach(old_inode
);
1037 fat_attach(old_inode
, sinfo
.i_pos
);
1038 mark_inode_dirty(old_inode
);
1040 old_dir
->i_version
++;
1041 old_dir
->i_ctime
= old_dir
->i_mtime
= CURRENT_TIME
;
1042 mark_inode_dirty(old_dir
);
1044 new_inode
->i_nlink
--;
1045 new_inode
->i_ctime
=CURRENT_TIME
;
1049 int start
= MSDOS_I(new_dir
)->i_logstart
;
1050 dotdot_de
->start
= cpu_to_le16(start
);
1051 dotdot_de
->starthi
= cpu_to_le16(start
>>16);
1052 mark_buffer_dirty(dotdot_bh
);
1055 new_inode
->i_nlink
--;
1058 mark_inode_dirty(new_dir
);
1071 static struct inode_operations vfat_dir_inode_operations
= {
1072 .create
= vfat_create
,
1073 .lookup
= vfat_lookup
,
1074 .unlink
= vfat_unlink
,
1075 .mkdir
= vfat_mkdir
,
1076 .rmdir
= vfat_rmdir
,
1077 .rename
= vfat_rename
,
1078 .setattr
= fat_notify_change
,
1081 static int vfat_fill_super(struct super_block
*sb
, void *data
, int silent
)
1085 res
= fat_fill_super(sb
, data
, silent
, &vfat_dir_inode_operations
, 1);
1089 if (MSDOS_SB(sb
)->options
.name_check
!= 's')
1090 sb
->s_root
->d_op
= &vfat_dentry_ops
[0];
1092 sb
->s_root
->d_op
= &vfat_dentry_ops
[2];
1097 static struct super_block
*vfat_get_sb(struct file_system_type
*fs_type
,
1098 int flags
, const char *dev_name
, void *data
)
1100 return get_sb_bdev(fs_type
, flags
, dev_name
, data
, vfat_fill_super
);
1103 static struct file_system_type vfat_fs_type
= {
1104 .owner
= THIS_MODULE
,
1106 .get_sb
= vfat_get_sb
,
1107 .kill_sb
= kill_block_super
,
1108 .fs_flags
= FS_REQUIRES_DEV
,
1111 static int __init
init_vfat_fs(void)
1113 return register_filesystem(&vfat_fs_type
);
1116 static void __exit
exit_vfat_fs(void)
1118 unregister_filesystem(&vfat_fs_type
);
1121 MODULE_LICENSE("GPL");
1122 MODULE_DESCRIPTION("VFAT filesystem support");
1123 MODULE_AUTHOR("Gordon Chaffee");
1125 module_init(init_vfat_fs
)
1126 module_exit(exit_vfat_fs
)