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>
14 #define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
16 #include <linux/version.h>
18 #include <linux/msdos_fs.h>
19 #include <linux/nls.h>
20 #include <linux/kernel.h>
21 #include <linux/errno.h>
22 #include <linux/stat.h>
23 #include <linux/string.h>
24 #include <linux/ioctl.h>
25 #include <linux/dirent.h>
28 #include <asm/uaccess.h>
34 static ssize_t
fat_dir_read(struct file
* filp
, char * buf
,
35 size_t count
, loff_t
*ppos
)
40 struct file_operations fat_dir_operations
= {
41 NULL
, /* lseek - default */
42 fat_dir_read
, /* read */
43 NULL
, /* write - bad */
44 fat_readdir
, /* readdir */
45 NULL
, /* select v2.0.x/poll v2.1.x - default */
46 fat_dir_ioctl
, /* ioctl - default */
48 NULL
, /* no special open code */
49 NULL
, /* no special release code */
50 file_fsync
/* fsync */
54 * Convert Unicode 16 to UTF8, translated unicode, or ascii.
55 * If uni_xlate is enabled and we
56 * can't get a 1:1 conversion, use a colon as an escape character since
57 * it is normally invalid on the vfat filesystem. The following three
58 * characters are a sort of uuencoded 16 bit Unicode value. This lets
59 * us do a full dump and restore of Unicode filenames. We could get
60 * into some trouble with long Unicode names, but ignore that right now.
63 uni16_to_x8(unsigned char *ascii
, unsigned char *uni
, int uni_xlate
,
64 struct nls_table
*nls
)
66 unsigned char *ip
, *op
;
68 unsigned char *uni_page
;
74 while (*ip
|| ip
[1]) {
78 uni_page
= nls
->page_uni2charset
[ch
];
79 if (uni_page
&& uni_page
[cl
]) {
85 op
[2] = fat_uni2esc
[val
& 0x3f];
87 op
[1] = fat_uni2esc
[val
& 0x3f];
89 *op
= fat_uni2esc
[val
& 0x3f];
101 static void dump_de(struct msdos_dir_entry
*de
)
104 unsigned char *p
= (unsigned char *) de
;
107 for (i
= 0; i
< 32; i
++, p
++) {
117 fat_filldir_t fat_filldir
,
123 struct super_block
*sb
= inode
->i_sb
;
126 struct buffer_head
*bh
;
127 struct msdos_dir_entry
*de
;
128 unsigned long oldpos
= filp
->f_pos
;
132 unsigned char long_len
= 0; /* Make compiler warning go away */
133 unsigned char alias_checksum
= 0; /* Make compiler warning go away */
134 unsigned char long_slots
= 0;
135 int uni_xlate
= MSDOS_SB(sb
)->options
.unicode_xlate
;
136 int utf8
= MSDOS_SB(sb
)->options
.utf8
;
137 unsigned char *unicode
= NULL
;
138 struct nls_table
*nls
= MSDOS_SB(sb
)->nls_io
;
140 if (!inode
|| !S_ISDIR(inode
->i_mode
))
142 /* Fake . and .. for the root directory. */
143 if (inode
->i_ino
== MSDOS_ROOT_INO
) {
145 if (fat_filldir(filldir
, dirent
, "..", oldpos
+1, 0, oldpos
, oldpos
, 0, MSDOS_ROOT_INO
) < 0)
153 if (filp
->f_pos
& (sizeof(struct msdos_dir_entry
)-1))
157 longname
[0] = longname
[1] = 0;
159 ino
= fat_get_entry(inode
,&filp
->f_pos
,&bh
,&de
);
164 /* Check for long filename entry */
165 if (MSDOS_SB(sb
)->options
.isvfat
&& (de
->name
[0] == (__s8
) DELETED_FLAG
)) {
167 oldpos
= filp
->f_pos
;
168 } else if (MSDOS_SB(sb
)->options
.isvfat
&& de
->attr
== ATTR_EXT
) {
170 struct msdos_dir_slot
*ds
;
174 unsigned char slots
= 0;
177 unicode
= (unsigned char *)
178 __get_free_page(GFP_KERNEL
);
184 ds
= (struct msdos_dir_slot
*) de
;
190 alias_checksum
= ds
->alias_checksum
;
196 PRINTK(("1. get_new_entry: %d\n", get_new_entry
));
197 if (ds
->attr
!= ATTR_EXT
) {
202 if ((ds
->id
& ~0x40) != slot
) {
206 if (ds
->alias_checksum
!= alias_checksum
) {
212 PRINTK(("2. get_new_entry: %d\n", get_new_entry
));
213 memcpy(&unicode
[offset
], ds
->name0_4
, 10);
215 memcpy(&unicode
[offset
], ds
->name5_10
, 12);
217 memcpy(&unicode
[offset
], ds
->name11_12
, 4);
222 unicode
[offset
+1] = 0;
225 ino
= fat_get_entry(inode
,&filp
->f_pos
,&bh
,&de
);
226 PRINTK(("4. get_new_entry: %d\n", get_new_entry
));
232 ds
= (struct msdos_dir_slot
*) de
;
234 PRINTK(("5. get_new_entry: %d\n", get_new_entry
));
236 } else if (!IS_FREE(de
->name
) && !(de
->attr
& ATTR_VOLUME
)) {
238 char *ptname
= bufname
;
240 int was_long
= is_long
;
244 for (sum
= 0, i
= 0; i
< 11; i
++) {
245 sum
= (((sum
&1)<<7)|((sum
&0xfe)>>1)) + de
->name
[i
];
248 if (sum
!= alias_checksum
) {
249 PRINTK(("Checksums don't match %d != %d\n", sum
, alias_checksum
));
254 long_len
= utf8_wcstombs(longname
, (__u16
*) unicode
, sizeof(longname
));
256 long_len
= uni16_to_x8(longname
, unicode
, uni_xlate
, nls
);
260 if ((de
->attr
& ATTR_HIDDEN
) && MSDOS_SB(sb
)->options
.dotsOK
) {
265 for (i
= 0, last
= 0; i
< 8; i
++) {
266 if (!(c
= de
->name
[i
])) break;
267 if (c
>= 'A' && c
<= 'Z') c
+= 32;
268 /* see namei.c, msdos_format_name */
269 if (c
== 0x05) c
= 0xE5;
277 for (i2
= 0; i2
< 3; i2
++) {
278 if (!(c
= de
->ext
[i2
])) break;
279 if (c
>= 'A' && c
<= 'Z') c
+= 32;
285 if ((i
= last
) != 0) {
286 if (!strcmp(de
->name
,MSDOS_DOT
))
288 else if (!strcmp(de
->name
,MSDOS_DOTDOT
))
289 ino
= fat_parent_ino(inode
,0);
291 if (shortnames
|| !is_long
) {
293 bufname
[i
+dotoffset
] = '\0';
296 spos
= filp
->f_pos
- sizeof(struct msdos_dir_entry
);
300 if (fat_filldir(filldir
, dirent
, bufname
, i
+dotoffset
, 0, oldpos
, spos
, long_slots
, ino
) < 0) {
301 filp
->f_pos
= oldpos
;
305 if (is_long
&& longnames
) {
307 memcpy(&longname
[long_len
+1], bufname
, i
+dotoffset
);
308 long_len
+= i
+dotoffset
;
310 spos
= filp
->f_pos
- sizeof(struct msdos_dir_entry
);
311 if (fat_filldir(filldir
, dirent
, longname
, long_len
, 1, oldpos
, spos
, long_slots
, ino
) < 0) {
312 filp
->f_pos
= oldpos
;
316 oldpos
= filp
->f_pos
;
321 oldpos
= filp
->f_pos
;
323 ino
= fat_get_entry(inode
,&filp
->f_pos
,&bh
,&de
);
328 free_page((unsigned long) unicode
);
333 static int fat_filldir(
344 return filldir(buf
, name
, name_len
, offset
, ino
);
352 struct inode
*inode
= filp
->f_dentry
->d_inode
;
353 return fat_readdirx(inode
, filp
, dirent
, fat_filldir
, filldir
,
357 static int vfat_ioctl_fill(
368 struct dirent
*d1
= (struct dirent
*)buf
;
369 struct dirent
*d2
= d1
+ 1;
373 get_user(len
, &d1
->d_reclen
);
378 if ((name_len
== 1 && name
[0] == '.') ||
379 (name_len
== 2 && name
[0] == '.' && name
[1] == '.')) {
386 if (len
!= name_len
) {
387 copy_to_user(d2
->d_name
, name
, len
);
388 put_user(0, d2
->d_name
+ len
);
389 put_user(len
, &d2
->d_reclen
);
390 put_user(ino
, &d2
->d_ino
);
391 put_user(offset
, &d2
->d_off
);
392 slen
= name_len
- len
;
393 copy_to_user(d1
->d_name
, name
+len
+1, slen
);
394 put_user(0, d1
->d_name
+slen
);
395 put_user(slen
, &d1
->d_reclen
);
397 put_user(0, d2
->d_name
);
398 put_user(0, &d2
->d_reclen
);
399 copy_to_user(d1
->d_name
, name
, len
);
400 put_user(0, d1
->d_name
+len
);
401 put_user(len
, &d1
->d_reclen
);
403 PRINTK(("FAT d1=%p d2=%p len=%d, name_len=%d\n",
404 d1
, d2
, len
, name_len
));
409 int fat_dir_ioctl(struct inode
* inode
, struct file
* filp
,
410 unsigned int cmd
, unsigned long arg
)
414 * We want to provide an interface for Samba to be able
415 * to get the short filename for a given long filename.
416 * Samba should use this ioctl instead of readdir() to
417 * get the information it needs.
420 case VFAT_IOCTL_READDIR_BOTH
: {
421 struct dirent
*d1
= (struct dirent
*)arg
;
422 err
= verify_area(VERIFY_WRITE
, d1
, sizeof(struct dirent
[2]));
425 put_user(0, &d1
->d_reclen
);
426 return fat_readdirx(inode
,filp
,(void *)arg
,
427 vfat_ioctl_fill
, NULL
, 0, 1, 1);
429 case VFAT_IOCTL_READDIR_SHORT
: {
430 struct dirent
*d1
= (struct dirent
*)arg
;
431 put_user(0, &d1
->d_reclen
);
432 err
= verify_area(VERIFY_WRITE
, d1
, sizeof(struct dirent
[2]));
435 return fat_readdirx(inode
,filp
,(void *)arg
,
436 vfat_ioctl_fill
, NULL
, 1, 0, 1);
439 /* forward ioctl to CVF extension */
440 if (MSDOS_SB(inode
->i_sb
)->cvf_format
&&
441 MSDOS_SB(inode
->i_sb
)->cvf_format
->cvf_dir_ioctl
)
442 return MSDOS_SB(inode
->i_sb
)->cvf_format
443 ->cvf_dir_ioctl(inode
,filp
,cmd
,arg
);
451 * Overrides for Emacs so that we follow Linus's tabbing style.
452 * Emacs will notice this stuff at the end of the file and automatically
453 * adjust the settings for this buffer only. This must remain at the end
455 * ---------------------------------------------------------------------------
458 * c-brace-imaginary-offset: 0
460 * c-argdecl-indent: 8
462 * c-continued-statement-offset: 8
463 * c-continued-brace-offset: 0