FreeCalypso > hg > freecalypso-reveng
view mysteryffs/dump2.c @ 408:14302e075f37 default tip
hr-bits: further conditionalize SID-1-diff
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 22 Jul 2024 10:06:38 +0000 |
parents | 9f3a7b014e63 |
children |
line wrap: on
line source
/* * This program attempts to traverse the FFS directory tree * from the root down, following the descendant and sibling * pointers, and dumps everything it encounters. * * The objective is to understand how to extract the precise * content of data files. */ #include <sys/types.h> #include <sys/file.h> #include <sys/stat.h> #include <endian.h> #include <ctype.h> #include <stdio.h> #include <string.h> #include <strings.h> #include <stdlib.h> #include <unistd.h> typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; u8 mysteryffs_hdr[6] = {'F', 'f', 's', '#', 0x10, 0x02}; struct index_entry { u16 len; u8 unknown_b1; u8 type; u16 descend; u16 sibling; u32 dataptr; u16 unknown_w1; u16 unknown_w2; }; char *imgfile; u32 eraseblk_size; int total_blocks; u32 total_img_size; u8 *image, *indexblk; char workpath[512]; read_img_file() { int fd; struct stat st; fd = open(imgfile, O_RDONLY); if (fd < 0) { perror(imgfile); exit(1); } fstat(fd, &st); if (!S_ISREG(st.st_mode)) { fprintf(stderr, "%s is not a regular file\n", imgfile); exit(1); } if (st.st_size < total_img_size) { fprintf(stderr, "%s has fewer than 0x%x bytes\n", imgfile, total_img_size); exit(1); } image = malloc(total_img_size); if (!image) { perror("malloc"); exit(1); } read(fd, image, total_img_size); close(fd); } find_index_block() { int i; u8 *ptr; for (ptr = image, i = 0; i < total_blocks; i++, ptr += eraseblk_size) { if (bcmp(ptr, mysteryffs_hdr, 6)) continue; if (ptr[8] != 0xAB) continue; printf("Found index in erase block #%d (offset %x)\n", i, ptr - image); indexblk = ptr; return(0); } fprintf(stderr, "could not find a MysteryFFS index block in %s\n", imgfile); exit(1); } get_index_entry(num, host) int num; struct index_entry *host; { struct index_entry *le; le = (struct index_entry *) indexblk + num; host->len = le16toh(le->len); host->unknown_b1 = le->unknown_b1; host->type = le->type; host->descend = le16toh(le->descend); host->sibling = le16toh(le->sibling); host->dataptr = le32toh(le->dataptr); host->unknown_w1 = le16toh(le->unknown_w1); host->unknown_w2 = le16toh(le->unknown_w2); } is_namestr_ok(s) char *s; { int cnt; for (cnt = 0; *s; s++, cnt++) { if (cnt >= 32) return(0); if (!isprint(*s)) return(0); } if (cnt) return(1); else return(0); } char * get_name(dptr) u32 dptr; { u8 *name; if (dptr > 0x0FFFFFFF) return(0); dptr <<= 4; if (dptr >= total_img_size - 32) return(0); name = image + dptr; if (is_namestr_ok(name)) return(name); else return(0); } dump_common(idx, rec, path_prefix, typestr, newprefix) int idx, path_prefix, *newprefix; struct index_entry *rec; char *typestr; { u8 *name; name = get_name(rec->dataptr); if (!name) { printf("entry #%x has an invalid name pointer!\n", idx); return(-1); } if (sizeof(workpath) - path_prefix < strlen(name) + 2) { printf("entry #%x: pathname buffer overflow!\n", idx); return(-1); } path_prefix += sprintf(workpath + path_prefix, "/%s", name); printf("\n%s (%s)\n", workpath, typestr); printf("len=%x, unknown fields: %02X %04X %04X\n", rec->len, rec->unknown_b1, rec->unknown_w1, rec->unknown_w2); if (newprefix) *newprefix = path_prefix; return(0); } dump_data_frag(entryidx, rec) struct index_entry *rec; { u32 dptr, endptr; int i, c; if (rec->len & 0xF || !rec->len) { printf("entry #%x: don't know how to dump fragment of length %x\n", entryidx, rec->len); return(-1); } dptr = rec->dataptr; if (dptr > 0x0FFFFFFF) { inv: printf("entry #%x: invalid data pointer\n", entryidx); return(-1); } dptr <<= 4; if (dptr > total_img_size - rec->len) goto inv; for (endptr = dptr + rec->len; dptr < endptr; dptr += 0x10) { printf("%08X: ", dptr); for (i = 0; i < 16; i++) { printf("%02X ", image[dptr + i]); if (i == 7 || i == 15) putchar(' '); } for (i = 0; i < 16; i++) { c = image[dptr + i]; if (!isprint(c)) c = '.'; putchar(c); } putchar('\n'); } return(0); } dump_file_chain(firstent) { struct index_entry rec; int ent; for (ent = firstent; ent != 0xFFFF; ent = rec.descend) { get_index_entry(ent, &rec); if (rec.type == 0xF4) { printf("\nfile continuation (entry #%x)\n", ent); printf("len=%x, unknown fields: %02X %04X %04X\n", rec.len, rec.unknown_b1, rec.unknown_w1, rec.unknown_w2); dump_data_frag(ent, &rec); } else { printf("\ncontinuation entry at %x: type %02X != F4\n", ent, rec.type); printf("len=%x, unknown fields: %02X %04X %04X\n", rec.len, rec.unknown_b1, rec.unknown_w1, rec.unknown_w2); } if (rec.sibling != 0xFFFF) printf("warning: non-nil sibling pointer\n"); } } dump_dir(firstent, path_prefix) { struct index_entry rec; int ent; int subprefix; for (ent = firstent; ent != 0xFFFF; ent = rec.sibling) { get_index_entry(ent, &rec); switch (rec.type) { case 0x00: /* deleted object - skip it */ continue; case 0xF2: /* subdirectory */ if (dump_common(ent, &rec, path_prefix, "directory", &subprefix) < 0) continue; dump_dir(rec.descend, subprefix); continue; case 0xF1: /* regular file */ if (dump_common(ent, &rec, path_prefix, "file", 0) < 0) continue; dump_data_frag(ent, &rec); dump_file_chain(rec.descend); continue; case 0xE1: /* special .journal file */ if (dump_common(ent, &rec, path_prefix, "E1 file", 0)<0) continue; dump_data_frag(ent, &rec); dump_file_chain(rec.descend); continue; default: printf("entry #%x: unexpected type %02X\n", ent, rec.type); } } } dump_root() { struct index_entry rec; char *name; get_index_entry(1, &rec); if (rec.type != 0xF2) { fprintf(stderr, "error: entry #1 (expected root dir) is not a directory\n"); exit(1); } name = get_name(rec.dataptr); if (!name) { fprintf(stderr, "root entry has an invalid name pointer!\n"); exit(1); } printf("Root node name: %s\n", name); printf("len=%x, unknown fields: %02X %04X %04X\n", rec.len, rec.unknown_b1, rec.unknown_w1, rec.unknown_w2); if (rec.sibling != 0xFFFF) printf("warning: root entry has a non-nil sibling pointer\n"); dump_dir(rec.descend, 0); } main(argc, argv) char **argv; { if (argc != 4) { fprintf(stderr, "usage: %s imgfile blksize nblocks\n", argv[0]); exit(1); } imgfile = argv[1]; eraseblk_size = strtoul(argv[2], 0, 0); total_blocks = strtoul(argv[3], 0, 0); total_img_size = eraseblk_size * total_blocks; read_img_file(); find_index_block(); dump_root(); exit(0); }