2 * Copyright © 2013 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 /* Include FAT commands */
26 #define FAT_COMMANDS 1
28 /* Spew FAT tracing */
32 #define DBG(...) printf(__VA_ARGS__)
38 * Basic file system types
41 typedef ao_fat_offset_t offset_t;
42 typedef ao_fat_sector_t sector_t;
43 typedef ao_fat_cluster_t cluster_t;
44 typedef ao_fat_dirent_t dirent_t;
45 typedef ao_fat_cluster_offset_t cluster_offset_t;
47 /* Partition information, sector numbers */
49 static uint8_t partition_type;
50 static sector_t partition_start, partition_end;
52 #define AO_FAT_BAD_CLUSTER 0xffffff7
53 #define AO_FAT_LAST_CLUSTER 0xfffffff
54 #define AO_FAT_IS_LAST_CLUSTER(c) (((c) & 0xffffff8) == 0xffffff8)
55 #define AO_FAT_IS_LAST_CLUSTER16(c) (((c) & 0xfff8) == 0xfff8)
58 #define SECTOR_SIZE 512
59 #define SECTOR_MASK (SECTOR_SIZE - 1)
60 #define SECTOR_SHIFT 9
62 #define DIRENT_SIZE 32
64 /* File system parameters */
65 static uint8_t sectors_per_cluster;
66 static uint32_t bytes_per_cluster;
67 static sector_t reserved_sector_count;
68 static uint8_t number_fat;
69 static dirent_t root_entries;
70 static sector_t sectors_per_fat;
71 static cluster_t number_cluster;
72 static sector_t fat_start;
73 static sector_t root_start;
74 static sector_t data_start;
75 static cluster_t next_free;
76 static uint8_t filesystem_full;
78 /* FAT32 extra data */
80 static uint8_t fsinfo_dirty;
81 static cluster_t root_cluster;
82 static sector_t fsinfo_sector;
83 static cluster_t free_count;
86 * Deal with LSB FAT data structures
89 get_u32(uint8_t *base)
91 return ((uint32_t) base[0] |
92 ((uint32_t) base[1] << 8) |
93 ((uint32_t) base[2] << 16) |
94 ((uint32_t) base[3] << 24));
98 put_u32(uint8_t *base, uint32_t value)
101 base[1] = value >> 8;
102 base[2] = value >> 16;
103 base[3] = value >> 24;
107 get_u16(uint8_t *base)
109 return ((uint16_t) base[0] | ((uint16_t) base[1] << 8));
113 put_u16(uint8_t *base, uint16_t value)
116 base[1] = value >> 8;
120 ao_fat_cluster_valid(cluster_t cluster)
122 return (2 <= cluster && cluster < number_cluster);
125 /* Start using a sector */
127 ao_fat_sector_get(sector_t sector)
129 sector += partition_start;
130 if (sector >= partition_end)
132 return ao_bufio_get(sector);
135 /* Finish using a sector, 'w' is 1 if modified */
136 #define ao_fat_sector_put(b,w) ao_bufio_put(b,w)
138 /* Get the next cluster entry in the chain */
140 ao_fat_entry_read(cluster_t cluster)
147 if (!ao_fat_cluster_valid(cluster))
154 sector = cluster >> (SECTOR_SHIFT);
155 offset = cluster & SECTOR_MASK;
156 buf = ao_fat_sector_get(fat_start + sector);
161 ret = get_u32(buf + offset);
164 ret = get_u16(buf + offset);
165 if (AO_FAT_IS_LAST_CLUSTER16(ret))
168 ao_fat_sector_put(buf, 0);
172 /* Replace the referenced cluster entry in the chain with
173 * 'new_value'. Return the previous value.
176 ao_fat_entry_replace(cluster_t cluster, cluster_t new_value)
179 cluster_offset_t offset;
185 if (!ao_fat_cluster_valid(cluster))
188 /* Convert from cluster index to byte index */
193 sector = cluster >> SECTOR_SHIFT;
194 offset = cluster & SECTOR_MASK;
196 new_value &= 0xfffffff;
197 for (fat = 0; fat < number_fat; fat++) {
198 buf = ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector);
202 old_value = get_u32(buf + offset);
203 put_u32(buf + offset, new_value | (old_value & 0xf0000000));
205 ret = old_value & 0xfffffff;
207 /* Track the free count if it wasn't marked
208 * invalid when we mounted the file system
210 if (free_count != 0xffffffff) {
211 if (new_value && !ret) {
214 } else if (!new_value && ret) {
222 ret = get_u16(buf + offset);
223 if (AO_FAT_IS_LAST_CLUSTER16(ret))
226 put_u16(buf + offset, new_value);
228 ao_fat_sector_put(buf, 1);
235 * Walk a cluster chain and mark
236 * all of them as free
239 ao_fat_free_cluster_chain(cluster_t cluster)
241 while (ao_fat_cluster_valid(cluster)) {
242 if (cluster < next_free) {
246 cluster = ao_fat_entry_replace(cluster, 0x00000000);
251 * ao_fat_cluster_seek
253 * The basic file system operation -- map a file cluster index to a
254 * partition cluster number. Done by computing the cluster number and
255 * then walking that many clusters from the first cluster. Returns
256 * 0xffff if we walk off the end of the file or the cluster chain
260 ao_fat_cluster_seek(cluster_t cluster, cluster_t distance)
263 cluster = ao_fat_entry_read(cluster);
264 if (!ao_fat_cluster_valid(cluster))
272 * ao_fat_cluster_set_size
274 * Set the number of clusters in the specified chain,
275 * freeing extra ones or alocating new ones as needed
277 * Returns AO_FAT_BAD_CLUSTER on allocation failure
281 ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size)
283 cluster_t clear_cluster = 0;
286 clear_cluster = first_cluster;
290 cluster_t last_cluster = 0;
291 cluster_t next_cluster;
293 /* Walk the cluster chain to the
294 * spot where it needs to change. That
295 * will either be the end of the chain (in case it needs to grow),
296 * or after the desired number of clusters, in which case it needs to shrink
298 next_cluster = first_cluster;
299 for (have = 0; have < size; have++) {
300 last_cluster = next_cluster;
301 next_cluster = ao_fat_entry_read(last_cluster);
302 if (!ao_fat_cluster_valid(next_cluster))
307 /* The file is large enough, truncate as needed */
308 if (ao_fat_cluster_valid(next_cluster)) {
309 /* Rewrite that cluster entry with 0xffff to mark the end of the chain */
310 clear_cluster = ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER);
313 /* The chain is already the right length, don't mess with it */
321 return AO_FAT_BAD_CLUSTER;
323 if (next_free < 2 || number_cluster <= next_free) {
328 /* See if there are enough free clusters in the file system */
331 #define loop_cluster for (free = next_free; need > 0;)
332 #define next_cluster \
333 if (++free == number_cluster) \
335 if (free == next_free) \
339 if (!ao_fat_entry_read(free))
343 /* Still need some, tell the user that we've failed */
346 return AO_FAT_BAD_CLUSTER;
349 /* Now go allocate those clusters and
350 * thread them onto the chain
354 if (!ao_fat_entry_read(free)) {
355 next_free = free + 1;
356 if (next_free >= number_cluster)
360 ao_fat_entry_replace(last_cluster, free);
362 first_cluster = free;
370 /* Mark the new end of the chain */
371 ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER);
375 /* Deallocate clusters off the end of the file */
376 if (ao_fat_cluster_valid(clear_cluster))
377 ao_fat_free_cluster_chain(clear_cluster);
378 return first_cluster;
381 /* Start using a root directory entry */
383 ao_fat_root_get(dirent_t e)
385 offset_t byte = e * DIRENT_SIZE;
386 sector_t sector = byte >> SECTOR_SHIFT;
387 cluster_offset_t offset = byte & SECTOR_MASK;
391 cluster_t cluster_distance = sector / sectors_per_cluster;
392 sector_t sector_index = sector % sectors_per_cluster;
393 cluster_t cluster = ao_fat_cluster_seek(root_cluster, cluster_distance);
395 if (ao_fat_cluster_valid(cluster))
396 sector = data_start + (cluster-2) * sectors_per_cluster + sector_index;
400 if (e >= root_entries)
402 sector = root_start + sector;
405 buf = ao_fat_sector_get(sector);
411 /* Finish using a root directory entry, 'w' is 1 if modified */
413 ao_fat_root_put(uint8_t *root, dirent_t e, uint8_t write)
415 cluster_offset_t offset = ((e * DIRENT_SIZE) & SECTOR_MASK);
416 uint8_t *buf = root - offset;
418 ao_fat_sector_put(buf, write);
424 * On FAT32, make the root directory at least 'ents' entries long
427 ao_fat_root_extend(dirent_t ents)
430 cluster_t cluster_size;
434 byte_size = ents * 0x20;
435 cluster_size = byte_size / bytes_per_cluster;
436 if (ao_fat_cluster_set_size(root_cluster, cluster_size) != AO_FAT_BAD_CLUSTER)
442 * ao_fat_setup_partition
444 * Load the boot block and find the first partition
447 ao_fat_setup_partition(void)
451 uint32_t partition_size;
453 mbr = ao_bufio_get(0);
455 return AO_FAT_FILESYSTEM_MBR_READ_FAILURE;
457 /* Check the signature */
458 if (mbr[0x1fe] != 0x55 || mbr[0x1ff] != 0xaa) {
459 DBG ("Invalid MBR signature %02x %02x\n",
460 mbr[0x1fe], mbr[0x1ff]);
461 ao_bufio_put(mbr, 0);
462 return AO_FAT_FILESYSTEM_INVALID_MBR_SIGNATURE;
465 /* Check to see if it's actually a boot block, in which
466 * case it's presumably not a paritioned device
469 if (mbr[0] == 0xeb) {
471 partition_size = get_u16(mbr + 0x13);
472 if (partition_size == 0)
473 partition_size = get_u32(mbr + 0x20);
475 /* Just use the first partition */
476 partition = &mbr[0x1be];
478 partition_type = partition[4];
479 switch (partition_type) {
480 case 4: /* FAT16 up to 32M */
481 case 6: /* FAT16 over 32M */
483 case 0x0b: /* FAT32 up to 2047GB */
484 case 0x0c: /* FAT32 LBA */
487 DBG ("Invalid partition type %02x\n", partition_type);
488 ao_bufio_put(mbr, 0);
489 return AO_FAT_FILESYSTEM_INVALID_PARTITION_TYPE;
492 partition_start = get_u32(partition+8);
493 partition_size = get_u32(partition+12);
494 if (partition_size == 0) {
495 DBG ("Zero-sized partition\n");
496 ao_bufio_put(mbr, 0);
497 return AO_FAT_FILESYSTEM_ZERO_SIZED_PARTITION;
500 partition_end = partition_start + partition_size;
501 ao_bufio_put(mbr, 0);
502 return AO_FAT_FILESYSTEM_SUCCESS;
506 ao_fat_setup_fs(void)
508 uint8_t *boot = ao_fat_sector_get(0);
509 uint32_t data_sectors;
512 return AO_FAT_FILESYSTEM_BOOT_READ_FAILURE;
514 /* Check the signature */
515 if (boot[0x1fe] != 0x55 || boot[0x1ff] != 0xaa) {
516 DBG ("Invalid BOOT signature %02x %02x\n",
517 boot[0x1fe], boot[0x1ff]);
518 ao_fat_sector_put(boot, 0);
519 return AO_FAT_FILESYSTEM_INVALID_BOOT_SIGNATURE;
522 /* Check the sector size */
523 if (get_u16(boot + 0xb) != SECTOR_SIZE) {
524 DBG ("Invalid sector size %d\n",
525 get_u16(boot + 0xb));
526 ao_fat_sector_put(boot, 0);
527 return AO_FAT_FILESYSTEM_INVALID_SECTOR_SIZE;
530 sectors_per_cluster = boot[0xd];
531 bytes_per_cluster = sectors_per_cluster << SECTOR_SHIFT;
532 reserved_sector_count = get_u16(boot+0xe);
533 number_fat = boot[0x10];
534 root_entries = get_u16(boot + 0x11);
535 sectors_per_fat = get_u16(boot+0x16);
537 if (sectors_per_fat == 0) {
539 sectors_per_fat = get_u32(boot+0x24);
540 root_cluster = get_u32(boot+0x2c);
541 fsinfo_sector = get_u16(boot + 0x30);
543 ao_fat_sector_put(boot, 0);
545 free_count = 0xffffffff;
547 if (fat32 && fsinfo_sector) {
548 uint8_t *fsinfo = ao_fat_sector_get(fsinfo_sector);
551 free_count = get_u32(fsinfo + 0x1e8);
552 next_free = get_u32(fsinfo + 0x1ec);
553 ao_fat_sector_put(fsinfo, 0);
557 fat_start = reserved_sector_count;;
558 root_start = fat_start + number_fat * sectors_per_fat;
559 data_start = root_start + ((root_entries * DIRENT_SIZE + SECTOR_MASK) >> SECTOR_SHIFT);
561 data_sectors = (partition_end - partition_start) - data_start;
563 number_cluster = data_sectors / sectors_per_cluster;
565 return AO_FAT_FILESYSTEM_SUCCESS;
569 * State for the current opened file
571 static struct ao_fat_dirent ao_file_dirent;
572 static uint32_t ao_file_offset;
573 static uint32_t ao_file_cluster_offset;
574 static cluster_t ao_file_cluster;
575 static uint8_t ao_file_opened;
576 static uint8_t ao_filesystem_available;
577 static uint8_t ao_filesystem_setup;
578 static uint8_t ao_filesystem_status;
583 if (!ao_filesystem_setup) {
585 ao_filesystem_setup = 1;
588 /* Re-initialize all global state; this will help to allow the
589 * file system to get swapped someday
591 partition_type = partition_start = partition_end = 0;
592 sectors_per_cluster = bytes_per_cluster = reserved_sector_count = 0;
593 number_fat = root_entries = sectors_per_fat = 0;
594 number_cluster = fat_start = root_start = data_start = 0;
595 next_free = filesystem_full = 0;
596 fat32 = fsinfo_dirty = root_cluster = fsinfo_sector = free_count = 0;
597 memset(&ao_file_dirent, '\0', sizeof (ao_file_dirent));
599 ao_file_offset = ao_file_cluster_offset = ao_file_cluster = ao_file_opened = 0;
600 ao_filesystem_status = ao_fat_setup_partition();
601 if (ao_filesystem_status != AO_FAT_FILESYSTEM_SUCCESS)
602 return ao_filesystem_status;
603 ao_filesystem_status = ao_fat_setup_fs();
604 if (ao_filesystem_status != AO_FAT_FILESYSTEM_SUCCESS)
605 return ao_filesystem_status;
607 return ao_filesystem_status;
611 * Basic file operations
615 ao_fat_current_sector(void)
617 cluster_t cluster_offset;
618 uint32_t sector_offset;
619 uint16_t sector_index;
622 DBG("current sector offset %d size %d\n",
623 ao_file_offset, ao_file_dirent.size);
625 if (ao_file_offset > ao_file_dirent.size)
628 sector_offset = ao_file_offset >> SECTOR_SHIFT;
630 if (!ao_file_cluster || ao_file_offset < ao_file_cluster_offset) {
631 ao_file_cluster = ao_file_dirent.cluster;
632 ao_file_cluster_offset = 0;
633 DBG("\treset to start of file %08x\n", ao_file_cluster);
636 if (ao_file_cluster_offset + bytes_per_cluster <= ao_file_offset) {
637 cluster_t cluster_distance;
639 cluster_offset = sector_offset / sectors_per_cluster;
641 cluster_distance = cluster_offset - ao_file_cluster_offset / bytes_per_cluster;
643 DBG("\tseek forward %d clusters\n", cluster_distance);
644 cluster = ao_fat_cluster_seek(ao_file_cluster, cluster_distance);
646 if (!ao_fat_cluster_valid(cluster))
648 ao_file_cluster = cluster;
649 ao_file_cluster_offset = cluster_offset * bytes_per_cluster;
652 sector_index = sector_offset % sectors_per_cluster;
653 DBG("current cluster %08x sector_index %d sector %d\n",
654 ao_file_cluster, sector_index,
655 data_start + (uint32_t) (ao_file_cluster-2) * sectors_per_cluster + sector_index);
656 return data_start + (uint32_t) (ao_file_cluster-2) * sectors_per_cluster + sector_index;
660 ao_fat_set_offset(uint32_t offset)
662 DBG("Set offset %d\n", offset);
663 ao_file_offset = offset;
669 * Set the size of the current file, truncating or extending
670 * the cluster chain as needed
673 ao_fat_set_size(uint32_t size)
676 cluster_t first_cluster;
677 cluster_t have_clusters, need_clusters;
679 DBG ("Set size %d\n", size);
680 if (size == ao_file_dirent.size) {
681 DBG("\tsize match\n");
682 return AO_FAT_SUCCESS;
685 first_cluster = ao_file_dirent.cluster;
686 have_clusters = (ao_file_dirent.size + bytes_per_cluster - 1) / bytes_per_cluster;
687 need_clusters = (size + bytes_per_cluster - 1) / bytes_per_cluster;
689 DBG ("\tfirst cluster %08x have %d need %d\n", first_cluster, have_clusters, need_clusters);
690 if (have_clusters != need_clusters) {
691 if (ao_file_cluster && size >= ao_file_cluster_offset) {
692 cluster_t offset_clusters = (ao_file_cluster_offset + bytes_per_cluster) / bytes_per_cluster;
693 cluster_t extra_clusters = need_clusters - offset_clusters;
694 cluster_t next_cluster;
696 DBG ("\tset size relative offset_clusters %d extra_clusters %d\n",
697 offset_clusters, extra_clusters);
698 next_cluster = ao_fat_cluster_set_size(ao_file_cluster, extra_clusters);
699 if (next_cluster == AO_FAT_BAD_CLUSTER)
700 return -AO_FAT_ENOSPC;
702 DBG ("\tset size absolute need_clusters %d\n", need_clusters);
703 first_cluster = ao_fat_cluster_set_size(first_cluster, need_clusters);
705 if (first_cluster == AO_FAT_BAD_CLUSTER)
706 return -AO_FAT_ENOSPC;
710 DBG ("\tupdate directory size\n");
711 /* Update the directory entry */
712 dent = ao_fat_root_get(ao_file_dirent.entry);
715 put_u32(dent + 0x1c, size);
716 put_u16(dent + 0x1a, first_cluster);
718 put_u16(dent + 0x14, first_cluster >> 16);
719 ao_fat_root_put(dent, ao_file_dirent.entry, 1);
721 ao_file_dirent.size = size;
722 ao_file_dirent.cluster = first_cluster;
723 DBG ("set size done\n");
724 return AO_FAT_SUCCESS;
730 * Initialize a root directory entry
733 ao_fat_root_init(uint8_t *dent, char name[11], uint8_t attr)
735 memset(dent, '\0', 0x20);
736 memmove(dent, name, 11);
743 put_u16(dent + 0x0e, 0);
745 put_u16(dent + 0x10, 0);
747 put_u16(dent + 0x12, 0);
750 put_u16(dent + 0x16, 0);
752 put_u16(dent + 0x18, 0);
755 /* Low cluster bytes */
756 put_u16(dent + 0x1a, 0);
757 /* FAT32 high cluster bytes */
758 put_u16(dent + 0x14, 0);
761 put_u32(dent + 0x1c, 0);
766 ao_fat_dirent_init(uint8_t *dent, uint16_t entry, struct ao_fat_dirent *dirent)
768 memcpy(dirent->name, dent + 0x00, 11);
769 dirent->attr = dent[0x0b];
770 dirent->size = get_u32(dent+0x1c);
771 dirent->cluster = get_u16(dent+0x1a);
773 dirent->cluster |= (cluster_t) get_u16(dent + 0x14) << 16;
774 dirent->entry = entry;
778 * ao_fat_flush_fsinfo
780 * Write out any fsinfo changes to disk
784 ao_fat_flush_fsinfo(void)
797 fsinfo = ao_fat_sector_get(fsinfo_sector);
799 put_u32(fsinfo + 0x1e8, free_count);
800 put_u32(fsinfo + 0x1ec, next_free);
801 ao_fat_sector_put(fsinfo, 1);
812 * Flush any pending I/O to storage
818 if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS)
820 ao_fat_flush_fsinfo();
827 * Returns TRUE if the filesystem cannot take
834 if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS)
836 return filesystem_full;
842 * Open an existing file.
845 ao_fat_open(char name[11], uint8_t mode)
848 struct ao_fat_dirent dirent;
850 if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS)
854 return -AO_FAT_EMFILE;
856 while (ao_fat_readdir(&entry, &dirent)) {
857 if (!memcmp(name, dirent.name, 11)) {
858 if (AO_FAT_IS_DIR(dirent.attr))
859 return -AO_FAT_EISDIR;
860 if (!AO_FAT_IS_FILE(dirent.attr))
861 return -AO_FAT_EPERM;
862 if (mode > AO_FAT_OPEN_READ && (dirent.attr & AO_FAT_FILE_READ_ONLY))
863 return -AO_FAT_EACCESS;
864 ao_file_dirent = dirent;
865 ao_fat_set_offset(0);
867 return AO_FAT_SUCCESS;
870 return -AO_FAT_ENOENT;
876 * Open and truncate an existing file or
880 ao_fat_creat(char name[11])
886 if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS)
890 return -AO_FAT_EMFILE;
892 status = ao_fat_open(name, AO_FAT_OPEN_WRITE);
895 case -AO_FAT_SUCCESS:
896 status = ao_fat_set_size(0);
901 dent = ao_fat_root_get(entry);
904 if (ao_fat_root_extend(entry))
906 status = -AO_FAT_ENOSPC;
910 if (dent[0] == AO_FAT_DENT_EMPTY || dent[0] == AO_FAT_DENT_END) {
911 ao_fat_root_init(dent, name, AO_FAT_FILE_REGULAR);
912 ao_fat_dirent_init(dent, entry, &ao_file_dirent);
913 ao_fat_root_put(dent, entry, 1);
915 ao_fat_set_offset(0);
916 status = -AO_FAT_SUCCESS;
919 ao_fat_root_put(dent, entry, 0);
930 * Close the currently open file
936 return -AO_FAT_EBADF;
938 memset(&ao_file_dirent, '\0', sizeof (struct ao_fat_dirent));
944 return AO_FAT_SUCCESS;
950 * Map the sector pointed at by the current file offset
954 ao_fat_map_current(int len, cluster_offset_t *offsetp, cluster_offset_t *this_time)
956 cluster_offset_t offset;
960 offset = ao_file_offset & SECTOR_MASK;
961 sector = ao_fat_current_sector();
962 if (sector == 0xffffffff)
964 buf = ao_fat_sector_get(sector);
965 if (offset + len < SECTOR_SIZE)
968 *this_time = SECTOR_SIZE - offset;
979 ao_fat_read(void *dst, int len)
981 uint8_t *dst_b = dst;
982 cluster_offset_t this_time;
983 cluster_offset_t offset;
988 return -AO_FAT_EBADF;
990 if (ao_file_offset + len > ao_file_dirent.size)
991 len = ao_file_dirent.size - ao_file_offset;
997 buf = ao_fat_map_current(len, &offset, &this_time);
1002 memcpy(dst_b, buf + offset, this_time);
1003 ao_fat_sector_put(buf, 0);
1008 ao_fat_set_offset(ao_file_offset + this_time);
1016 * Write to the file, extended as necessary
1019 ao_fat_write(void *src, int len)
1021 uint8_t *src_b = src;
1028 if (!ao_file_opened)
1029 return -AO_FAT_EBADF;
1031 if (ao_file_offset + len > ao_file_dirent.size) {
1032 ret = ao_fat_set_size(ao_file_offset + len);
1038 buf = ao_fat_map_current(len, &offset, &this_time);
1043 memcpy(buf + offset, src_b, this_time);
1044 ao_fat_sector_put(buf, 1);
1049 ao_fat_set_offset(ao_file_offset + this_time);
1057 * Set the position for the next I/O operation
1058 * Note that this doesn't actually change the size
1059 * of the file if the requested position is beyond
1060 * the current file length, that would take a future
1064 ao_fat_seek(int32_t pos, uint8_t whence)
1066 uint32_t new_offset = ao_file_offset;
1068 if (!ao_file_opened)
1069 return -AO_FAT_EBADF;
1072 case AO_FAT_SEEK_SET:
1075 case AO_FAT_SEEK_CUR:
1078 case AO_FAT_SEEK_END:
1079 new_offset = ao_file_dirent.size + pos;
1082 ao_fat_set_offset(new_offset);
1083 return ao_file_offset;
1089 * Remove a file from the directory, marking
1090 * all clusters as free
1093 ao_fat_unlink(char name[11])
1096 struct ao_fat_dirent dirent;
1098 if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS)
1101 while (ao_fat_readdir(&entry, &dirent)) {
1102 if (memcmp(name, dirent.name, 11) == 0) {
1107 if (AO_FAT_IS_DIR(dirent.attr))
1108 return -AO_FAT_EISDIR;
1109 if (!AO_FAT_IS_FILE(dirent.attr))
1110 return -AO_FAT_EPERM;
1112 ao_fat_free_cluster_chain(dirent.cluster);
1113 next = ao_fat_root_get(dirent.entry + 1);
1114 if (next && next[0] != AO_FAT_DENT_END)
1115 delete = AO_FAT_DENT_EMPTY;
1117 delete = AO_FAT_DENT_END;
1119 ao_fat_root_put(next, dirent.entry + 1, 0);
1120 ent = ao_fat_root_get(dirent.entry);
1122 memset(ent, '\0', DIRENT_SIZE);
1124 ao_fat_root_put(ent, dirent.entry, 1);
1127 return AO_FAT_SUCCESS;
1130 return -AO_FAT_ENOENT;
1134 ao_fat_rename(char old[11], char new[11])
1140 ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent)
1144 if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS)
1148 dent = ao_fat_root_get(*entry);
1152 if (dent[0] == AO_FAT_DENT_END) {
1153 ao_fat_root_put(dent, *entry, 0);
1156 if (dent[0] != AO_FAT_DENT_EMPTY && (dent[0xb] & 0xf) != 0xf) {
1157 ao_fat_dirent_init(dent, *entry, dirent);
1158 ao_fat_root_put(dent, *entry, 0);
1162 ao_fat_root_put(dent, *entry, 0);
1167 static const char *filesystem_errors[] = {
1168 [AO_FAT_FILESYSTEM_SUCCESS] = "FAT file system operating normally",
1169 [AO_FAT_FILESYSTEM_MBR_READ_FAILURE] = "MBR media read error",
1170 [AO_FAT_FILESYSTEM_INVALID_MBR_SIGNATURE] = "MBR signature invalid",
1171 [AO_FAT_FILESYSTEM_INVALID_PARTITION_TYPE] = "Unsupported paritition type",
1172 [AO_FAT_FILESYSTEM_ZERO_SIZED_PARTITION] = "Partition has zero sectors",
1173 [AO_FAT_FILESYSTEM_BOOT_READ_FAILURE] = "Boot block media read error",
1174 [AO_FAT_FILESYSTEM_INVALID_BOOT_SIGNATURE] = "Boot block signature invalid",
1175 [AO_FAT_FILESYSTEM_INVALID_SECTOR_SIZE] = "Sector size not 512",
1179 ao_fat_mbr_cmd(void)
1183 status = ao_fat_setup();
1184 if (status == AO_FAT_FILESYSTEM_SUCCESS) {
1185 printf ("partition type: %02x\n", partition_type);
1186 printf ("partition start: %08x\n", partition_start);
1188 printf ("partition end: %08x\n", partition_end);
1190 printf ("fat32: %d\n", fat32);
1191 printf ("sectors per cluster %d\n", sectors_per_cluster);
1192 printf ("reserved sectors %d\n", reserved_sector_count);
1193 printf ("number of FATs %d\n", number_fat);
1194 printf ("root entries %d\n", root_entries);
1195 printf ("sectors per fat %d\n", sectors_per_fat);
1197 printf ("fat start %d\n", fat_start);
1198 printf ("root start %d\n", root_start);
1199 printf ("data start %d\n", data_start);
1201 printf ("FAT filesystem not available: %s\n", filesystem_errors[status]);
1205 struct ao_fat_attr {
1210 static const struct ao_fat_attr ao_fat_attr[] = {
1211 { .bit = AO_FAT_FILE_READ_ONLY, .label = 'R' },
1212 { .bit = AO_FAT_FILE_HIDDEN, .label = 'H' },
1213 { .bit = AO_FAT_FILE_SYSTEM, .label = 'S' },
1214 { .bit = AO_FAT_FILE_VOLUME_LABEL, .label = 'V' },
1215 { .bit = AO_FAT_FILE_DIRECTORY, .label = 'D' },
1216 { .bit = AO_FAT_FILE_ARCHIVE, .label = 'A' },
1219 #define NUM_FAT_ATTR (sizeof (ao_fat_attr) / sizeof (ao_fat_attr[0]))
1222 ao_fat_list_cmd(void)
1225 struct ao_fat_dirent dirent;
1228 while (ao_fat_readdir(&entry, &dirent)) {
1229 for (i = 0; i < 8; i++)
1230 putchar(dirent.name[i]);
1233 putchar(dirent.name[i]);
1234 for (i = 0; i < NUM_FAT_ATTR; i++)
1235 putchar (dirent.attr & ao_fat_attr[i].bit ? ao_fat_attr[i].label : ' ');
1236 printf (" @%08x %d\n", dirent.cluster, dirent.size);
1241 ao_fat_parse_name(char name[11])
1248 while (ao_cmd_lex_c != '\n') {
1249 if (ao_cmd_lex_c == '.') {
1254 name[c++] = ao_cmd_lex_c;
1261 ao_fat_show_cmd(void)
1268 ao_fat_parse_name(name);
1269 if (name[0] == '\0') {
1270 ao_cmd_status = ao_cmd_syntax_error;
1274 status = ao_fat_open(name, AO_FAT_OPEN_READ);
1276 printf ("Open failed: %d\n", status);
1279 while ((cnt = ao_fat_read(buf, sizeof(buf))) > 0) {
1280 for (i = 0; i < cnt; i++)
1287 ao_fat_putchar(char c)
1292 ao_fat_write_cmd(void)
1300 ao_fat_parse_name(name);
1301 if (name[0] == '\0') {
1302 ao_cmd_status = ao_cmd_syntax_error;
1306 status = ao_fat_creat(name);
1308 printf ("Open failed: %d\n", status);
1312 while ((c = getchar()) != 4) {
1313 if (c == '\r') c = '\n';
1315 if (c == '\n') putchar ('\r');
1316 putchar(c); flush();
1318 if (ao_fat_write(&c, 1) != 1) {
1319 printf ("Write failure\n");
1326 static const struct ao_cmds ao_fat_cmds[] = {
1327 { ao_fat_mbr_cmd, "M\0Show FAT MBR and other info" },
1328 { ao_fat_list_cmd, "F\0List FAT directory" },
1329 { ao_fat_show_cmd, "S <name>\0Show FAT file" },
1330 { ao_fat_write_cmd, "W <name>\0Write FAT file (end with ^D)" },
1338 ao_cmd_register(&ao_fat_cmds[0]);