/* * build a map in mem of the files */ #define _GNU_SOURCE #define _FILE_OFFSET_BITS 64 #include #include #include #define NUM_PARTS 2 struct part_table { char type; gulong block_ofs; gulong size; }; guint64 get64(char *ptr) { gint64 *ptr64 = (gint64*) ptr; return GUINT64_FROM_BE(*ptr64); } void traverse_inodes(FILE *fp, gint64 start, gint64 cluster, int cluster_size, int level, int plev, const char *parent, int bucket) { int i; char *buf = malloc(cluster_size); fseeko(fp, start + cluster * cluster_size, SEEK_SET); fread(buf, 1, cluster_size, fp); // check header gint64 me = get64(buf); if (me != cluster) { printf("Incorrect cluster: %llx (wanted %llx)\n", me, cluster); return; } char type = buf[0x53]; char *name = &buf[0x98]; if (type == 'F' || type == 'D') { int printed = strlen(name) + 4 * level; if (plev == level) { for (i=0; i 0) traverse_inodes(fp, start, sibling, cluster_size, level, level, name, 0); else printf("\n"); } } else { printf ("type %u at %llu\n", type, ftell(fp)); } int data_size = GUINT_FROM_BE(*(int*) &buf[8]); int dir_ofs = 0x1b8; char *dirent = &buf[dir_ofs]; for (i=0; type == 'D' && i<(data_size - dir_ofs)/8; i++) { gint64 nextblk = get64(dirent); if (nextblk > 0) { traverse_inodes(fp, start, nextblk, cluster_size, level+1, level, name, i); } dirent+=8; } free(buf); } void display_partition(FILE *fp, int id, struct part_table *part) { char buf[338]; guint clusters, cluster_size, rootptr, mirrors; double size = part->size * 512.0 / 1000000.0; fseeko(fp, part->block_ofs * 512, SEEK_SET); // signature block follows, just skip to the super fseeko(fp, 0x2000, SEEK_CUR); fread(buf, 1, sizeof(buf), fp); clusters = GUINT_FROM_BE(*(gint*) (buf + 0x24)); rootptr = GUINT_FROM_BE(*(gint*) (buf + 0x2c)); cluster_size = GUINT_FROM_BE(*(gint*) (buf + 0x38)); mirrors = GUINT_FROM_BE(*(gint*) (buf + 0x44)); traverse_inodes(fp, part->block_ofs * 512, rootptr, cluster_size, 0, 0, "root", 0); } int read_partitions(FILE *fp, struct part_table *parts) { struct part_table p; char buf[16]; gint32 *iptr = (gint32 *) &buf[8]; int i; fseeko(fp, 0x10e, SEEK_SET); for (i=0; i < NUM_PARTS; i++) { fread(&buf, 1, sizeof(buf), fp); parts[i].type = buf[4]; parts[i].block_ofs = GINT_FROM_LE(*iptr); parts[i].size = GINT_FROM_LE(*(iptr+1)); if (parts[i].type != 0x4d) { fprintf(stderr, "invalid partition type: %02x\n", p.type); return -1; } } return 0; } int main(int argc, char *argv[]) { FILE *fp; int i; struct part_table parts[2]; if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); exit(1); } fp = fopen(argv[1], "rb"); if (!fp) { perror("karma_ls: "); exit(1); } if (read_partitions(fp, parts)) { exit(1); } for (i=0; i<2; i++) display_partition(fp, i, &parts[i]); fclose(fp); }