DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦6e6066e56⟧ TextFile

    Length: 8345 (0x2099)
    Types: TextFile
    Notes: UNIX file
    Names: »dumpdir.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦f4b8d8c84⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »cmd/dump/dumpdir.c« 

TextFile

/*
 * dumpdir [af [dumpfile]]
 * a	Show all entries (include `.' and `..').
 * f	Use `dumpfile', not default.
 */
#include <stdio.h>
#include <dumptape.h>
#include <canon.h>
#include <mdata.h>
#include <signal.h>

/*
 * Structure used to remember
 * things about all the directories
 * on the tape.
 */
struct	dlist
{
	struct	dlist	*dl_dlp;	/* Link to next */
	ino_t	dl_ino;			/* Inumber */
	int	dl_dejavu;		/* Already seen flag */
	long	dl_seek;		/* Tempfile base */
	long	dl_size;		/* Size */
};

char	*dtn	= DTAPE;		/* Tape name */
FILE	*dtp;				/* Tape file pointer */
char	tfn[30]	= "/tmp/ddXXXXXX";	/* Temp file name */
FILE	*tfp;				/* Temp file pointer */
int	aflag;				/* All flag */
size_t	length = 1;			/* Length in bytes of volume */
size_t	nread;				/* Number of bytes read from volume */
struct	dlist	*dlist;			/* List of remembered directories */
struct	dlist	*droot;			/* Pointer to first directory */
char	dstr[1000];			/* Name string */
char	*dstrp	= &dstr[0];		/* Pointer into the above */
int	reel	= 1;			/* Reel # */
char	*ddbuf;				/* Dump data buffer */
char	*ddend;				/* Ptr to end of dump data buffer */
int	ddnbuf;				/* Size of buffer (bytes) */
union	dumpdata *ddptr;		/* Ptr to current record in buffer */
char	*map;				/* Inode map */

union	dumpdata *readdump();
struct	dlist	 *findnode();
int	cleanup();
char	*calloc();

main(argc, argv)
char *argv[];
{
	register char *p;
	register c, i;

	if (argc > 1) {
		i = 1;
		p = argv[1];
		while ((c = *p++) != '\0') {
			switch (c) {

			case 'a':
				aflag = 1;
				break;

			case 'f':
				if (++i >= argc)
					usage();
				dtn = argv[i];
				break;

			default:
				usage();
			}
		}
	}
	if ((dtp=fopen(dtn, "r")) == NULL)
		fatal("%s: cannot open dump file", dtn);
	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
		signal(SIGINT, cleanup);
	mktemp(tfn);
	if ((tfp=fopen(tfn, "w")) == NULL
	||  (tfp=freopen(tfn, "r+w", tfp)) == NULL)
		fatal("%s: cannot create temporary file", tfn);
	nextvol();
	readdirs();
	if (droot == NULL)
		fatal("no directories");
	dumpdirs(droot);
	delexit(0);
}

/*
 * This routine has two jobs.
 * It reads in the dump file header and
 * checks it out, looking for strangenesses
 * in format. It also is responsible for
 * using information in the header to
 * allocate the necessary map and dump I/O
 * buffers.
 */
readhead()
{
	static struct dumpheader dh;
	register char *p;
	register checksum;

	if (read(fileno(dtp), &dh, sizeof dh) != sizeof dh)
		fatal("header read error");
	nread = sizeof dh;
	canint(dh.dh_magic);
	canino(dh.dh_nino);
	cantime(dh.dh_bdate);
	cantime(dh.dh_ddate);
	canint(dh.dh_level);
	canint(dh.dh_reel);
	canint(dh.dh_blocking);
	cansize(dh.dh_nbyte);
	canint(dh.dh_checksum);
	if (dh.dh_magic != DH_MAG)
		fatal("not a dump");
	p = (char *) &dh;
	checksum = 0;
	while (p < (char *) &dh.dh_checksum)
		checksum += (*p++) & 0377;
	if (checksum != dh.dh_checksum)
		fatal("header checksum error");
	if (dh.dh_reel != reel)
		fatal("wrong reel (is %d, not %d)", dh.dh_reel, reel);
	++reel;
	if (map != NULL)
		free(map);
	if (ddbuf != NULL)
		free(ddbuf);
	if ((map = calloc(sizeof(char), (dh.dh_nino+NBCHAR-1)/NBCHAR)) == NULL)
		fatal("out of memory (map)");
	ddnbuf = dh.dh_blocking * sizeof(union dumpdata);
	if ((ddbuf = malloc(ddnbuf)) == NULL)
		fatal("out of memory (buffer)");
	ddend = &ddbuf[ddnbuf];
	ddptr = (union dumpdata *) ddend;
	length = dh.dh_nbyte;
}

/*
 * Read in all the directories.
 * This routine assumes that the map entries
 * have been put out before the inodes and
 * that all the directories have been put out
 * before the files.
 */
readdirs()
{
	register union dumpdata *ddp;
	register struct dlist *dlp;

	while ((ddp=readdump()) != NULL) {
		canint(ddp->dd_type);
		switch (ddp->dd_type) {

		case DD_EOT:
			return;

		case DD_DATA:
			canino(ddp->dd_ino);
			candaddr(ddp->dd_block);
			canint(ddp->dd_size);
			if (dlist==NULL || dlist->dl_ino!=ddp->dd_ino)
				fatal("out of sync");
			fseek(tfp, dlist->dl_seek+(BUFSIZ*ddp->dd_block), 0);
			fwrite(ddp->dd_data, sizeof(char), BUFSIZ, tfp);
			if (ferror(tfp))
				fatal("temporary file write error");
			break;

		case DD_INO:
			canino(ddp->dd_ino);
			canshort(ddp->dd_dinode.di_mode);
			cansize(ddp->dd_dinode.di_size);
			if ((ddp->dd_dinode.di_mode&IFMT) != IFDIR)
				return;
			dlp = (struct dlist *) malloc(sizeof(struct dlist));
			if (dlp == NULL)
				fatal("out of memory (directory)");
			dlp->dl_dlp = dlist;
			dlist = dlp;
			if (droot == NULL)
				droot = dlp;
			dlp->dl_ino = ddp->dd_ino;
			dlp->dl_dejavu = 0;
			dlp->dl_seek = ftell(tfp);
			dlp->dl_size = ddp->dd_dinode.di_size;
			break;

		case DD_MAP:
			canino(ddp->dd_ino);
			canint(ddp->dd_nmap);
			setmap(ddp);
			break;

		default:
			fatal("bad type %d", ddp->dd_type);
		}
	}
}

/*
 * Process a map entry.
 * Set a bit in the map for every inode
 * whose dump map entry has the DD_DUMP flag
 * set.
 */
setmap(ddp)
union dumpdata *ddp;
{
	register char *mmapp, *dmapp;
	register mmask;
	register nmapb;

	mmapp = &map[--ddp->dd_ino/NBCHAR];
	mmask = 01 << (ddp->dd_ino%NBCHAR);
	dmapp = &ddp->dd_map[0];
	nmapb = ddp->dd_nmap;
	while (nmapb--) {
		if (((*dmapp++)&DD_DUMP) != 0)
			*mmapp |= mmask;
		if ((mmask <<= 1) == (01<<NBCHAR)) {
			++mmapp;
			mmask = 01;
		}
	}
}

/*
 * Return a pointer to the 
 * next dump file item. This routine
 * knows all about reading the
 * next tape in a multitape dump.
 */
union dumpdata *
readdump()
{
	register nb;

	while ((char *) ddptr == ddend) {
		if (length != 0 && (nread+ddnbuf) > length) {
			nextvol();
			continue;
		}
		if ((nb = read(fileno(dtp), ddbuf, ddnbuf)) != ddnbuf) {
			if (nb != 0)
				fatal("dump read error");
			nextvol();
			continue;
		}
		nread += nb;
		ddptr = (union dumpdata *) ddbuf;
		break;
	}
	return (ddptr++);
}

/*
 * Read the next reel or volume.
 */
nextvol()
{
	fclose(dtp);
	fprintf(stderr, "dumpdir: mount %s %d, type return key ...",
		length ? "volume" : "reel", reel);
	if (fgets(dstr, sizeof(dstr), stdin) == NULL)
		delexit(1);
	if ((dtp = fopen(dtn, "r")) == NULL)
		fatal("%s: cannot open dump tape", dtn);
	readhead();
}

/*
 * Start at the root and
 * print all of the directories.
 * Don't print the names of things that
 * the map says are not on the tape.
 */
dumpdirs(dlp)
register struct dlist *dlp;
{
	char *sdstrp;
	struct direct dirbuf;
	register char *p1, *p2;
	register c;
	register struct dlist *sdlp;
	ino_t ino;

	dlp->dl_dejavu = 1;
	while (dlp->dl_size != 0) {
		fseek(tfp, dlp->dl_seek, 0);
		if (fread(&dirbuf, sizeof(dirbuf), 1, tfp) != 1)
			fatal("temporary file read error");
		dlp->dl_seek += sizeof(struct direct);
		dlp->dl_size -= sizeof(struct direct);
		if (aflag == 0) {
			if (strncmp(dirbuf.d_name, ".",  DIRSIZ) == 0)
				continue;
			if (strncmp(dirbuf.d_name, "..", DIRSIZ) == 0)
				continue;
		}
		canino(dirbuf.d_ino);
		if ((ino = dirbuf.d_ino)!=0 && getbit(ino)!=0) {
			p1 = sdstrp = dstrp;
			if (p1 != dstr)
				*p1++ = '/';
			p2 = dirbuf.d_name;
			while (p2<&dirbuf.d_name[DIRSIZ] && (c=*p2++))
				*p1++ = c;
			*p1 = '\0';
			dstrp = p1;
			printf("%u\t%s\n", ino, dstr);
			if ((sdlp=findnode(ino))!=NULL && sdlp->dl_dejavu==0)
				dumpdirs(sdlp);
			dstrp = sdstrp;
			*dstrp = '\0';
		}
	}
	dlp->dl_dejavu = 0;
}

/*
 * Get the dumped bit for
 * inode `ino' from the big bit map.
 */
getbit(ino)
ino_t ino;
{
	register mapent;

	mapent = map[--ino/NBCHAR];
	return (mapent & (01<<ino%NBCHAR));
}

/*
 * Return the dlist pointer
 * for directory inode `ino', or NULL
 * if it is not there. Not there means
 * not a directory.
 */
struct	dlist *
findnode(ino)
register ino_t ino;
{
	register struct dlist *dlp;

	dlp = dlist;
	while (dlp != NULL) {
		if (dlp->dl_ino == ino)
			break;
		dlp = dlp->dl_dlp;
	}
	return (dlp);
}

/*
 * Nasty nasty nasty.
 */
fatal(a)
{
	fprintf(stderr, "dumpdir: %r", &a);
	fprintf(stderr, "\n");
	delexit(1);
}

/*
 * This routine is called from the
 * interupt signal. It points off to dumpdir
 * who deletes the temp file and returns
 * the error status.
 */
cleanup()
{
	delexit(1);
}

/*
 * A special version of `exit' that
 * cleans up by unlinking the temporary
 * file.
 */
delexit(s)
{
	if (tfp != NULL)
		unlink(tfn);
	exit(s);
}

/*
 * Print the usage message and
 * exit.
 */
usage()
{
	fprintf(stderr, "Usage: dumpdir [af [dumpfile]]\n");
	exit(1);
}