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
++) {
96 static inline unsigned char
97 fat_tolower(struct nls_table
*t
, unsigned char c
)
99 unsigned char nc
= t
->charset2lower
[c
];
105 fat_short2uni(struct nls_table
*t
, unsigned char *c
, int clen
, wchar_t *uni
)
109 charlen
= t
->char2uni(c
, clen
, uni
);
111 *uni
= 0x003f; /* a question mark */
118 fat_short2lower_uni(struct nls_table
*t
, unsigned char *c
, int clen
, wchar_t *uni
)
123 charlen
= t
->char2uni(c
, clen
, &wc
);
125 *uni
= 0x003f; /* a question mark */
127 } else if (charlen
<= 1) {
128 unsigned char nc
= t
->charset2lower
[*c
];
133 if ( (charlen
= t
->char2uni(&nc
, 1, uni
)) < 0) {
134 *uni
= 0x003f; /* a question mark */
144 fat_strnicmp(struct nls_table
*t
, const unsigned char *s1
,
145 const unsigned char *s2
, int len
)
148 if (fat_tolower(t
, *s1
++) != fat_tolower(t
, *s2
++))
155 fat_shortname2uni(struct nls_table
*nls
, char *buf
, int buf_size
,
156 wchar_t *uni_buf
, unsigned short opt
, int lower
)
160 if (opt
& VFAT_SFN_DISPLAY_LOWER
)
161 len
= fat_short2lower_uni(nls
, buf
, buf_size
, uni_buf
);
162 else if (opt
& VFAT_SFN_DISPLAY_WIN95
)
163 len
= fat_short2uni(nls
, buf
, buf_size
, uni_buf
);
164 else if (opt
& VFAT_SFN_DISPLAY_WINNT
) {
166 len
= fat_short2lower_uni(nls
, buf
, buf_size
, uni_buf
);
168 len
= fat_short2uni(nls
, buf
, buf_size
, uni_buf
);
170 len
= fat_short2uni(nls
, buf
, buf_size
, uni_buf
);
176 * Return values: negative -> error, 0 -> not found, positive -> found,
177 * value is the total amount of slots, including the shortname entry.
179 int fat_search_long(struct inode
*inode
, const char *name
, int name_len
,
180 int anycase
, loff_t
*spos
, loff_t
*lpos
)
182 struct super_block
*sb
= inode
->i_sb
;
183 struct buffer_head
*bh
= NULL
;
184 struct msdos_dir_entry
*de
;
185 struct nls_table
*nls_io
= MSDOS_SB(sb
)->nls_io
;
186 struct nls_table
*nls_disk
= MSDOS_SB(sb
)->nls_disk
;
187 wchar_t bufuname
[14];
188 unsigned char xlate_len
, long_slots
;
189 wchar_t *unicode
= NULL
;
190 char work
[8], bufname
[260]; /* 256 + 4 */
191 int uni_xlate
= MSDOS_SB(sb
)->options
.unicode_xlate
;
192 int utf8
= MSDOS_SB(sb
)->options
.utf8
;
193 unsigned short opt_shortname
= MSDOS_SB(sb
)->options
.shortname
;
194 int chl
, i
, j
, last_u
, res
= 0;
195 loff_t i_pos
, cpos
= 0;
198 if (fat_get_entry(inode
,&cpos
,&bh
,&de
,&i_pos
) == -1)
202 if (de
->name
[0] == (__s8
) DELETED_FLAG
)
204 if (de
->attr
!= ATTR_EXT
&& (de
->attr
& ATTR_VOLUME
))
206 if (de
->attr
!= ATTR_EXT
&& IS_FREE(de
->name
))
208 if (de
->attr
== ATTR_EXT
) {
209 struct msdos_dir_slot
*ds
;
214 unsigned char alias_checksum
;
217 unicode
= (wchar_t *)
218 __get_free_page(GFP_KERNEL
);
226 ds
= (struct msdos_dir_slot
*) de
;
231 if (slots
> 20 || !slots
) /* ceil(256 * 2 / 26) */
234 alias_checksum
= ds
->alias_checksum
;
242 fat16_towchar(unicode
+ offset
, ds
->name0_4
, 5);
243 fat16_towchar(unicode
+ offset
+ 5, ds
->name5_10
, 6);
244 fat16_towchar(unicode
+ offset
+ 11, ds
->name11_12
, 2);
247 unicode
[offset
+ 13] = 0;
249 if (fat_get_entry(inode
,&cpos
,&bh
,&de
,&i_pos
)<0)
253 ds
= (struct msdos_dir_slot
*) de
;
254 if (ds
->attr
!= ATTR_EXT
)
256 if ((ds
->id
& ~0x40) != slot
)
258 if (ds
->alias_checksum
!= alias_checksum
)
261 if (de
->name
[0] == (__s8
) DELETED_FLAG
)
263 if (de
->attr
== ATTR_EXT
)
265 if (IS_FREE(de
->name
) || (de
->attr
& ATTR_VOLUME
))
267 for (sum
= 0, i
= 0; i
< 11; i
++)
268 sum
= (((sum
&1)<<7)|((sum
&0xfe)>>1)) + de
->name
[i
];
269 if (sum
!= alias_checksum
)
273 memcpy(work
, de
->name
, sizeof(de
->name
));
274 /* see namei.c, msdos_format_name */
277 for (i
= 0, j
= 0, last_u
= 0; i
< 8;) {
279 chl
= fat_shortname2uni(nls_disk
, &work
[i
], 8 - i
,
280 &bufuname
[j
++], opt_shortname
,
281 de
->lcase
& CASE_LOWER_BASE
);
291 fat_short2uni(nls_disk
, ".", 1, &bufuname
[j
++]);
292 for (i
= 0; i
< 3;) {
293 if (!de
->ext
[i
]) break;
294 chl
= fat_shortname2uni(nls_disk
, &de
->ext
[i
], 3 - i
,
295 &bufuname
[j
++], opt_shortname
,
296 de
->lcase
& CASE_LOWER_EXT
);
298 if (de
->ext
[i
] != ' ')
308 bufuname
[last_u
] = 0x0000;
310 ?utf8_wcstombs(bufname
, bufuname
, sizeof(bufname
))
311 :uni16_to_x8(bufname
, bufuname
, uni_xlate
, nls_io
);
312 if (xlate_len
== name_len
)
313 if ((!anycase
&& !memcmp(name
, bufname
, xlate_len
)) ||
314 (anycase
&& !fat_strnicmp(nls_io
, name
, bufname
,
320 ?utf8_wcstombs(bufname
, unicode
, sizeof(bufname
))
321 :uni16_to_x8(bufname
, unicode
, uni_xlate
, nls_io
);
322 if (xlate_len
!= name_len
)
324 if ((!anycase
&& !memcmp(name
, bufname
, xlate_len
)) ||
325 (anycase
&& !fat_strnicmp(nls_io
, name
, bufname
,
332 res
= long_slots
+ 1;
333 *spos
= cpos
- sizeof(struct msdos_dir_entry
);
334 *lpos
= cpos
- res
*sizeof(struct msdos_dir_entry
);
338 free_page((unsigned long) unicode
);
343 static int fat_readdirx(struct inode
*inode
, struct file
*filp
, void *dirent
,
344 filldir_t filldir
, int shortnames
, int both
)
346 struct super_block
*sb
= inode
->i_sb
;
347 struct buffer_head
*bh
;
348 struct msdos_dir_entry
*de
;
349 struct nls_table
*nls_io
= MSDOS_SB(sb
)->nls_io
;
350 struct nls_table
*nls_disk
= MSDOS_SB(sb
)->nls_disk
;
351 wchar_t bufuname
[14];
352 unsigned char long_slots
;
353 wchar_t *unicode
= NULL
;
354 char c
, work
[8], bufname
[56], *ptname
= bufname
;
355 unsigned long lpos
, dummy
, *furrfu
= &lpos
;
356 int uni_xlate
= MSDOS_SB(sb
)->options
.unicode_xlate
;
357 int isvfat
= MSDOS_SB(sb
)->options
.isvfat
;
358 int utf8
= MSDOS_SB(sb
)->options
.utf8
;
359 int nocase
= MSDOS_SB(sb
)->options
.nocase
;
360 unsigned short opt_shortname
= MSDOS_SB(sb
)->options
.shortname
;
362 int chi
, chl
, i
, i2
, j
, last
, last_u
, dotoffset
= 0;
369 /* Fake . and .. for the root directory. */
370 if (inode
->i_ino
== MSDOS_ROOT_INO
) {
372 if (filldir(dirent
, "..", cpos
+1, cpos
, MSDOS_ROOT_INO
, DT_DIR
) < 0)
383 if (cpos
& (sizeof(struct msdos_dir_entry
)-1)) {
391 if (fat_get_entry(inode
,&cpos
,&bh
,&de
,&i_pos
) == -1)
393 /* Check for long filename entry */
395 if (de
->name
[0] == (__s8
) DELETED_FLAG
)
397 if (de
->attr
!= ATTR_EXT
&& (de
->attr
& ATTR_VOLUME
))
399 if (de
->attr
!= ATTR_EXT
&& IS_FREE(de
->name
))
402 if ((de
->attr
& ATTR_VOLUME
) || IS_FREE(de
->name
))
406 if (isvfat
&& de
->attr
== ATTR_EXT
) {
407 struct msdos_dir_slot
*ds
;
412 unsigned char alias_checksum
;
415 unicode
= (wchar_t *)
416 __get_free_page(GFP_KERNEL
);
426 ds
= (struct msdos_dir_slot
*) de
;
431 if (slots
> 20 || !slots
) /* ceil(256 * 2 / 26) */
434 alias_checksum
= ds
->alias_checksum
;
442 fat16_towchar(unicode
+ offset
, ds
->name0_4
, 5);
443 fat16_towchar(unicode
+ offset
+ 5, ds
->name5_10
, 6);
444 fat16_towchar(unicode
+ offset
+ 11, ds
->name11_12
, 2);
447 unicode
[offset
+ 13] = 0;
449 if (fat_get_entry(inode
,&cpos
,&bh
,&de
,&i_pos
) == -1)
453 ds
= (struct msdos_dir_slot
*) de
;
454 if (ds
->attr
!= ATTR_EXT
)
455 goto RecEnd
; /* XXX */
456 if ((ds
->id
& ~0x40) != slot
)
458 if (ds
->alias_checksum
!= alias_checksum
)
461 if (de
->name
[0] == (__s8
) DELETED_FLAG
)
463 if (de
->attr
== ATTR_EXT
)
465 if (IS_FREE(de
->name
) || (de
->attr
& ATTR_VOLUME
))
467 for (sum
= 0, i
= 0; i
< 11; i
++)
468 sum
= (((sum
&1)<<7)|((sum
&0xfe)>>1)) + de
->name
[i
];
469 if (sum
!= alias_checksum
)
473 if ((de
->attr
& ATTR_HIDDEN
) && MSDOS_SB(sb
)->options
.dotsOK
) {
478 memcpy(work
, de
->name
, sizeof(de
->name
));
479 /* see namei.c, msdos_format_name */
482 for (i
= 0, j
= 0, last
= 0, last_u
= 0; i
< 8;) {
483 if (!(c
= work
[i
])) break;
484 chl
= fat_shortname2uni(nls_disk
, &work
[i
], 8 - i
,
485 &bufuname
[j
++], opt_shortname
,
486 de
->lcase
& CASE_LOWER_BASE
);
488 ptname
[i
++] = (!nocase
&& c
>='A' && c
<='Z') ? c
+32 : c
;
495 for (chi
= 0; chi
< chl
&& i
< 8; chi
++) {
503 fat_short2uni(nls_disk
, ".", 1, &bufuname
[j
++]);
505 for (i2
= 0; i2
< 3;) {
506 if (!(c
= de
->ext
[i2
])) break;
507 chl
= fat_shortname2uni(nls_disk
, &de
->ext
[i2
], 3 - i2
,
508 &bufuname
[j
++], opt_shortname
,
509 de
->lcase
& CASE_LOWER_EXT
);
512 ptname
[i
++] = (!nocase
&& c
>='A' && c
<='Z') ? c
+32 : c
;
519 for (chi
= 0; chi
< chl
&& i2
< 3; chi
++) {
520 ptname
[i
++] = de
->ext
[i2
++];
528 i
= last
+ dotoffset
;
531 lpos
= cpos
- (long_slots
+1)*sizeof(struct msdos_dir_entry
);
532 if (!memcmp(de
->name
,MSDOS_DOT
,11))
534 else if (!memcmp(de
->name
,MSDOS_DOTDOT
,11)) {
535 inum
= parent_ino(filp
->f_dentry
);
537 struct inode
*tmp
= fat_iget(sb
, i_pos
);
542 inum
= iunique(sb
, MSDOS_ROOT_INO
);
546 bufuname
[j
] = 0x0000;
547 i
= utf8
? utf8_wcstombs(bufname
, bufuname
, sizeof(bufname
))
548 : uni16_to_x8(bufname
, bufuname
, uni_xlate
, nls_io
);
551 if (!long_slots
||shortnames
) {
554 if (filldir(dirent
, bufname
, i
, *furrfu
, inum
,
555 (de
->attr
& ATTR_DIR
) ? DT_DIR
: DT_REG
) < 0)
560 ? utf8_wcstombs(longname
, unicode
, sizeof(longname
))
561 : uni16_to_x8(longname
, unicode
, uni_xlate
,
564 memcpy(&longname
[long_len
+1], bufname
, i
);
567 if (filldir(dirent
, longname
, long_len
, *furrfu
, inum
,
568 (de
->attr
& ATTR_DIR
) ? DT_DIR
: DT_REG
) < 0)
582 free_page((unsigned long) unicode
);
589 int fat_readdir(struct file
*filp
, void *dirent
, filldir_t filldir
)
591 struct inode
*inode
= filp
->f_dentry
->d_inode
;
592 return fat_readdirx(inode
, filp
, dirent
, filldir
, 0, 0);
595 struct fat_ioctl_filldir_callback
{
596 struct dirent __user
*dirent
;
600 static int fat_ioctl_filldir(void *__buf
, const char * name
, int name_len
,
601 loff_t offset
, ino_t ino
, unsigned int d_type
)
603 struct fat_ioctl_filldir_callback
*buf
= __buf
;
604 struct dirent __user
*d1
= buf
->dirent
;
605 struct dirent __user
*d2
= d1
+ 1;
613 if ((name_len
== 1 && name
[0] == '.') ||
614 (name_len
== 2 && name
[0] == '.' && name
[1] == '.')) {
621 if (len
!= name_len
) {
622 slen
= name_len
- len
;
623 if (copy_to_user(d2
->d_name
, name
, len
) ||
624 put_user(0, d2
->d_name
+ len
) ||
625 put_user(len
, &d2
->d_reclen
) ||
626 put_user(ino
, &d2
->d_ino
) ||
627 put_user(offset
, &d2
->d_off
) ||
628 copy_to_user(d1
->d_name
, name
+len
+1, slen
) ||
629 put_user(0, d1
->d_name
+slen
) ||
630 put_user(slen
, &d1
->d_reclen
))
633 if (put_user(0, d2
->d_name
) ||
634 put_user(0, &d2
->d_reclen
) ||
635 copy_to_user(d1
->d_name
, name
, len
) ||
636 put_user(0, d1
->d_name
+len
) ||
637 put_user(len
, &d1
->d_reclen
))
642 buf
->result
= -EFAULT
;
646 int fat_dir_ioctl(struct inode
* inode
, struct file
* filp
,
647 unsigned int cmd
, unsigned long arg
)
649 struct fat_ioctl_filldir_callback buf
;
650 struct dirent __user
*d1
= (struct dirent
*)arg
;
651 int ret
, shortname
, both
;
653 if (!access_ok(VERIFY_WRITE
, d1
, sizeof(struct dirent
[2])))
656 * Yes, we don't need this put_user() absolutely. However old
657 * code didn't return the right value. So, app use this value,
658 * in order to check whether it is EOF.
660 if (put_user(0, &d1
->d_reclen
))
666 case VFAT_IOCTL_READDIR_SHORT
:
670 case VFAT_IOCTL_READDIR_BOTH
:
677 ret
= fat_readdirx(inode
, filp
, &buf
, fat_ioctl_filldir
,
684 /***** See if directory is empty */
685 int fat_dir_empty(struct inode
*dir
)
688 struct buffer_head
*bh
;
689 struct msdos_dir_entry
*de
;
694 while (fat_get_entry(dir
,&pos
,&bh
,&de
,&i_pos
) > -1) {
695 /* Ignore vfat longname entries */
696 if (de
->attr
== ATTR_EXT
)
698 if (!IS_FREE(de
->name
) &&
699 strncmp(de
->name
,MSDOS_DOT
, MSDOS_NAME
) &&
700 strncmp(de
->name
,MSDOS_DOTDOT
, MSDOS_NAME
)) {
710 /* This assumes that size of cluster is above the 32*slots */
712 int fat_add_entries(struct inode
*dir
,int slots
, struct buffer_head
**bh
,
713 struct msdos_dir_entry
**de
, loff_t
*i_pos
)
715 struct super_block
*sb
= dir
->i_sb
;
718 struct buffer_head
*new_bh
;
723 while (fat_get_entry(dir
, &curr
, bh
, de
, i_pos
) > -1) {
724 /* check the maximum size of directory */
725 if (curr
>= FAT_MAX_DIR_SIZE
) {
730 if (IS_FREE((*de
)->name
)) {
738 if ((dir
->i_ino
== MSDOS_ROOT_INO
) && (MSDOS_SB(sb
)->fat_bits
!= 32))
740 new_bh
= fat_extend_dir(dir
);
742 return PTR_ERR(new_bh
);
745 fat_get_entry(dir
, &curr
, bh
, de
, i_pos
);
746 } while (++row
< slots
);
751 int fat_new_dir(struct inode
*dir
, struct inode
*parent
, int is_vfat
)
753 struct buffer_head
*bh
;
754 struct msdos_dir_entry
*de
;
757 bh
= fat_extend_dir(dir
);
761 /* zeroed out, so... */
762 fat_date_unix2dos(dir
->i_mtime
.tv_sec
,&time
,&date
);
763 de
= (struct msdos_dir_entry
*)&bh
->b_data
[0];
764 memcpy(de
[0].name
,MSDOS_DOT
,MSDOS_NAME
);
765 memcpy(de
[1].name
,MSDOS_DOTDOT
,MSDOS_NAME
);
766 de
[0].attr
= de
[1].attr
= ATTR_DIR
;
767 de
[0].time
= de
[1].time
= CT_LE_W(time
);
768 de
[0].date
= de
[1].date
= CT_LE_W(date
);
769 if (is_vfat
) { /* extra timestamps */
770 de
[0].ctime
= de
[1].ctime
= CT_LE_W(time
);
771 de
[0].adate
= de
[0].cdate
=
772 de
[1].adate
= de
[1].cdate
= CT_LE_W(date
);
774 de
[0].start
= CT_LE_W(MSDOS_I(dir
)->i_logstart
);
775 de
[0].starthi
= CT_LE_W(MSDOS_I(dir
)->i_logstart
>>16);
776 de
[1].start
= CT_LE_W(MSDOS_I(parent
)->i_logstart
);
777 de
[1].starthi
= CT_LE_W(MSDOS_I(parent
)->i_logstart
>>16);
778 mark_buffer_dirty(bh
);
780 dir
->i_atime
= dir
->i_ctime
= dir
->i_mtime
= CURRENT_TIME
;
781 mark_inode_dirty(dir
);
787 * Overrides for Emacs so that we follow Linus's tabbing style.
788 * Emacs will notice this stuff at the end of the file and automatically
789 * adjust the settings for this buffer only. This must remain at the end
791 * ---------------------------------------------------------------------------
794 * c-brace-imaginary-offset: 0
796 * c-argdecl-indent: 8
798 * c-continued-statement-offset: 8
799 * c-continued-brace-offset: 0