[alt.sources] fssal - BSD filesystem salvage program, Part 01/01

bob@reed.UUCP (Bob Ankeney) (04/10/91)

#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  README
#	  FILES
#	  NOTES
#	  Makefile
#	  defs.h
#	  fs.h
#	  idir.c
#	  iname.c
#	  io.c
#	  ls.c
#	  main.c
#	  namei.c
#	  restore.c
#	  stat.c
#
sed 's/^X//' << 'SHAR_EOF' > README &&
X     Fssal is a utility to salvage files from damaged BSD filesystems.
XSuch damage might include a lost super-block, trashed cylinder group,
Xdrive with bad blocks, or perhaps a filesystem with files that may get
Xconsumed by a fsck.  It requires the presence of a relatively intact
Xfilesystem (an intact original or alternate super-block, some semblence
Xof an inode-structure, and some intact cylinder-groups).  Thus such
Xthings as deleted files cannot be restored.
X
X     The impetus for writing this program was to recover files from a
Xfilesystem with the original super-block and first (of six) cylinder
Xgroups walked on.  What happened was a mkfs of a small system was
Xaccidentally done, which wiped the initial data.  Data from all other
Xcylinder groups was still intact and recoverable.  An alternate (spare)
Xsuper-block is found within each cylinder group.
X
X     All restored files are placed relative to the working directory,
Xand all permissions, creation/modification times, and ownerships are
Xrestored.  Both real and symbolic links are handled, as well as
Xcharacter and block special devices and sockets.
X
X     At no time is the specified file-system written on, thus data is
Xsafe.  The specified file-system need not be mounted (and probably
Xshouldn't be lest others modify it as a restore is in progress).
X
X     The general usage is:
X
X        fssal [-f device] [-s super-block] [-r root-inode] [-a] [-R] [-v]
X
X     where:
X	-f device: is the file-system to use (do not use the raw device!!)
X	-s super-block: is an alternate super-block
X	-r root-inode: is an alternate directory inode to start at
X
X	-a: stats all inodes in file-system and restores those that are
X	    directories.  The -R flag can be used to recursively walk each
X	    sub-directory.  Each directory found that has not yet been
X	    restored will be created with the directory name '#inum', where
X	    inum is the inode number of that directory.
X
X	-R: recursively walk each sub-directory found.
X
X	-v: verbose mode.  Spews out lots of information as to what's been
X	    restored.
X
X     A link to fssal called fsls exists which does a directory listing on
Xthe specified file system.  The general usage is:
X
X        fsls [-f device] [-s super-block] [-r root-inode] [-a] [-R] [-l]
X
X     where:
X	-f device: is the file-system to use (do not use the raw device!!)
X	-s super-block: is an alternate super-block
X	-r root-inode: is an alternate directory inode to start at
X
X	-a: stats all inodes in file-system and lists those that are
X	    directories.  The -R flag can be used to recursively walk each
X	    sub-directory.
X
X	-R: recursively walk each sub-directory found.
X
X	-l: do a long directory list (like 'ls -liga')
X
X
X     Hopefully someone will take this under their wing and make improvements
Xto it.  Some suggestions are:
X     a) Make it interactive (ala restore -i).
X     b) Port it to other platforms; it has been used successfully on:
X		DEC VAX with Mt. Xinu
X		DEC VAX with Ultrix V2.3
X		Sun-4 with SunOs V4.1
X		Tektronix Utek V2.2
X     c) A manual page.
X
X
X     Feel free to mail me any suggestions, bug fixes and enhancements.  I'll
Xtry to integrate them (it's been a while since I wrote this) and make occasional
Xreleases.  If it looks solid enough, I'll post to comp.sources.unix.
X
X     Bob Ankeney
X     ...!tektronix!bob@reed.bitnet
X
SHAR_EOF
chmod 0644 README || echo "restore of README fails"
sed 's/^X//' << 'SHAR_EOF' > FILES &&
XREADME
XFILES
XNOTES
XMakefile
Xdefs.h
Xfs.h
Xidir.c
Xiname.c
Xio.c
Xls.c
Xmain.c
Xnamei.c
Xrestore.c
Xstat.c
SHAR_EOF
chmod 0644 FILES || echo "restore of FILES fails"
sed 's/^X//' << 'SHAR_EOF' > NOTES &&
XThings to check for:
X
X     Error handling (failed reads especially).
X
X     Freeing of malloced space.
X
XTo do:
X
X     Read inode into buffer and get inode structures from it (fixes reads on
X     raw device).
X
X     Cache ureads?  (uread reads entire block and bcopies desired info).
X     Keep track of last block read to avoid duplicate reads.
X
SHAR_EOF
chmod 0644 NOTES || echo "restore of NOTES fails"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X#CFLAGS = -g -DDEBUG
XCFLAGS = -g -DBSD4_3
X
XSRCS = io.c namei.c iname.c ls.c restore.c main.c stat.c idir.c
XOBJS = io.o namei.o iname.o ls.o restore.o main.o stat.o idir.o
X
Xall:	fssal fsls
X
Xfssal:	$(OBJS)
X	rm -f fsls
X	cc $(CFLAGS) $(OBJS) -o fssal
X
Xfsls:	fssal
X	ln fssal fsls
X
Xio.o: defs.h fs.h
X
Xnamei.o: defs.h fs.h
X
Xiname.o: defs.h fs.h
X
Xls.o: defs.h fs.h
X
Xrestore.o: defs.h fs.h
X
Xmain.o: defs.h fs.h
X
Xstat.o: defs.h fs.h
X
Xidir.o: defs.h fs.h
X
Xclean:
X	rm -f $(OBJS)
X
Xlint:
X	lint $(SRCS)
X
SHAR_EOF
chmod 0644 Makefile || echo "restore of Makefile fails"
sed 's/^X//' << 'SHAR_EOF' > defs.h &&
X
X#define FS_TO_READ	"/dev/dh60h"
X
X	/* Maximum size for path name */
X#define MAX_PATH_LEN	128
X
X	/* Number of inode numbers per sturct idir segment */
X#define MAX_ICNT	32
X
X#ifndef TRUE
X#define	TRUE	(1)
X#define FALSE	(0)
X#endif
X
SHAR_EOF
chmod 0644 defs.h || echo "restore of defs.h fails"
sed 's/^X//' << 'SHAR_EOF' > fs.h &&
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/param.h>
X#ifdef BSD4_2
X#include <sys/fs.h>
X#include <sys/inode.h>
X#endif
X#ifdef BSD4_3
X#include <sys/time.h>
X#include <sys/vnode.h>
X#include <ufs/fs.h>
X#include <ufs/inode.h>
X#endif
X#include <sys/dir.h>
X#include <sys/errno.h>
X
X#include "defs.h"
X
X/*
X *	itobo -	Convert inode number to file system byte offset (for lseek).
X *
X *		Converts inode to file system block (itod), then to device
X *		block (fsbtodb), multiplies by size of device block (DEV_BSIZE
X *		= 512), and adds offset into block of inode (itoo).
X */
X#define itobo(x) (fsbtodb(&sb, itod(&sb, x)) * DEV_BSIZE +	\
X	 	 itoo(&sb,x) * sizeof(struct icommon))
X
X/*
X *	btobo - Convert file system block number to byte offset (for lseek).
X */
X#define btobo(x) (fsbtodb(&sb, x) * DEV_BSIZE)
X
X#define ISIZE	sizeof(struct icommon)
X
X
X/*
X *	struct file_ptr is the structure returned from a uopen() call.
X */
Xstruct file_ptr {
X	struct icommon	*ip;		/* Pointer to inode for file */
X	long		file_ptr;	/* # bytes into file */
X	long		file_size;	/* # bytes in file */
X};
X
X/*
X *	struct iname_list is a linked list of paths returned by iname() call.
X */
Xstruct iname_list {
X	char	name[MAX_PATH_LEN];
X	struct	iname_list *next_iname;
X};
X
X/*
X *	struct idir is a linked list of arrays of directory inode numbers.
X *	inums[] is the array containing icnt inode numbers.  next_idir
X *	points to the next list of numbers
X */
Xstruct idir {
X	ino_t	inums[MAX_ICNT];
X	int	icnt;
X	struct	idir *next_idir;
X};
X
SHAR_EOF
chmod 0644 fs.h || echo "restore of fs.h fails"
sed 's/^X//' << 'SHAR_EOF' > idir.c &&
X
X/*
X *     fssal - BSD file system salvage program
X *
X *     Copyright 1989, Robert Ankeney
X *                     Generic Computer Products
X *                     5315 S.W. 53rd Court
X *                     Portland, Oregon  97221
X *                     (503) 244-3699
X *     All Rights Reserved
X *
X *     Distribution of any portion of this software as part of any product
X *     for sale is prohibited.
X *
X *     Version 1.00 (Preliminary)
X */
X
X#include "fs.h"
X#include <sys/stat.h>
X
X	/* File descriptor filesystem is open on */
Xextern int		fs_fd;
X
X	/* struct holding super block */
Xextern struct fs	sb;
X
X	/* size of file system block (= 4096) */
X#define BLKSIZE sb.fs_bsize
X
X/*
X *	get_dir_inodes - stats inodes from from_inode to to_inode and, if
X *			 a directory, adds to return_list.
X */
Xget_dir_inodes(return_list, from_inode, to_inode)
Xstruct	idir **return_list;
Xino_t	from_inode, to_inode;
X{
X	struct stat	statb;
X	struct idir	*idir_list, *cur_ilist;
X
X	ino_t	i;
X
X	new_idir(&idir_list);
X	cur_ilist = idir_list;
X
X	for (i = from_inode; i < to_inode; i++) {
X		if (fs_stat (i, &statb)) {
X			printf ("error reading inode %d\n");
X			break;
X		}
X		if ((statb.st_mode & S_IFMT) == S_IFDIR) {
X				/* Add inode number to list */
X			add_dir_inode(&cur_ilist, i);
X			printf ("found directory at %d\n", i);
X		}
X	}
X	*return_list = idir_list;
X}
X
X/*
X *	new_idir - makes new idir segment and returns pointer new_ptr
X */
Xnew_idir(new_ptr)
Xstruct	idir **new_ptr;
X{
X	char *malloc();
X
X	*new_ptr = (struct idir *) malloc(sizeof(struct idir));
X	(*new_ptr)->icnt = 0;
X	(*new_ptr)->next_idir = NULL;
X}
X
X/*
X *	add_dir_inode - adds inode number to struct idir, mallocing a new
X *			one if needed.
X */
Xadd_dir_inode(idir_ptr, inum)
Xstruct	idir **idir_ptr;
Xino_t	inum;
X{
X	if ((*idir_ptr)->icnt == MAX_ICNT) {
X			/* Current list full, add new segment */
X		new_idir(&((*idir_ptr)->next_idir));
X		*idir_ptr = (*idir_ptr)->next_idir;
X	}
X	(*idir_ptr)->inums[(*idir_ptr)->icnt++] = inum;
X}
X
X/*
X *	in_idir - returns TRUE if inum is found in idir_ptr
X */
Xin_idir(idir_ptr, inum)
Xstruct	idir *idir_ptr;
Xino_t	inum;
X{
X	struct	idir *itmp_ptr;
X
X	ino_t	itmp;
X
X	itmp_ptr = idir_ptr;
X	while (itmp_ptr) {
X		for (itmp = 0; itmp < itmp_ptr->icnt; itmp++)
X			if (itmp_ptr->inums[itmp] == inum)
X				return TRUE;
X		itmp_ptr = itmp_ptr->next_idir;
X	}
X	return FALSE;
X}
X
SHAR_EOF
chmod 0644 idir.c || echo "restore of idir.c fails"
sed 's/^X//' << 'SHAR_EOF' > iname.c &&
X
X/*
X *     fssal - BSD file system salvage program
X *
X *     Copyright 1989, Robert Ankeney
X *                     Generic Computer Products
X *                     5315 S.W. 53rd Court
X *                     Portland, Oregon  97221
X *                     (503) 244-3699
X *     All Rights Reserved
X *
X *     Distribution of any portion of this software as part of any product
X *     for sale is prohibited.
X *
X *     Version 1.00 (Preliminary)
X */
X
X#include "fs.h"
X#include <sys/time.h>
X
X	/* struct holding super block */
Xextern struct fs	sb;
X
X	/* File system block size */
X#define BLKSIZE sb.fs_bsize
X
X/*
X *	iname - generate list of file names based on given inode number.
X *		Given inode inum and maximum count icnt, returns linked list
X *		inames of path names and actual number found found_cnt.
X *		ipath is path name to inode istart, which is prepended to each
X *		iname.
X *
X *		Used for determining links to regular files.
X */
Xiname(ipath, istart, inum, icnt, inames, found_cnt)
Xchar	ipath[MAX_PATH_LEN];
Xino_t	istart, inum;
Xint	icnt, *found_cnt;
Xstruct	iname_list **inames;
X{
X	*inames = NULL;
X	*found_cnt = 0;
X	if (ilist(ipath, istart, inum, icnt, inames, found_cnt))
X		fprintf(stderr, "Inode %d is not a directory\n", inum);
X}
X
Xilist(ipath, istart, inum, icnt, inames, found_cnt)
Xchar	ipath[MAX_PATH_LEN];
Xino_t	istart, inum;
Xint	icnt, *found_cnt;
Xstruct	iname_list **inames;
X{
X	struct icommon	fs_inode;		/* Inode for directory */
X	struct direct	*fs_dir;		/* Directory structure */
X	struct file_ptr	dir_ptr;		/* Directory pointer */
X
X	char		dir_buf[MAXBSIZE];	/* Directory buffer */
X	int		buf_cnt;		/* # chars in buffer */
X	int		next_ent;		/* Buf offset of next dir */
X
X	char		cur_name[MAX_PATH_LEN];	/* Current directory pathname */
X
X	struct icommon	file_inode;		/* Inode for ls file */
X
X	static struct iname_list *cur_iname, *tmp_iname;
X
X	char		*strcpy(), *sprintf(), *strcat();
X	char		*malloc();
X
X	extern int	errno;
X
X
X		/* Fetch inode */
X	get_inode(istart, &fs_inode);
X
X		/* Make sure it's a directory! */
X	if ((fs_inode.ic_mode & IFMT) != IFDIR) {
X		errno = ENOTDIR;
X		return -1;
X	}
X		/* Open directory */
X	uopen(&fs_inode, &dir_ptr);
X
X		/* Read each directory block */
X	do {
X		    /* Read next block of directory */
X	    if ((buf_cnt = uread(&dir_ptr, dir_buf, BLKSIZE)) == -1) {
X		    perror("Cannot read directory");
X		    exit(1);
X	    }
X
X	    if (buf_cnt == 0)
X		break;
X
X		    /* For each file in directory, check inode # */
X	    next_ent = 0;
X	    do {
X			/* Point to next directory entry */
X		fs_dir = (struct direct *) &dir_buf[next_ent];
X
X			/* Directory entry here? */
X		if (fs_dir->d_ino != 0) {
X				/* Get inode */
X			get_inode(fs_dir->d_ino, &file_inode);
X
X				/* Desired inode #? */
X			if (fs_dir->d_ino == inum) {
X					/* Yep - Malloc new iname_list */
X				tmp_iname = cur_iname;
X				cur_iname = (struct iname_list *)
X					malloc(sizeof(struct iname_list));
X				cur_iname->next_iname = NULL;
X				if (tmp_iname)
X					tmp_iname->next_iname = cur_iname;
X				if (*inames == NULL)
X					*inames = cur_iname;
X
X					/* Copy starting path */
X				(void) strcpy(cur_iname->name, ipath);
X				(void) strcat(cur_iname->name, "/");
X					/* Append actual file name */
X				(void) strcat(cur_iname->name, fs_dir->d_name);
X				++*found_cnt;
X			}
X		}
X		next_ent += fs_dir->d_reclen;
X	    } while (next_ent < buf_cnt);
X
X	} while (buf_cnt > 0);
X
X		/* Open directory again */
X	uopen(&fs_inode, &dir_ptr);
X
X		/* Read each directory block */
X	do {
X		    /* Read next block of directory */
X	    if ((buf_cnt = uread(&dir_ptr, dir_buf, BLKSIZE)) == -1) {
X		    perror("Cannot read directory");
X		    exit(1);
X	    }
X
X	    if (buf_cnt == 0)
X		break;
X
X		    /* For each subdirectory in directory, check it */
X	    next_ent = 0;
X	    do {
X			/* Point to next directory entry */
X		fs_dir = (struct direct *) &dir_buf[next_ent];
X
X			/* Directory entry here? */
X		if (fs_dir->d_ino != 0) {
X				/* Get inode */
X			get_inode(fs_dir->d_ino, &file_inode);
X
X				/* Make sure is dir and not . or .. */
X			if ((file_inode.ic_mode & IFMT) == IFDIR)
X			    if (strcmp(fs_dir->d_name, ".") &&
X				strcmp(fs_dir->d_name, "..")) {
X				    if (*ipath)
X					(void) sprintf(cur_name, "%s/%s",
X						ipath, fs_dir->d_name);
X				    else
X					(void) strcpy(cur_name, fs_dir->d_name);
X
X					/* Check this directory! */
X				if (ilist(cur_name, fs_dir->d_ino, inum,
X				    icnt - *found_cnt, inames, found_cnt)) {
X				    fprintf(stderr,
X					"Inode %d is not a directory\n", inum);
X				    return -1;
X				}
X			    }
X		}
X		next_ent += fs_dir->d_reclen;
X	    } while (next_ent < buf_cnt);
X
X	} while (buf_cnt > 0);
X	return 0;
X}
SHAR_EOF
chmod 0644 iname.c || echo "restore of iname.c fails"
sed 's/^X//' << 'SHAR_EOF' > io.c &&
X
X/*
X *     fssal - BSD file system salvage program
X *
X *     Copyright 1989, Robert Ankeney
X *                     Generic Computer Products
X *                     5315 S.W. 53rd Court
X *                     Portland, Oregon  97221
X *                     (503) 244-3699
X *     All Rights Reserved
X *
X *     Distribution of any portion of this software as part of any product
X *     for sale is prohibited.
X *
X *     Version 1.00 (Preliminary)
X */
X
X#include "fs.h"
X
X
X	/* File descriptor filesystem is open on */
Xextern int	fs_fd;
X
X	/* struct holding super block */
Xextern struct fs	sb;
X
X	/* size of file system block */
X#define BLKSIZE sb.fs_bsize
X
X/*
X *	getsb - read super block into struct sb
X */
Xgetsb(fs_to_read, sb_block)
Xchar	*fs_to_read;
Xint	sb_block;
X{
X	long	lseek();
X
X		/* Open file system */
X	if ((fs_fd = open(fs_to_read, O_RDONLY)) == -1) {
X		perror("Cannot open filesystem");
X		exit(1);
X	}
X
X		/* Seek to super block */
X/*
X	(void) lseek(fs_fd, (long) BBSIZE, L_SET);
X*/
X	(void) lseek(fs_fd, (long) 512 * sb_block, L_SET);
X
X		/* Read super block */
X	if (read(fs_fd, (char *) &sb, sizeof(sb)) == -1) {
X		perror("Cannot read filesystem");
X		exit(1);
X	}
X
X		/* Check magic number */
X	if (sb.fs_magic != FS_MAGIC) {
X		fprintf(stderr, "Bad magic number for super block\n");
X		exit(1);
X	}
X
X}
X
X/*
X *	uopen - open file on unmounted file system.
X *
X *		Input is a pointer to the icommon for the file to open,
X *		and a pointer (struct file_ptr) to the info to be
X *		returned.  (Includes pointer to inode, index into file,
X *		and size of file).
X */
Xuopen(ip, fp)
Xstruct icommon	*ip;
Xstruct file_ptr	*fp;
X{
X	fp->ip = ip;
X	fp->file_ptr = 0;
X	fp->file_size = fp->ip->ic_size.val[0];
X}
X
X/*
X *	uread - read data from uopened file.
X *
X *		Input is pointer to struct file_ptr returned from uopen,
X *		pointer to buffer to place data in, and count of number
X *		of bytes to read.
X *
X *		Note - Doesn't handle double-indirect blocks!
X *			(Gawd, I'm lazy!)
X *
X *		Returns:
X *		    -1 if no data was read,
X *		    count if all data was transferred,
X *		    else actual number of bytes transferred.
X */
Xuread(fp, bp, count)
Xstruct file_ptr	*fp;
Xchar		*bp;
Xlong		count;
X{
X	/* # indirect pointers in an indirect block */
X#define	NUM_IND_PTRS	(BLKSIZE / sizeof(long))
X	/* # bytes pointed to by an indirect block */
X#define	IND_CNT		(NUM_IND_PTRS * BLKSIZE)
X
X	long	direct_blk;		/* Index into direct block numbers */
X	long	ind_ptr;		/* Which byte in indirect block */
X	int	ind_blk;		/* Which indirect pointer of NIADDR */
X	int	ind_off;		/* Which indirect pointer in block */
Xstatic	char	ind_buf[MAXBSIZE];	/* Indirect block */
Xstatic	int	last_ind_blk;		/* Last indirect block read */
X
X	int	num_to_read;		/* # bytes of block to read */
X	int	offset;			/* Offset into block to start read */
X	int	nr;			/* # bytes actually read */
X	long	file_cnt;		/* # bytes left in file */
X	long	num_read;		/* # bytes read so far */
X	long	block_to_read;		/* Block # for read */
X
X	char	*bufptr;		/* Next byte in buffer to read into */
X
X	long	lseek();
X
X	bufptr = bp;
X	num_read = 0;
X
X		/* # bytes left in file */
X	file_cnt = fp->file_size - fp->file_ptr;
X
X		/* Limit count to size of file */
X	if (count > file_cnt)
X	    count = file_cnt;
X
X	while (count != 0) {
X
X			/* Get direct block # */
X		direct_blk = fp->file_ptr / BLKSIZE;
X
X			/* Into indirect blocks? */
X		if (direct_blk >= NDADDR) {
X			ind_ptr = fp->file_ptr - NDADDR * BLKSIZE;
X
X				/* Into double-indirect blocks? */
X			if ((ind_blk = ind_ptr / IND_CNT) >= NIADDR) {
X				fprintf(stderr, "File too large\n");
X				exit(1);
X			}
X
X			ind_off = ind_ptr / BLKSIZE;
X
X			if (last_ind_blk != fp->ip->ic_ib[ind_blk]) {
X					/* Read indirect block */
X#ifdef DEBUG
X				printf("Reading indirect block %d\n",
X							last_ind_blk);
X#endif
X				last_ind_blk = fp->ip->ic_ib[ind_blk];
X				(void) lseek(fs_fd, btobo(last_ind_blk), L_SET);
X				if (read(fs_fd, ind_buf, (int) BLKSIZE) == -1) {
X					perror("Cannot read indirect block");
X					exit(1);
X				}
X			}
X
X			block_to_read = * ((long *) &ind_buf[ind_off *
X								sizeof(long)]);
X		} else
X			block_to_read = fp->ip->ic_db[direct_blk];
X
X			/* Offset into block to start read */
X		offset = fp->file_ptr % BLKSIZE;
X
X			/* # bytes in block to read */
X		num_to_read = ((BLKSIZE - offset) < count) ?
X				(BLKSIZE - offset) : count;
X
X			/* Check for pointer to empty block */
X		if (block_to_read == 0) {
X			for (nr = 0; nr < num_to_read; nr++)
X				bufptr[nr] = '\0';
X		} else {
X
X#ifdef DEBUG
X			printf("Reading block %d\n", block_to_read);
X#endif
X				/* Seek to block */
X			(void) lseek(fs_fd, btobo(block_to_read), L_SET);
X
X				/* Read them */
X			if ((nr = read(fs_fd, bufptr, num_to_read)) == -1)
X					/* Return error if nothing read,
X					 * else # bytes actually read	*/
X				return (num_read == 0) ? -1 : num_read;
X		}
X
X		count -= nr;
X		file_cnt -= nr;
X		fp->file_ptr += nr;
X		num_read += nr;
X		bufptr += nr;		/* Point to next part of buffer */
X
X			/* Read short */
X		if (nr < num_to_read)
X			return num_read;
X	}
X	return num_read;
X}
X
SHAR_EOF
chmod 0644 io.c || echo "restore of io.c fails"
sed 's/^X//' << 'SHAR_EOF' > ls.c &&
X
X/*
X *     fssal - BSD file system salvage program
X *
X *     Copyright 1989, Robert Ankeney
X *                     Generic Computer Products
X *                     5315 S.W. 53rd Court
X *                     Portland, Oregon  97221
X *                     (503) 244-3699
X *     All Rights Reserved
X *
X *     Distribution of any portion of this software as part of any product
X *     for sale is prohibited.
X *
X *     Version 1.00 (Preliminary)
X */
X
X#include "fs.h"
X#include <sys/time.h>
X
X	/* struct holding super block */
Xextern struct fs	sb;
X
X	/* File system block size */
X#define BLKSIZE sb.fs_bsize
X
X/*
X *	ls -	Do a directory listing of given inode.  Do a 'ls -l'
X *		if Lflag is set;  do a 'ls -R' if Rflag is set.
X *		dir_name is name of passed directory.  idir_list is
X *		updated with inode number of each listed directory.
X */
Xls(ls_inode, dir_name, idir_list, Lflag, Rflag)
Xino_t	ls_inode;
Xchar	*dir_name;
Xstruct	idir **idir_list;
Xchar	Lflag, Rflag;
X{
X	struct icommon	fs_inode;	/* Inode for directory */
X	struct direct	*fs_dir;	/* Directory structure */
X	struct file_ptr	dir_ptr;	/* Directory pointer */
X
X	struct icommon	sym_inode;	/* Inode for symbolic link */
X	struct file_ptr	sym_ptr;	/* Symbolic link pointer */
X	long		sym_size;	/* Length of symbolic name */
X	char		sym_buf[MAX_PATH_LEN];	/* Buffer for symbolic name */
X
X	char		dir_buf[MAXBSIZE];	/* Directory buffer */
X	int		buf_cnt;	/* # chars in buffer */
X	int		next_ent;	/* Offset into buf of next direct */
X
X	int		mode;		/* File mode */
X	char		modes[11];	/* File mode string */
X	struct icommon	file_inode;	/* Inode for ls file */
X	int		i;
X	char		*create_time;	/* Creation date string */
X	char		cur_name[1024];	/* Current directory pathname */
X
X	char		*ctime();
X	char		*strcpy();
X	char		*sprintf();
X
X	extern int	errno;
X
X		/* Fetch inode */
X	get_inode(ls_inode, &fs_inode);
X
X		/* Make sure it's a directory! */
X	if ((fs_inode.ic_mode & IFMT) != IFDIR) {
X		errno = ENOTDIR;
X		return -1;
X	}
X
X		/* Add directory inode number to list */
X	add_dir_inode(idir_list, ls_inode);
X
X		/* Open directory */
X	uopen(&fs_inode, &dir_ptr);
X
X	if (Rflag && *dir_name)
X		printf("%s:\n", dir_name);
X
X		/* Read each directory block */
X	do {
X		    /* Read next block of directory */
X	    if ((buf_cnt = uread(&dir_ptr, dir_buf, BLKSIZE)) == -1) {
X		    perror("Cannot read directory");
X		    exit(1);
X	    }
X
X	    if (buf_cnt == 0)
X		break;
X
X		    /* For each file in directory, list it */
X	    next_ent = 0;
X	    do {
X			/* Point to next directory entry */
X		fs_dir = (struct direct *) &dir_buf[next_ent];
X
X			/* Directory entry here? */
X		if (fs_dir->d_ino != 0) {
X		    if (Lflag) {
X				/* Get inode */
X			get_inode(fs_dir->d_ino, &file_inode);
X
X			printf("%5d ", fs_dir->d_ino);		/* Inode # */
X			(void) strcpy(modes, "-rwxrwxrwx");
X			mode = file_inode.ic_mode;
X			for (i = 8; i >= 0; i--)
X				if ((mode & (1 << i)) == 0)
X					modes[9 - i] = '-';	/* rwx bits */
X			if ((mode & IFMT) == IFDIR)
X					  modes[0] = 'd';	/* directory */
X			if ((mode & IFMT) == IFLNK)
X					  modes[0] = 'l';	/* sym link */
X
X			if (mode & ISUID) modes[3] = 's';	/* setuid */
X			if (mode & ISGID) modes[6] = 's';	/* setgid */
X			if (mode & ISVTX) modes[9] = 't';	/* sticky */
X			printf("%s %3d %3d/%-3d %8ld",
X				modes,				/* modes */
X				file_inode.ic_nlink,		/* link cnt */
X				file_inode.ic_uid,		/* uid */
X				file_inode.ic_gid,		/* gid */
X				file_inode.ic_size.val[0]);	/* size */
X			create_time = ctime((long *) &file_inode.ic_ctime);
X			printf(" %-12.12s %-4.4s ", create_time + 4,
X						    create_time + 20);
X		        printf("%s", fs_dir->d_name);		/* file name */
X
X				/* Symbolic link? */
X			if ((mode & IFMT) == IFLNK) {
X					/* Yup - print name of link */
X				get_inode(fs_dir->d_ino, &sym_inode);
X				sym_size = sym_inode.ic_size.val[0];
X				if (sym_size >= sizeof(sym_buf))
X					printf(" -> ?name too big");
X				else {
X					uopen(&sym_inode, &sym_ptr);
X					if (uread(&sym_ptr, sym_buf, sym_size)
X							!= sym_size) {
X						perror("Cannot read symlink");
X						exit(1);
X					}
X					sym_buf[sym_size] = '\0';
X					printf(" -> %s", sym_buf);
X				}
X			}
X			printf("\n");
X
X		    } else
X		        printf("%s\n", fs_dir->d_name);		/* file name */
X		}
X		next_ent += fs_dir->d_reclen;
X	    } while (next_ent < buf_cnt);
X
X    } while (buf_cnt > 0);
X
X    printf("\n");
X
X	/* Recursive (ls -R)? */
X    if (Rflag) {
X		/* Open directory again */
X	uopen(&fs_inode, &dir_ptr);
X
X		/* Read each directory block */
X	do {
X		    /* Read next block of directory */
X	    if ((buf_cnt = uread(&dir_ptr, dir_buf, BLKSIZE)) == -1) {
X		    perror("Cannot read directory");
X		    exit(1);
X	    }
X
X	    if (buf_cnt == 0)
X		break;
X
X		    /* For each directory in directory, list it */
X	    next_ent = 0;
X	    do {
X			/* Point to next directory entry */
X		fs_dir = (struct direct *) &dir_buf[next_ent];
X
X			/* Directory entry here? */
X		if (fs_dir->d_ino != 0) {
X				/* Get inode */
X			get_inode(fs_dir->d_ino, &file_inode);
X
X				/* Make sure is dir and not . or .. */
X			if ((file_inode.ic_mode & IFMT) == IFDIR)
X			    if (strcmp(fs_dir->d_name, ".") &&
X				strcmp(fs_dir->d_name, ".."))
X
X				/* Make sure not already listed */
X			    if (in_idir(*idir_list, fs_dir->d_ino))
X				fprintf(stderr, "Already ls'd inum %d, directory: %s !\n", fs_dir->d_ino, cur_name);
X			    else {
X				    if (*dir_name)
X					(void) sprintf(cur_name, "%s/%s",
X						dir_name, fs_dir->d_name);
X				    else
X					(void) strcpy(cur_name, fs_dir->d_name);
X
X					/* List this directory! */
X				    if (ls(fs_dir->d_ino, cur_name, idir_list,
X					Lflag, Rflag))
X						return -1;
X			    }
X		}
X		next_ent += fs_dir->d_reclen;
X	    } while (next_ent < buf_cnt);
X
X	} while (buf_cnt > 0);
X    }
X    return 0;
X}
X
X
Xls_all(Rflag, verbose)
Xchar	Rflag, verbose;
X{
X	struct	idir *idir_list, *ls_list, *idir_ptr, *ls_ptr;
X
X	ino_t	inum;
X	int	icnt = 0;
X	char	iname[MAX_PATH_LEN];
X
X		/* Get list of directory inodes for filesystem */
X	get_dir_inodes(&idir_list, (ino_t) 2, (ino_t) sb.fs_ncg * sb.fs_ipg);
X
X		/* Make list of ls'd directory inodes */
X	new_idir(&ls_list);
X	idir_ptr = idir_list;
X	while (idir_ptr) {
X		inum = idir_ptr->inums[icnt];
X			/* Inode been ls'd? */
X		if (!in_idir(ls_list, inum)) {
X
X				/* Point to end of ls'd inode list */
X			ls_ptr = ls_list;
X			while(ls_ptr->next_idir)
X				ls_ptr = ls_ptr->next_idir;
X			
X				/* Append to end of ls'd inode list */
X			if (ls(inum, iname, &ls_ptr, Rflag, verbose))
X				return -1;
X		}
X		if (++icnt == idir_ptr->icnt) {
X			icnt = 0;
X			idir_ptr = idir_ptr->next_idir;
X		}
X	}
X	return 0;
X}
SHAR_EOF
chmod 0644 ls.c || echo "restore of ls.c fails"
sed 's/^X//' << 'SHAR_EOF' > main.c &&
X
X/*
X *     fssal - BSD file system salvage program
X *
X *     Copyright 1989, Robert Ankeney
X *                     Generic Computer Products
X *                     5315 S.W. 53rd Court
X *                     Portland, Oregon  97221
X *                     (503) 244-3699
X *     All Rights Reserved
X *
X *     Distribution of any portion of this software as part of any product
X *     for sale is prohibited.
X *
X *     Version 1.00 (Preliminary)
X */
X
X#include "fs.h"
X#include <sys/stat.h>
X
X	/* File descriptor filesystem is open on */
Xint		fs_fd;
X
X	/* struct holding super block */
Xstruct fs	sb;
X
X	/* Current root inode */
Xino_t	root_inode = ROOTINO;
X
Xchar	*fs_to_read = FS_TO_READ;
Xint	sb_block = BBSIZE / 512;
X
Xusage(fs_name)
Xchar	*fs_name;
X{
X    fprintf (stderr,
X"usage: %s [-f device] [-s super-block] [-r root-inode] [-a] [-l] [-R] [-v]\n",
X	fs_name);
X    exit(1);
X}
X
Xmain(argc, argv)
Xint	argc;
Xchar	*argv[];
X{
X	char	do_all, verbose, recurse, long_ls = FALSE;
X	char	*fs_name = argv[0];
X	struct	stat statb;
X	struct	idir *idir_list;
X
X	for (fs_name = argv[0] + strlen(argv[0]);
X	    (fs_name != argv[0]) && (*(fs_name - 1) != '/'); fs_name--) ;
X
X	while (*++argv) {
X		if (**argv == '-') {
X			switch (*++*argv) {
X			case 'f':
X				fs_to_read = *++argv;
X				break;
X			case 's':
X				sb_block = atoi (*++argv);
X				break;
X			case 'r':
X				root_inode = atoi (*++argv);
X				break;
X			case 'a':
X				do_all = TRUE;
X				break;
X			case 'v':
X				verbose = TRUE;
X				break;
X			case 'R':
X				recurse = TRUE;
X				break;
X			case 'l':
X				long_ls = TRUE;
X				break;
X
X			default:
X				usage(fs_name);
X			}
X		}
X	}
X
X		/* Stat file and see if it's a block special device */
X	if (stat(fs_to_read, &statb)) {
X		perror("Cannot stat file");
X		exit(1);
X	} else
X		if ((statb.st_mode & S_IFMT) != S_IFBLK) {
X			fprintf(stderr, "%s not a block special device\n",
X				fs_to_read);
X		exit(1);
X	}
X
X		/* Read in superblock */
X	getsb(fs_to_read, sb_block);
X	
X	new_idir(&idir_list);
X
X	if (!strcmp(fs_name, "fssal"))
X		if (do_all)
X			exit( restore_all(recurse, verbose) );
X		else
X			exit( restore(".", root_inode, ".",
X					&idir_list, recurse, verbose) );
X
X	if (!strcmp(fs_name, "fsls"))
X		if (do_all)
X			exit( ls_all(long_ls, recurse) );
X		else
X			exit( ls(root_inode, "", &idir_list, long_ls, recurse));
X
X	usage(fs_name);
X
X	(void) close(fs_fd);
X	exit(0);
X}
SHAR_EOF
chmod 0644 main.c || echo "restore of main.c fails"
sed 's/^X//' << 'SHAR_EOF' > namei.c &&
X
X/*
X *     fssal - BSD file system salvage program
X *
X *     Copyright 1989, Robert Ankeney
X *                     Generic Computer Products
X *                     5315 S.W. 53rd Court
X *                     Portland, Oregon  97221
X *                     (503) 244-3699
X *     All Rights Reserved
X *
X *     Distribution of any portion of this software as part of any product
X *     for sale is prohibited.
X *
X *     Version 1.00 (Preliminary)
X */
X
X#include "fs.h"
X
X
X	/* File descriptor filesystem is open on */
Xextern int	fs_fd;
X
X	/* struct holding super block */
Xextern struct fs	sb;
X
X	/* File system block size */
X#define BLKSIZE sb.fs_bsize
X
X/*
X *	get_inode - read inode inum into struct rd_inode
X */
Xget_inode(inum, rd_inode)
Xino_t		inum;
Xstruct icommon	*rd_inode;
X{
X	long	lseek();
X
X		/* Seek to desired inode */
X	(void) lseek(fs_fd, (long) itobo(inum), L_SET);
X
X		/* Read that inode */
X	if (read(fs_fd, (char *) rd_inode, ISIZE) == -1) {
X		perror("Cannot read file system");
X		exit(1);
X	}
X}
X
X/*
X *	namei -	Convert filename to inode number.
X *
X *		First get root inode for file system.
X *		From there, search each directory in path for next
X *		component of path name, till final filename found.
X *
X *		Returns:
X *		    0 if file not found (ENOENT),
X *		    0 if file in path was not a directory (ENOTDIR),
X *		    else inode of file filename.
X */
Xnamei(filename)
Xchar	*filename;
X{
X	char	tmp_name[1024];		/* Copy of filename */
X	ino_t	cur_ino;		/* Current inode in path */
X	char 	*curnam;		/* Points to next char in filename */
X	char	*next_name;		/* Next name to scan */
X	int	next_slash;
X
X	struct icommon	fs_inode;	/* Inode for file/directory */
X	struct direct	*fs_dir;	/* Directory structure */
X	struct file_ptr	dir_ptr;	/* Directory pointer */
X
X	char	dir_buf[MAXBSIZE];	/* Directory buffer */
X	int		buf_cnt;	/* # chars in buffer */
X
X	int		next_ent;	/* Offset into buf of next direct */
X
X	char		*strcpy();
X
X	extern int	errno;
X
X		/* Save copy of path name */
X	(void) strcpy(tmp_name, filename);
X	curnam = tmp_name;
X
X		/* Start at root inode */
X	cur_ino = ROOTINO;
X
X		/* Search till nothing left of path name */
X	while ((*curnam != '\0') && (cur_ino != 0)) {
X
X#ifdef DEBUG
X		printf("Reading inode %d\n", cur_ino);
X#endif
X			/* Get current inode */
X		get_inode(cur_ino, &fs_inode);
X
X			/* Make sure it's a directory! */
X		if ((fs_inode.ic_mode & IFMT) != IFDIR) {
X			errno = ENOTDIR;
X			return 0;
X		}
X
X			/* Skip /'s in next component of name */
X		while (*curnam == '/') curnam++;
X
X			/* Get next component of path in next_name */
X		for (next_slash = 0;
X		    (curnam[next_slash] != '\0') && (curnam[next_slash] != '/');
X		     next_slash ++) ;
X		
X		next_name = curnam;
X		curnam += next_slash;
X		if (*curnam == '/') curnam++;
X		next_name[next_slash] = '\0';
X
X#ifdef DEBUG
X		printf("Scanning directory for file '%s'.\n", next_name);
X#endif
X
X			/* Open directory */
X		uopen(&fs_inode, &dir_ptr);
X
X			/*
X			 * Search each directory block for name.
X			 * Return inode number in cur_ino when found.
X			 */
X		cur_ino = 0;
X		do {
X
X				/* Read next block of directory */
X			if ((buf_cnt = uread(&dir_ptr, dir_buf, BLKSIZE))
X								== -1) {
X				perror("Cannot read directory");
X				exit(1);
X			}
X
X			if (buf_cnt == 0)
X				break;
X
X				/* Scan directory block for desired name */
X			next_ent = 0;
X			do {
X					/* Point to next directory entry */
X				fs_dir = (struct direct *)
X						 &dir_buf[next_ent];
X
X					/* Directory entry here? */
X				if (fs_dir->d_ino != 0) {
X#ifdef DEBUG
X					printf("Inode: %6d file: %s\n",
X						fs_dir->d_ino, fs_dir->d_name);
X#endif
X
X						/* Names match? */
X					if (!strcmp(next_name, fs_dir->d_name))
X							/* Yes- save inode */
X						cur_ino = fs_dir->d_ino;
X				}
X				next_ent += fs_dir->d_reclen;
X			} while ((cur_ino == 0) &&
X				 (next_ent < buf_cnt));
X
X		} while ((cur_ino == 0) && (buf_cnt > 0));
X	}
X
X	if (cur_ino == 0) {
X		errno = ENOENT;
X		return 0;		/* File not found - return 0 */
X	} else
X		return cur_ino;		/* Found - return inode number */
X}
X
SHAR_EOF
chmod 0644 namei.c || echo "restore of namei.c fails"
sed 's/^X//' << 'SHAR_EOF' > restore.c &&
X
X/*
X *     fssal - BSD file system salvage program
X *
X *     Copyright 1989, Robert Ankeney
X *                     Generic Computer Products
X *                     5315 S.W. 53rd Court
X *                     Portland, Oregon  97221
X *                     (503) 244-3699
X *     All Rights Reserved
X *
X *     Distribution of any portion of this software as part of any product
X *     for sale is prohibited.
X *
X *     Version 1.00 (Preliminary)
X */
X
X#include "fs.h"
X#include <sys/stat.h>
X#include <sys/time.h>
X
X	/* struct holding super block */
Xextern struct fs	sb;
X
X	/* Current root inode */
Xextern ino_t	root_inode;
X
X	/* File system block size */
X#define BLKSIZE sb.fs_bsize
X
Xchar *base_path;	/* Initial restore path */
Xino_t   base_inode;	/* Initial restore inode # */
X
X/*
X *	restore - Restore files from given directory.
X *		  from_path is path name to from_inode, which is
X *		  directory to be restored.  Files are restored to
X *		  to_path.  If Rflag is set, restore is recursive
X *		  ( cp -R ).  idir_list is updated with inode number of
X *		  each directory restored.
X */
Xrestore(from_path, from_inode, to_path, idir_list, Rflag, verbose)
Xino_t	from_inode;
Xchar	*from_path, *to_path;
Xstruct	idir **idir_list;
Xchar	Rflag, verbose;
X{
X		/* Save initial restore path and inode # */
X	base_path = to_path;
X	base_inode = from_inode;
X	return
X	    rrestore(from_path, from_inode, to_path, idir_list, Rflag, verbose);
X}
X
Xrrestore(from_path, from_inode, to_path, idir_list, Rflag, verbose)
Xino_t	from_inode;
Xchar	*from_path, *to_path;
Xstruct	idir **idir_list;
Xchar	Rflag, verbose;
X{
X	struct icommon	fs_inode;	/* Inode for directory */
X	struct direct	*fs_dir;	/* Directory structure */
X	struct file_ptr	dir_ptr;	/* Directory pointer */
X
X	struct icommon	sym_inode;	/* Inode for symbolic link */
X	struct file_ptr	sym_ptr;	/* Symbolic link pointer */
X	long		sym_size;	/* Length of symbolic name */
X	char		sym_buf[MAX_PATH_LEN];	/* Buffer for symbolic name */
X
X	char		dir_buf[MAXBSIZE];	/* Directory buffer */
X	int		buf_cnt;	/* # chars in buffer */
X	int		next_ent;	/* Offset into buf of next direct */
X
X	int		mode;		/* File mode */
X	struct icommon	file_inode;	/* Inode for ls file */
X	char		in_path[MAX_PATH_LEN];	/* Current input file name */
X	char		out_path[MAX_PATH_LEN];	/* Current output file name */
X
X	char		set_times;	/* TRUE to set creation time */
X	struct timeval	file_times[2];
X
X	struct iname_list *link_list;	/* List of files with common inode */
X	struct iname_list *temp_link;
X	int		links_found;
X	struct stat	file_stat;	/* File status (for inode # to link) */
X	int		out_file;	/* Output file descriptor */
X
X	char		copy_file;	/* TRUE to copy (not link) file */
X	struct file_ptr	in_ptr;		/* File pointer for input file */
X	int		nr;
X	char		buf[8192];
X
X	char		*ctime();
X	char		*strcpy(), *strcat();
X
X	extern int	errno;
X
X	(void) umask(0);		/* Create any mode file */
X
X		/* Fetch inode */
X	get_inode(from_inode, &fs_inode);
X
X		/* Make sure it's a directory! */
X	if ((fs_inode.ic_mode & IFMT) != IFDIR) {
X		errno = ENOTDIR;
X		return -1;
X	}
X
X		/* Add directory inode number to list */
X	add_dir_inode(idir_list, from_inode);
X
X		/* Open directory */
X	uopen(&fs_inode, &dir_ptr);
X
X		/* Read each directory block */
X	do {
X		    /* Read next block of directory */
X	    if ((buf_cnt = uread(&dir_ptr, dir_buf, BLKSIZE)) == -1) {
X		    perror("Cannot read directory");
X		    exit(1);
X	    }
X
X	    if (buf_cnt == 0)
X		break;
X
X		    /* For each file in directory, restore it */
X	    next_ent = 0;
X	    do {
X			/* Point to next directory entry */
X		fs_dir = (struct direct *) &dir_buf[next_ent];
X
X			/* Directory entry here? */
X		if ((fs_dir->d_ino != 0) && strcmp(fs_dir->d_name, ".")
X					 && strcmp(fs_dir->d_name, "..")) {
X				/* Get inode */
X			get_inode(fs_dir->d_ino, &file_inode);
X
X			(void) strcpy(in_path, from_path);
X			(void) strcat(in_path, "/");
X			(void) strcat(in_path, fs_dir->d_name);
X			(void) strcpy(out_path, to_path);
X			(void) strcat(out_path, "/");
X			(void) strcat(out_path, fs_dir->d_name);
X
X				/* Set up access and mod times */
X			set_times = TRUE;
X			file_times[0].tv_sec = file_inode.ic_atime;
X			file_times[0].tv_usec = file_times[1].tv_usec = 0;
X			file_times[1].tv_sec = file_inode.ic_mtime;
X
X			mode = file_inode.ic_mode;
X
X			switch (mode & IFMT) {
X
X			case 0020000:		/* character special */
X			case 0060000:		/* block special */
X			case 0140000:		/* socket - will it work? */
X				if (verbose)
X					printf("Creating special file: %s\n",
X						out_path);
X				if (mknod(out_path, mode,
X					(int) file_inode.ic_db[0]))
X				{
X					fprintf(stderr,
X					    "Cannot create special file: %s; ",
X						out_path);
X					perror("");
X					set_times = FALSE;
X				}
X				break;
X
X			case 0040000:		/* directory */
X				if (verbose)
X					printf("Creating directory: %s\n",
X						out_path);
X				if (mkdir(out_path, mode)) {
X					fprintf(stderr,
X					    "Cannot create directory: %s; ",
X						out_path);
X					perror("");
X					set_times = FALSE;
X				}
X				break;
X
X			case 0100000:		/* regular file */
X				copy_file = (file_inode.ic_nlink == 1);
X				if (!copy_file) {
X						/* Oh shit; it's a link */
X						/* Get filenames with inode # */
X					iname(base_path, base_inode,
X					    fs_dir->d_ino, file_inode.ic_nlink,
X						&link_list, &links_found);
X
X						/* Search for existing file */
X						/* to link to */
X					for (temp_link = link_list;
X					     temp_link;
X					     temp_link = temp_link->next_iname)
X					{
X					    if (stat(temp_link->name,
X							&file_stat)) {
X						    if (errno != ENOENT) {
X							fprintf(stderr,
X							    "Cannot stat %s: ",
X							    temp_link->name);
X							perror("");
X						    }
X					    } else
X					    if (mode != file_stat.st_mode) {
X						fprintf(stderr,
X						    "Mode mismatch on %s\n",
X							temp_link->name);
X					    } else
X						break;
X					}
X
X					if (temp_link) {
X						/* Found file to link to */
X					    if (verbose)
X						printf("Linking %s to %s\n",
X						    temp_link->name, out_path);
X					    if (link(temp_link->name, out_path))
X					    {
X						fprintf(stderr,
X						    "Cannot link %s to %s: ",
X						    temp_link->name, out_path);
X						perror("");
X						copy_file = TRUE;
X					    } else
X						set_times = FALSE;
X					} else
X					    copy_file = TRUE;
X				}
X
X				if (copy_file) {
X						/* Copy file */
X					if (verbose)
X						printf("Copying %s to %s\n",
X							in_path, out_path);
X					uopen(&file_inode, &in_ptr);
X					if ((out_file = open(out_path,
X							    O_CREAT | O_WRONLY,
X							    mode)) == -1) {
X						fprintf(stderr,
X							"Cannot create %s: ",
X							out_path);
X						perror("");
X						break;
X					}
X
X						/* Copy file */
X					do {
X						if ((nr = uread(&in_ptr, buf,
X							    BLKSIZE)) == -1) {
X							fprintf(stderr,
X							    "Cannot read %s: ",
X								in_path);
X							perror("");
X						}
X
X						if (nr > 0)
X						    if (write(out_file, buf, nr)
X								== -1) {
X							fprintf(stderr,
X							    "Cannot write %s: ",
X								out_path);
X							perror("");
X						}
X					} while (nr > 0);
X
X					(void) close(out_file);
X				}
X				break;
X
X			case 0120000:			/* symbolic link */
X					/* Can't utime symlink */
X				set_times = FALSE;
X					/* Get name of link */
X				get_inode(fs_dir->d_ino, &sym_inode);
X				sym_size = sym_inode.ic_size.val[0];
X				if (sym_size >= sizeof(sym_buf)) {
X					fprintf(stderr,
X					    "Symbolic link to %s too long\n",
X						out_path);
X					set_times = FALSE;
X				} else {
X					uopen(&sym_inode, &sym_ptr);
X					if (uread(&sym_ptr, sym_buf, sym_size)
X							!= sym_size) {
X						perror("Cannot read symlink");
X						set_times = FALSE;
X					}
X					sym_buf[sym_size] = '\0';
X
X					if (verbose)
X					    printf("Creating symbolic link %s -> %s\n",
X						    sym_buf, out_path);
X					if (symlink(sym_buf, out_path)) {
X						fprintf(stderr,
X						    "Cannot create symbolic link %s -> %s: ",
X						    out_path, sym_buf);
X						perror("");
X#ifdef UTEK
X						if (errno != EDFSNOSUCHHOST)
X							set_times = FALSE;
X#endif
X					}
X				}
X				break;
X
X			default:
X				fprintf(stderr, "Unknown mode %o on file %s\n",
X					mode, in_path);
X				set_times = FALSE;
X			}
X
X			if (set_times) {
X					/* Set creation times on file */
X				if (utimes(out_path, file_times)) {
X					fprintf(stderr,
X					    "Cannot set creation times on %s: ",
X						out_path);
X					perror("");
X				}
X					/* Set owner and group */
X				if (chown(out_path, file_inode.ic_uid,
X						    file_inode.ic_gid)) {
X					fprintf(stderr,
X						"Cannot set owner on %s: ",
X						out_path);
X					perror("");
X				}
X			}
X
X		}
X		next_ent += fs_dir->d_reclen;
X	    } while (next_ent < buf_cnt);
X
X    } while (buf_cnt > 0);
X
X	/* Recursive (cp -R)? */
X    if (Rflag) {
X		/* Open directory again */
X	uopen(&fs_inode, &dir_ptr);
X
X		/* Read each directory block */
X	do {
X		    /* Read next block of directory */
X	    if ((buf_cnt = uread(&dir_ptr, dir_buf, BLKSIZE)) == -1) {
X		    perror("Cannot read directory");
X		    exit(1);
X	    }
X
X	    if (buf_cnt == 0)
X		break;
X
X		    /* For each sub-directory in directory, restore it */
X	    next_ent = 0;
X	    do {
X			/* Point to next directory entry */
X		fs_dir = (struct direct *) &dir_buf[next_ent];
X
X			/* Directory entry here? */
X		if (fs_dir->d_ino != 0) {
X				/* Get inode */
X			get_inode(fs_dir->d_ino, &file_inode);
X
X
X				/* Make sure is dir and not . or .. */
X			if ((file_inode.ic_mode & IFMT) == IFDIR)
X					if (strcmp(fs_dir->d_name, ".") &&
X					strcmp(fs_dir->d_name, "..")) {
X
X				/* Make sure not restored yet */
X			    if (in_idir(*idir_list, fs_dir->d_ino)) {
X				fprintf(stderr,
X				  "Already restored inum %d, directory: %s !\n",
X					fs_dir->d_ino, from_path);
X			    } else {
X				(void) strcpy(in_path, from_path);
X				(void) strcat(in_path, "/");
X				(void) strcat(in_path, fs_dir->d_name);
X				(void) strcpy(out_path, to_path);
X				(void) strcat(out_path, "/");
X				(void) strcat(out_path, fs_dir->d_name);
X
X				file_times[0].tv_sec = file_inode.ic_atime;
X				file_times[0].tv_usec = file_times[1].tv_usec
X									= 0;
X				file_times[1].tv_sec = file_inode.ic_mtime;
X
X					/* Restore this directory! */
X				if (rrestore(in_path, fs_dir->d_ino, out_path,
X						idir_list, Rflag, verbose))
X					return -1;
X
X					/* Set creation times on directory */
X				if (utimes(out_path, file_times)) {
X					fprintf(stderr,
X					    "Cannot set creation times on %s: ",
X						out_path);
X					perror("");
X				}
X			    }
X			}
X		}
X		next_ent += fs_dir->d_reclen;
X	    } while (next_ent < buf_cnt);
X
X	} while (buf_cnt > 0);
X    }
X    return 0;
X}
X
Xrestore_all(Rflag, verbose)
Xchar	Rflag, verbose;
X{
X	struct	idir *idir_list, *restore_list, *idir_ptr, *restore_ptr;
X
X	ino_t	inum;
X	int	icnt = 0;
X	char	iname[MAX_PATH_LEN];
X
X	char 	*sprintf();
X
X		/* Get list of directory inodes for filesystem */
X	get_dir_inodes(&idir_list, (ino_t) 2, (ino_t) sb.fs_ncg * sb.fs_ipg);
X
X		/* Make list of restored directory inodes */
X	new_idir(&restore_list);
X	idir_ptr = idir_list;
X	while (idir_ptr) {
X		inum = idir_ptr->inums[icnt];
X			/* Inode been restored? */
X		if (!in_idir(restore_list, inum)) {
X
X				/* Nope - create directory and restore */
X			(void) sprintf(iname, "i%d", inum);
X
X			if (verbose)
X				printf("Creating new base directory: %s\n",
X					iname);
X			if (mkdir(iname, 0775)) {
X				fprintf(stderr,
X				    "Cannot create directory: %s; ",
X					iname);
X				perror("");
X			}
X
X				/* Point to end of restored inode list */
X			restore_ptr = restore_list;
X			while(restore_ptr->next_idir)
X				restore_ptr = restore_ptr->next_idir;
X			
X				/* Append to end of restored inode list */
X			if (restore(iname, inum, iname, &restore_ptr,
X						Rflag, verbose))
X				return -1;
X		}
X		if (++icnt == idir_ptr->icnt) {
X			icnt = 0;
X			idir_ptr = idir_ptr->next_idir;
X		}
X	}
X	return 0;
X}
SHAR_EOF
chmod 0644 restore.c || echo "restore of restore.c fails"
sed 's/^X//' << 'SHAR_EOF' > stat.c &&
X
X/*
X *     fssal - BSD file system salvage program
X *
X *     Copyright 1989, Robert Ankeney
X *                     Generic Computer Products
X *                     5315 S.W. 53rd Court
X *                     Portland, Oregon  97221
X *                     (503) 244-3699
X *     All Rights Reserved
X *
X *     Distribution of any portion of this software as part of any product
X *     for sale is prohibited.
X *
X *     Version 1.00 (Preliminary)
X */
X
X/*
X * stat.c
X *
X * load an inode into memory
X */
X
X# include	"fs.h"
X# include	<sys/stat.h>
X
Xextern struct fs	sb;
Xextern int		fs_fd;
X
Xfs_stat (inum, statb)
Xino_t		inum;
Xstruct stat	*statb;
X{
X	long	off;
X	struct	dinode di;
X
X	long	lseek();
X
X	off = itobo (inum);
X	(void) lseek (fs_fd, off, L_SET);
X	if (read (fs_fd, (char *) &di, sizeof (di)) != sizeof (di))
X		return -1;
X	statb->st_dev = 0;
X	statb->st_ino = inum;
X	statb->st_mode = di.di_mode;
X	statb->st_nlink = di.di_nlink;
X	statb->st_uid = di.di_uid;
X	statb->st_gid = di.di_gid;
X	statb->st_atime = di.di_atime;
X	statb->st_mtime = di.di_mtime;
X	statb->st_ctime = di.di_ctime;
X	statb->st_blocks = di.di_blocks;
X	return 0;
X}
SHAR_EOF
chmod 0644 stat.c || echo "restore of stat.c fails"
exit 0