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; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 #include <openssl/md5.h>
33 ao_mutex_get(uint8_t *mutex)
38 ao_mutex_put(uint8_t *mutex)
43 ao_panic(uint8_t panic)
45 printf ("panic %d\n", panic);
49 #define AO_PANIC_BUFIO 15
51 #define ao_cmd_success 0
53 uint8_t ao_cmd_status;
54 uint32_t ao_cmd_lex_u32;
61 #define ao_cmd_register(x)
70 uint64_t total_reads, total_writes;
73 ao_sdcard_read_block(uint32_t block, uint8_t *data)
76 lseek(fs_fd, block * 512, 0);
77 return read(fs_fd, data, 512) == 512;
81 ao_sdcard_write_block(uint32_t block, uint8_t *data)
84 lseek(fs_fd, block * 512, 0);
85 return write(fs_fd, data, 512) == 512;
92 { .fat = 16, .blocks = 16384 },
93 { .fat = 32, .blocks = 16384 },
94 { .fat = 16, .blocks = 65536 },
95 { .fat = 32, .blocks = 65536 },
96 { .fat = 16, .blocks = 1048576 },
97 { .fat = 32, .blocks = 1048576 },
98 { .fat = 0, .blocks = 0 },
102 struct fs_param *param;
113 snprintf(cmd, sizeof(cmd), "rm -f %s && mkfs.vfat -F %d -C %s %d",
114 fs, param->fat, fs, param->blocks);
115 if (system (cmd) != 0) {
116 fprintf(stderr, "'%s' failed\n", cmd);
126 #include "ao_bufio.c"
128 check_bufio(char *where)
132 for (b = 0; b < AO_NUM_BUF; b++) {
133 if (ao_bufio[b].busy) {
134 printf ("%s: buffer %d busy. block %d seqno %u\n",
135 where, b, ao_bufio[b].block, ao_bufio[b].seqno & 0xffff);
147 /* Get the next cluster entry in the chain */
149 ao_fat_entry_raw_read(cluster_t cluster, uint8_t fat)
152 cluster_offset_t offset;
160 sector = cluster >> SECTOR_SHIFT;
161 offset = cluster & SECTOR_MASK;
162 buf = _ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector);
166 ret = get_u32(buf + offset);
168 ret = get_u16(buf + offset);
169 _ao_fat_sector_put(buf, 0);
178 printf ("\n **** FAT ****\n\n");
179 for (e = 0; e < number_cluster; e++) {
180 if ((e & 0xf) == 0x0)
181 printf ("%04x: ", e);
183 printf (" %08x", ao_fat_entry_raw_read(e, 0));
185 printf (" %04x", ao_fat_entry_raw_read(e, 0));
186 if ((e & 0xf) == 0xf)
197 struct ao_fat_dirent dirent;
199 printf (" **** Root directory ****\n");
200 while (ao_fat_readdir(&entry, &dirent)) {
201 printf ("%04x: %-8.8s.%-3.3s %02x %04x %d\n",
210 printf (" **** End of root directory ****\n");
214 fatal(char *msg, ...)
221 vfprintf(stderr, msg, l);
233 for (e = 0; e < number_cluster; e++) {
234 cluster_t v = ao_fat_entry_raw_read(e, 0);
235 for (f = 1; f < number_fat; f++) {
236 cluster_t o = ao_fat_entry_raw_read(e, f);
238 fatal ("fats differ at %08x (0 %08x %d %08x)\n", e, v, f, o);
244 check_file(dirent_t dent, cluster_t first_cluster, dirent_t *used)
246 cluster_t clusters = 0;
252 for (cluster = first_cluster;
253 fat32 ? !AO_FAT_IS_LAST_CLUSTER(cluster) : !AO_FAT_IS_LAST_CLUSTER16(cluster);
254 cluster = ao_fat_entry_raw_read(cluster, 0))
256 if (!_ao_fat_cluster_valid(cluster))
257 fatal("file %d: invalid cluster %08x\n", dent, cluster);
259 fatal("file %d: duplicate cluster %08x also in file %d\n", dent, cluster, used[cluster]-1);
260 used[cluster] = dent;
270 cluster_t cluster, chain;
276 used = calloc(sizeof (dirent_t), number_cluster);
278 for (r = 0; (dent = _ao_fat_root_get(r)); r++) {
281 cluster_t first_cluster;
285 fatal("cannot map dent %d\n", r);
286 memcpy(name, dent+0, 11);
287 first_cluster = get_u16(dent + 0x1a);
289 first_cluster |= (cluster_t) get_u16(dent + 0x14) << 16;
290 size = get_u32(dent + 0x1c);
291 _ao_fat_root_put(dent, r, 0);
293 if (name[0] == AO_FAT_DENT_END) {
297 clusters = check_file(r + 1, first_cluster, used);
300 fatal("file %d: zero sized, but %d clusters\n", clusters);
302 if (size > clusters * bytes_per_cluster)
303 fatal("file %d: size %u beyond clusters %d (%u)\n",
304 r, size, clusters, clusters * bytes_per_cluster);
305 if (size <= (clusters - 1) * bytes_per_cluster)
306 fatal("file %d: size %u too small clusters %d (%u)\n",
307 r, size, clusters, clusters * bytes_per_cluster);
311 for (; r < root_entries; r++) {
312 uint8_t *dent = _ao_fat_root_get(r);
314 fatal("cannot map dent %d\n", r);
315 if (dent[0] != AO_FAT_DENT_END)
316 fatal("found non-zero dent past end %d\n", r);
317 _ao_fat_root_put(dent, r, 0);
320 check_file((dirent_t) -1, root_cluster, used);
323 for (cluster = 0; cluster < 2; cluster++) {
324 chain = ao_fat_entry_raw_read(cluster, 0);
327 if ((chain & 0xffffff8) != 0xffffff8)
328 fatal("cluster %d: not marked busy\n", cluster);
330 if ((chain & 0xfff8) != 0xfff8)
331 fatal("cluster %d: not marked busy\n", cluster);
334 for (; cluster < number_cluster; cluster++) {
335 chain = ao_fat_entry_raw_read(cluster, 0);
338 if (used[cluster] == 0)
339 fatal("cluster %d: marked busy, but not in any file\n", cluster);
341 if (used[cluster] != 0)
342 fatal("cluster %d: marked free, but found in file %d\n", cluster, used[cluster]-1);
347 #define NUM_FILES 100
348 #define LINES_FILE 500000
350 uint32_t sizes[NUM_FILES];
352 unsigned char md5[NUM_FILES][MD5_DIGEST_LENGTH];
358 char name[] = "FOO ";
362 printf ("write once\n");
363 if ((fd = ao_fat_creat(name)) >= 0) {
364 ao_fat_write(fd, "hello world\n", 12);
368 printf ("read first\n");
369 if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) {
370 len = ao_fat_read(fd, buf, sizeof(buf));
375 printf ("write again\n");
376 if ((fd = ao_fat_creat(name)) >= 0) {
377 ao_fat_write(fd, "hi\n", 3);
381 printf ("read again\n");
382 if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) {
383 len = ao_fat_read(fd, buf, sizeof(buf));
388 printf ("write 3\n");
389 if ((fd = ao_fat_creat(name)) >= 0) {
393 for (l = 0; l < 10; l++) {
394 for (c = ' '; c < '~'; c++)
395 ao_fat_write(fd, &c, 1);
397 ao_fat_write(fd, &c, 1);
403 if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) {
404 while ((len = ao_fat_read(fd, buf, sizeof(buf))) > 0)
410 printf ("all done\n");
421 if ((fd = ao_fat_open("HELLO TXT",AO_FAT_OPEN_READ)) >= 0) {
422 printf ("File contents for HELLO.TXT\n");
423 while ((len = ao_fat_read(fd, buf, sizeof(buf))))
428 if ((fd = ao_fat_creat("NEWFILE TXT")) >= 0) {
429 printf ("Create new file\n");
430 for (len = 0; len < 2; len++)
431 ao_fat_write(fd, "hello, world!\n", 14);
432 ao_fat_seek(fd, 0, AO_FAT_SEEK_SET);
433 printf ("read new file\n");
434 while ((len = ao_fat_read(fd, buf, sizeof (buf))))
448 unsigned char md5_check[MD5_DIGEST_LENGTH];
452 uint64_t total_file_size = 0;
454 total_reads = total_writes = 0;
456 printf (" **** Creating %d files\n", NUM_FILES);
458 memset(sizes, '\0', sizeof (sizes));
459 for (id = 0; id < NUM_FILES; id++) {
460 sprintf(name, "D%07dTXT", id);
461 if ((id % ((NUM_FILES+49)/50)) == 0) {
462 printf ("."); fflush(stdout);
464 if ((fd = ao_fat_creat(name)) >= 0) {
467 check_bufio("file created");
469 for (j = 0; j < LINES_FILE; j++) {
471 sprintf (line, "Hello, world %d %d\r\n", id, j);
473 ret = ao_fat_write(fd, line, len);
476 total_file_size += ret;
477 MD5_Update(&ctx, line, ret);
480 printf ("write failed %d\n", ret);
483 MD5_Final(&md5[id][0], &ctx);
484 check_bufio("file written");
488 printf ("\n **** Write IO: read %llu write %llu data sectors %llu\n", total_reads, total_writes, (total_file_size + 511) / 512);
490 check_bufio("all files created");
491 printf (" **** All done creating files\n");
494 total_reads = total_writes = 0;
496 printf (" **** Comparing %d files\n", NUM_FILES);
498 for (id = 0; id < NUM_FILES; id++) {
500 sprintf(name, "D%07dTXT", id);
502 if ((id % ((NUM_FILES+49)/50)) == 0) {
503 printf ("."); fflush(stdout);
505 if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) {
507 while ((len = ao_fat_read(fd, buf, sizeof(buf))) > 0) {
508 MD5_Update(&ctx, buf, len);
512 MD5_Final(md5_check, &ctx);
513 if (size != sizes[id])
514 fatal("file %d: size differs %d written %d read\n",
515 id, sizes[id], size);
516 if (memcmp(md5_check, &md5[id][0], sizeof (md5_check)) != 0)
517 fatal ("file %d: checksum failed\n", id);
518 check_bufio("file shown");
521 printf ("\n **** Read IO: read %llu write %llu\n", total_reads, total_writes);
529 "-F 16 -C %s 1048576",
530 "-F 32 -C %s 1048576",
535 do_test(void (*test)(void))
543 check_bufio("after setup");
549 main(int argc, char **argv)
556 for (p = 0; fs_params[p].fat; p++) {
557 param = &fs_params[p];
559 do_test(micro_test_fs);
560 do_test(short_test_fs);
561 do_test(long_test_fs);