BSD 4_3_Reno release
[unix-history] / usr / src / sbin / dump / dumptraverse.c
/*
* Copyright (c) 1980, 1988 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef lint
static char sccsid[] = "@(#)dumptraverse.c 5.5 (Berkeley) 5/20/88";
#endif not lint
#include "dump.h"
pass(fn, map)
register int (*fn)();
register char *map;
{
register int bits;
ino_t maxino;
maxino = sblock->fs_ipg * sblock->fs_ncg - 1;
for (ino = 0; ino < maxino; ) {
if ((ino % NBBY) == 0) {
bits = ~0;
if (map != NULL)
bits = *map++;
}
ino++;
if (bits & 1)
(*fn)(getino(ino));
bits >>= 1;
}
}
mark(ip)
struct dinode *ip;
{
register int f;
extern int anydskipped;
f = ip->di_mode & IFMT;
if (f == 0)
return;
BIS(ino, clrmap);
if (f == IFDIR)
BIS(ino, dirmap);
if ((ip->di_mtime >= spcl.c_ddate || ip->di_ctime >= spcl.c_ddate) &&
!BIT(ino, nodmap)) {
BIS(ino, nodmap);
if (f != IFREG && f != IFDIR && f != IFLNK) {
esize += 1;
return;
}
est(ip);
} else if (f == IFDIR)
anydskipped = 1;
}
add(ip)
register struct dinode *ip;
{
register int i;
long filesize;
if(BIT(ino, nodmap))
return;
nsubdir = 0;
dadded = 0;
filesize = ip->di_size;
for (i = 0; i < NDADDR; i++) {
if (ip->di_db[i] != 0)
dsrch(ip->di_db[i], dblksize(sblock, ip, i), filesize);
filesize -= sblock->fs_bsize;
}
for (i = 0; i < NIADDR; i++) {
if (ip->di_ib[i] != 0)
indir(ip->di_ib[i], i, &filesize);
}
if(dadded) {
nadded++;
if (!BIT(ino, nodmap)) {
BIS(ino, nodmap);
est(ip);
}
}
if(nsubdir == 0)
if(!BIT(ino, nodmap))
BIC(ino, dirmap);
}
indir(d, n, filesize)
daddr_t d;
int n, *filesize;
{
register i;
daddr_t idblk[MAXNINDIR];
bread(fsbtodb(sblock, d), (char *)idblk, sblock->fs_bsize);
if(n <= 0) {
for(i=0; i < NINDIR(sblock); i++) {
d = idblk[i];
if(d != 0)
dsrch(d, sblock->fs_bsize, *filesize);
*filesize -= sblock->fs_bsize;
}
} else {
n--;
for(i=0; i < NINDIR(sblock); i++) {
d = idblk[i];
if(d != 0)
indir(d, n, filesize);
}
}
}
dirdump(ip)
struct dinode *ip;
{
/* watchout for dir inodes deleted and maybe reallocated */
if ((ip->di_mode & IFMT) != IFDIR)
return;
dump(ip);
}
dump(ip)
struct dinode *ip;
{
register int i;
long size;
if(newtape) {
newtape = 0;
bitmap(nodmap, TS_BITS);
}
BIC(ino, nodmap);
spcl.c_dinode = *ip;
spcl.c_type = TS_INODE;
spcl.c_count = 0;
i = ip->di_mode & IFMT;
if (i == 0) /* free inode */
return;
if ((i != IFDIR && i != IFREG && i != IFLNK) || ip->di_size == 0) {
spclrec();
return;
}
if (ip->di_size > NDADDR * sblock->fs_bsize)
i = NDADDR * sblock->fs_frag;
else
i = howmany(ip->di_size, sblock->fs_fsize);
blksout(&ip->di_db[0], i);
size = ip->di_size - NDADDR * sblock->fs_bsize;
if (size <= 0)
return;
for (i = 0; i < NIADDR; i++) {
dmpindir(ip->di_ib[i], i, &size);
if (size <= 0)
return;
}
}
dmpindir(blk, lvl, size)
daddr_t blk;
int lvl;
long *size;
{
int i, cnt;
daddr_t idblk[MAXNINDIR];
if (blk != 0)
bread(fsbtodb(sblock, blk), (char *)idblk, sblock->fs_bsize);
else
bzero(idblk, sblock->fs_bsize);
if (lvl <= 0) {
if (*size < NINDIR(sblock) * sblock->fs_bsize)
cnt = howmany(*size, sblock->fs_fsize);
else
cnt = NINDIR(sblock) * sblock->fs_frag;
*size -= NINDIR(sblock) * sblock->fs_bsize;
blksout(&idblk[0], cnt);
return;
}
lvl--;
for (i = 0; i < NINDIR(sblock); i++) {
dmpindir(idblk[i], lvl, size);
if (*size <= 0)
return;
}
}
blksout(blkp, frags)
daddr_t *blkp;
int frags;
{
int i, j, count, blks, tbperdb;
blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
tbperdb = sblock->fs_bsize / TP_BSIZE;
for (i = 0; i < blks; i += TP_NINDIR) {
if (i + TP_NINDIR > blks)
count = blks;
else
count = i + TP_NINDIR;
for (j = i; j < count; j++)
if (blkp[j / tbperdb] != 0)
spcl.c_addr[j - i] = 1;
else
spcl.c_addr[j - i] = 0;
spcl.c_count = count - i;
spclrec();
for (j = i; j < count; j += tbperdb)
if (blkp[j / tbperdb] != 0)
if (j + tbperdb <= count)
dmpblk(blkp[j / tbperdb],
sblock->fs_bsize);
else
dmpblk(blkp[j / tbperdb],
(count - j) * TP_BSIZE);
spcl.c_type = TS_ADDR;
}
}
bitmap(map, typ)
char *map;
{
register i;
char *cp;
spcl.c_type = typ;
spcl.c_count = howmany(msiz * sizeof(map[0]), TP_BSIZE);
spclrec();
for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE)
taprec(cp);
}
spclrec()
{
register int s, i, *ip;
spcl.c_inumber = ino;
spcl.c_magic = NFS_MAGIC;
spcl.c_checksum = 0;
ip = (int *)&spcl;
s = 0;
i = sizeof(union u_spcl) / (4*sizeof(int));
while (--i >= 0) {
s += *ip++; s += *ip++;
s += *ip++; s += *ip++;
}
spcl.c_checksum = CHECKSUM - s;
taprec((char *)&spcl);
}
dsrch(d, size, filesize)
daddr_t d;
int size, filesize;
{
register struct direct *dp;
long loc;
char dblk[MAXBSIZE];
if(dadded)
return;
if (filesize > size)
filesize = size;
bread(fsbtodb(sblock, d), dblk, filesize);
for (loc = 0; loc < filesize; ) {
dp = (struct direct *)(dblk + loc);
if (dp->d_reclen == 0) {
msg("corrupted directory, inumber %d\n", ino);
break;
}
loc += dp->d_reclen;
if(dp->d_ino == 0)
continue;
if(dp->d_name[0] == '.') {
if(dp->d_name[1] == '\0')
continue;
if(dp->d_name[1] == '.' && dp->d_name[2] == '\0')
continue;
}
if(BIT(dp->d_ino, nodmap)) {
dadded++;
return;
}
if(BIT(dp->d_ino, dirmap))
nsubdir++;
}
}
struct dinode *
getino(ino)
daddr_t ino;
{
static daddr_t minino, maxino;
static struct dinode itab[MAXINOPB];
if (ino >= minino && ino < maxino) {
return (&itab[ino - minino]);
}
bread(fsbtodb(sblock, itod(sblock, ino)), itab, sblock->fs_bsize);
minino = ino - (ino % INOPB(sblock));
maxino = minino + INOPB(sblock);
return (&itab[ino - minino]);
}
int breaderrors = 0;
#define BREADEMAX 32
bread(da, ba, cnt)
daddr_t da;
char *ba;
int cnt;
{
int n, i;
extern int errno;
loop:
if (lseek(fi, (long)(da * dev_bsize), 0) < 0){
msg("bread: lseek fails\n");
}
n = read(fi, ba, cnt);
if (n == cnt)
return;
if (da + (cnt / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) {
/*
* Trying to read the final fragment.
*
* NB - dump only works in TP_BSIZE blocks, hence
* rounds `dev_bsize' fragments up to TP_BSIZE pieces.
* It should be smarter about not actually trying to
* read more than it can get, but for the time being
* we punt and scale back the read only when it gets
* us into trouble. (mkm 9/25/83)
*/
cnt -= dev_bsize;
goto loop;
}
msg("read error from %s [block %d]: count=%d, got=%d, errno=%d\n",
disk, da, cnt, n, errno);
if (++breaderrors > BREADEMAX){
msg("More than %d block read errors from %d\n",
BREADEMAX, disk);
broadcast("DUMP IS AILING!\n");
msg("This is an unrecoverable error.\n");
if (!query("Do you want to attempt to continue?")){
dumpabort();
/*NOTREACHED*/
} else
breaderrors = 0;
}
/*
* Zero buffer, then try to read each sector of buffer separately.
*/
bzero(ba, cnt);
for (i = 0; i < cnt; i += dev_bsize, ba += dev_bsize, da++) {
if (lseek(fi, (long)(da * dev_bsize), 0) < 0)
msg("bread: lseek2 fails!\n");
n = read(fi, ba, dev_bsize);
if (n != dev_bsize)
msg(" read error from %s [sector %d, errno %d]\n",
disk, da, errno);
}
}