[net.sources] cpfix - salvage damaged cpio archives

dan@prairie.UUCP (Daniel M. Frank) (01/20/87)

--------------- cpfix.c ---------------------------------- cut here ---

/* cpfix:  repair damaged cpio archives.
 *		cpfix does its best to repair a cpio archive that has had
 *		extra bytes inserted, destroying sync.  This happens with
 *		amazing regularity, especially when cpio is used to backup
 *		damaged file systems.
 *
 *		There are two arguments.  The first is the input file name,
 *		which may be `-' for stdin.  The second is an explicit output 
 *		filename.  
 *
 *		cpfix works only for binary cpio headers.  It shouldn't be
 *		too hard to add an option for character headers.
 *
 *		Operating Systems:  known to work under SVR2, but probably
 *					  fine under others.  I hear that Sun did something
 *					  funny to the header.
 *		Author:	Daniel M. Frank (dan@prairie.uucp)
 *		Permissions:  Permission is granted for distribution, without
 *					  charge, of this program.  Anyone who wants to
 *					  sell it must ask my permission and grease my
 *					  palm.
 *		cpfix is Copyright (C) 1987 by Daniel M. Frank.
 */

#include <stdio.h>
#include <sys/types.h>

struct Hdr {
	short	h_magic ,
			h_dev ;
	ushort	h_ino,
			h_mode,
			h_uid,
			h_gid;
	short	h_nlink,
			h_rdev,
			h_mtime[2],
			h_namesize ;
	ushort	h_filesize[2] ;
};

main(argc, argv)
int argc ;
char **argv ;
{
	char name[132] ;
	struct Hdr header ;
	int namesize ;
	long filesize, fsadj, outpos, lastpos ;
	FILE *inp, *outp ;
	char buf[1024] ;

	if (argv[1][0] == '-')
		inp = stdin ;
	else if ((inp = fopen(argv[1], "r")) == 0) {
		perror("input file") ;
		exit(1) ;
	}

	if ((outp = fopen(argv[2], "w")) == 0) {
		perror("output file") ;
		exit(1) ;
	}

	lastpos = 0 ;

	while(1) {
		outpos = ftell(outp) ;	/* save current output position */
		if (fread(&header, sizeof(header), 1, inp) != 1) {
			perror("header read") ;
			exit(1) ;
		}
		if (header.h_magic != 070707) {
			printf("No magic - number was %o\n", header.h_magic) ;
			fseek(outp, lastpos, 0) ;	/* reset to last write postion */
			outpos = lastpos ;
			while(1) {
				if (fread(&header, sizeof(header.h_magic), 1, inp) != 1) {
					printf("Read failure during recovery scan\n") ;
					exit(1) ;
				}
				if (header.h_magic == 070707) {
					if (fread(&header.h_dev, 
							  sizeof(header) - sizeof(header.h_magic), 
							  1, inp) != 1) {
						printf("Failure reading rest of header\n") ;
						exit(1) ;
					}
					break ;	/* leave while loop */
				}
			}
		}

		lastpos = outpos ;

		namesize = (header.h_namesize + 1) & ~1 ;
		if (fread(name, namesize, 1, inp) != 1) {
			perror("name read") ;
			exit(1) ;
		}

		if (fwrite(&header, sizeof(header), 1, outp) != 1) {
			perror("header write") ;
			exit(1) ;
		}
		if (fwrite(name, namesize, 1, outp) != 1) {
			perror("name write") ;
			exit(1) ;
		}

		if (strcmp(name, "TRAILER!!!") == 0) {
			/* we have to adjust to a 512-byte boundary */
			long adjust ;
			outpos += sizeof(header) + namesize ;
			adjust = ((outpos - 1) / 512 * 512 + 512) - outpos ;
			if (adjust)
				if (fwrite(buf, (int)adjust, 1, outp) != 1) {
					perror("padding write") ;
					exit(1) ;
				}
			printf("end of the archive!\n") ;
			exit(0) ;
		}
		filesize = ((long)header.h_filesize[0] << 16) + header.h_filesize[1] ;
		printf("file %s, size %ld\n", name, filesize) ;
		fsadj = (filesize + 1) & ~1L ;
		while (fsadj > 0) {
			if (fread(buf, (fsadj > 1024 ? 1024 : (int)fsadj), 1, inp) != 1) {
				perror("data read") ;
				exit(1) ;
			}
			if (fwrite(buf, (fsadj > 1024 ? 1024 : (int)fsadj), 1, outp) != 1) {
				perror("data write") ;
				exit(1) ;
			}
			fsadj -= 1024 ;
		}
	}
}
		

-- 
    Dan Frank
    uucp: ... uwvax!prairie!dan
    arpa: dan%caseus@spool.wisc.edu