X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=src%2Fdrivers%2Fao_fat.c;h=fb8eecff177322cf9b46a959f87fee4bbe9fbf89;hp=9cd3d34be25b32cc83ccae414befd1e1b1b5a204;hb=1085ec5d57e0ed5d132f2bbdac1a0b6a32c0ab4a;hpb=144b44e13ce3361ff59cbb555e84d542455a4e17 diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index 9cd3d34b..fb8eecff 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -3,7 +3,8 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of @@ -30,6 +31,10 @@ /* Spew FAT tracing */ #define FAT_TRACE 0 +#ifdef DBG +#undef DBG +#endif + #if FAT_TRACE #define DBG(...) printf(__VA_ARGS__) #else @@ -46,6 +51,9 @@ typedef ao_fat_cluster_t cluster_t; typedef ao_fat_dirent_t dirent_t; typedef ao_fat_cluster_offset_t cluster_offset_t; +/* Global FAT lock */ +static uint8_t ao_fat_mutex; + /* Partition information, sector numbers */ static uint8_t partition_type; @@ -119,14 +127,14 @@ put_u16(uint8_t *base, uint16_t value) } static uint8_t -ao_fat_cluster_valid(cluster_t cluster) +_ao_fat_cluster_valid(cluster_t cluster) { return (2 <= cluster && cluster < number_cluster); } /* Start using a sector */ static uint8_t * -ao_fat_sector_get(sector_t sector) +_ao_fat_sector_get(sector_t sector) { sector += partition_start; if (sector >= partition_end) @@ -135,18 +143,18 @@ ao_fat_sector_get(sector_t sector) } /* Finish using a sector, 'w' is 1 if modified */ -#define ao_fat_sector_put(b,w) ao_bufio_put(b,w) +#define _ao_fat_sector_put(b,w) ao_bufio_put(b,w) /* Get the next cluster entry in the chain */ static cluster_t -ao_fat_entry_read(cluster_t cluster) +_ao_fat_entry_read(cluster_t cluster) { sector_t sector; cluster_t offset; uint8_t *buf; cluster_t ret; - if (!ao_fat_cluster_valid(cluster)) + if (!_ao_fat_cluster_valid(cluster)) return 0xfffffff7; if (fat32) @@ -155,7 +163,7 @@ ao_fat_entry_read(cluster_t cluster) cluster <<= 1; sector = cluster >> (SECTOR_SHIFT); offset = cluster & SECTOR_MASK; - buf = ao_fat_sector_get(fat_start + sector); + buf = _ao_fat_sector_get(fat_start + sector); if (!buf) return 0; @@ -167,7 +175,7 @@ ao_fat_entry_read(cluster_t cluster) if (AO_FAT_IS_LAST_CLUSTER16(ret)) ret |= 0xfff0000; } - ao_fat_sector_put(buf, 0); + _ao_fat_sector_put(buf, 0); return ret; } @@ -175,16 +183,16 @@ ao_fat_entry_read(cluster_t cluster) * 'new_value'. Return the previous value. */ static cluster_t -ao_fat_entry_replace(cluster_t cluster, cluster_t new_value) +_ao_fat_entry_replace(cluster_t cluster, cluster_t new_value) { sector_t sector; cluster_offset_t offset; uint8_t *buf; - cluster_t ret; + cluster_t ret = 0; cluster_t old_value; uint8_t fat; - if (!ao_fat_cluster_valid(cluster)) + if (!_ao_fat_cluster_valid(cluster)) return 0xfffffff7; /* Convert from cluster index to byte index */ @@ -197,7 +205,7 @@ ao_fat_entry_replace(cluster_t cluster, cluster_t new_value) new_value &= 0xfffffff; for (fat = 0; fat < number_fat; fat++) { - buf = ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector); + buf = _ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector); if (!buf) return 0; if (fat32) { @@ -227,7 +235,7 @@ ao_fat_entry_replace(cluster_t cluster, cluster_t new_value) } put_u16(buf + offset, new_value); } - ao_fat_sector_put(buf, 1); + _ao_fat_sector_put(buf, 1); } return ret; @@ -238,19 +246,19 @@ ao_fat_entry_replace(cluster_t cluster, cluster_t new_value) * all of them as free */ static void -ao_fat_free_cluster_chain(cluster_t cluster) +_ao_fat_free_cluster_chain(cluster_t cluster) { - while (ao_fat_cluster_valid(cluster)) { + while (_ao_fat_cluster_valid(cluster)) { if (cluster < next_free) { next_free = cluster; fsinfo_dirty = 1; } - cluster = ao_fat_entry_replace(cluster, 0x00000000); + cluster = _ao_fat_entry_replace(cluster, 0x00000000); } } /* - * ao_fat_cluster_seek + * _ao_fat_cluster_seek * * The basic file system operation -- map a file cluster index to a * partition cluster number. Done by computing the cluster number and @@ -259,11 +267,11 @@ ao_fat_free_cluster_chain(cluster_t cluster) * is damaged somehow */ static cluster_t -ao_fat_cluster_seek(cluster_t cluster, cluster_t distance) +_ao_fat_cluster_seek(cluster_t cluster, cluster_t distance) { while (distance) { - cluster = ao_fat_entry_read(cluster); - if (!ao_fat_cluster_valid(cluster)) + cluster = _ao_fat_entry_read(cluster); + if (!_ao_fat_cluster_valid(cluster)) break; distance--; } @@ -271,7 +279,7 @@ ao_fat_cluster_seek(cluster_t cluster, cluster_t distance) } /* - * ao_fat_cluster_set_size + * _ao_fat_cluster_set_size * * Set the number of clusters in the specified chain, * freeing extra ones or alocating new ones as needed @@ -280,109 +288,138 @@ ao_fat_cluster_seek(cluster_t cluster, cluster_t distance) */ static cluster_t -ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) +_ao_fat_cluster_set_size(cluster_t first_cluster, cluster_t size) { - cluster_t clear_cluster = 0; + cluster_t have; + cluster_t last_cluster; + cluster_t next_cluster; + + /* Walk the cluster chain to the + * spot where it needs to change. That + * will either be the end of the chain (in case it needs to grow), + * or after the desired number of clusters, in which case it needs to shrink + */ + next_cluster = first_cluster; + last_cluster = 0; + DBG("\tclusters:"); + for (have = 0; have < size; have++) { + DBG(" %08x", next_cluster); + if (!_ao_fat_cluster_valid(next_cluster)) + break; + last_cluster = next_cluster; + next_cluster = _ao_fat_entry_read(next_cluster); + } + DBG("\n"); + + /* At this point, last_cluster points to the last valid + * cluster in the file, if any. That's the spot in the FAT + * that needs to be rewritten, either to truncate the file by + * writing an END marker, or to extend the file by writing + * more clusters. next_cluster will contain the value of the + * FAT at last_cluster. + * + * If this is at the head of the cluster chain, then + * last_cluster will be zero and next_cluster will + * be the first cluster in the chain. + */ + if (have == size) { + /* The file is large enough, truncate as needed */ + if (_ao_fat_cluster_valid(next_cluster)) { + DBG("truncate between %08x and %08x\n", last_cluster, next_cluster); + if (last_cluster) + /* + * Otherwise, rewrite the last cluster + * in the chain with a LAST marker + */ + (void) _ao_fat_entry_replace(last_cluster, + AO_FAT_LAST_CLUSTER); + else + /* + * If the file is getting erased, then + * rewrite the directory entry cluster + * value + */ + first_cluster = 0; - if (size == 0) { - clear_cluster = first_cluster; - first_cluster = 0; - } else { - cluster_t have; - cluster_t last_cluster = 0; - cluster_t next_cluster; - - /* Walk the cluster chain to the - * spot where it needs to change. That - * will either be the end of the chain (in case it needs to grow), - * or after the desired number of clusters, in which case it needs to shrink - */ - next_cluster = first_cluster; - for (have = 0; have < size; have++) { - last_cluster = next_cluster; - next_cluster = ao_fat_entry_read(last_cluster); - if (!ao_fat_cluster_valid(next_cluster)) - break; - } + /* Clear the remaining clusters in the chain */ + _ao_fat_free_cluster_chain(next_cluster); - if (have == size) { - /* The file is large enough, truncate as needed */ - if (ao_fat_cluster_valid(next_cluster)) { - /* Rewrite that cluster entry with 0xffff to mark the end of the chain */ - clear_cluster = ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER); - filesystem_full = 0; - } else { - /* The chain is already the right length, don't mess with it */ - ; - } + /* The file system is no longer full (if it was) */ + filesystem_full = 0; } else { - cluster_t need; - cluster_t free; + DBG("unchanged FAT chain\n"); + /* The chain is already the right length, don't mess with it */ + ; + } + } else { + cluster_t need; + cluster_t free; - if (filesystem_full) - return AO_FAT_BAD_CLUSTER; + if (filesystem_full) + return AO_FAT_BAD_CLUSTER; - if (next_free < 2 || number_cluster <= next_free) { - next_free = 2; - fsinfo_dirty = 1; - } + /* Set next_free if it has wrapped or wasn't set before */ + if (next_free < 2 || number_cluster <= next_free) { + next_free = 2; + fsinfo_dirty = 1; + } - /* See if there are enough free clusters in the file system */ - need = size - have; + /* See if there are enough free clusters in the file system */ + need = size - have; #define loop_cluster for (free = next_free; need > 0;) -#define next_cluster \ - if (++free == number_cluster) \ - free = 2; \ - if (free == next_free) \ - break; \ - - loop_cluster { - if (!ao_fat_entry_read(free)) - need--; - next_cluster; - } - /* Still need some, tell the user that we've failed */ - if (need) { - filesystem_full = 1; - return AO_FAT_BAD_CLUSTER; - } +#define next_cluster \ + if (++free == number_cluster) \ + free = 2; \ + if (free == next_free) \ + break; \ + + loop_cluster { + if (!_ao_fat_entry_read(free)) + need--; + next_cluster; + } - /* Now go allocate those clusters and - * thread them onto the chain - */ - need = size - have; - loop_cluster { - if (!ao_fat_entry_read(free)) { - next_free = free + 1; - if (next_free >= number_cluster) - next_free = 2; - fsinfo_dirty = 1; - if (last_cluster) - ao_fat_entry_replace(last_cluster, free); - else - first_cluster = free; - last_cluster = free; - need--; - } - next_cluster; + /* Still need some, tell the user that we've failed */ + if (need) { + filesystem_full = 1; + return AO_FAT_BAD_CLUSTER; + } + + /* Now go allocate those clusters and + * thread them onto the chain + */ + need = size - have; + loop_cluster { + if (_ao_fat_entry_read(free) == 0) { + next_free = free + 1; + if (next_free >= number_cluster) + next_free = 2; + fsinfo_dirty = 1; + DBG("\tadd cluster. old %08x new %08x\n", last_cluster, free); + if (last_cluster) + _ao_fat_entry_replace(last_cluster, free); + else + first_cluster = free; + last_cluster = free; + need--; } + next_cluster; + } #undef loop_cluster #undef next_cluster - /* Mark the new end of the chain */ - ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER); - } + DBG("\tlast cluster %08x\n", last_cluster); + /* Mark the new end of the chain */ + _ao_fat_entry_replace(last_cluster, AO_FAT_LAST_CLUSTER); } - /* Deallocate clusters off the end of the file */ - if (ao_fat_cluster_valid(clear_cluster)) - ao_fat_free_cluster_chain(clear_cluster); + DBG("\tfirst cluster %08x\n", first_cluster); return first_cluster; } /* Start using a root directory entry */ static uint8_t * -ao_fat_root_get(dirent_t e) +_ao_fat_root_get(dirent_t e) { offset_t byte = e * DIRENT_SIZE; sector_t sector = byte >> SECTOR_SHIFT; @@ -392,9 +429,9 @@ ao_fat_root_get(dirent_t e) if (fat32) { cluster_t cluster_distance = sector / sectors_per_cluster; sector_t sector_index = sector % sectors_per_cluster; - cluster_t cluster = ao_fat_cluster_seek(root_cluster, cluster_distance); + cluster_t cluster = _ao_fat_cluster_seek(root_cluster, cluster_distance); - if (ao_fat_cluster_valid(cluster)) + if (_ao_fat_cluster_valid(cluster)) sector = data_start + (cluster-2) * sectors_per_cluster + sector_index; else return NULL; @@ -404,7 +441,7 @@ ao_fat_root_get(dirent_t e) sector = root_start + sector; } - buf = ao_fat_sector_get(sector); + buf = _ao_fat_sector_get(sector); if (!buf) return NULL; return buf + offset; @@ -412,41 +449,41 @@ ao_fat_root_get(dirent_t e) /* Finish using a root directory entry, 'w' is 1 if modified */ static void -ao_fat_root_put(uint8_t *root, dirent_t e, uint8_t write) +_ao_fat_root_put(uint8_t *root, dirent_t e, uint8_t write) { cluster_offset_t offset = ((e * DIRENT_SIZE) & SECTOR_MASK); uint8_t *buf = root - offset; - ao_fat_sector_put(buf, write); + _ao_fat_sector_put(buf, write); } /* - * ao_fat_root_extend + * _ao_fat_root_extend * * On FAT32, make the root directory at least 'ents' entries long */ static int8_t -ao_fat_root_extend(dirent_t ents) +_ao_fat_root_extend(dirent_t ents) { offset_t byte_size; cluster_t cluster_size; if (!fat32) return 0; - byte_size = ents * 0x20; - cluster_size = byte_size / bytes_per_cluster; - if (ao_fat_cluster_set_size(root_cluster, cluster_size) != AO_FAT_BAD_CLUSTER) + byte_size = (ents + 1) * 0x20; + cluster_size = (byte_size + bytes_per_cluster - 1) / bytes_per_cluster; + if (_ao_fat_cluster_set_size(root_cluster, cluster_size) != AO_FAT_BAD_CLUSTER) return 1; return 0; } /* - * ao_fat_setup_partition + * _ao_fat_setup_partition * * Load the boot block and find the first partition */ static uint8_t -ao_fat_setup_partition(void) +_ao_fat_setup_partition(void) { uint8_t *mbr; uint8_t *partition; @@ -505,9 +542,9 @@ ao_fat_setup_partition(void) } static uint8_t -ao_fat_setup_fs(void) +_ao_fat_setup_fs(void) { - uint8_t *boot = ao_fat_sector_get(0); + uint8_t *boot = _ao_fat_sector_get(0); uint32_t data_sectors; if (!boot) @@ -517,7 +554,7 @@ ao_fat_setup_fs(void) if (boot[0x1fe] != 0x55 || boot[0x1ff] != 0xaa) { DBG ("Invalid BOOT signature %02x %02x\n", boot[0x1fe], boot[0x1ff]); - ao_fat_sector_put(boot, 0); + _ao_fat_sector_put(boot, 0); return AO_FAT_FILESYSTEM_INVALID_BOOT_SIGNATURE; } @@ -525,7 +562,7 @@ ao_fat_setup_fs(void) if (get_u16(boot + 0xb) != SECTOR_SIZE) { DBG ("Invalid sector size %d\n", get_u16(boot + 0xb)); - ao_fat_sector_put(boot, 0); + _ao_fat_sector_put(boot, 0); return AO_FAT_FILESYSTEM_INVALID_SECTOR_SIZE; } @@ -542,17 +579,17 @@ ao_fat_setup_fs(void) root_cluster = get_u32(boot+0x2c); fsinfo_sector = get_u16(boot + 0x30); } - ao_fat_sector_put(boot, 0); + _ao_fat_sector_put(boot, 0); free_count = 0xffffffff; next_free = 0; if (fat32 && fsinfo_sector) { - uint8_t *fsinfo = ao_fat_sector_get(fsinfo_sector); + uint8_t *fsinfo = _ao_fat_sector_get(fsinfo_sector); if (fsinfo) { free_count = get_u32(fsinfo + 0x1e8); next_free = get_u32(fsinfo + 0x1ec); - ao_fat_sector_put(fsinfo, 0); + _ao_fat_sector_put(fsinfo, 0); } } @@ -568,18 +605,99 @@ ao_fat_setup_fs(void) } /* - * State for the current opened file + * State for an open file */ -static struct ao_fat_dirent ao_file_dirent; -static uint32_t ao_file_offset; -static uint32_t ao_file_cluster_offset; -static cluster_t ao_file_cluster; -static uint8_t ao_file_opened; + +struct ao_file { + struct ao_fat_dirent *dirent; + offset_t offset; + offset_t cluster_offset; + cluster_t cluster; + uint8_t busy; +}; + +#define AO_FAT_NFILE 8 + +static struct ao_fat_dirent ao_file_dirent[AO_FAT_NFILE]; + +static struct ao_fat_dirent * +_ao_fat_file_dirent_alloc(struct ao_fat_dirent *want) +{ + int8_t d; + struct ao_fat_dirent *free = NULL, *dirent; + + for (d = 0; d < AO_FAT_NFILE; d++) { + + dirent = &ao_file_dirent[d]; + /* See if there's another user of this file already */ + if (want && dirent->name[0] != 0) { + if (dirent->entry == want->entry) + return dirent; + } else { + if (!free) { + free = dirent; + if (!want) + break; + } + } + } + if (free && want) + *free = *want; + return free; +} + +static struct ao_file ao_file_table[AO_FAT_NFILE]; + +static int8_t +_ao_fat_fd_alloc(struct ao_fat_dirent *dirent) +{ + int8_t fd; + + for (fd = 0; fd < AO_FAT_NFILE; fd++) + if (!ao_file_table[fd].busy) { + ao_file_table[fd].dirent = _ao_fat_file_dirent_alloc(dirent); + ao_file_table[fd].busy = 1; + ao_file_table[fd].offset = 0; + ao_file_table[fd].cluster_offset = 0; + ao_file_table[fd].cluster = ao_file_table[fd].dirent->cluster; + + return fd; + } + return -AO_FAT_EMFILE; +} + +static void +_ao_fat_fd_free(int8_t fd) +{ + struct ao_file *file = &ao_file_table[fd]; + struct ao_fat_dirent *dirent = file->dirent; + memset(&ao_file_table[fd], '\0', sizeof (struct ao_file)); + + /* Check and see if another ao_file references the same dirent */ + for (fd = 0; fd < AO_FAT_NFILE; fd++) + if (ao_file_table[fd].dirent == dirent) + return; + memset(dirent, '\0', sizeof (struct ao_fat_dirent)); +} + +static struct ao_file * +_ao_fat_fd_to_file(int8_t fd) +{ + struct ao_file *file; + if (fd < 0 || AO_FAT_NFILE <= fd) + return NULL; + + file = &ao_file_table[fd]; + if (!file->busy) + return NULL; + return file; +} + static uint8_t ao_filesystem_setup; static uint8_t ao_filesystem_status; static uint8_t -ao_fat_setup(void) +_ao_fat_setup(void) { if (!ao_filesystem_setup) { @@ -595,13 +713,14 @@ ao_fat_setup(void) number_cluster = fat_start = root_start = data_start = 0; next_free = filesystem_full = 0; fat32 = fsinfo_dirty = root_cluster = fsinfo_sector = free_count = 0; - memset(&ao_file_dirent, '\0', sizeof (ao_file_dirent)); - ao_file_offset = ao_file_cluster_offset = ao_file_cluster = ao_file_opened = 0; - ao_filesystem_status = ao_fat_setup_partition(); + /* Reset open file table */ + memset(&ao_file_table, '\0', sizeof (ao_file_table)); + + ao_filesystem_status = _ao_fat_setup_partition(); if (ao_filesystem_status != AO_FAT_FILESYSTEM_SUCCESS) return ao_filesystem_status; - ao_filesystem_status = ao_fat_setup_fs(); + ao_filesystem_status = _ao_fat_setup_fs(); if (ao_filesystem_status != AO_FAT_FILESYSTEM_SUCCESS) return ao_filesystem_status; } @@ -619,7 +738,7 @@ ao_fat_unmount(void) */ static uint32_t -ao_fat_current_sector(void) +_ao_fat_current_sector(struct ao_file *file) { cluster_t cluster_offset; uint32_t sector_offset; @@ -627,87 +746,114 @@ ao_fat_current_sector(void) cluster_t cluster; DBG("current sector offset %d size %d\n", - ao_file_offset, ao_file_dirent.size); + file->offset, file->dirent->size); - if (ao_file_offset > ao_file_dirent.size) + if (file->offset > (offset_t) file->dirent->size) { + printf ("file offset %d larger than size %d\n", + file->offset, file->dirent->size); return 0xffffffff; + } - sector_offset = ao_file_offset >> SECTOR_SHIFT; + sector_offset = file->offset >> SECTOR_SHIFT; - if (!ao_file_cluster || ao_file_offset < ao_file_cluster_offset) { - ao_file_cluster = ao_file_dirent.cluster; - ao_file_cluster_offset = 0; - DBG("\treset to start of file %08x\n", ao_file_cluster); + if (!file->cluster || file->offset < file->cluster_offset) { + file->cluster = file->dirent->cluster; + file->cluster_offset = 0; + DBG("\treset to start of file %08x\n", file->cluster); } - if (ao_file_cluster_offset + bytes_per_cluster <= ao_file_offset) { + if ((offset_t) (file->cluster_offset + bytes_per_cluster) <= file->offset) { cluster_t cluster_distance; cluster_offset = sector_offset / sectors_per_cluster; - cluster_distance = cluster_offset - ao_file_cluster_offset / bytes_per_cluster; + cluster_distance = cluster_offset - file->cluster_offset / bytes_per_cluster; DBG("\tseek forward %d clusters\n", cluster_distance); - cluster = ao_fat_cluster_seek(ao_file_cluster, cluster_distance); + cluster = _ao_fat_cluster_seek(file->cluster, cluster_distance); - if (!ao_fat_cluster_valid(cluster)) + if (!_ao_fat_cluster_valid(cluster)) { + printf ("invalid cluster %08x\n", cluster); return 0xffffffff; - ao_file_cluster = cluster; - ao_file_cluster_offset = cluster_offset * bytes_per_cluster; + } + file->cluster = cluster; + file->cluster_offset = cluster_offset * bytes_per_cluster; } sector_index = sector_offset % sectors_per_cluster; DBG("current cluster %08x sector_index %d sector %d\n", - ao_file_cluster, sector_index, - data_start + (uint32_t) (ao_file_cluster-2) * sectors_per_cluster + sector_index); - return data_start + (uint32_t) (ao_file_cluster-2) * sectors_per_cluster + sector_index; + file->cluster, sector_index, + data_start + (uint32_t) (file->cluster-2) * sectors_per_cluster + sector_index); + return data_start + (uint32_t) (file->cluster-2) * sectors_per_cluster + sector_index; } +/* + * _ao_fat_invaldate_cluster_offset + * + * When the file size gets shrunk, invalidate + * any file structures referencing clusters beyond that point + */ + static void -ao_fat_set_offset(uint32_t offset) +_ao_fat_invalidate_cluster_offset(struct ao_fat_dirent *dirent) { - DBG("Set offset %d\n", offset); - ao_file_offset = offset; + int8_t fd; + struct ao_file *file; + + for (fd = 0; fd < AO_FAT_NFILE; fd++) { + file = &ao_file_table[fd]; + if (!file->busy) + continue; + if (file->dirent == dirent) { + if (file->cluster_offset >= (offset_t) dirent->size) { + file->cluster_offset = 0; + file->cluster = dirent->cluster; + } + } + } } + /* - * ao_fat_set_size + * _ao_fat_set_size * * Set the size of the current file, truncating or extending * the cluster chain as needed */ static int8_t -ao_fat_set_size(uint32_t size) +_ao_fat_set_size(struct ao_file *file, uint32_t size) { uint8_t *dent; cluster_t first_cluster; cluster_t have_clusters, need_clusters; DBG ("Set size %d\n", size); - if (size == ao_file_dirent.size) { + if (size == file->dirent->size) { DBG("\tsize match\n"); return AO_FAT_SUCCESS; } - first_cluster = ao_file_dirent.cluster; - have_clusters = (ao_file_dirent.size + bytes_per_cluster - 1) / bytes_per_cluster; + first_cluster = file->dirent->cluster; + have_clusters = (file->dirent->size + bytes_per_cluster - 1) / bytes_per_cluster; need_clusters = (size + bytes_per_cluster - 1) / bytes_per_cluster; DBG ("\tfirst cluster %08x have %d need %d\n", first_cluster, have_clusters, need_clusters); if (have_clusters != need_clusters) { - if (ao_file_cluster && size >= ao_file_cluster_offset) { - cluster_t offset_clusters = (ao_file_cluster_offset + bytes_per_cluster) / bytes_per_cluster; + if (file->cluster && (offset_t) size > file->cluster_offset) { + cluster_t offset_clusters = (file->cluster_offset + bytes_per_cluster) / bytes_per_cluster; cluster_t extra_clusters = need_clusters - offset_clusters; cluster_t next_cluster; DBG ("\tset size relative offset_clusters %d extra_clusters %d\n", offset_clusters, extra_clusters); - next_cluster = ao_fat_cluster_set_size(ao_file_cluster, extra_clusters); + + /* Need one more to account for file->cluster, which we already have */ + next_cluster = _ao_fat_cluster_set_size(file->cluster, extra_clusters + 1); if (next_cluster == AO_FAT_BAD_CLUSTER) return -AO_FAT_ENOSPC; } else { DBG ("\tset size absolute need_clusters %d\n", need_clusters); - first_cluster = ao_fat_cluster_set_size(first_cluster, need_clusters); + first_cluster = _ao_fat_cluster_set_size(first_cluster, need_clusters); if (first_cluster == AO_FAT_BAD_CLUSTER) return -AO_FAT_ENOSPC; @@ -716,29 +862,34 @@ ao_fat_set_size(uint32_t size) DBG ("\tupdate directory size\n"); /* Update the directory entry */ - dent = ao_fat_root_get(ao_file_dirent.entry); - if (!dent) + dent = _ao_fat_root_get(file->dirent->entry); + if (!dent) { + printf ("dent update failed\n"); return -AO_FAT_EIO; + } put_u32(dent + 0x1c, size); put_u16(dent + 0x1a, first_cluster); if (fat32) put_u16(dent + 0x14, first_cluster >> 16); - ao_fat_root_put(dent, ao_file_dirent.entry, 1); + _ao_fat_root_put(dent, file->dirent->entry, 1); - ao_file_dirent.size = size; - ao_file_dirent.cluster = first_cluster; + file->dirent->size = size; + file->dirent->cluster = first_cluster; + if (have_clusters > need_clusters) + _ao_fat_invalidate_cluster_offset(file->dirent); DBG ("set size done\n"); return AO_FAT_SUCCESS; } /* - * ao_fat_root_init + * _ao_fat_root_init * * Initialize a root directory entry */ static void -ao_fat_root_init(uint8_t *dent, char name[11], uint8_t attr) +_ao_fat_root_init(uint8_t *dent, char name[11], uint8_t attr) { + (void) attr; memset(dent, '\0', 0x20); memmove(dent, name, 11); @@ -770,7 +921,7 @@ ao_fat_root_init(uint8_t *dent, char name[11], uint8_t attr) static void -ao_fat_dirent_init(uint8_t *dent, uint16_t entry, struct ao_fat_dirent *dirent) +_ao_fat_dirent_init(struct ao_fat_dirent *dirent, uint8_t *dent, uint16_t entry) { memcpy(dirent->name, dent + 0x00, 11); dirent->attr = dent[0x0b]; @@ -782,13 +933,13 @@ ao_fat_dirent_init(uint8_t *dent, uint16_t entry, struct ao_fat_dirent *dirent) } /* - * ao_fat_flush_fsinfo + * _ao_fat_flush_fsinfo * * Write out any fsinfo changes to disk */ static void -ao_fat_flush_fsinfo(void) +_ao_fat_flush_fsinfo(void) { uint8_t *fsinfo; @@ -801,11 +952,11 @@ ao_fat_flush_fsinfo(void) if (!fsinfo_sector) return; - fsinfo = ao_fat_sector_get(fsinfo_sector); + fsinfo = _ao_fat_sector_get(fsinfo_sector); if (fsinfo) { put_u32(fsinfo + 0x1e8, free_count); put_u32(fsinfo + 0x1ec, next_free); - ao_fat_sector_put(fsinfo, 1); + _ao_fat_sector_put(fsinfo, 1); } } @@ -819,15 +970,23 @@ ao_fat_flush_fsinfo(void) * Flush any pending I/O to storage */ -void -ao_fat_sync(void) +static void +_ao_fat_sync(void) { - if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) + if (_ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return; - ao_fat_flush_fsinfo(); + _ao_fat_flush_fsinfo(); ao_bufio_flush(); } +void +ao_fat_sync(void) +{ + ao_mutex_get(&ao_fat_mutex); + _ao_fat_sync(); + ao_mutex_put(&ao_fat_mutex); +} + /* * ao_fat_full * @@ -838,29 +997,76 @@ ao_fat_sync(void) int8_t ao_fat_full(void) { - if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) + ao_mutex_get(&ao_fat_mutex); + if (_ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) { + ao_mutex_put(&ao_fat_mutex); return 1; + } + ao_mutex_put(&ao_fat_mutex); return filesystem_full; } +static int8_t +_ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) +{ + uint8_t *dent; + + if (_ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) + return -AO_FAT_EIO; + + for (;;) { + dent = _ao_fat_root_get(*entry); + if (!dent) + return -AO_FAT_EDIREOF; + + if (dent[0] == AO_FAT_DENT_END) { + _ao_fat_root_put(dent, *entry, 0); + return -AO_FAT_EDIREOF; + } + if (dent[0] != AO_FAT_DENT_EMPTY && (dent[0xb] & 0xf) != 0xf) { + _ao_fat_dirent_init(dirent, dent, *entry); + _ao_fat_root_put(dent, *entry, 0); + (*entry)++; + return AO_FAT_SUCCESS; + } + _ao_fat_root_put(dent, *entry, 0); + (*entry)++; + } +} + +int8_t +ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) +{ + int8_t status; + + ao_mutex_get(&ao_fat_mutex); + status = _ao_fat_readdir(entry, dirent); + ao_mutex_put(&ao_fat_mutex); + return status; +} + /* * ao_fat_open * * Open an existing file. */ -int8_t -ao_fat_open(char name[11], uint8_t mode) +static int8_t +_ao_fat_open(char name[11], uint8_t mode) { uint16_t entry = 0; - struct ao_fat_dirent dirent; + static struct ao_fat_dirent dirent; + int8_t status; - if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) + if (_ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return -AO_FAT_EIO; - if (ao_file_opened) - return -AO_FAT_EMFILE; - - while (ao_fat_readdir(&entry, &dirent)) { + for (;;) { + status = _ao_fat_readdir(&entry, &dirent); + if (status < 0) { + if (status == -AO_FAT_EDIREOF) + return -AO_FAT_ENOENT; + return status; + } if (!memcmp(name, dirent.name, 11)) { if (AO_FAT_IS_DIR(dirent.attr)) return -AO_FAT_EISDIR; @@ -868,87 +1074,130 @@ ao_fat_open(char name[11], uint8_t mode) return -AO_FAT_EPERM; if (mode > AO_FAT_OPEN_READ && (dirent.attr & AO_FAT_FILE_READ_ONLY)) return -AO_FAT_EACCESS; - ao_file_dirent = dirent; - ao_fat_set_offset(0); - ao_file_opened = 1; - return AO_FAT_SUCCESS; + return _ao_fat_fd_alloc(&dirent); } } return -AO_FAT_ENOENT; } +int8_t +ao_fat_open(char name[11], uint8_t mode) +{ + int8_t status; + + ao_mutex_get(&ao_fat_mutex); + status = _ao_fat_open(name, mode); + ao_mutex_put(&ao_fat_mutex); + return status; +} + +/* + * ao_fat_close + * + * Close the currently open file + */ +static int8_t +_ao_fat_close(int8_t fd) +{ + struct ao_file *file; + + file = _ao_fat_fd_to_file(fd); + if (!file) + return -AO_FAT_EBADF; + + _ao_fat_fd_free(fd); + _ao_fat_sync(); + return AO_FAT_SUCCESS; +} + +int8_t +ao_fat_close(int8_t fd) +{ + int8_t status; + + ao_mutex_get(&ao_fat_mutex); + status = _ao_fat_close(fd); + ao_mutex_put(&ao_fat_mutex); + return status; +} + /* * ao_fat_creat * * Open and truncate an existing file or * create a new file */ -int8_t -ao_fat_creat(char name[11]) + +static int8_t +_ao_fat_creat(char name[11]) { - uint16_t entry; - int8_t status; - uint8_t *dent; + uint16_t entry; + int8_t fd; + int8_t status; + uint8_t *dent; + struct ao_file *file; - if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) + if (_ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) return -AO_FAT_EIO; - if (ao_file_opened) - return -AO_FAT_EMFILE; + fd = _ao_fat_open(name, AO_FAT_OPEN_WRITE); + if (fd >= 0) { + file = &ao_file_table[fd]; + status = _ao_fat_set_size(file, 0); + if (status < 0) { + _ao_fat_close(fd); + fd = status; + } + } else { + if (fd == -AO_FAT_ENOENT) { + entry = 0; + for (;;) { + dent = _ao_fat_root_get(entry); + if (!dent) { + + if (_ao_fat_root_extend(entry)) + continue; + fd = -AO_FAT_ENOSPC; + break; + } + if (dent[0] == AO_FAT_DENT_EMPTY || dent[0] == AO_FAT_DENT_END) { + fd = _ao_fat_fd_alloc(NULL); + if (fd < 0) { + _ao_fat_root_put(dent, entry, 0); + break; + } - status = ao_fat_open(name, AO_FAT_OPEN_WRITE); + file = &ao_file_table[fd]; + /* Initialize the dent */ + _ao_fat_root_init(dent, name, AO_FAT_FILE_REGULAR); - switch (status) { - case -AO_FAT_SUCCESS: - status = ao_fat_set_size(0); - break; - case -AO_FAT_ENOENT: - entry = 0; - for (;;) { - dent = ao_fat_root_get(entry); - if (!dent) { - - if (ao_fat_root_extend(entry)) - continue; - status = -AO_FAT_ENOSPC; - break; - } - - if (dent[0] == AO_FAT_DENT_EMPTY || dent[0] == AO_FAT_DENT_END) { - ao_fat_root_init(dent, name, AO_FAT_FILE_REGULAR); - ao_fat_dirent_init(dent, entry, &ao_file_dirent); - ao_fat_root_put(dent, entry, 1); - ao_file_opened = 1; - ao_fat_set_offset(0); - status = -AO_FAT_SUCCESS; - break; - } else { - ao_fat_root_put(dent, entry, 0); + /* Now initialize the dirent from the dent */ + _ao_fat_dirent_init(file->dirent, dent, entry); + + /* And write the dent to storage */ + _ao_fat_root_put(dent, entry, 1); + + status = -AO_FAT_SUCCESS; + break; + } else { + _ao_fat_root_put(dent, entry, 0); + } + entry++; } - entry++; } } - return status; + return fd; } -/* - * ao_fat_close - * - * Close the currently open file - */ int8_t -ao_fat_close(void) +ao_fat_creat(char name[11]) { - if (!ao_file_opened) - return -AO_FAT_EBADF; - - memset(&ao_file_dirent, '\0', sizeof (struct ao_fat_dirent)); - ao_file_offset = 0; - ao_file_cluster = 0; - ao_file_opened = 0; + int8_t status; - ao_fat_sync(); - return AO_FAT_SUCCESS; + ao_mutex_get(&ao_fat_mutex); + status = _ao_fat_creat(name); + ao_mutex_put(&ao_fat_mutex); + return status; } /* @@ -958,17 +1207,20 @@ ao_fat_close(void) */ static void * -ao_fat_map_current(int len, cluster_offset_t *offsetp, cluster_offset_t *this_time) +ao_fat_map_current(struct ao_file *file, int len, cluster_offset_t *offsetp, cluster_offset_t *this_time) { cluster_offset_t offset; sector_t sector; void *buf; - offset = ao_file_offset & SECTOR_MASK; - sector = ao_fat_current_sector(); - if (sector == 0xffffffff) + offset = file->offset & SECTOR_MASK; + sector = _ao_fat_current_sector(file); + if (sector == 0xffffffff) { + return NULL; + } + buf = _ao_fat_sector_get(sector); + if (!buf) return NULL; - buf = ao_fat_sector_get(sector); if (offset + len < SECTOR_SIZE) *this_time = len; else @@ -983,37 +1235,44 @@ ao_fat_map_current(int len, cluster_offset_t *offsetp, cluster_offset_t *this_ti * Read from the file */ int -ao_fat_read(void *dst, int len) +ao_fat_read(int8_t fd, void *dst, int len) { uint8_t *dst_b = dst; cluster_offset_t this_time; cluster_offset_t offset; uint8_t *buf; int ret = 0; + struct ao_file *file; - if (!ao_file_opened) - return -AO_FAT_EBADF; + ao_mutex_get(&ao_fat_mutex); + file = _ao_fat_fd_to_file(fd); + if (!file) { + ret = -AO_FAT_EBADF; + goto done; + } - if (ao_file_offset + len > ao_file_dirent.size) - len = ao_file_dirent.size - ao_file_offset; + if (file->offset + len > (offset_t) file->dirent->size) + len = file->dirent->size - file->offset; if (len < 0) len = 0; while (len) { - buf = ao_fat_map_current(len, &offset, &this_time); + buf = ao_fat_map_current(file, len, &offset, &this_time); if (!buf) { ret = -AO_FAT_EIO; break; } memcpy(dst_b, buf + offset, this_time); - ao_fat_sector_put(buf, 0); + _ao_fat_sector_put(buf, 0); ret += this_time; len -= this_time; dst_b += this_time; - ao_fat_set_offset(ao_file_offset + this_time); + file->offset = file->offset + this_time; } +done: + ao_mutex_put(&ao_fat_mutex); return ret; } @@ -1023,37 +1282,44 @@ ao_fat_read(void *dst, int len) * Write to the file, extended as necessary */ int -ao_fat_write(void *src, int len) +ao_fat_write(int8_t fd, void *src, int len) { - uint8_t *src_b = src; - uint16_t this_time; - uint16_t offset; - uint8_t *buf; - int ret = 0; + uint8_t *src_b = src; + cluster_offset_t this_time; + cluster_offset_t offset; + uint8_t *buf; + int ret = 0; + struct ao_file *file; - if (!ao_file_opened) - return -AO_FAT_EBADF; + ao_mutex_get(&ao_fat_mutex); + file = _ao_fat_fd_to_file(fd); + if (!file) { + ret = -AO_FAT_EBADF; + goto done; + } - if (ao_file_offset + len > ao_file_dirent.size) { - ret = ao_fat_set_size(ao_file_offset + len); + if (file->offset + len > (offset_t) file->dirent->size) { + ret = _ao_fat_set_size(file, file->offset + len); if (ret < 0) - return ret; + goto done; } while (len) { - buf = ao_fat_map_current(len, &offset, &this_time); + buf = ao_fat_map_current(file, len, &offset, &this_time); if (!buf) { ret = -AO_FAT_EIO; break; } memcpy(buf + offset, src_b, this_time); - ao_fat_sector_put(buf, 1); + _ao_fat_sector_put(buf, 1); ret += this_time; len -= this_time; src_b += this_time; - ao_fat_set_offset(ao_file_offset + this_time); + file->offset = file->offset + this_time; } +done: + ao_mutex_put(&ao_fat_mutex); return ret; } @@ -1067,13 +1333,20 @@ ao_fat_write(void *src, int len) * write */ int32_t -ao_fat_seek(int32_t pos, uint8_t whence) +ao_fat_seek(int8_t fd, int32_t pos, uint8_t whence) { - uint32_t new_offset = ao_file_offset; - - if (!ao_file_opened) - return -AO_FAT_EBADF; + offset_t new_offset; + struct ao_file *file; + int32_t ret; + + ao_mutex_get(&ao_fat_mutex); + file = _ao_fat_fd_to_file(fd); + if (!file) { + ret = -AO_FAT_EBADF; + goto done; + } + new_offset = file->offset; switch (whence) { case AO_FAT_SEEK_SET: new_offset = pos; @@ -1082,11 +1355,13 @@ ao_fat_seek(int32_t pos, uint8_t whence) new_offset += pos; break; case AO_FAT_SEEK_END: - new_offset = ao_file_dirent.size + pos; + new_offset = file->dirent->size + pos; break; } - ao_fat_set_offset(new_offset); - return ao_file_offset; + ret = file->offset = new_offset; +done: + ao_mutex_put(&ao_fat_mutex); + return ret; } /* @@ -1099,10 +1374,14 @@ int8_t ao_fat_unlink(char name[11]) { uint16_t entry = 0; - struct ao_fat_dirent dirent; + static struct ao_fat_dirent dirent; + int8_t ret; - if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) - return -AO_FAT_EIO; + ao_mutex_get(&ao_fat_mutex); + if (_ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) { + ret = -AO_FAT_EIO; + goto done; + } while (ao_fat_readdir(&entry, &dirent)) { if (memcmp(name, dirent.name, 11) == 0) { @@ -1110,66 +1389,48 @@ ao_fat_unlink(char name[11]) uint8_t *ent; uint8_t delete; - if (AO_FAT_IS_DIR(dirent.attr)) - return -AO_FAT_EISDIR; - if (!AO_FAT_IS_FILE(dirent.attr)) - return -AO_FAT_EPERM; + if (AO_FAT_IS_DIR(dirent.attr)) { + ret = -AO_FAT_EISDIR; + goto done; + } + if (!AO_FAT_IS_FILE(dirent.attr)) { + ret = -AO_FAT_EPERM; + goto done; + } - ao_fat_free_cluster_chain(dirent.cluster); - next = ao_fat_root_get(dirent.entry + 1); + _ao_fat_free_cluster_chain(dirent.cluster); + next = _ao_fat_root_get(dirent.entry + 1); if (next && next[0] != AO_FAT_DENT_END) delete = AO_FAT_DENT_EMPTY; else delete = AO_FAT_DENT_END; if (next) - ao_fat_root_put(next, dirent.entry + 1, 0); - ent = ao_fat_root_get(dirent.entry); + _ao_fat_root_put(next, dirent.entry + 1, 0); + ent = _ao_fat_root_get(dirent.entry); if (ent) { memset(ent, '\0', DIRENT_SIZE); *ent = delete; - ao_fat_root_put(ent, dirent.entry, 1); + _ao_fat_root_put(ent, dirent.entry, 1); } ao_bufio_flush(); - return AO_FAT_SUCCESS; + ret = AO_FAT_SUCCESS; + goto done; } } - return -AO_FAT_ENOENT; + ret = -AO_FAT_ENOENT; +done: + ao_mutex_put(&ao_fat_mutex); + return ret; } int8_t ao_fat_rename(char old[11], char new[11]) { + (void) old; + (void) new; return -AO_FAT_EIO; } -int8_t -ao_fat_readdir(uint16_t *entry, struct ao_fat_dirent *dirent) -{ - uint8_t *dent; - - if (ao_fat_setup() != AO_FAT_FILESYSTEM_SUCCESS) - return -AO_FAT_EIO; - - for (;;) { - dent = ao_fat_root_get(*entry); - if (!dent) - return 0; - - if (dent[0] == AO_FAT_DENT_END) { - ao_fat_root_put(dent, *entry, 0); - return 0; - } - if (dent[0] != AO_FAT_DENT_EMPTY && (dent[0xb] & 0xf) != 0xf) { - ao_fat_dirent_init(dent, *entry, dirent); - ao_fat_root_put(dent, *entry, 0); - (*entry)++; - return 1; - } - ao_fat_root_put(dent, *entry, 0); - (*entry)++; - } -} - #if FAT_COMMANDS static const char *filesystem_errors[] = { @@ -1188,7 +1449,8 @@ ao_fat_mbr_cmd(void) { uint8_t status; - status = ao_fat_setup(); + ao_mutex_get(&ao_fat_mutex); + status = _ao_fat_setup(); if (status == AO_FAT_FILESYSTEM_SUCCESS) { printf ("partition type: %02x\n", partition_type); printf ("partition start: %08x\n", partition_start); @@ -1208,6 +1470,7 @@ ao_fat_mbr_cmd(void) } else { printf ("FAT filesystem not available: %s\n", filesystem_errors[status]); } + ao_mutex_put(&ao_fat_mutex); } struct ao_fat_attr { @@ -1230,22 +1493,25 @@ static void ao_fat_list_cmd(void) { uint16_t entry = 0; - struct ao_fat_dirent dirent; + static struct ao_fat_dirent dirent; int i; + int8_t status; - while (ao_fat_readdir(&entry, &dirent)) { + while ((status = ao_fat_readdir(&entry, &dirent)) == AO_FAT_SUCCESS) { for (i = 0; i < 8; i++) putchar(dirent.name[i]); putchar('.'); for (; i < 11; i++) putchar(dirent.name[i]); - for (i = 0; i < NUM_FAT_ATTR; i++) + for (i = 0; i < (int) NUM_FAT_ATTR; i++) putchar (dirent.attr & ao_fat_attr[i].bit ? ao_fat_attr[i].label : ' '); printf (" @%08x %d\n", dirent.cluster, dirent.size); } + if (status != -AO_FAT_EDIREOF) + printf ("readdir failed: %d\n", status); } -static uint8_t +static void ao_fat_parse_name(char name[11]) { uint8_t c; @@ -1263,15 +1529,17 @@ ao_fat_parse_name(char name[11]) } ao_cmd_lex(); } + while (c < 11) + name[c++] = ' '; } static void -ao_fat_show_cmd(void) +ao_fat_dump_cmd(void) { - char name[11]; - int8_t status; + static char name[11]; + int8_t fd; int cnt, i; - char buf[64]; + static char buf[32]; ao_fat_parse_name(name); if (name[0] == '\0') { @@ -1279,31 +1547,25 @@ ao_fat_show_cmd(void) return; } - status = ao_fat_open(name, AO_FAT_OPEN_READ); - if (status) { - printf ("Open failed: %d\n", status); + fd = ao_fat_open(name, AO_FAT_OPEN_READ); + if (fd < 0) { + printf ("Open failed: %d\n", fd); return; } - while ((cnt = ao_fat_read(buf, sizeof(buf))) > 0) { + while ((cnt = ao_fat_read(fd, buf, sizeof(buf))) > 0) { for (i = 0; i < cnt; i++) putchar(buf[i]); } - ao_fat_close(); -} - -static void -ao_fat_putchar(char c) -{ + ao_fat_close(fd); } static void ao_fat_write_cmd(void) { - char name[11]; - int8_t status; - int cnt, i; - char buf[64]; + static char name[11]; + int8_t fd; char c; + int status; ao_fat_parse_name(name); if (name[0] == '\0') { @@ -1311,9 +1573,9 @@ ao_fat_write_cmd(void) return; } - status = ao_fat_creat(name); - if (status) { - printf ("Open failed: %d\n", status); + fd = ao_fat_creat(name); + if (fd < 0) { + printf ("Open failed: %d\n", fd); return; } flush(); @@ -1323,19 +1585,61 @@ ao_fat_write_cmd(void) if (c == '\n') putchar ('\r'); putchar(c); flush(); } - if (ao_fat_write(&c, 1) != 1) { - printf ("Write failure\n"); + status = ao_fat_write(fd, &c, 1); + if (status != 1) { + printf ("Write failure %d\n", status); break; } } - ao_fat_close(); + ao_fat_close(fd); +} + +static void +put32(uint32_t a) +{ + ao_cmd_put16(a >> 16); + ao_cmd_put16(a); +} + +static void +ao_fat_hexdump_cmd(void) +{ + char name[11]; + int8_t fd; + int cnt, i; + char buf[8]; + uint32_t addr; + + ao_fat_parse_name(name); + if (name[0] == '\0') { + ao_cmd_status = ao_cmd_syntax_error; + return; + } + + fd = ao_fat_open(name, AO_FAT_OPEN_READ); + if (fd < 0) { + printf ("Open failed: %d\n", fd); + return; + } + addr = 0; + while ((cnt = ao_fat_read(fd, buf, sizeof(buf))) > 0) { + put32(addr); + for (i = 0; i < cnt; i++) { + putchar(' '); + ao_cmd_put8(buf[i]); + } + putchar('\n'); + addr += cnt; + } + ao_fat_close(fd); } static const struct ao_cmds ao_fat_cmds[] = { { ao_fat_mbr_cmd, "M\0Show FAT MBR and other info" }, { ao_fat_list_cmd, "F\0List FAT directory" }, - { ao_fat_show_cmd, "S \0Show FAT file" }, + { ao_fat_dump_cmd, "D \0Dump FAT file" }, { ao_fat_write_cmd, "W \0Write FAT file (end with ^D)" }, + { ao_fat_hexdump_cmd, "H \0HEX dump FAT file" }, { 0, NULL }, };