+ cluster_t e;
+ int f;
+
+ for (e = 0; e < number_cluster; e++) {
+ cluster_t v = ao_fat_entry_raw_read(e, 0);
+ for (f = 1; f < number_fat; f++) {
+ cluster_t o = ao_fat_entry_raw_read(e, f);
+ if (o != v)
+ fatal ("fats differ at %08x (0 %08x %d %08x)\n", e, v, f, o);
+ }
+ }
+}
+
+cluster_t
+check_file(dirent_t dent, cluster_t first_cluster, dirent_t *used)
+{
+ cluster_t clusters = 0;
+ cluster_t cluster;
+
+ if (!first_cluster)
+ return 0;
+
+ for (cluster = first_cluster;
+ fat32 ? !AO_FAT_IS_LAST_CLUSTER(cluster) : !AO_FAT_IS_LAST_CLUSTER16(cluster);
+ cluster = ao_fat_entry_raw_read(cluster, 0))
+ {
+ if (!_ao_fat_cluster_valid(cluster))
+ fatal("file %d: invalid cluster %08x\n", dent, cluster);
+ if (used[cluster])
+ fatal("file %d: duplicate cluster %08x also in file %d\n", dent, cluster, used[cluster]-1);
+ used[cluster] = dent;
+ clusters++;
+ }
+ return clusters;
+}
+
+void
+check_fs(void)
+{
+ dirent_t r;
+ cluster_t cluster, chain;
+ dirent_t *used;
+ uint8_t *dent;
+
+ check_fat();
+
+ used = calloc(sizeof (dirent_t), number_cluster);
+
+ for (r = 0; (dent = _ao_fat_root_get(r)); r++) {
+ cluster_t clusters;
+ offset_t size;
+ cluster_t first_cluster;
+ char name[11];
+
+ if (!dent)
+ fatal("cannot map dent %d\n", r);
+ memcpy(name, dent+0, 11);
+ first_cluster = get_u16(dent + 0x1a);
+ if (fat32)
+ first_cluster |= (cluster_t) get_u16(dent + 0x14) << 16;
+ size = get_u32(dent + 0x1c);
+ _ao_fat_root_put(dent, r, 0);
+
+ if (name[0] == AO_FAT_DENT_END) {
+ break;
+ }
+
+ clusters = check_file(r + 1, first_cluster, used);
+ if (size == 0) {
+ if (clusters != 0)
+ fatal("file %d: zero sized, but %d clusters\n", clusters);
+ } else {
+ if (size > clusters * bytes_per_cluster)
+ fatal("file %d: size %u beyond clusters %d (%u)\n",
+ r, size, clusters, clusters * bytes_per_cluster);
+ if (size <= (clusters - 1) * bytes_per_cluster)
+ fatal("file %d: size %u too small clusters %d (%u)\n",
+ r, size, clusters, clusters * bytes_per_cluster);
+ }
+ }
+ if (!fat32) {
+ for (; r < root_entries; r++) {
+ uint8_t *dent = _ao_fat_root_get(r);
+ if (!dent)
+ fatal("cannot map dent %d\n", r);
+ if (dent[0] != AO_FAT_DENT_END)
+ fatal("found non-zero dent past end %d\n", r);
+ _ao_fat_root_put(dent, r, 0);
+ }
+ } else {
+ check_file((dirent_t) -1, root_cluster, used);
+ }
+
+ for (cluster = 0; cluster < 2; cluster++) {
+ chain = ao_fat_entry_raw_read(cluster, 0);
+
+ if (fat32) {
+ if ((chain & 0xffffff8) != 0xffffff8)
+ fatal("cluster %d: not marked busy\n", cluster);
+ } else {
+ if ((chain & 0xfff8) != 0xfff8)
+ fatal("cluster %d: not marked busy\n", cluster);
+ }
+ }
+ for (; cluster < number_cluster; cluster++) {
+ chain = ao_fat_entry_raw_read(cluster, 0);
+
+ if (chain != 0) {
+ if (used[cluster] == 0)
+ fatal("cluster %d: marked busy, but not in any file\n", cluster);
+ } else {
+ if (used[cluster] != 0)
+ fatal("cluster %d: marked free, but found in file %d\n", cluster, used[cluster]-1);
+ }
+ }
+}
+
+#define NUM_FILES 100
+#define LINES_FILE 500000
+
+uint32_t sizes[NUM_FILES];
+
+unsigned char md5[NUM_FILES][MD5_DIGEST_LENGTH];
+
+void
+micro_test_fs(void)
+{
+ int8_t fd;
+ char name[] = "FOO ";
+ char buf[512];