/* Spew FAT tracing */
#define FAT_TRACE 0
+#ifdef DBG
+#undef DBG
+#endif
+
#if FAT_TRACE
#define DBG(...) printf(__VA_ARGS__)
#else
static cluster_t
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;
}
if (!fat32)
return 0;
- byte_size = ents * 0x20;
- cluster_size = byte_size / bytes_per_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;
return ao_filesystem_status;
}
+void
+ao_fat_unmount(void)
+{
+ ao_filesystem_setup = 0;
+}
+
/*
* Basic file operations
*/
for (;;) {
dent = ao_fat_root_get(*entry);
if (!dent)
- return 0;
+ return -AO_FAT_EDIREOF;
if (dent[0] == AO_FAT_DENT_END) {
ao_fat_root_put(dent, *entry, 0);
- return 0;
+ return -AO_FAT_EDIREOF;
}
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;
+ return AO_FAT_SUCCESS;
}
ao_fat_root_put(dent, *entry, 0);
(*entry)++;
uint16_t entry = 0;
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('.');
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
}
ao_cmd_lex();
}
+ while (c < 11)
+ name[c++] = ' ';
}
static void