view mpffs/xtr.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 7ceab8bfacb3
children
line wrap: on
line source

/*
 * This module contains the main function and other code specific to mpffs-xtr
 */

#include <sys/types.h>
#include <sys/file.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 struct objinfo root;
extern int verbose;

extern u8 *find_end_of_chunk();

char workpath[512];

name_safe_for_extract(oi)
	struct objinfo *oi;
{
	char *s;

	s = (char *)oi->dataptr;
	if (!isalnum(*s) && *s != '_')
		return(0);
	for (s++; *s; s++)
		if (!isalnum(*s) && *s != '_' && *s != '.')
			return(0);
	return(1);
}

void
dump_head_chunk(fd, ch)
	struct objinfo *ch;
{
	u8 *endname, *endchunk;

	endname = (u8 *) index((char *)ch->dataptr, '\0') + 1;
	endchunk = find_end_of_chunk(ch);
	if (endchunk <= endname)
		return;
	write(fd, endname, endchunk - endname);
}

void
dump_extra_chunk(ch, opaque)
	struct objinfo *ch;
	u_long opaque;
{
	int fd = (int) opaque;
	u8 *endchunk;

	endchunk = find_end_of_chunk(ch);
	write(fd, ch->dataptr, endchunk - ch->dataptr);
}

extract_file(head)
	struct objinfo *head;
{
	int fd;

	fd = open(workpath + 1, O_WRONLY|O_CREAT|O_TRUNC, 0666);
	if (fd < 0) {
		perror(workpath + 1);
		exit(1);
	}
	dump_head_chunk(fd, head);
	iterate_extra_chunks(head->descend, dump_extra_chunk, (u_long) fd);
	close(fd);
}

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);
		switch (obj.type) {
		case 0xF2:
			/* directory */
			if (verbose)
				printf("dir: %s\n", workpath);
			if (!name_safe_for_extract(&obj)) {
				fprintf(stderr,
"warning: directory name contains unsafe characters; subtree skipped\n");
				continue;
			}
			if (mkdir(workpath + 1, 0777) < 0) {
				perror(workpath + 1);
				exit(1);
			}
			dump_dir(obj.descend, strlen(workpath));
			continue;
		case 0xF1:
			/* regular file */
			if (verbose)
				printf("file: %s\n", workpath);
			if (!name_safe_for_extract(&obj)) {
				fprintf(stderr,
	"warning: file name contains unsafe characters; file skipped\n");
				continue;
			}
			extract_file(&obj);
			continue;
		case 0xE1:
			/* special .journal file */
			if (verbose)
				printf("skipping E1 file: %s\n", workpath);
			continue;
		default:
			fprintf(stderr,
	"warning: %s (index entry #%x): unexpected type %02X; skipping\n",
				workpath, obj.entryno, obj.type);
			continue;
		}
	}
}

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

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

	parse_cmdline_options(argc, argv);
	if (argc - optind != 2)
		usage();
	imgfile = argv[optind];
	preliminaries();
	if (chdir(argv[optind+1]) < 0) {
		perror(argv[optind+1]);
		exit(1);
	}
	dump_dir(root.descend, 0);
	exit(0);
}