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 */
50 NULL
, /* no special release code */
51 file_fsync
/* fsync */
55 * Convert Unicode 16 to UTF8, translated Unicode, or ASCII.
56 * If uni_xlate is enabled and we
57 * can't get a 1:1 conversion, use a colon as an escape character since
58 * it is normally invalid on the vfat filesystem. The following three
59 * characters are a sort of uuencoded 16 bit Unicode value. This lets
60 * us do a full dump and restore of Unicode filenames. We could get
61 * into some trouble with long Unicode names, but ignore that right now.
64 uni16_to_x8(unsigned char *ascii
, unsigned char *uni
, int uni_xlate
,
65 struct nls_table
*nls
)
67 unsigned char *ip
, *op
;
69 unsigned char *uni_page
;
75 while (*ip
|| ip
[1]) {
79 uni_page
= nls
->page_uni2charset
[ch
];
80 if (uni_page
&& uni_page
[cl
]) {
86 op
[2] = fat_uni2esc
[val
& 0x3f];
88 op
[1] = fat_uni2esc
[val
& 0x3f];
90 *op
= fat_uni2esc
[val
& 0x3f];
102 static void dump_de(struct msdos_dir_entry
*de
)
105 unsigned char *p
= (unsigned char *) de
;
108 for (i
= 0; i
< 32; i
++, p
++) {
118 fat_filldir_t fat_filldir
,
124 struct super_block
*sb
= inode
->i_sb
;
127 struct buffer_head
*bh
;
128 struct msdos_dir_entry
*de
;
129 unsigned long oldpos
= filp
->f_pos
;
133 unsigned char long_len
= 0; /* Make compiler warning go away */
134 unsigned char alias_checksum
= 0; /* Make compiler warning go away */
135 unsigned char long_slots
= 0;
136 int uni_xlate
= MSDOS_SB(sb
)->options
.unicode_xlate
;
137 int utf8
= MSDOS_SB(sb
)->options
.utf8
;
138 unsigned char *unicode
= NULL
;
139 struct nls_table
*nls
= MSDOS_SB(sb
)->nls_io
;
141 if (!inode
|| !S_ISDIR(inode
->i_mode
))
143 /* Fake . and .. for the root directory. */
144 if (inode
->i_ino
== MSDOS_ROOT_INO
) {
146 if (fat_filldir(filldir
, dirent
, "..", oldpos
+1, 0, oldpos
, oldpos
, 0, MSDOS_ROOT_INO
) < 0)
154 if (filp
->f_pos
& (sizeof(struct msdos_dir_entry
)-1))
158 longname
[0] = longname
[1] = 0;
160 ino
= fat_get_entry(inode
,&filp
->f_pos
,&bh
,&de
);
165 /* Check for long filename entry */
166 if (MSDOS_SB(sb
)->options
.isvfat
&& (de
->name
[0] == (__s8
) DELETED_FLAG
)) {
168 oldpos
= filp
->f_pos
;
169 } else if (MSDOS_SB(sb
)->options
.isvfat
&& de
->attr
== ATTR_EXT
) {
171 struct msdos_dir_slot
*ds
;
175 unsigned char slots
= 0;
178 unicode
= (unsigned char *)
179 __get_free_page(GFP_KERNEL
);
185 ds
= (struct msdos_dir_slot
*) de
;
191 alias_checksum
= ds
->alias_checksum
;
197 PRINTK(("1. get_new_entry: %d\n", get_new_entry
));
198 if (ds
->attr
!= ATTR_EXT
) {
203 if ((ds
->id
& ~0x40) != slot
) {
207 if (ds
->alias_checksum
!= alias_checksum
) {
213 PRINTK(("2. get_new_entry: %d\n", get_new_entry
));
214 memcpy(&unicode
[offset
], ds
->name0_4
, 10);
216 memcpy(&unicode
[offset
], ds
->name5_10
, 12);
218 memcpy(&unicode
[offset
], ds
->name11_12
, 4);
223 unicode
[offset
+1] = 0;
226 ino
= fat_get_entry(inode
,&filp
->f_pos
,&bh
,&de
);
227 PRINTK(("4. get_new_entry: %d\n", get_new_entry
));
233 ds
= (struct msdos_dir_slot
*) de
;
235 PRINTK(("5. get_new_entry: %d\n", get_new_entry
));
237 } else if (!IS_FREE(de
->name
) && !(de
->attr
& ATTR_VOLUME
)) {
239 char *ptname
= bufname
;
241 int was_long
= is_long
;
245 for (sum
= 0, i
= 0; i
< 11; i
++) {
246 sum
= (((sum
&1)<<7)|((sum
&0xfe)>>1)) + de
->name
[i
];
249 if (sum
!= alias_checksum
) {
250 PRINTK(("Checksums don't match %d != %d\n", sum
, alias_checksum
));
255 long_len
= utf8_wcstombs(longname
, (__u16
*) unicode
, sizeof(longname
));
257 long_len
= uni16_to_x8(longname
, unicode
, uni_xlate
, nls
);
261 if ((de
->attr
& ATTR_HIDDEN
) && MSDOS_SB(sb
)->options
.dotsOK
) {
266 for (i
= 0, last
= 0; i
< 8; i
++) {
267 if (!(c
= de
->name
[i
])) break;
268 if (c
>= 'A' && c
<= 'Z') c
+= 32;
269 /* see namei.c, msdos_format_name */
270 if (c
== 0x05) c
= 0xE5;
278 for (i2
= 0; i2
< 3; i2
++) {
279 if (!(c
= de
->ext
[i2
])) break;
280 if (c
>= 'A' && c
<= 'Z') c
+= 32;
286 if ((i
= last
) != 0) {
287 if (!strcmp(de
->name
,MSDOS_DOT
))
289 else if (!strcmp(de
->name
,MSDOS_DOTDOT
))
290 ino
= fat_parent_ino(inode
,0);
292 if (shortnames
|| !is_long
) {
294 bufname
[i
+dotoffset
] = '\0';
297 spos
= filp
->f_pos
- sizeof(struct msdos_dir_entry
);
301 if (fat_filldir(filldir
, dirent
, bufname
, i
+dotoffset
, 0, oldpos
, spos
, long_slots
, ino
) < 0) {
302 filp
->f_pos
= oldpos
;
306 if (is_long
&& longnames
) {
308 memcpy(&longname
[long_len
+1], bufname
, i
+dotoffset
);
309 long_len
+= i
+dotoffset
;
311 spos
= filp
->f_pos
- sizeof(struct msdos_dir_entry
);
312 if (fat_filldir(filldir
, dirent
, longname
, long_len
, 1, oldpos
, spos
, long_slots
, ino
) < 0) {
313 filp
->f_pos
= oldpos
;
317 oldpos
= filp
->f_pos
;
322 oldpos
= filp
->f_pos
;
324 ino
= fat_get_entry(inode
,&filp
->f_pos
,&bh
,&de
);
329 free_page((unsigned long) unicode
);
334 static int fat_filldir(
345 return filldir(buf
, name
, name_len
, offset
, ino
);
353 struct inode
*inode
= filp
->f_dentry
->d_inode
;
354 return fat_readdirx(inode
, filp
, dirent
, fat_filldir
, filldir
,
358 static int vfat_ioctl_fill(
369 struct dirent
*d1
= (struct dirent
*)buf
;
370 struct dirent
*d2
= d1
+ 1;
374 get_user(len
, &d1
->d_reclen
);
379 if ((name_len
== 1 && name
[0] == '.') ||
380 (name_len
== 2 && name
[0] == '.' && name
[1] == '.')) {
387 if (len
!= name_len
) {
388 copy_to_user(d2
->d_name
, name
, len
);
389 put_user(0, d2
->d_name
+ len
);
390 put_user(len
, &d2
->d_reclen
);
391 put_user(ino
, &d2
->d_ino
);
392 put_user(offset
, &d2
->d_off
);
393 slen
= name_len
- len
;
394 copy_to_user(d1
->d_name
, name
+len
+1, slen
);
395 put_user(0, d1
->d_name
+slen
);
396 put_user(slen
, &d1
->d_reclen
);
398 put_user(0, d2
->d_name
);
399 put_user(0, &d2
->d_reclen
);
400 copy_to_user(d1
->d_name
, name
, len
);
401 put_user(0, d1
->d_name
+len
);
402 put_user(len
, &d1
->d_reclen
);
404 PRINTK(("FAT d1=%p d2=%p len=%d, name_len=%d\n",
405 d1
, d2
, len
, name_len
));
410 int fat_dir_ioctl(struct inode
* inode
, struct file
* filp
,
411 unsigned int cmd
, unsigned long arg
)
415 * We want to provide an interface for Samba to be able
416 * to get the short filename for a given long filename.
417 * Samba should use this ioctl instead of readdir() to
418 * get the information it needs.
421 case VFAT_IOCTL_READDIR_BOTH
: {
422 struct dirent
*d1
= (struct dirent
*)arg
;
423 err
= verify_area(VERIFY_WRITE
, d1
, sizeof(struct dirent
[2]));
426 put_user(0, &d1
->d_reclen
);
427 return fat_readdirx(inode
,filp
,(void *)arg
,
428 vfat_ioctl_fill
, NULL
, 0, 1, 1);
430 case VFAT_IOCTL_READDIR_SHORT
: {
431 struct dirent
*d1
= (struct dirent
*)arg
;
432 put_user(0, &d1
->d_reclen
);
433 err
= verify_area(VERIFY_WRITE
, d1
, sizeof(struct dirent
[2]));
436 return fat_readdirx(inode
,filp
,(void *)arg
,
437 vfat_ioctl_fill
, NULL
, 1, 0, 1);
440 /* forward ioctl to CVF extension */
441 if (MSDOS_SB(inode
->i_sb
)->cvf_format
&&
442 MSDOS_SB(inode
->i_sb
)->cvf_format
->cvf_dir_ioctl
)
443 return MSDOS_SB(inode
->i_sb
)->cvf_format
444 ->cvf_dir_ioctl(inode
,filp
,cmd
,arg
);
452 * Overrides for Emacs so that we follow Linus's tabbing style.
453 * Emacs will notice this stuff at the end of the file and automatically
454 * adjust the settings for this buffer only. This must remain at the end
456 * ---------------------------------------------------------------------------
459 * c-brace-imaginary-offset: 0
461 * c-argdecl-indent: 8
463 * c-continued-statement-offset: 8
464 * c-continued-brace-offset: 0