4 * directory handling functions for fat-based filesystems
6 * Written 1992,1993 by Werner Almesberger
8 * Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
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>
16 #include <linux/slab.h>
17 #include <linux/time.h>
18 #include <linux/msdos_fs.h>
19 #include <linux/dirent.h>
20 #include <linux/smp_lock.h>
21 #include <linux/buffer_head.h>
23 #include <asm/uaccess.h>
25 struct file_operations fat_dir_operations
= {
26 .read
= generic_read_dir
,
27 .readdir
= fat_readdir
,
28 .ioctl
= fat_dir_ioctl
,
33 * Convert Unicode 16 to UTF8, translated Unicode, or ASCII.
34 * If uni_xlate is enabled and we can't get a 1:1 conversion, use a
35 * colon as an escape character since it is normally invalid on the vfat
36 * filesystem. The following four characters are the hexadecimal digits
37 * of Unicode value. This lets us do a full dump and restore of Unicode
38 * filenames. We could get into some trouble with long Unicode names,
39 * but ignore that right now.
40 * Ahem... Stack smashing in ring 0 isn't fun. Fixed.
43 uni16_to_x8(unsigned char *ascii
, wchar_t *uni
, int uni_xlate
,
44 struct nls_table
*nls
)
47 unsigned char *op
, nc
;
56 if ( (charlen
= nls
->uni2char(ec
, op
, NLS_MAX_CHARSET_SIZE
)) > 0) {
61 for (k
= 4; k
> 0; k
--) {
63 op
[k
] = nc
> 9 ? nc
+ ('a' - 10)
72 /* We have some slack there, so it's OK */
83 static void dump_de(struct msdos_dir_entry
*de
)
86 unsigned char *p
= (unsigned char *) de
;
89 for (i
= 0; i
< 32; i
++, p
++) {
97 fat_short2uni(struct nls_table
*t
, unsigned char *c
, int clen
, wchar_t *uni
)
101 charlen
= t
->char2uni(c
, clen
, uni
);
103 *uni
= 0x003f; /* a question mark */
110 fat_short2lower_uni(struct nls_table
*t
, unsigned char *c
, int clen
, wchar_t *uni
)
115 charlen
= t
->char2uni(c
, clen
, &wc
);
117 *uni
= 0x003f; /* a question mark */
119 } else if (charlen
<= 1) {
120 unsigned char nc
= t
->charset2lower
[*c
];
125 if ( (charlen
= t
->char2uni(&nc
, 1, uni
)) < 0) {
126 *uni
= 0x003f; /* a question mark */
136 fat_shortname2uni(struct nls_table
*nls
, unsigned char *buf
, int buf_size
,
137 wchar_t *uni_buf
, unsigned short opt
, int lower
)
141 if (opt
& VFAT_SFN_DISPLAY_LOWER
)
142 len
= fat_short2lower_uni(nls
, buf
, buf_size
, uni_buf
);
143 else if (opt
& VFAT_SFN_DISPLAY_WIN95
)
144 len
= fat_short2uni(nls
, buf
, buf_size
, uni_buf
);
145 else if (opt
& VFAT_SFN_DISPLAY_WINNT
) {
147 len
= fat_short2lower_uni(nls
, buf
, buf_size
, uni_buf
);
149 len
= fat_short2uni(nls
, buf
, buf_size
, uni_buf
);
151 len
= fat_short2uni(nls
, buf
, buf_size
, uni_buf
);
157 * Return values: negative -> error, 0 -> not found, positive -> found,
158 * value is the total amount of slots, including the shortname entry.
160 int fat_search_long(struct inode
*inode
, const unsigned char *name
,
161 int name_len
, int anycase
, loff_t
*spos
, loff_t
*lpos
)
163 struct super_block
*sb
= inode
->i_sb
;
164 struct buffer_head
*bh
= NULL
;
165 struct msdos_dir_entry
*de
;
166 struct nls_table
*nls_io
= MSDOS_SB(sb
)->nls_io
;
167 struct nls_table
*nls_disk
= MSDOS_SB(sb
)->nls_disk
;
168 wchar_t bufuname
[14];
169 unsigned char xlate_len
, long_slots
;
170 wchar_t *unicode
= NULL
;
171 unsigned char work
[8], bufname
[260]; /* 256 + 4 */
172 int uni_xlate
= MSDOS_SB(sb
)->options
.unicode_xlate
;
173 int utf8
= MSDOS_SB(sb
)->options
.utf8
;
174 unsigned short opt_shortname
= MSDOS_SB(sb
)->options
.shortname
;
175 int chl
, i
, j
, last_u
, res
= 0;
176 loff_t i_pos
, cpos
= 0;
179 if (fat_get_entry(inode
,&cpos
,&bh
,&de
,&i_pos
) == -1)
183 if (de
->name
[0] == DELETED_FLAG
)
185 if (de
->attr
!= ATTR_EXT
&& (de
->attr
& ATTR_VOLUME
))
187 if (de
->attr
!= ATTR_EXT
&& IS_FREE(de
->name
))
189 if (de
->attr
== ATTR_EXT
) {
190 struct msdos_dir_slot
*ds
;
195 unsigned char alias_checksum
;
198 unicode
= (wchar_t *)
199 __get_free_page(GFP_KERNEL
);
207 ds
= (struct msdos_dir_slot
*) de
;
212 if (slots
> 20 || !slots
) /* ceil(256 * 2 / 26) */
215 alias_checksum
= ds
->alias_checksum
;
223 fat16_towchar(unicode
+ offset
, ds
->name0_4
, 5);
224 fat16_towchar(unicode
+ offset
+ 5, ds
->name5_10
, 6);
225 fat16_towchar(unicode
+ offset
+ 11, ds
->name11_12
, 2);
228 unicode
[offset
+ 13] = 0;
230 if (fat_get_entry(inode
,&cpos
,&bh
,&de
,&i_pos
)<0)
234 ds
= (struct msdos_dir_slot
*) de
;
235 if (ds
->attr
!= ATTR_EXT
)
237 if ((ds
->id
& ~0x40) != slot
)
239 if (ds
->alias_checksum
!= alias_checksum
)
242 if (de
->name
[0] == DELETED_FLAG
)
244 if (de
->attr
== ATTR_EXT
)
246 if (IS_FREE(de
->name
) || (de
->attr
& ATTR_VOLUME
))
248 for (sum
= 0, i
= 0; i
< 11; i
++)
249 sum
= (((sum
&1)<<7)|((sum
&0xfe)>>1)) + de
->name
[i
];
250 if (sum
!= alias_checksum
)
254 memcpy(work
, de
->name
, sizeof(de
->name
));
255 /* see namei.c, msdos_format_name */
258 for (i
= 0, j
= 0, last_u
= 0; i
< 8;) {
260 chl
= fat_shortname2uni(nls_disk
, &work
[i
], 8 - i
,
261 &bufuname
[j
++], opt_shortname
,
262 de
->lcase
& CASE_LOWER_BASE
);
272 fat_short2uni(nls_disk
, ".", 1, &bufuname
[j
++]);
273 for (i
= 0; i
< 3;) {
274 if (!de
->ext
[i
]) break;
275 chl
= fat_shortname2uni(nls_disk
, &de
->ext
[i
], 3 - i
,
276 &bufuname
[j
++], opt_shortname
,
277 de
->lcase
& CASE_LOWER_EXT
);
279 if (de
->ext
[i
] != ' ')
289 bufuname
[last_u
] = 0x0000;
291 ?utf8_wcstombs(bufname
, bufuname
, sizeof(bufname
))
292 :uni16_to_x8(bufname
, bufuname
, uni_xlate
, nls_io
);
293 if (xlate_len
== name_len
)
294 if ((!anycase
&& !memcmp(name
, bufname
, xlate_len
)) ||
295 (anycase
&& !nls_strnicmp(nls_io
, name
, bufname
,
301 ?utf8_wcstombs(bufname
, unicode
, sizeof(bufname
))
302 :uni16_to_x8(bufname
, unicode
, uni_xlate
, nls_io
);
303 if (xlate_len
!= name_len
)
305 if ((!anycase
&& !memcmp(name
, bufname
, xlate_len
)) ||
306 (anycase
&& !nls_strnicmp(nls_io
, name
, bufname
,
313 res
= long_slots
+ 1;
314 *spos
= cpos
- sizeof(struct msdos_dir_entry
);
315 *lpos
= cpos
- res
*sizeof(struct msdos_dir_entry
);
319 free_page((unsigned long) unicode
);
324 static int fat_readdirx(struct inode
*inode
, struct file
*filp
, void *dirent
,
325 filldir_t filldir
, int shortnames
, int both
)
327 struct super_block
*sb
= inode
->i_sb
;
328 struct buffer_head
*bh
;
329 struct msdos_dir_entry
*de
;
330 struct nls_table
*nls_io
= MSDOS_SB(sb
)->nls_io
;
331 struct nls_table
*nls_disk
= MSDOS_SB(sb
)->nls_disk
;
332 wchar_t bufuname
[14];
333 unsigned char long_slots
;
334 wchar_t *unicode
= NULL
;
335 unsigned char c
, work
[8], bufname
[56], *ptname
= bufname
;
336 unsigned long lpos
, dummy
, *furrfu
= &lpos
;
337 int uni_xlate
= MSDOS_SB(sb
)->options
.unicode_xlate
;
338 int isvfat
= MSDOS_SB(sb
)->options
.isvfat
;
339 int utf8
= MSDOS_SB(sb
)->options
.utf8
;
340 int nocase
= MSDOS_SB(sb
)->options
.nocase
;
341 unsigned short opt_shortname
= MSDOS_SB(sb
)->options
.shortname
;
343 int chi
, chl
, i
, i2
, j
, last
, last_u
, dotoffset
= 0;
350 /* Fake . and .. for the root directory. */
351 if (inode
->i_ino
== MSDOS_ROOT_INO
) {
353 if (filldir(dirent
, "..", cpos
+1, cpos
, MSDOS_ROOT_INO
, DT_DIR
) < 0)
364 if (cpos
& (sizeof(struct msdos_dir_entry
)-1)) {
372 if (fat_get_entry(inode
,&cpos
,&bh
,&de
,&i_pos
) == -1)
374 /* Check for long filename entry */
376 if (de
->name
[0] == DELETED_FLAG
)
378 if (de
->attr
!= ATTR_EXT
&& (de
->attr
& ATTR_VOLUME
))
380 if (de
->attr
!= ATTR_EXT
&& IS_FREE(de
->name
))
383 if ((de
->attr
& ATTR_VOLUME
) || IS_FREE(de
->name
))
387 if (isvfat
&& de
->attr
== ATTR_EXT
) {
388 struct msdos_dir_slot
*ds
;
393 unsigned char alias_checksum
;
396 unicode
= (wchar_t *)
397 __get_free_page(GFP_KERNEL
);
407 ds
= (struct msdos_dir_slot
*) de
;
412 if (slots
> 20 || !slots
) /* ceil(256 * 2 / 26) */
415 alias_checksum
= ds
->alias_checksum
;
423 fat16_towchar(unicode
+ offset
, ds
->name0_4
, 5);
424 fat16_towchar(unicode
+ offset
+ 5, ds
->name5_10
, 6);
425 fat16_towchar(unicode
+ offset
+ 11, ds
->name11_12
, 2);
428 unicode
[offset
+ 13] = 0;
430 if (fat_get_entry(inode
,&cpos
,&bh
,&de
,&i_pos
) == -1)
434 ds
= (struct msdos_dir_slot
*) de
;
435 if (ds
->attr
!= ATTR_EXT
)
436 goto RecEnd
; /* XXX */
437 if ((ds
->id
& ~0x40) != slot
)
439 if (ds
->alias_checksum
!= alias_checksum
)
442 if (de
->name
[0] == DELETED_FLAG
)
444 if (de
->attr
== ATTR_EXT
)
446 if (IS_FREE(de
->name
) || (de
->attr
& ATTR_VOLUME
))
448 for (sum
= 0, i
= 0; i
< 11; i
++)
449 sum
= (((sum
&1)<<7)|((sum
&0xfe)>>1)) + de
->name
[i
];
450 if (sum
!= alias_checksum
)
454 if ((de
->attr
& ATTR_HIDDEN
) && MSDOS_SB(sb
)->options
.dotsOK
) {
459 memcpy(work
, de
->name
, sizeof(de
->name
));
460 /* see namei.c, msdos_format_name */
463 for (i
= 0, j
= 0, last
= 0, last_u
= 0; i
< 8;) {
464 if (!(c
= work
[i
])) break;
465 chl
= fat_shortname2uni(nls_disk
, &work
[i
], 8 - i
,
466 &bufuname
[j
++], opt_shortname
,
467 de
->lcase
& CASE_LOWER_BASE
);
469 ptname
[i
++] = (!nocase
&& c
>='A' && c
<='Z') ? c
+32 : c
;
476 for (chi
= 0; chi
< chl
&& i
< 8; chi
++) {
484 fat_short2uni(nls_disk
, ".", 1, &bufuname
[j
++]);
486 for (i2
= 0; i2
< 3;) {
487 if (!(c
= de
->ext
[i2
])) break;
488 chl
= fat_shortname2uni(nls_disk
, &de
->ext
[i2
], 3 - i2
,
489 &bufuname
[j
++], opt_shortname
,
490 de
->lcase
& CASE_LOWER_EXT
);
493 ptname
[i
++] = (!nocase
&& c
>='A' && c
<='Z') ? c
+32 : c
;
500 for (chi
= 0; chi
< chl
&& i2
< 3; chi
++) {
501 ptname
[i
++] = de
->ext
[i2
++];
509 i
= last
+ dotoffset
;
512 lpos
= cpos
- (long_slots
+1)*sizeof(struct msdos_dir_entry
);
513 if (!memcmp(de
->name
,MSDOS_DOT
,11))
515 else if (!memcmp(de
->name
,MSDOS_DOTDOT
,11)) {
516 inum
= parent_ino(filp
->f_dentry
);
518 struct inode
*tmp
= fat_iget(sb
, i_pos
);
523 inum
= iunique(sb
, MSDOS_ROOT_INO
);
527 bufuname
[j
] = 0x0000;
528 i
= utf8
? utf8_wcstombs(bufname
, bufuname
, sizeof(bufname
))
529 : uni16_to_x8(bufname
, bufuname
, uni_xlate
, nls_io
);
532 if (!long_slots
||shortnames
) {
535 if (filldir(dirent
, bufname
, i
, *furrfu
, inum
,
536 (de
->attr
& ATTR_DIR
) ? DT_DIR
: DT_REG
) < 0)
539 unsigned char longname
[275];
541 ? utf8_wcstombs(longname
, unicode
, sizeof(longname
))
542 : uni16_to_x8(longname
, unicode
, uni_xlate
,
545 memcpy(&longname
[long_len
+1], bufname
, i
);
548 if (filldir(dirent
, longname
, long_len
, *furrfu
, inum
,
549 (de
->attr
& ATTR_DIR
) ? DT_DIR
: DT_REG
) < 0)
563 free_page((unsigned long) unicode
);
570 int fat_readdir(struct file
*filp
, void *dirent
, filldir_t filldir
)
572 struct inode
*inode
= filp
->f_dentry
->d_inode
;
573 return fat_readdirx(inode
, filp
, dirent
, filldir
, 0, 0);
576 struct fat_ioctl_filldir_callback
{
577 struct dirent __user
*dirent
;
581 static int fat_ioctl_filldir(void *__buf
, const char * name
, int name_len
,
582 loff_t offset
, ino_t ino
, unsigned int d_type
)
584 struct fat_ioctl_filldir_callback
*buf
= __buf
;
585 struct dirent __user
*d1
= buf
->dirent
;
586 struct dirent __user
*d2
= d1
+ 1;
594 if ((name_len
== 1 && name
[0] == '.') ||
595 (name_len
== 2 && name
[0] == '.' && name
[1] == '.')) {
602 if (len
!= name_len
) {
603 slen
= name_len
- len
;
604 if (copy_to_user(d2
->d_name
, name
, len
) ||
605 put_user(0, d2
->d_name
+ len
) ||
606 put_user(len
, &d2
->d_reclen
) ||
607 put_user(ino
, &d2
->d_ino
) ||
608 put_user(offset
, &d2
->d_off
) ||
609 copy_to_user(d1
->d_name
, name
+len
+1, slen
) ||
610 put_user(0, d1
->d_name
+slen
) ||
611 put_user(slen
, &d1
->d_reclen
))
614 if (put_user(0, d2
->d_name
) ||
615 put_user(0, &d2
->d_reclen
) ||
616 copy_to_user(d1
->d_name
, name
, len
) ||
617 put_user(0, d1
->d_name
+len
) ||
618 put_user(len
, &d1
->d_reclen
))
623 buf
->result
= -EFAULT
;
627 int fat_dir_ioctl(struct inode
* inode
, struct file
* filp
,
628 unsigned int cmd
, unsigned long arg
)
630 struct fat_ioctl_filldir_callback buf
;
631 struct dirent __user
*d1
;
632 int ret
, shortname
, both
;
635 case VFAT_IOCTL_READDIR_SHORT
:
639 case VFAT_IOCTL_READDIR_BOTH
:
647 d1
= (struct dirent __user
*)arg
;
648 if (!access_ok(VERIFY_WRITE
, d1
, sizeof(struct dirent
[2])))
651 * Yes, we don't need this put_user() absolutely. However old
652 * code didn't return the right value. So, app use this value,
653 * in order to check whether it is EOF.
655 if (put_user(0, &d1
->d_reclen
))
662 if (!IS_DEADDIR(inode
)) {
663 ret
= fat_readdirx(inode
, filp
, &buf
, fat_ioctl_filldir
,
672 /* This assumes that size of cluster is above the 32*slots */
674 int fat_add_entries(struct inode
*dir
,int slots
, struct buffer_head
**bh
,
675 struct msdos_dir_entry
**de
, loff_t
*i_pos
)
677 struct super_block
*sb
= dir
->i_sb
;
680 struct buffer_head
*new_bh
;
685 while (fat_get_entry(dir
, &curr
, bh
, de
, i_pos
) > -1) {
686 /* check the maximum size of directory */
687 if (curr
>= FAT_MAX_DIR_SIZE
) {
692 if (IS_FREE((*de
)->name
)) {
700 if ((dir
->i_ino
== MSDOS_ROOT_INO
) && (MSDOS_SB(sb
)->fat_bits
!= 32))
702 new_bh
= fat_extend_dir(dir
);
704 return PTR_ERR(new_bh
);
707 fat_get_entry(dir
, &curr
, bh
, de
, i_pos
);
708 } while (++row
< slots
);
713 int fat_new_dir(struct inode
*dir
, struct inode
*parent
, int is_vfat
)
715 struct buffer_head
*bh
;
716 struct msdos_dir_entry
*de
;
719 bh
= fat_extend_dir(dir
);
723 /* zeroed out, so... */
724 fat_date_unix2dos(dir
->i_mtime
.tv_sec
,&time
,&date
);
725 de
= (struct msdos_dir_entry
*)&bh
->b_data
[0];
726 memcpy(de
[0].name
,MSDOS_DOT
,MSDOS_NAME
);
727 memcpy(de
[1].name
,MSDOS_DOTDOT
,MSDOS_NAME
);
728 de
[0].attr
= de
[1].attr
= ATTR_DIR
;
729 de
[0].time
= de
[1].time
= time
;
730 de
[0].date
= de
[1].date
= date
;
731 if (is_vfat
) { /* extra timestamps */
732 de
[0].ctime
= de
[1].ctime
= time
;
733 de
[0].adate
= de
[0].cdate
=
734 de
[1].adate
= de
[1].cdate
= date
;
736 de
[0].start
= CT_LE_W(MSDOS_I(dir
)->i_logstart
);
737 de
[0].starthi
= CT_LE_W(MSDOS_I(dir
)->i_logstart
>>16);
738 de
[1].start
= CT_LE_W(MSDOS_I(parent
)->i_logstart
);
739 de
[1].starthi
= CT_LE_W(MSDOS_I(parent
)->i_logstart
>>16);
740 mark_buffer_dirty(bh
);
742 dir
->i_atime
= dir
->i_ctime
= dir
->i_mtime
= CURRENT_TIME
;
743 mark_inode_dirty(dir
);
748 static int fat_get_short_entry(struct inode
*dir
, loff_t
*pos
,
749 struct buffer_head
**bh
,
750 struct msdos_dir_entry
**de
, loff_t
*i_pos
)
752 while (fat_get_entry(dir
, pos
, bh
, de
, i_pos
) >= 0) {
753 /* free entry or long name entry or volume label */
754 if (!IS_FREE((*de
)->name
) && !((*de
)->attr
& ATTR_VOLUME
))
760 /* See if directory is empty */
761 int fat_dir_empty(struct inode
*dir
)
763 struct buffer_head
*bh
;
764 struct msdos_dir_entry
*de
;
770 while (fat_get_short_entry(dir
, &cpos
, &bh
, &de
, &i_pos
) >= 0) {
771 if (strncmp(de
->name
, MSDOS_DOT
, MSDOS_NAME
) &&
772 strncmp(de
->name
, MSDOS_DOTDOT
, MSDOS_NAME
)) {
782 * fat_subdirs counts the number of sub-directories of dir. It can be run
783 * on directories being created.
785 int fat_subdirs(struct inode
*dir
)
787 struct buffer_head
*bh
;
788 struct msdos_dir_entry
*de
;
794 while (fat_get_short_entry(dir
, &cpos
, &bh
, &de
, &i_pos
) >= 0) {
795 if (de
->attr
& ATTR_DIR
)
803 * Scans a directory for a given file (name points to its formatted name).
804 * Returns an error code or zero.
806 int fat_scan(struct inode
*dir
, const unsigned char *name
,
807 struct buffer_head
**bh
, struct msdos_dir_entry
**de
,
814 while (fat_get_short_entry(dir
, &cpos
, bh
, de
, i_pos
) >= 0) {
815 if (!strncmp((*de
)->name
, name
, MSDOS_NAME
))