*
* 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
return write(fs_fd, data, 512) == 512;
}
-char *fs = "fs.fat";
+struct fs_param {
+ int fat;
+ int blocks;
+} fs_params[] = {
+ { .fat = 16, .blocks = 16384 },
+ { .fat = 32, .blocks = 16384 },
+ { .fat = 16, .blocks = 65536 },
+ { .fat = 32, .blocks = 65536 },
+ { .fat = 16, .blocks = 1048576 },
+ { .fat = 32, .blocks = 1048576 },
+ { .fat = 0, .blocks = 0 },
+};
+
+char *fs = "fs.fat";
+struct fs_param *param;
void
ao_sdcard_init(void)
{
char cmd[1024];
- snprintf(cmd, sizeof(cmd), "rm -f %s && mkfs.vfat -C %s 16384", fs, fs);
+ if (fs_fd) {
+ close(fs_fd);
+ fs_fd = 0;
+ }
+ snprintf(cmd, sizeof(cmd), "rm -f %s && mkfs.vfat -F %d -C %s %d",
+ fs, param->fat, fs, param->blocks);
if (system (cmd) != 0) {
fprintf(stderr, "'%s' failed\n", cmd);
exit(1);
#include "ao_fat.c"
/* Get the next cluster entry in the chain */
-static uint16_t
-ao_fat_entry_raw_read(uint16_t cluster, uint8_t fat)
+static cluster_t
+ao_fat_entry_raw_read(cluster_t cluster, uint8_t fat)
{
- uint32_t sector;
- uint16_t offset;
- uint8_t *buf;
- uint16_t ret;
-
-// cluster -= 2;
- sector = cluster >> (SECTOR_SHIFT - 1);
- offset = (cluster << 1) & SECTOR_MASK;
- buf = ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector);
+ sector_t sector;
+ cluster_offset_t offset;
+ uint8_t *buf;
+ cluster_t ret;
+
+ if (fat32)
+ cluster <<= 2;
+ else
+ cluster <<= 1;
+ sector = cluster >> SECTOR_SHIFT;
+ offset = cluster & SECTOR_MASK;
+ buf = _ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector);
if (!buf)
return 0;
- ret = get_u16(buf + offset);
- ao_fat_sector_put(buf, 0);
+ if (fat32)
+ ret = get_u32(buf + offset);
+ else
+ ret = get_u16(buf + offset);
+ _ao_fat_sector_put(buf, 0);
return ret;
}
for (e = 0; e < number_cluster; e++) {
if ((e & 0xf) == 0x0)
printf ("%04x: ", e);
- printf (" %04x", ao_fat_entry_raw_read(e, 0));
+ if (fat32)
+ printf (" %08x", ao_fat_entry_raw_read(e, 0));
+ else
+ printf (" %04x", ao_fat_entry_raw_read(e, 0));
if ((e & 0xf) == 0xf)
putchar ('\n');
}
+ if (e & 0xf)
+ putchar('\n');
}
void
fat_list(void)
{
- uint16_t entry = 0;
+ dirent_t entry = 0;
struct ao_fat_dirent dirent;
printf (" **** Root directory ****\n");
void
fatal(char *msg, ...)
{
- dump_fat();
- fat_list();
+// dump_fat();
+// fat_list();
va_list l;
va_start(l, msg);
void
check_fat(void)
{
- int e;
- int f;
+ cluster_t e;
+ int f;
for (e = 0; e < number_cluster; e++) {
- uint16_t v = ao_fat_entry_raw_read(e, 0);
+ cluster_t v = ao_fat_entry_raw_read(e, 0);
for (f = 1; f < number_fat; f++) {
- if (ao_fat_entry_raw_read(e, f) != v)
- fatal ("fats differ at %d\n", e);
+ 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);
}
}
}
-uint16_t
-check_file(uint16_t dent, uint16_t first_cluster, uint8_t *used)
+cluster_t
+check_file(dirent_t dent, cluster_t first_cluster, dirent_t *used)
{
- uint16_t clusters = 0;
- uint16_t cluster;
+ cluster_t clusters = 0;
+ cluster_t cluster;
if (!first_cluster)
return 0;
for (cluster = first_cluster;
- (cluster & 0xfff8) != 0xfff8;
+ 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 %04x\n", dent, cluster);
+ if (!_ao_fat_cluster_valid(cluster))
+ fatal("file %d: invalid cluster %08x\n", dent, cluster);
if (used[cluster])
- fatal("file %d: duplicate cluster %04x\n", dent, cluster);
- used[cluster] = 1;
+ 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)
{
- uint16_t r;
- uint16_t cluster, chain;
- uint8_t *used;
+ dirent_t r;
+ cluster_t cluster, chain;
+ dirent_t *used;
+ uint8_t *dent;
check_fat();
- used = calloc(1, number_cluster);
+ used = calloc(sizeof (dirent_t), number_cluster);
- for (r = 0; r < root_entries; r++) {
- uint8_t *dent = ao_fat_root_get(r);
- uint16_t clusters;
- uint32_t size;
- uint16_t first_cluster;
- uint8_t name[11];
+ 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);
+ _ao_fat_root_put(dent, r, 0);
if (name[0] == AO_FAT_DENT_END) {
break;
}
- clusters = check_file(r, first_cluster, used);
+ clusters = check_file(r + 1, first_cluster, used);
if (size == 0) {
if (clusters != 0)
fatal("file %d: zero sized, but %d clusters\n", clusters);
r, size, clusters, clusters * bytes_per_cluster);
}
}
- 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);
+ 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 ((chain & 0xfff8) != 0xfff8)
- fatal("cluster %d: not marked busy\n", cluster);
+ 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);
fatal("cluster %d: marked busy, but not in any file\n", cluster);
} else {
if (used[cluster] != 0)
- fatal("cluster %d: marked free, but foudn in file\n", cluster);
+ fatal("cluster %d: marked free, but found in file %d\n", cluster, used[cluster]-1);
}
}
}
-#define NUM_FILES 10
-#define LINES_FILE 80000
+#define NUM_FILES 100
+#define LINES_FILE 500000
uint32_t sizes[NUM_FILES];
unsigned char md5[NUM_FILES][MD5_DIGEST_LENGTH];
-int
-main(int argc, char **argv)
+void
+micro_test_fs(void)
+{
+ int8_t fd;
+ char name[] = "FOO ";
+ char buf[512];
+ int len;
+
+ printf ("write once\n");
+ if ((fd = ao_fat_creat(name)) >= 0) {
+ ao_fat_write(fd, "hello world\n", 12);
+ ao_fat_close(fd);
+ }
+
+ printf ("read first\n");
+ if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) {
+ len = ao_fat_read(fd, buf, sizeof(buf));
+ write (1, buf, len);
+ ao_fat_close(fd);
+ }
+
+ printf ("write again\n");
+ if ((fd = ao_fat_creat(name)) >= 0) {
+ ao_fat_write(fd, "hi\n", 3);
+ ao_fat_close(fd);
+ }
+
+ printf ("read again\n");
+ if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) {
+ len = ao_fat_read(fd, buf, sizeof(buf));
+ write (1, buf, len);
+ ao_fat_close(fd);
+ }
+
+ printf ("write 3\n");
+ if ((fd = ao_fat_creat(name)) >= 0) {
+ int l;
+ char c;
+
+ for (l = 0; l < 10; l++) {
+ for (c = ' '; c < '~'; c++)
+ ao_fat_write(fd, &c, 1);
+ c = '\n';
+ ao_fat_write(fd, &c, 1);
+ }
+ ao_fat_close(fd);
+ }
+
+ printf ("read 3\n");
+ if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) {
+ while ((len = ao_fat_read(fd, buf, sizeof(buf))) > 0)
+ write (1, buf, len);
+ ao_fat_close(fd);
+ }
+
+ check_fs();
+ printf ("all done\n");
+}
+
+
+void
+short_test_fs(void)
+{
+ int len;
+ int8_t fd;
+ char buf[345];
+
+ if ((fd = ao_fat_open("HELLO TXT",AO_FAT_OPEN_READ)) >= 0) {
+ printf ("File contents for HELLO.TXT\n");
+ while ((len = ao_fat_read(fd, buf, sizeof(buf))))
+ write(1, buf, len);
+ ao_fat_close(fd);
+ }
+
+ if ((fd = ao_fat_creat("NEWFILE TXT")) >= 0) {
+ printf ("Create new file\n");
+ for (len = 0; len < 2; len++)
+ ao_fat_write(fd, "hello, world!\n", 14);
+ ao_fat_seek(fd, 0, AO_FAT_SEEK_SET);
+ printf ("read new file\n");
+ while ((len = ao_fat_read(fd, buf, sizeof (buf))))
+ write (1, buf, len);
+ ao_fat_close(fd);
+ }
+
+ check_fs();
+}
+
+void
+long_test_fs(void)
{
char name[12];
int id;
MD5_CTX ctx;
unsigned char md5_check[MD5_DIGEST_LENGTH];
+ char buf[337];
+ int len;
+ int8_t fd;
+ uint64_t total_file_size = 0;
- if (argv[1])
- fs = argv[1];
-
- ao_fat_init();
-
- check_bufio("top");
- ao_fat_setup();
+ total_reads = total_writes = 0;
- check_fs();
- check_bufio("after setup");
printf (" **** Creating %d files\n", NUM_FILES);
+ memset(sizes, '\0', sizeof (sizes));
for (id = 0; id < NUM_FILES; id++) {
sprintf(name, "D%07dTXT", id);
- if (ao_fat_creat(name) == AO_FAT_SUCCESS) {
+ if ((id % ((NUM_FILES+49)/50)) == 0) {
+ printf ("."); fflush(stdout);
+ }
+ if ((fd = ao_fat_creat(name)) >= 0) {
int j;
char line[64];
check_bufio("file created");
int len, ret;
sprintf (line, "Hello, world %d %d\r\n", id, j);
len = strlen(line);
- ret = ao_fat_write((uint8_t *) line, len);
+ ret = ao_fat_write(fd, line, len);
if (ret <= 0)
break;
+ total_file_size += ret;
MD5_Update(&ctx, line, ret);
sizes[id] += ret;
if (ret != len)
printf ("write failed %d\n", ret);
}
- ao_fat_close();
+ ao_fat_close(fd);
MD5_Final(&md5[id][0], &ctx);
check_bufio("file written");
}
}
+ printf ("\n **** Write IO: read %llu write %llu data sectors %llu\n", total_reads, total_writes, (total_file_size + 511) / 512);
+
check_bufio("all files created");
printf (" **** All done creating files\n");
check_fs();
+ total_reads = total_writes = 0;
+
printf (" **** Comparing %d files\n", NUM_FILES);
for (id = 0; id < NUM_FILES; id++) {
- char buf[337];
uint32_t size;
sprintf(name, "D%07dTXT", id);
size = 0;
- if (ao_fat_open(name, AO_FAT_OPEN_READ) == AO_FAT_SUCCESS) {
- int len;
-
+ if ((id % ((NUM_FILES+49)/50)) == 0) {
+ printf ("."); fflush(stdout);
+ }
+ if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) {
MD5_Init(&ctx);
- while ((len = ao_fat_read((uint8_t *) buf, sizeof(buf))) > 0) {
+ while ((len = ao_fat_read(fd, buf, sizeof(buf))) > 0) {
MD5_Update(&ctx, buf, len);
size += len;
}
- ao_fat_close();
+ ao_fat_close(fd);
MD5_Final(md5_check, &ctx);
if (size != sizes[id])
fatal("file %d: size differs %d written %d read\n",
check_bufio("file shown");
}
}
+ printf ("\n **** Read IO: read %llu write %llu\n", total_reads, total_writes);
+}
+
+char *params[] = {
+ "-F 16 -C %s 16384",
+ "-F 32 -C %s 16384",
+ "-F 16 -C %s 65536",
+ "-F 32 -C %s 65536",
+ "-F 16 -C %s 1048576",
+ "-F 32 -C %s 1048576",
+ NULL
+};
+
+void
+do_test(void (*test)(void))
+{
+ ao_fat_init();
+
+ check_bufio("top");
+ _ao_fat_setup();
+
+ check_fs();
+ check_bufio("after setup");
+ (*test)();
+ ao_fat_unmount();
+}
+
+int
+main(int argc, char **argv)
+{
+ int p;
+
+ if (argv[1])
+ fs = argv[1];
+
+ for (p = 0; fs_params[p].fat; p++) {
+ param = &fs_params[p];
+
+ do_test(micro_test_fs);
+ do_test(short_test_fs);
+ do_test(long_test_fs);
+ }
+ unlink (fs);
- printf ("\n **** Total IO: read %llu write %llu\n", total_reads, total_writes);
return 0;
}