4 #include <sys/dirent.h>
10 #include <klibc/compiler.h>
14 static struct inode
* new_fat_inode(struct fs_info
*fs
)
16 struct inode
*inode
= alloc_inode(fs
, 0, sizeof(struct fat_pvt_inode
));
18 malloc_error("inode structure");
24 * Check for a particular sector in the FAT cache
26 static const void *get_fat_sector(struct fs_info
*fs
, sector_t sector
)
28 return get_cache(fs
->fs_dev
, FAT_SB(fs
)->fat
+ sector
);
31 static uint32_t get_next_cluster(struct fs_info
*fs
, uint32_t clust_num
)
33 uint32_t next_cluster
= 0;
36 uint32_t sector_mask
= SECTOR_SIZE(fs
) - 1;
39 switch(FAT_SB(fs
)->fat_type
) {
41 offset
= clust_num
+ (clust_num
>> 1);
42 fat_sector
= offset
>> SECTOR_SHIFT(fs
);
43 offset
&= sector_mask
;
44 data
= get_fat_sector(fs
, fat_sector
);
45 if (offset
== sector_mask
) {
47 * we got the end of the one fat sector,
48 * but we have just one byte and we need two,
49 * so store the low part, then read the next fat
50 * sector, read the high part, then combine it.
52 next_cluster
= data
[offset
];
53 data
= get_fat_sector(fs
, fat_sector
+ 1);
54 next_cluster
+= data
[0] << 8;
56 next_cluster
= *(const uint16_t *)(data
+ offset
);
59 if (clust_num
& 0x0001)
60 next_cluster
>>= 4; /* cluster number is ODD */
62 next_cluster
&= 0x0fff; /* cluster number is EVEN */
66 offset
= clust_num
<< 1;
67 fat_sector
= offset
>> SECTOR_SHIFT(fs
);
68 offset
&= sector_mask
;
69 data
= get_fat_sector(fs
, fat_sector
);
70 next_cluster
= *(const uint16_t *)(data
+ offset
);
74 offset
= clust_num
<< 2;
75 fat_sector
= offset
>> SECTOR_SHIFT(fs
);
76 offset
&= sector_mask
;
77 data
= get_fat_sector(fs
, fat_sector
);
78 next_cluster
= *(const uint32_t *)(data
+ offset
);
79 next_cluster
&= 0x0fffffff;
86 static int fat_next_extent(struct inode
*inode
, uint32_t lstart
)
88 struct fs_info
*fs
= inode
->fs
;
89 struct fat_sb_info
*sbi
= FAT_SB(fs
);
90 uint32_t mcluster
= lstart
>> sbi
->clust_shift
;
95 const uint32_t cluster_bytes
= UINT32_C(1) << sbi
->clust_byte_shift
;
96 const uint32_t cluster_secs
= UINT32_C(1) << sbi
->clust_shift
;
97 sector_t data_area
= sbi
->data
;
99 tcluster
= (inode
->size
+ cluster_bytes
- 1) >> sbi
->clust_byte_shift
;
100 if (mcluster
>= tcluster
)
101 goto err
; /* Requested cluster beyond end of file */
103 lcluster
= PVT(inode
)->offset
>> sbi
->clust_shift
;
104 pcluster
= ((PVT(inode
)->here
- data_area
) >> sbi
->clust_shift
) + 2;
106 if (lcluster
> mcluster
|| PVT(inode
)->here
< data_area
) {
108 pcluster
= PVT(inode
)->start_cluster
;
112 if (pcluster
-2 >= sbi
->clusters
) {
113 inode
->size
= lcluster
<< sbi
->clust_shift
;
117 if (lcluster
>= mcluster
)
121 pcluster
= get_next_cluster(fs
, pcluster
);
124 inode
->next_extent
.pstart
=
125 ((sector_t
)(pcluster
-2) << sbi
->clust_shift
) + data_area
;
126 inode
->next_extent
.len
= cluster_secs
;
127 xcluster
= 0; /* Nonsense */
129 while (++lcluster
< tcluster
) {
130 xcluster
= get_next_cluster(fs
, pcluster
);
131 if (xcluster
!= ++pcluster
)
132 break; /* Not contiguous */
133 inode
->next_extent
.len
+= cluster_secs
;
136 /* Note: ->here is bogus if ->offset >= EOF, but that's okay */
137 PVT(inode
)->offset
= lcluster
<< sbi
->clust_shift
;
138 PVT(inode
)->here
= ((xcluster
-2) << sbi
->clust_shift
) + data_area
;
146 static sector_t
get_next_sector(struct fs_info
* fs
, uint32_t sector
)
148 struct fat_sb_info
*sbi
= FAT_SB(fs
);
149 sector_t data_area
= sbi
->data
;
150 sector_t data_sector
;
152 int clust_shift
= sbi
->clust_shift
;
154 if (sector
< data_area
) {
155 /* Root directory sector... */
157 if (sector
>= data_area
)
158 sector
= 0; /* Ran out of root directory, return EOF */
162 data_sector
= sector
- data_area
;
163 if ((data_sector
+ 1) & sbi
->clust_mask
) /* Still in the same cluster */
164 return sector
+ 1; /* Next sector inside cluster */
166 /* get a new cluster */
167 cluster
= data_sector
>> clust_shift
;
168 cluster
= get_next_cluster(fs
, cluster
+ 2) - 2;
170 if (cluster
>= sbi
->clusters
)
173 /* return the start of the new cluster */
174 sector
= (cluster
<< clust_shift
) + data_area
;
179 * The FAT is a single-linked list. We remember the last place we
180 * were, so for a forward seek we can move forward from there, but
181 * for a reverse seek we have to start over...
183 static sector_t
get_the_right_sector(struct file
*file
)
185 struct inode
*inode
= file
->inode
;
186 uint32_t sector_pos
= file
->offset
>> SECTOR_SHIFT(file
->fs
);
190 if (sector_pos
< PVT(inode
)->offset
) {
193 sector
= PVT(inode
)->start
;
195 where
= PVT(inode
)->offset
;
196 sector
= PVT(inode
)->here
;
199 while (where
< sector_pos
) {
200 sector
= get_next_sector(file
->fs
, sector
);
204 PVT(inode
)->offset
= sector_pos
;
205 PVT(inode
)->here
= sector
;
211 * Get the next sector in sequence
213 static sector_t
next_sector(struct file
*file
)
215 struct inode
*inode
= file
->inode
;
216 sector_t sector
= get_next_sector(file
->fs
, PVT(inode
)->here
);
217 PVT(inode
)->offset
++;
218 PVT(inode
)->here
= sector
;
224 * Mangle a filename pointed to by src into a buffer pointed to by dst;
225 * ends on encountering any whitespace.
228 static void vfat_mangle_name(char *dst
, const char *src
)
232 int i
= FILENAME_MAX
-1;
235 * Copy the filename, converting backslash to slash and
236 * collapsing duplicate separators.
238 while (not_whitespace(c
= *src
)) {
243 if (src
[1] == '/' || src
[1] == '\\') {
253 /* Strip terminal slashes or whitespace */
257 if (*(dst
-1) == '/' && dst
-1 == p
) /* it's the '/' case */
259 if ((*(dst
-1) != '/') && (*(dst
-1) != '.'))
272 * Mangle a normal style string to DOS style string.
274 static void mangle_dos_name(char *mangle_buf
, const char *src
)
279 if (src
[0] == '.' && (!src
[1] || (src
[1] == '.' && !src
[2]))) {
280 /* . and .. mangle to their respective zero-padded version */
281 i
= stpcpy(mangle_buf
, src
) - mangle_buf
;
287 if ((c
<= ' ') || (c
== '/'))
292 mangle_buf
[i
++] = ' ';
297 c
= codepage
.upper
[c
];
298 if (i
== 0 && c
== 0xe5)
299 c
= 0x05; /* Special hack for the first byte only! */
306 mangle_buf
[i
++] = ' ';
308 mangle_buf
[i
] = '\0';
312 * Match a string name against a longname. "len" is the number of
313 * codepoints in the input; including padding.
315 * Returns true on match.
317 static bool vfat_match_longname(const char *str
, const uint16_t *match
,
320 unsigned char c
= -1; /* Nonzero: we have not yet seen NUL */
323 dprintf("Matching: %s\n", str
);
331 if (cp
!= codepage
.uni
[0][c
] && cp
!= codepage
.uni
[1][c
])
332 return false; /* Also handles c == '\0' */
335 /* This should have been the end of the matching string */
339 /* Any padding entries must be FFFF */
341 if (*match
++ != 0xffff)
348 * Convert an UTF-16 longname to the system codepage; return
349 * the length on success or -1 on failure.
351 static int vfat_cvt_longname(char *entry_name
, const uint16_t *long_name
)
357 static struct unicache unicache
[256];
361 char *p
= entry_name
;
365 uc
= &unicache
[cp
% 256];
367 if (__likely(uc
->utf16
== cp
)) {
370 for (c
= 0; c
< 512; c
++) {
371 /* This is a bit hacky... */
372 if (codepage
.uni
[0][c
] == cp
) {
374 *p
++ = uc
->cp
= (uint8_t)c
;
378 return -1; /* Impossible character */
384 return (p
-entry_name
)-1;
387 static void copy_long_chunk(uint16_t *buf
, const struct fat_dir_entry
*de
)
389 const struct fat_long_name_entry
*le
=
390 (const struct fat_long_name_entry
*)de
;
392 memcpy(buf
, le
->name1
, 5 * 2);
393 memcpy(buf
+ 5, le
->name2
, 6 * 2);
394 memcpy(buf
+ 11, le
->name3
, 2 * 2);
397 static uint8_t get_checksum(const char *dir_name
)
403 sum
= ((sum
& 1) << 7) + (sum
>> 1) + (uint8_t)*dir_name
++;
408 /* compute the first sector number of one dir where the data stores */
409 static inline sector_t
first_sector(struct fs_info
*fs
,
410 const struct fat_dir_entry
*dir
)
412 const struct fat_sb_info
*sbi
= FAT_SB(fs
);
413 sector_t first_clust
;
416 first_clust
= (dir
->first_cluster_high
<< 16) + dir
->first_cluster_low
;
417 if (first_clust
== 0)
418 sector
= sbi
->root
; /* first_clust == 0 means root directory */
420 sector
= ((first_clust
- 2) << sbi
->clust_shift
) + sbi
->data
;
425 static inline enum dirent_type
get_inode_mode(uint8_t attr
)
427 return (attr
& FAT_ATTR_DIRECTORY
) ? DT_DIR
: DT_REG
;
431 static struct inode
*vfat_find_entry(const char *dname
, struct inode
*dir
)
433 struct fs_info
*fs
= dir
->fs
;
435 const struct fat_dir_entry
*de
;
436 struct fat_long_name_entry
*long_de
;
438 char mangled_name
[12];
439 uint16_t long_name
[260]; /* == 20*13 */
442 sector_t dir_sector
= PVT(dir
)->start
;
443 uint8_t vfat_init
, vfat_next
, vfat_csum
= 0;
450 slots
= (strlen(dname
) + 12) / 13;
452 return NULL
; /* Name too long */
455 vfat_init
= vfat_next
= slots
;
458 /* Produce the shortname version, in case we need it. */
459 mangle_dos_name(mangled_name
, dname
);
462 de
= get_cache(fs
->fs_dev
, dir_sector
);
463 entries
= 1 << (fs
->sector_shift
- 5);
466 if (de
->name
[0] == 0)
469 if (de
->attr
== 0x0f) {
471 * It's a long name entry.
473 long_de
= (struct fat_long_name_entry
*)de
;
479 /* get the initial checksum value */
480 vfat_csum
= long_de
->checksum
;
484 /* ZERO the long_name buffer */
485 memset(long_name
, 0, sizeof long_name
);
487 if (long_de
->checksum
!= vfat_csum
)
493 /* got the long entry name */
494 copy_long_chunk(long_name
+ id
*13, de
);
497 * If we got the last entry, check it.
498 * Or, go on with the next entry.
501 if (!vfat_match_longname(dname
, long_name
, long_len
))
506 continue; /* Try the next entry */
511 if (de
->attr
& 0x08) /* ignore volume labels */
516 * We already have a VFAT long name match. However, the
517 * match is only valid if the checksum matches.
519 checksum
= get_checksum(de
->name
);
520 if (checksum
== vfat_csum
)
521 goto found
; /* Got it */
523 if (!memcmp(mangled_name
, de
->name
, 11))
529 vfat_next
= vfat_init
;
535 /* Try with the next sector */
536 dir_sector
= get_next_sector(fs
, dir_sector
);
538 return NULL
; /* Nothing found... */
541 inode
= new_fat_inode(fs
);
542 inode
->size
= de
->file_size
;
543 PVT(inode
)->start_cluster
=
544 (de
->first_cluster_high
<< 16) + de
->first_cluster_low
;
545 if (PVT(inode
)->start_cluster
== 0) {
547 int root_size
= FAT_SB(fs
)->root_size
;
549 PVT(inode
)->start_cluster
= FAT_SB(fs
)->root_cluster
;
550 inode
->size
= root_size
? root_size
<< fs
->sector_shift
: ~0;
551 PVT(inode
)->start
= PVT(inode
)->here
= FAT_SB(fs
)->root
;
553 PVT(inode
)->start
= PVT(inode
)->here
= first_sector(fs
, de
);
555 inode
->mode
= get_inode_mode(de
->attr
);
560 static struct inode
*vfat_iget_root(struct fs_info
*fs
)
562 struct inode
*inode
= new_fat_inode(fs
);
563 int root_size
= FAT_SB(fs
)->root_size
;
566 * For FAT32, the only way to get the root directory size is to
567 * follow the entire FAT chain to the end... which seems pointless.
569 PVT(inode
)->start_cluster
= FAT_SB(fs
)->root_cluster
;
570 inode
->size
= root_size
? root_size
<< fs
->sector_shift
: ~0;
571 PVT(inode
)->start
= PVT(inode
)->here
= FAT_SB(fs
)->root
;
572 inode
->mode
= DT_DIR
;
577 static struct inode
*vfat_iget(const char *dname
, struct inode
*parent
)
579 return vfat_find_entry(dname
, parent
);
582 static int vfat_readdir(struct file
*file
, struct dirent
*dirent
)
584 struct fs_info
*fs
= file
->fs
;
585 const struct fat_dir_entry
*de
;
587 const struct fat_long_name_entry
*long_de
;
589 sector_t sector
= get_the_right_sector(file
);
591 uint16_t long_name
[261]; /* == 20*13 + 1 (to guarantee null) */
595 uint8_t vfat_init
, vfat_next
, vfat_csum
;
598 bool long_entry
= false;
599 int sec_off
= file
->offset
& ((1 << fs
->sector_shift
) - 1);
601 data
= get_cache(fs
->fs_dev
, sector
);
602 de
= (const struct fat_dir_entry
*)(data
+ sec_off
);
603 entries_left
= ((1 << fs
->sector_shift
) - sec_off
) >> 5;
605 vfat_next
= vfat_csum
= 0xff;
608 while (entries_left
--) {
609 if (de
->name
[0] == 0)
610 return -1; /* End of directory */
611 if ((uint8_t)de
->name
[0] == 0xe5)
614 if (de
->attr
== 0x0f) {
616 * It's a long name entry.
618 long_de
= (struct fat_long_name_entry
*)de
;
622 /* init vfat_csum and vfat_init */
623 vfat_csum
= long_de
->checksum
;
626 goto invalid
; /* Too long! */
630 /* ZERO the long_name buffer */
631 memset(long_name
, 0, sizeof long_name
);
633 if (long_de
->checksum
!= vfat_csum
|| id
!= vfat_next
)
639 /* got the long entry name */
640 copy_long_chunk(long_name
+ id
*13, de
);
643 name_len
= vfat_cvt_longname(filename
, long_name
);
644 if (name_len
> 0 && name_len
< sizeof(dirent
->d_name
))
653 if (de
->attr
& 0x08) /* ignore volume labels */
656 if (long_entry
&& get_checksum(de
->name
) == vfat_csum
) {
657 /* Got a long entry */
659 /* Use the shortname */
664 for (i
= 0; i
< 8; i
++) {
668 if (de
->lcase
& LCASE_BASE
)
669 c
= codepage
.lower
[c
];
672 if (de
->name
[8] != ' ') {
674 for (i
= 8; i
< 11; i
++) {
678 if (de
->lcase
& LCASE_EXT
)
679 c
= codepage
.lower
[c
];
684 name_len
= p
- filename
;
686 goto got
; /* Got something one way or the other */
693 file
->offset
+= sizeof(struct fat_dir_entry
);
696 /* Try with the next sector */
697 sector
= next_sector(file
);
700 de
= get_cache(fs
->fs_dev
, sector
);
701 entries_left
= 1 << (fs
->sector_shift
- 5);
705 name_len
++; /* Include final null */
706 dirent
->d_ino
= de
->first_cluster_low
| (de
->first_cluster_high
<< 16);
707 dirent
->d_off
= file
->offset
;
708 dirent
->d_reclen
= offsetof(struct dirent
, d_name
) + name_len
;
709 dirent
->d_type
= get_inode_mode(de
->attr
);
710 memcpy(dirent
->d_name
, filename
, name_len
);
712 file
->offset
+= sizeof(*de
); /* Update for next reading */
717 /* init. the fs meta data, return the block size in bits */
718 static int vfat_fs_init(struct fs_info
*fs
)
721 struct fat_sb_info
*sbi
;
722 struct disk
*disk
= fs
->fs_dev
->disk
;
725 sector_t total_sectors
;
727 fs
->sector_shift
= fs
->block_shift
= disk
->sector_shift
;
728 fs
->sector_size
= 1 << fs
->sector_shift
;
729 fs
->block_size
= 1 << fs
->block_shift
;
731 disk
->rdwr_sectors(disk
, &fat
, 0, 1, 0);
733 /* XXX: Find better sanity checks... */
734 if (!fat
.bxResSectors
|| !fat
.bxFATs
)
736 sbi
= malloc(sizeof(*sbi
));
738 malloc_error("fat_sb_info structure");
741 sectors_per_fat
= fat
.bxFATsecs
? : fat
.fat32
.bxFATsecs_32
;
742 total_sectors
= fat
.bxSectors
? : fat
.bsHugeSectors
;
744 sbi
->fat
= fat
.bxResSectors
;
745 sbi
->root
= sbi
->fat
+ sectors_per_fat
* fat
.bxFATs
;
746 sbi
->root_size
= root_dir_size(fs
, &fat
);
747 sbi
->data
= sbi
->root
+ sbi
->root_size
;
749 sbi
->clust_shift
= ilog2(fat
.bxSecPerClust
);
750 sbi
->clust_byte_shift
= sbi
->clust_shift
+ fs
->sector_shift
;
751 sbi
->clust_mask
= fat
.bxSecPerClust
- 1;
752 sbi
->clust_size
= fat
.bxSecPerClust
<< fs
->sector_shift
;
754 clusters
= (total_sectors
- sbi
->data
) >> sbi
->clust_shift
;
755 if (clusters
<= 0xff4) {
756 sbi
->fat_type
= FAT12
;
757 } else if (clusters
<= 0xfff4) {
758 sbi
->fat_type
= FAT16
;
760 sbi
->fat_type
= FAT32
;
762 if (clusters
> 0x0ffffff4)
763 clusters
= 0x0ffffff4; /* Maximum possible */
765 if (fat
.fat32
.extended_flags
& 0x80) {
766 /* Non-mirrored FATs, we need to read the active one */
767 sbi
->fat
+= (fat
.fat32
.extended_flags
& 0x0f) * sectors_per_fat
;
770 /* FAT32: root directory is a cluster chain */
771 sbi
->root
= sbi
->data
772 + ((fat
.fat32
.root_cluster
-2) << sbi
->clust_shift
);
774 sbi
->clusters
= clusters
;
776 /* Initialize the cache */
777 cache_init(fs
->fs_dev
, fs
->block_shift
);
779 return fs
->block_shift
;
782 const struct fs_ops vfat_fs_ops
= {
784 .fs_flags
= FS_USEMEM
| FS_THISIND
,
785 .fs_init
= vfat_fs_init
,
787 .getfssec
= generic_getfssec
,
788 .close_file
= generic_close_file
,
789 .mangle_name
= vfat_mangle_name
,
790 .load_config
= generic_load_config
,
791 .readdir
= vfat_readdir
,
792 .iget_root
= vfat_iget_root
,
794 .next_extent
= fat_next_extent
,