view mpffs/dbgls.c @ 215:d69f7512e3c1

Pirelli: documented and verified the checksum scheme used for the factory block
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 25 Dec 2016 23:48:16 +0000
parents e9c6d6615f32
children
line wrap: on
line source

/*
 * Whereas mpffs-ls is more user-oriented, mpffs-dbgls is structured a little
 * different in order to provide a more low-level view of the FFS structure.
 */

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include "types.h"
#include "struct.h"

extern char *imgfile;
extern u8 *image;
extern struct objinfo root;
extern int verbose;

char workpath[512];

void
dump_extra_chunks(first_extra_chunk)
{
	int ent;
	struct objinfo ch;
	struct chunkinfo chi;

	for (ent = first_extra_chunk; ent != 0xFFFF; ent = ch.descend) {
loop:		ch.entryno = ent;
		get_index_entry(&ch);
		switch (ch.type) {
		case 0xF4:
			validate_chunk(&ch);
			printf("  #%x chunk addr=0x%x len=0x%x\n", ch.entryno,
				ch.offset, ch.len);
			size_extra_chunk(&ch, &chi);
			printf("  extra chunk: %lu bytes at 0x%lx\n",
				(u_long) chi.len, (u_long)(chi.start-image));
			break;
		case 0x00:
			printf("  #%x marked as deleted\n", ch.entryno);
			if (ch.sibling == 0xFFFF) {
				printf("  nil sibling pointer!\n");
				break;
			}
			ent = ch.sibling;
			printf("  relocated to #%x\n", ent);
			goto loop;
		default:
			printf(
	"  file continuation object at index %x: unexpected type %02X\n",
				ent, ch.type);
		}
		if (ch.sibling != 0xFFFF)
			printf(
	"  file continuation object (index %x) has a non-nil sibling pointer\n",
				ent);
	}
}

void
dump_object(obj)
	struct objinfo *obj;
{
	int typechar;
	struct chunkinfo chi;

	switch (obj->type) {
	case 0xF2:
		/* directory */
		typechar = 'd';
		break;
	case 0xF1:
		/* regular file */
		typechar = 'f';
		break;
	case 0xE1:
		/* special .journal file */
		typechar = 'j';
		break;
	default:
		/* unknown! */
		typechar = 'U';
	}
	printf("%c %s\n", typechar, workpath);
	printf("  #%x chunk addr=0x%x len=0x%x\n", obj->entryno,
		obj->offset, obj->len);
	switch (obj->type) {
	case 0xF2:
		/* directory */
		return;
	case 0xF1:
		/* regular file */
		size_head_chunk(obj, &chi);
		printf("  head chunk: %lu bytes at 0x%lx\n", (u_long) chi.len,
			(u_long)(chi.start-image));
		dump_extra_chunks(obj->descend);
		return;
	default:
		if (obj->descend != 0xFFFF)
			printf("  unexpected descend pointer: %x\n",
				obj->descend);
	}
}

dump_dir(firstent, path_prefix)
{
	int ent;
	struct objinfo obj;

	for (ent = firstent; ent != 0xFFFF; ent = obj.sibling) {
		obj.entryno = ent;
		get_index_entry(&obj);
		if (!obj.type) /* skip deleted objects w/o further validation */
			continue;
		validate_chunk(&obj);
		validate_obj_name(&obj);
		if (path_prefix + strlen(obj.dataptr) + 2 > sizeof workpath) {
			fprintf(stderr,
	"handling object at index %x, name \"%s\": path buffer overflow\n",
				obj.entryno, (char *)obj.dataptr);
			exit(1);
		}
		sprintf(workpath + path_prefix, "/%s", (char *)obj.dataptr);
		dump_object(&obj);
		if (obj.type == 0xF2)
			dump_dir(obj.descend, strlen(workpath));
	}
}

save_pathname_arg(pnarg)
	char *pnarg;
{
	if (*pnarg == '/')
		pnarg++;
	if (strlen(pnarg) + 2 > sizeof workpath) {
		fprintf(stderr,
	"error: specified pathname is too long (overflows internal buffer)\n");
		exit(1);
	}
	sprintf(workpath, "/%s", pnarg);
}

dump_by_pathname(pnarg)
	char *pnarg;
{
	struct objinfo obj;

	save_pathname_arg(pnarg);
	obj.entryno = find_pathname(pnarg);
	get_index_entry(&obj);
	validate_chunk(&obj);
	dump_object(&obj);
}

usage()
{
	fprintf(stderr, "usage: mpffs-dbgls [options] ffs-image [pathname]\n");
	exit(1);
}

main(argc, argv)
	char **argv;
{
	extern int optind;

	parse_cmdline_options(argc, argv);
	argc -= optind;
	argv += optind;
	if (argc < 1 || argc > 2)
		usage();
	verbose++;
	imgfile = argv[0];
	preliminaries();
	if (argc == 1)
		dump_dir(root.descend, 0);
	else
		dump_by_pathname(argv[1]);
	exit(0);
}