Пример #1
0
static int
find_indirblks32(uint32_t blk, int ind_level, uint32_t *wantedblk)
{
#define MAXNINDIR	(MAXBSIZE / sizeof(uint32_t))
	uint32_t idblk[MAXNINDIR];
	size_t i;

	bread(fsreadfd, (char *)idblk, FFS_FSBTODB(sblock, blk),
	    (int)sblock->fs_bsize);
	if (ind_level <= 0) {
		if (find_blks32(idblk,
		    sblock->fs_bsize / sizeof(uint32_t), wantedblk))
			return 1;
	} else {
		ind_level--;
		for (i = 0; i < sblock->fs_bsize / sizeof(uint32_t); i++) {
			if (compare_blk32(wantedblk, iswap32(idblk[i]))) {
				if (founddatablk(iswap32(idblk[i])))
					return 1;
			}
			if(idblk[i] != 0)
				if (find_indirblks32(iswap32(idblk[i]),
				    ind_level, wantedblk))
				return 1;
		}
	}
#undef MAXNINDIR
	return 0;
}
Пример #2
0
/*
 * Fill in the ufsi struct, as well as the maxino and dev_bsize global
 * variables.
 */
struct ufsi *
fs_parametrize(void)
{
	static struct ufsi ufsi;

	spcl.c_flags = iswap32(iswap32(spcl.c_flags) | DR_NEWINODEFMT);

	ufsi.ufs_dsize = fsbtodb(sblock,sblock->lfs_size);
	if (sblock->lfs_version == 1) 
		ufsi.ufs_dsize = sblock->lfs_size >> sblock->lfs_blktodb;
	ufsi.ufs_bsize = sblock->lfs_bsize;
	ufsi.ufs_bshift = sblock->lfs_bshift;
	ufsi.ufs_fsize = sblock->lfs_fsize;
	ufsi.ufs_frag = sblock->lfs_frag;
	ufsi.ufs_fsatoda = sblock->lfs_fsbtodb;
	if (sblock->lfs_version == 1)
		ufsi.ufs_fsatoda = 0;
	ufsi.ufs_nindir = sblock->lfs_nindir;
	ufsi.ufs_inopb = sblock->lfs_inopb;
	ufsi.ufs_maxsymlinklen = sblock->lfs_maxsymlinklen;
	ufsi.ufs_bmask = ~(sblock->lfs_bmask);
	ufsi.ufs_qbmask = sblock->lfs_bmask;
	ufsi.ufs_fmask = ~(sblock->lfs_ffmask);
	ufsi.ufs_qfmask = sblock->lfs_ffmask;

	dev_bsize = sblock->lfs_bsize >> sblock->lfs_blktodb;

	return &ufsi;
}
Пример #3
0
static int
dotime(char *name, int32_t *rsec, int32_t *rnsec)
{
	char   *p, *val;
	struct tm t;
	int32_t sec;
	int32_t nsec;
	p = strchr(name, '.');
	if (p) {
		*p = '\0';
		nsec = strtoul(++p, &val, 0);
		if (val == p || *val != '\0' || nsec >= 1000000000 || nsec < 0) {
			warnx("invalid nanoseconds");
			goto badformat;
		}
	} else
		nsec = 0;
	if (strlen(name) != 14) {
badformat:
		warnx("date format: YYYYMMDDHHMMSS[.nsec]");
		return 1;
	}
	for (p = name; *p; p++)
		if (*p < '0' || *p > '9')
			goto badformat;

	p = name;
#define VAL() ((*p++) - '0')
	t.tm_year = VAL();
	t.tm_year = VAL() + t.tm_year * 10;
	t.tm_year = VAL() + t.tm_year * 10;
	t.tm_year = VAL() + t.tm_year * 10 - 1900;
	t.tm_mon = VAL();
	t.tm_mon = VAL() + t.tm_mon * 10 - 1;
	t.tm_mday = VAL();
	t.tm_mday = VAL() + t.tm_mday * 10;
	t.tm_hour = VAL();
	t.tm_hour = VAL() + t.tm_hour * 10;
	t.tm_min = VAL();
	t.tm_min = VAL() + t.tm_min * 10;
	t.tm_sec = VAL();
	t.tm_sec = VAL() + t.tm_sec * 10;
	t.tm_isdst = -1;

	sec = mktime(&t);
	if (sec == -1) {
		warnx("date/time out of range");
		return 1;
	}
	*rsec = iswap32(sec);
	*rnsec = iswap32(nsec);
	return 0;
}
Пример #4
0
static int
find_blks32(uint32_t *buf, int size, uint32_t *wantedblk)
{
	int blk;
	for(blk = 0; blk < size; blk++) {
		if (buf[blk] == 0)
			continue;
		if (compare_blk32(wantedblk, iswap32(buf[blk]))) {
			if (founddatablk(iswap32(buf[blk])))
				return 1;
		}
	}
	return 0;
}
Пример #5
0
static void
print_indirblks32(uint32_t blk, int ind_level, uint64_t *blknum)
{
#define MAXNINDIR	(MAXBSIZE / sizeof(int32_t))
	const int ptrperblk_shift = sblock->fs_bshift - 2;
	const int ptrperblk = 1 << ptrperblk_shift;
	int32_t idblk[MAXNINDIR];
	int i;

	if (blk == 0) {
		*blknum += (uint64_t)ptrperblk << (ptrperblk_shift * ind_level);
		return;
	}
 
	printf("Indirect block %lld (level %d):\n", (long long)blk,
	    ind_level+1);
	bread(fsreadfd, (char *)idblk, FFS_FSBTODB(sblock, blk),
	    (int)sblock->fs_bsize);
	if (ind_level <= 0) {
		print_blks32(idblk, ptrperblk, blknum);
	} else {
		ind_level--;
		for (i = 0; i < ptrperblk; i++)
			print_indirblks32(iswap32(idblk[i]), ind_level, blknum);
	}
#undef MAXNINDIR
}
Пример #6
0
static int
chinumfunc(struct inodesc *idesc)
{
	struct direct *dirp = idesc->id_dirp;

	if (slotcount++ == desired) {
		dirp->d_ino = iswap32(idesc->id_parent);
		return STOP | ALTERED | FOUND;
	}
	return KEEPON;
}
Пример #7
0
static int
scannames(struct inodesc *idesc)
{
	struct direct *dirp = idesc->id_dirp;

	printf("slot %d ino %d reclen %d: %s, `%.*s'\n",
	    slot++, iswap32(dirp->d_ino), iswap16(dirp->d_reclen),
		typename[dirp->d_type],
	    dirp->d_namlen, dirp->d_name);
	return (KEEPON);
}
Пример #8
0
static void
print_blks32(int32_t *buf, int size, uint64_t *blknum)
{
	int chars;
	char prbuf[CHARS_PER_LINES+1];
	int blk;
 
	chars = 0;
	for(blk = 0; blk < size; blk++, (*blknum)++) {
		if (buf[blk] == 0)
			continue;
		snprintf(prbuf, CHARS_PER_LINES, "%d ", iswap32(buf[blk]));
		if ((chars + strlen(prbuf)) > CHARS_PER_LINES) {
			printf("\n");
			chars = 0;
		}
		if (chars == 0)
			printf("%" PRIu64 ": ", *blknum);
		printf("%s", prbuf);
		chars += strlen(prbuf);
	}
	printf("\n");
}
Пример #9
0
/*
 * Scan each entry in a directory block.
 */
int
dirscan(struct inodesc *idesc)
{
	struct direct *dp;
	struct bufarea *bp;
	int dsize, n;
	long blksiz;
#if DIRBLKSIZ > APPLEUFS_DIRBLKSIZ
	char dbuf[DIRBLKSIZ];
#else
	char dbuf[APPLEUFS_DIRBLKSIZ];
#endif

	if (idesc->id_type != DATA)
		errexit("wrong type to dirscan %d", idesc->id_type);
	if (idesc->id_entryno == 0 &&
	    (idesc->id_filesize & (dirblksiz - 1)) != 0)
		idesc->id_filesize = roundup(idesc->id_filesize, dirblksiz);
	blksiz = idesc->id_numfrags * sblock->fs_fsize;
	if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
		idesc->id_filesize -= blksiz;
		return (SKIP);
	}

	/*
	 * If we are are swapping byte order in directory entries, just swap
	 * this block and return.
	 */
	if (do_dirswap) {
		int off;
		bp = getdirblk(idesc->id_blkno, blksiz);
		for (off = 0; off < blksiz; off += iswap16(dp->d_reclen)) {
			dp = (struct direct *)(bp->b_un.b_buf + off);
			dp->d_ino = bswap32(dp->d_ino);
			dp->d_reclen = bswap16(dp->d_reclen);
			if (!newinofmt) {
				u_int8_t tmp = dp->d_namlen;
				dp->d_namlen = dp->d_type;
				dp->d_type = tmp;
			}
			if (dp->d_reclen == 0)
				break;
		}
		dirty(bp);
		idesc->id_filesize -= blksiz;
		return (idesc->id_filesize > 0 ? KEEPON : STOP);
	}

	idesc->id_loc = 0;
	for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
		dsize = iswap16(dp->d_reclen);
		if (dsize > sizeof dbuf)
			dsize = sizeof dbuf;
		memmove(dbuf, dp, (size_t)dsize);
#		if (BYTE_ORDER == LITTLE_ENDIAN)
			if (!newinofmt && !needswap) {
#		else
			if (!newinofmt && needswap) {
#		endif
				struct direct *tdp = (struct direct *)dbuf;
				u_char tmp;

				tmp = tdp->d_namlen;
				tdp->d_namlen = tdp->d_type;
				tdp->d_type = tmp;
			}
		idesc->id_dirp = (struct direct *)dbuf;
		if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
#			if (BYTE_ORDER == LITTLE_ENDIAN)
				if (!newinofmt && !doinglevel2 && !needswap) {
#			else
				if (!newinofmt && !doinglevel2 && needswap) {
#			endif
					struct direct *tdp;
					u_char tmp;

					tdp = (struct direct *)dbuf;
					tmp = tdp->d_namlen;
					tdp->d_namlen = tdp->d_type;
					tdp->d_type = tmp;
				}
			bp = getdirblk(idesc->id_blkno, blksiz);
			memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf,
			    (size_t)dsize);
			dirty(bp);
			sbdirty();
		}
		if (n & STOP) 
			return (n);
	}
	return (idesc->id_filesize > 0 ? KEEPON : STOP);
}

/*
 * get next entry in a directory.
 */
static struct direct *
fsck_readdir(struct inodesc *idesc)
{
	struct direct *dp, *ndp;
	struct bufarea *bp;
	long size, blksiz, fix, dploc;

	blksiz = idesc->id_numfrags * sblock->fs_fsize;
	bp = getdirblk(idesc->id_blkno, blksiz);
	if (idesc->id_loc % dirblksiz == 0 && idesc->id_filesize > 0 &&
	    idesc->id_loc < blksiz) {
		dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
		if (dircheck(idesc, dp))
			goto dpok;
		if (idesc->id_fix == IGNORE)
			return (0);
		fix = dofix(idesc, "DIRECTORY CORRUPTED");
		bp = getdirblk(idesc->id_blkno, blksiz);
		dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
		dp->d_reclen = iswap16(dirblksiz);
		dp->d_ino = 0;
		dp->d_type = 0;
		dp->d_namlen = 0;
		dp->d_name[0] = '\0';
		if (fix)
			dirty(bp);
		else 
			markclean = 0;
		idesc->id_loc += dirblksiz;
		idesc->id_filesize -= dirblksiz;
		return (dp);
	}
dpok:
	if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
		return NULL;
	dploc = idesc->id_loc;
	dp = (struct direct *)(bp->b_un.b_buf + dploc);
	idesc->id_loc += iswap16(dp->d_reclen);
	idesc->id_filesize -= iswap16(dp->d_reclen);
	if ((idesc->id_loc % dirblksiz) == 0)
		return (dp);
	ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
	if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
	    dircheck(idesc, ndp) == 0) {
		size = dirblksiz - (idesc->id_loc % dirblksiz);
		idesc->id_loc += size;
		idesc->id_filesize -= size;
		if (idesc->id_fix == IGNORE)
			return (0);
		fix = dofix(idesc, "DIRECTORY CORRUPTED");
		bp = getdirblk(idesc->id_blkno, blksiz);
		dp = (struct direct *)(bp->b_un.b_buf + dploc);
		dp->d_reclen = iswap16(iswap16(dp->d_reclen) + size);
		if (fix)
			dirty(bp);
		else 
			markclean = 0;
	}
	return (dp);
}

/*
 * Verify that a directory entry is valid.
 * This is a superset of the checks made in the kernel.
 */
static int
dircheck(struct inodesc *idesc, struct direct *dp)
{
	int size;
	char *cp;
	u_char namlen, type;
	int spaceleft;

	spaceleft = dirblksiz - (idesc->id_loc % dirblksiz);
	if (iswap32(dp->d_ino) >= maxino ||
	    dp->d_reclen == 0 ||
	    iswap16(dp->d_reclen) > spaceleft ||
	    (iswap16(dp->d_reclen) & 0x3) != 0) 
		return (0);
	if (dp->d_ino == 0)
		return (1);
	size = DIRSIZ(!newinofmt, dp, needswap);
#	if (BYTE_ORDER == LITTLE_ENDIAN)
		if (!newinofmt && !needswap) {
#	else
		if (!newinofmt && needswap) {
#	endif
			type = dp->d_namlen;
			namlen = dp->d_type;
		} else {
			namlen = dp->d_namlen;
			type = dp->d_type;
		}
	if (iswap16(dp->d_reclen) < size ||
	    idesc->id_filesize < size ||
	    /* namlen > MAXNAMLEN || */
	    type > 15)
		return (0);
	for (cp = dp->d_name, size = 0; size < namlen; size++)
		if (*cp == '\0' || (*cp++ == '/'))
			return (0);
	if (*cp != '\0')
		return (0);
	return (1);
}

void
direrror(ino_t ino, const char *errmesg)
{

	fileerror(ino, ino, errmesg);
}

void
fileerror(ino_t cwd, ino_t ino, const char *errmesg)
{
	union dinode *dp;
	char pathbuf[MAXPATHLEN + 1];
	uint16_t mode;

	pwarn("%s ", errmesg);
	pinode(ino);
	printf("\n");
	getpathname(pathbuf, sizeof(pathbuf), cwd, ino);
	if (ino < ROOTINO || ino > maxino) {
		pfatal("NAME=%s\n", pathbuf);
		return;
	}
	dp = ginode(ino);
	if (ftypeok(dp)) {
		mode = DIP(dp, mode);
		pfatal("%s=%s\n",
		    (iswap16(mode) & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf);
	}
	else
		pfatal("NAME=%s\n", pathbuf);
}

void
adjust(struct inodesc *idesc, int lcnt)
{
	union dinode *dp;
	int16_t nlink;
	int saveresolved;

	dp = ginode(idesc->id_number);
	nlink = iswap16(DIP(dp, nlink));
	if (nlink == lcnt) {
		/*
		 * If we have not hit any unresolved problems, are running
		 * in preen mode, and are on a file system using soft updates,
		 * then just toss any partially allocated files.
		 */
		if (resolved && preen && usedsoftdep) {
			clri(idesc, "UNREF", 1);
			return;
		} else {
			/*
			 * The file system can be marked clean even if
			 * a file is not linked up, but is cleared.
			 * Hence, resolved should not be cleared when
			 * linkup is answered no, but clri is answered yes.
			 */
			saveresolved = resolved;
			if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) {
				resolved = saveresolved;
				clri(idesc, "UNREF", 0);
				return;
			}
			/*
			 * Account for the new reference created by linkup().
			 */
			dp = ginode(idesc->id_number);
			lcnt--;
		}
	}
	if (lcnt != 0) {
		pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
			((iswap16(DIP(dp, mode)) & IFMT) == IFDIR ?
			"DIR" : "FILE"));
		pinode(idesc->id_number);
		printf(" COUNT %d SHOULD BE %d",
			nlink, nlink - lcnt);
		if (preen || usedsoftdep) {
			if (lcnt < 0) {
				printf("\n");
				pfatal("LINK COUNT INCREASING");
			}
			if (preen)
				printf(" (ADJUSTED)\n");
		}
		if (preen || reply("ADJUST") == 1) {
			DIP_SET(dp, nlink, iswap16(nlink - lcnt));
			inodirty();
		} else 
			markclean = 0;
	}
}

static int
mkentry(struct inodesc *idesc)
{
	struct direct *dirp = idesc->id_dirp;
	struct direct newent;
	int newlen, oldlen;

	newent.d_namlen = strlen(idesc->id_name);
	newlen = DIRSIZ(0, &newent, 0);
	if (dirp->d_ino != 0)
		oldlen = DIRSIZ(0, dirp, 0);
	else
		oldlen = 0;
	if (iswap16(dirp->d_reclen) - oldlen < newlen)
		return (KEEPON);
	newent.d_reclen = iswap16(iswap16(dirp->d_reclen) - oldlen);
	dirp->d_reclen = iswap16(oldlen);
	dirp = (struct direct *)(((char *)dirp) + oldlen);
	/* ino to be entered is in id_parent */
	dirp->d_ino = iswap32(idesc->id_parent);
	dirp->d_reclen = newent.d_reclen;
	if (newinofmt)
		dirp->d_type = inoinfo(idesc->id_parent)->ino_type;
	else
		dirp->d_type = 0;
	dirp->d_namlen = newent.d_namlen;
	memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1);
#	if (BYTE_ORDER == LITTLE_ENDIAN)
		/*
		 * If the entry was split, dirscan() will only reverse the byte
		 * order of the original entry, and not the new one, before
		 * writing it back out.  So, we reverse the byte order here if
		 * necessary.
		 */
		if (oldlen != 0 && !newinofmt && !doinglevel2 && !needswap) {
#	else
		if (oldlen != 0 && !newinofmt && !doinglevel2 && needswap) {
#	endif
			u_char tmp;

			tmp = dirp->d_namlen;
			dirp->d_namlen = dirp->d_type;
			dirp->d_type = tmp;
		}
	return (ALTERED|STOP);
}

static int
chgino(struct inodesc *idesc)
{
	struct direct *dirp = idesc->id_dirp;

	if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
		return (KEEPON);
	dirp->d_ino = iswap32(idesc->id_parent);
	if (newinofmt)
		dirp->d_type = inoinfo(idesc->id_parent)->ino_type;
	else
		dirp->d_type = 0;
	return (ALTERED|STOP);
}

int
linkup(ino_t orphan, ino_t parentdir, char *name)
{
	union dinode *dp;
	int lostdir;
	ino_t oldlfdir;
	struct inodesc idesc;
	char tempname[BUFSIZ];
	int16_t nlink;
	uint16_t mode;

	memset(&idesc, 0, sizeof(struct inodesc));
	dp = ginode(orphan);
	mode = iswap16(DIP(dp, mode));
	nlink = iswap16(DIP(dp, nlink));
	lostdir = (mode & IFMT) == IFDIR;
	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
	pinode(orphan);
	if (preen  && DIP(dp, size) == 0)
		return (0);
	if (preen)
		printf(" (RECONNECTED)\n");
	else
		if (reply("RECONNECT") == 0) {
			markclean = 0;
			return (0);
		}
	if (parentdir != 0)
		inoinfo(parentdir)->ino_linkcnt++;
	if (lfdir == 0) {
		dp = ginode(ROOTINO);
		idesc.id_name = lfname;
		idesc.id_type = DATA;
		idesc.id_func = findino;
		idesc.id_number = ROOTINO;
		if ((ckinode(dp, &idesc) & FOUND) != 0) {
			lfdir = idesc.id_parent;
		} else {
			pwarn("NO lost+found DIRECTORY");
			if (preen || reply("CREATE")) {
				lfdir = allocdir(ROOTINO, (ino_t)0, lfmode);
				if (lfdir != 0) {
					if (makeentry(ROOTINO, lfdir, lfname) != 0) {
						numdirs++;
						if (preen)
							printf(" (CREATED)\n");
					} else {
						freedir(lfdir, ROOTINO);
						lfdir = 0;
						if (preen)
							printf("\n");
					}
				}
				if (lfdir != 0) {
					reparent(lfdir, ROOTINO);
				}
			}
		}
		if (lfdir == 0) {
			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
			markclean = 0;
			return (0);
		}
	}
	dp = ginode(lfdir);
	mode = DIP(dp, mode);
	mode = iswap16(mode);
	if ((mode & IFMT) != IFDIR) {
		pfatal("lost+found IS NOT A DIRECTORY");
		if (reply("REALLOCATE") == 0) {
			markclean = 0;
			return (0);
		}
		oldlfdir = lfdir;
		lfdir = allocdir(ROOTINO, (ino_t)0, lfmode);
		if (lfdir == 0) {
			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
			markclean = 0;
			return (0);
		}
		if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) {
			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
			markclean = 0;
			return (0);
		}
		inodirty();
		reparent(lfdir, ROOTINO);
		idesc.id_type = ADDR;
		idesc.id_func = pass4check;
		idesc.id_number = oldlfdir;
		adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1);
		inoinfo(oldlfdir)->ino_linkcnt = 0;
		dp = ginode(lfdir);
	}
	if (inoinfo(lfdir)->ino_state != DFOUND) {
		pfatal("SORRY. NO lost+found DIRECTORY\n\n");
		markclean = 0;
		return (0);
	}
	(void)lftempname(tempname, orphan);
	if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) {
		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
		printf("\n\n");
		markclean = 0;
		return (0);
	}
	inoinfo(orphan)->ino_linkcnt--;
	if (lostdir) {
		if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
		    parentdir != (ino_t)-1)
			(void)makeentry(orphan, lfdir, "..");
		dp = ginode(lfdir);
		nlink = DIP(dp, nlink);
		DIP_SET(dp, nlink, iswap16(iswap16(nlink) + 1));
		inodirty();
		inoinfo(lfdir)->ino_linkcnt++;
		reparent(orphan, lfdir);
		pwarn("DIR I=%llu CONNECTED. ", (unsigned long long)orphan);
		if (parentdir != (ino_t)-1)
			printf("PARENT WAS I=%llu\n",
			    (unsigned long long)parentdir);
		if (preen == 0)
			printf("\n");
	}
	return (1);
}

/*
 * fix an entry in a directory.
 */
int
changeino(ino_t dir, const char *name, ino_t newnum)
{
	struct inodesc idesc;

	memset(&idesc, 0, sizeof(struct inodesc));
	idesc.id_type = DATA;
	idesc.id_func = chgino;
	idesc.id_number = dir;
	idesc.id_fix = DONTKNOW;
	idesc.id_name = name;
	idesc.id_parent = newnum;	/* new value for name */
	return (ckinode(ginode(dir), &idesc));
}

/*
 * make an entry in a directory
 */
int
makeentry(ino_t parent, ino_t ino, const char *name)
{
	union dinode *dp;
	struct inodesc idesc;
	char pathbuf[MAXPATHLEN + 1];
	
	if (parent < ROOTINO || parent >= maxino ||
	    ino < ROOTINO || ino >= maxino)
		return (0);
	memset(&idesc, 0, sizeof(struct inodesc));
	idesc.id_type = DATA;
	idesc.id_func = mkentry;
	idesc.id_number = parent;
	idesc.id_parent = ino;	/* this is the inode to enter */
	idesc.id_fix = DONTKNOW;
	idesc.id_name = name;
	dp = ginode(parent);
	if (iswap64(DIP(dp, size)) % dirblksiz) {
		DIP_SET(dp, size,
		    iswap64(roundup(iswap64(DIP(dp, size)), dirblksiz)));
		inodirty();
	}
	if ((ckinode(dp, &idesc) & ALTERED) != 0)
		return (1);
	getpathname(pathbuf, sizeof(pathbuf), parent, parent);
	dp = ginode(parent);
	if (expanddir(dp, pathbuf) == 0)
		return (0);
	return (ckinode(dp, &idesc) & ALTERED);
}

/*
 * Attempt to expand the size of a directory
 */
static int
expanddir(union dinode *dp, char *name)
{
	daddr_t lastbn, newblk, dirblk;
	struct bufarea *bp;
	char *cp;
#if DIRBLKSIZ > APPLEUFS_DIRBLKSIZ
	char firstblk[DIRBLKSIZ];
#else
	char firstblk[APPLEUFS_DIRBLKSIZ];
#endif
	struct ufs1_dinode *dp1 = NULL;
	struct ufs2_dinode *dp2 = NULL;

	if (is_ufs2)
		dp2 = &dp->dp2;
	else
		dp1 = &dp->dp1;

	lastbn = lblkno(sblock, iswap64(DIP(dp, size)));
	if (lastbn >= NDADDR - 1 || DIP(dp, db[lastbn]) == 0 ||
	    DIP(dp, size) == 0)
		return (0);
	if ((newblk = allocblk(sblock->fs_frag)) == 0)
		return (0);
	if (is_ufs2) {
		dp2->di_db[lastbn + 1] = dp2->di_db[lastbn];
		dp2->di_db[lastbn] = iswap64(newblk);
		dp2->di_size = iswap64(iswap64(dp2->di_size)+sblock->fs_bsize);
		dp2->di_blocks = iswap64(iswap64(dp2->di_blocks) +
		    btodb(sblock->fs_bsize));
		dirblk = iswap64(dp2->di_db[lastbn + 1]);
	} else {
		dp1->di_db[lastbn + 1] = dp1->di_db[lastbn];
		dp1->di_db[lastbn] = iswap32((int32_t)newblk);
		dp1->di_size = iswap64(iswap64(dp1->di_size)+sblock->fs_bsize);
		dp1->di_blocks = iswap32(iswap32(dp1->di_blocks) +
		    btodb(sblock->fs_bsize));
		dirblk = iswap32(dp1->di_db[lastbn + 1]);
	}
	bp = getdirblk(dirblk, sblksize(sblock, DIP(dp, size), lastbn + 1));
	if (bp->b_errs)
		goto bad;
	memmove(firstblk, bp->b_un.b_buf, dirblksiz);
	bp = getdirblk(newblk, sblock->fs_bsize);
	if (bp->b_errs)
		goto bad;
	memmove(bp->b_un.b_buf, firstblk, dirblksiz);
	emptydir.dot_reclen = iswap16(dirblksiz);
	for (cp = &bp->b_un.b_buf[dirblksiz];
	     cp < &bp->b_un.b_buf[sblock->fs_bsize];
	     cp += dirblksiz)
		memmove(cp, &emptydir, sizeof emptydir);
	dirty(bp);
	bp = getdirblk(dirblk, sblksize(sblock, DIP(dp, size), lastbn + 1));
	if (bp->b_errs)
		goto bad;
	memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir);
	pwarn("NO SPACE LEFT IN %s", name);
	if (preen)
		printf(" (EXPANDED)\n");
	else if (reply("EXPAND") == 0)
		goto bad;
	dirty(bp);
	inodirty();
	return (1);
bad:
	if (is_ufs2) {
		dp2->di_db[lastbn] = dp2->di_db[lastbn + 1];
		dp2->di_db[lastbn + 1] = 0;
		dp2->di_size = iswap64(iswap64(dp2->di_size)-sblock->fs_bsize);
		dp2->di_blocks = iswap64(iswap64(dp2->di_blocks) -
		    btodb(sblock->fs_bsize));
	} else {
		dp1->di_db[lastbn] = dp1->di_db[lastbn + 1];
		dp1->di_db[lastbn + 1] = 0;
		dp1->di_size = iswap64(iswap64(dp1->di_size)-sblock->fs_bsize);
		dp1->di_blocks = iswap32(iswap32(dp1->di_blocks) -
		    btodb(sblock->fs_bsize));
	}
	freeblk(newblk, sblock->fs_frag);
	markclean = 0;
	return (0);
}

/*
 * allocate a new directory
 */
ino_t
allocdir(ino_t parent, ino_t request, int mode)
{
	ino_t ino;
	char *cp;
	union dinode *dp;
	struct bufarea *bp;
	struct inoinfo *inp;
	struct dirtemplate *dirp;
	daddr_t dirblk;

	ino = allocino(request, IFDIR|mode);
	if (ino < ROOTINO)
		return 0;
	dirhead.dot_reclen = iswap16(12);
	dirhead.dotdot_reclen = iswap16(dirblksiz - 12);
	odirhead.dot_reclen = iswap16(12);
	odirhead.dotdot_reclen = iswap16(dirblksiz - 12);
	odirhead.dot_namlen = iswap16(1);
	odirhead.dotdot_namlen = iswap16(2);
	if (newinofmt)
		dirp = &dirhead;
	else
		dirp = (struct dirtemplate *)&odirhead;
	dirp->dot_ino = iswap32(ino);
	dirp->dotdot_ino = iswap32(parent);
	dp = ginode(ino);
	dirblk = is_ufs2 ? iswap64(dp->dp2.di_db[0])
		    : iswap32(dp->dp1.di_db[0]);
	bp = getdirblk(dirblk, sblock->fs_fsize);
	if (bp->b_errs) {
		freeino(ino);
		return (0);
	}
	memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate));
	emptydir.dot_reclen = iswap16(dirblksiz);
	for (cp = &bp->b_un.b_buf[dirblksiz];
	     cp < &bp->b_un.b_buf[sblock->fs_fsize];
	     cp += dirblksiz)
		memmove(cp, &emptydir, sizeof emptydir);
	dirty(bp);
	DIP_SET(dp, nlink, iswap16(2));
	inodirty();
	if (ino == ROOTINO) {
		inoinfo(ino)->ino_linkcnt = iswap16(DIP(dp, nlink));
		cacheino(dp, ino);
		return(ino);
	}
	if (inoinfo(parent)->ino_state != DSTATE &&
	    inoinfo(parent)->ino_state != DFOUND) {
		freeino(ino);
		return (0);
	}
	cacheino(dp, ino);
	inp = getinoinfo(ino);
	inp->i_parent = parent;
	inp->i_dotdot = parent;
	inoinfo(ino)->ino_state = inoinfo(parent)->ino_state;
	if (inoinfo(ino)->ino_state == DSTATE) {
		inoinfo(ino)->ino_linkcnt = iswap16(DIP(dp, nlink));
		inoinfo(parent)->ino_linkcnt++;
	}
	dp = ginode(parent);
	DIP_SET(dp, nlink, iswap16(iswap16(DIP(dp, nlink)) + 1));
	inodirty();
	return (ino);
}
Пример #10
0
int
main(int argc, char *argv[])
{
    ino_t ino;
    int dirty;
    union dinode *dp;
    struct fstab *dt;
    struct statvfs *mntinfo, fsbuf;
    char *map, *cp;
    int ch;
    int i, anydirskipped, bflag = 0, Tflag = 0, Fflag = 0, honorlevel = 1;
    int snap_internal = 0;
    ino_t maxino;
    time_t tnow, date;
    int dirc;
    char *mountpoint;
    int just_estimate = 0;
    char labelstr[LBLSIZE];
    char buf[MAXPATHLEN], rbuf[MAXPATHLEN];
    char *new_time_format;
    char *snap_backup = NULL;

    spcl.c_date = 0;
    (void)time(&tnow);
    spcl.c_date = tnow;
    tzset(); /* set up timezone for strftime */
    if ((new_time_format = getenv("TIMEFORMAT")) != NULL)
        time_string = new_time_format;

    tsize = 0;	/* Default later, based on 'c' option for cart tapes */
    if ((tape = getenv("TAPE")) == NULL)
        tape = _PATH_DEFTAPE;
    dumpdates = _PATH_DUMPDATES;
    temp = _PATH_DTMP;
    strcpy(labelstr, "none");	/* XXX safe strcpy. */
    if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0)
        quit("TP_BSIZE must be a multiple of DEV_BSIZE\n");
    level = '0';
    timestamp = 0;

    if (argc < 2)
        usage();

    obsolete(&argc, &argv);
    while ((ch = getopt(argc, argv,
                        "0123456789aB:b:cd:eFf:h:ik:l:L:nr:s:StT:uWwx:X")) != -1)
        switch (ch) {
        /* dump level */
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            level = ch;
            break;

        case 'a':		/* `auto-size', Write to EOM. */
            unlimited = 1;
            break;

        case 'B':		/* blocks per output file */
            blocksperfile = numarg("blocks per file", 1L, 0L);
            break;

        case 'b':		/* blocks per tape write */
            ntrec = numarg("blocks per write", 1L, 1000L);
            bflag = 1;
            break;

        case 'c':		/* Tape is cart. not 9-track */
            cartridge = 1;
            break;

        case 'd':		/* density, in bits per inch */
            density = numarg("density", 10L, 327670L) / 10;
            if (density >= 625 && !bflag)
                ntrec = HIGHDENSITYTREC;
            break;

        case 'e':		/* eject full tapes */
            eflag = 1;
            break;

        case 'F':		/* files-to-dump is an fs image */
            Fflag = 1;
            break;

        case 'f':		/* output file */
            tape = optarg;
            break;

        case 'h':
            honorlevel = numarg("honor level", 0L, 10L);
            break;

        case 'i':	/* "true incremental" regardless level */
            level = 'i';
            trueinc = 1;
            break;

        case 'k':
            readblksize = numarg("read block size", 0, 64) * 1024;
            break;

        case 'l':		/* autoload after eject full tapes */
            eflag = 1;
            lflag = numarg("timeout (in seconds)", 1, 0);
            break;

        case 'L':
            /*
             * Note that although there are LBLSIZE characters,
             * the last must be '\0', so the limit on strlen()
             * is really LBLSIZE-1.
             */
            if (strlcpy(labelstr, optarg, sizeof(labelstr))
                    >= sizeof(labelstr)) {
                msg(
                    "WARNING Label `%s' is larger than limit of %lu characters.\n",
                    optarg,
                    (unsigned long)sizeof(labelstr) - 1);
                msg("WARNING: Using truncated label `%s'.\n",
                    labelstr);
            }
            break;
        case 'n':		/* notify operators */
            notify = 1;
            break;

        case 'r':		/* read cache size */
            readcache = numarg("read cache size", 0, 512);
            break;

        case 's':		/* tape size, feet */
            tsize = numarg("tape size", 1L, 0L) * 12 * 10;
            break;

        case 'S':		/* exit after estimating # of tapes */
            just_estimate = 1;
            break;

        case 't':
            timestamp = 1;
            break;

        case 'T':		/* time of last dump */
            spcl.c_ddate = unctime(optarg);
            if (spcl.c_ddate < 0) {
                (void)fprintf(stderr, "bad time \"%s\"\n",
                              optarg);
                exit(X_STARTUP);
            }
            Tflag = 1;
            lastlevel = '?';
            break;

        case 'u':		/* update /etc/dumpdates */
            uflag = 1;
            break;

        case 'W':		/* what to do */
        case 'w':
            lastdump(ch);
            exit(X_FINOK);	/* do nothing else */

        case 'x':
            snap_backup = optarg;
            break;

        case 'X':
            snap_internal = 1;
            break;

        default:
            usage();
        }
    argc -= optind;
    argv += optind;

    if (argc < 1) {
        (void)fprintf(stderr,
                      "Must specify disk or image, or file list\n");
        exit(X_STARTUP);
    }


    /*
     *	determine if disk is a subdirectory, and setup appropriately
     */
    getfstab();		/* /etc/fstab snarfed */
    disk = NULL;
    disk_dev = NULL;
    mountpoint = NULL;
    dirc = 0;
    for (i = 0; i < argc; i++) {
        struct stat sb;
        int error;

        error = lstat(argv[i], &sb);
        if (Fflag || (!error && (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)))) {
            if (error)
                quit("Cannot stat %s: %s\n", argv[i], strerror(errno));
            disk = argv[i];
multicheck:
            if (dirc != 0)
                quit("Can't dump a disk or image at the same time as a file list\n");
            break;
        }
        if ((dt = fstabsearch(argv[i])) != NULL) {
            disk = argv[i];
            mountpoint = xstrdup(dt->fs_file);
            goto multicheck;
        }
        if (statvfs(argv[i], &fsbuf) == -1)
            quit("Cannot statvfs %s: %s\n", argv[i],
                 strerror(errno));
        disk = fsbuf.f_mntfromname;
        if (strcmp(argv[i], fsbuf.f_mntonname) == 0)
            goto multicheck;
        if (mountpoint == NULL) {
            mountpoint = xstrdup(fsbuf.f_mntonname);
            if (uflag) {
                msg("Ignoring u flag for subdir dump\n");
                uflag = 0;
            }
            if (level > '0') {
                msg("Subdir dump is done at level 0\n");
                level = '0';
            }
            msg("Dumping sub files/directories from %s\n",
                mountpoint);
        } else {
            if (strcmp(mountpoint, fsbuf.f_mntonname) != 0)
                quit("%s is not on %s\n", argv[i], mountpoint);
        }
        msg("Dumping file/directory %s\n", argv[i]);
        dirc++;
    }
    if (mountpoint)
        free(mountpoint);

    if (dirc == 0) {
        argv++;
        if (argc != 1) {
            (void)fprintf(stderr, "Excess arguments to dump:");
            while (--argc)
                (void)fprintf(stderr, " %s", *argv++);
            (void)fprintf(stderr, "\n");
            exit(X_STARTUP);
        }
    }
    if (Tflag && uflag) {
        (void)fprintf(stderr,
                      "You cannot use the T and u flags together.\n");
        exit(X_STARTUP);
    }
    if (strcmp(tape, "-") == 0) {
        pipeout++;
        tape = "standard output";
    }

    if (blocksperfile)
        blocksperfile = blocksperfile / ntrec * ntrec; /* round down */
    else if (!unlimited) {
        /*
         * Determine how to default tape size and density
         *
         *		density				tape size
         * 9-track	1600 bpi (160 bytes/.1")	2300 ft.
         * 9-track	6250 bpi (625 bytes/.1")	2300 ft.
         * cartridge	8000 bpi (100 bytes/.1")	1700 ft.
         *						(450*4 - slop)
         */
        if (density == 0)
            density = cartridge ? 100 : 160;
        if (tsize == 0)
            tsize = cartridge ? 1700L*120L : 2300L*120L;
    }

    if ((cp = strchr(tape, ':')) != NULL) {
        host = tape;
        /* This is fine, because all the const strings don't have : */
        *cp++ = '\0';
        tape = cp;
#ifdef RDUMP
        if (rmthost(host) == 0)
            exit(X_STARTUP);
#else
        (void)fprintf(stderr, "remote dump not enabled\n");
        exit(X_STARTUP);
#endif
    }

    if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
        signal(SIGHUP, sig);
    if (signal(SIGTRAP, SIG_IGN) != SIG_IGN)
        signal(SIGTRAP, sig);
    if (signal(SIGFPE, SIG_IGN) != SIG_IGN)
        signal(SIGFPE, sig);
    if (signal(SIGBUS, SIG_IGN) != SIG_IGN)
        signal(SIGBUS, sig);
#if 0
    if (signal(SIGSEGV, SIG_IGN) != SIG_IGN)
        signal(SIGSEGV, sig);
#endif
    if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
        signal(SIGTERM, sig);
    if (signal(SIGINT, interrupt) == SIG_IGN)
        signal(SIGINT, SIG_IGN);

    /*
     *	disk can be either the full special file name, or
     *	the file system name.
     */
    mountpoint = NULL;
    mntinfo = mntinfosearch(disk);
    if ((dt = fstabsearch(disk)) != NULL) {
        if (getfsspecname(buf, sizeof(buf), dt->fs_spec) == NULL)
            quit("%s (%s)", buf, strerror(errno));
        if (getdiskrawname(rbuf, sizeof(rbuf), buf) == NULL)
            quit("Can't get disk raw name for `%s' (%s)",
                 buf, strerror(errno));
        disk = rbuf;
        mountpoint = dt->fs_file;
        msg("Found %s on %s in %s\n", disk, mountpoint, _PATH_FSTAB);
    } else if (mntinfo != NULL) {
        if (getdiskrawname(rbuf, sizeof(rbuf), mntinfo->f_mntfromname)
                == NULL)
            quit("Can't get disk raw name for `%s' (%s)",
                 mntinfo->f_mntfromname, strerror(errno));
        disk = rbuf;
        mountpoint = mntinfo->f_mntonname;
        msg("Found %s on %s in mount table\n", disk, mountpoint);
    }
    if (mountpoint != NULL) {
        if (dirc != 0)
            (void)snprintf(spcl.c_filesys, sizeof(spcl.c_filesys),
                           "a subset of %s", mountpoint);
        else
            (void)strlcpy(spcl.c_filesys, mountpoint,
                          sizeof(spcl.c_filesys));
    } else if (Fflag) {
        (void)strlcpy(spcl.c_filesys, "a file system image",
                      sizeof(spcl.c_filesys));
    } else {
        (void)strlcpy(spcl.c_filesys, "an unlisted file system",
                      sizeof(spcl.c_filesys));
    }
    (void)strlcpy(spcl.c_dev, disk, sizeof(spcl.c_dev));
    (void)strlcpy(spcl.c_label, labelstr, sizeof(spcl.c_label));
    (void)gethostname(spcl.c_host, sizeof(spcl.c_host));
    spcl.c_host[sizeof(spcl.c_host) - 1] = '\0';

    if ((snap_backup != NULL || snap_internal) && mntinfo == NULL) {
        msg("WARNING: Cannot use -x or -X on unmounted file system.\n");
        snap_backup = NULL;
        snap_internal = 0;
    }

#ifdef DUMP_LFS
    sync();
    if (snap_backup != NULL || snap_internal) {
        if (lfs_wrap_stop(mountpoint) < 0) {
            msg("Cannot stop writing on %s\n", mountpoint);
            exit(X_STARTUP);
        }
    }
    if ((diskfd = open(disk, O_RDONLY)) < 0) {
        msg("Cannot open %s\n", disk);
        exit(X_STARTUP);
    }
    disk_dev = disk;
#else /* ! DUMP_LFS */
    if (snap_backup != NULL || snap_internal) {
        diskfd = snap_open(mntinfo->f_mntonname, snap_backup,
                           &tnow, &disk_dev);
        if (diskfd < 0) {
            msg("Cannot open snapshot of %s\n",
                mntinfo->f_mntonname);
            exit(X_STARTUP);
        }
        spcl.c_date = tnow;
    } else {
        if ((diskfd = open(disk, O_RDONLY)) < 0) {
            msg("Cannot open %s\n", disk);
            exit(X_STARTUP);
        }
        disk_dev = disk;
    }
    sync();
#endif /* ! DUMP_LFS */

    needswap = fs_read_sblock(sblock_buf);

    /* true incremental is always a level 10 dump */
    spcl.c_level = trueinc? iswap32(10): iswap32(level - '0');
    spcl.c_type = iswap32(TS_TAPE);
    spcl.c_date = iswap32(spcl.c_date);
    spcl.c_ddate = iswap32(spcl.c_ddate);
    if (!Tflag)
        getdumptime();		/* /etc/dumpdates snarfed */

    date = iswap32(spcl.c_date);
    msg("Date of this level %c dump: %s", level,
        spcl.c_date == 0 ? "the epoch\n" : ctime(&date));
    date = iswap32(spcl.c_ddate);
    msg("Date of last level %c dump: %s", lastlevel,
        spcl.c_ddate == 0 ? "the epoch\n" : ctime(&date));
    msg("Dumping ");
    if (snap_backup != NULL || snap_internal)
        msgtail("a snapshot of ");
    if (dirc != 0)
        msgtail("a subset of ");
    msgtail("%s (%s) ", disk, spcl.c_filesys);
    if (host)
        msgtail("to %s on host %s\n", tape, host);
    else
        msgtail("to %s\n", tape);
    msg("Label: %s\n", labelstr);

    ufsib = fs_parametrize();

    dev_bshift = ffs(dev_bsize) - 1;
    if (dev_bsize != (1 << dev_bshift))
        quit("dev_bsize (%ld) is not a power of 2", dev_bsize);
    tp_bshift = ffs(TP_BSIZE) - 1;
    if (TP_BSIZE != (1 << tp_bshift))
        quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE);
    maxino = fs_maxino();
    mapsize = roundup(howmany(maxino, NBBY), TP_BSIZE);
    usedinomap = (char *)xcalloc((unsigned) mapsize, sizeof(char));
    dumpdirmap = (char *)xcalloc((unsigned) mapsize, sizeof(char));
    dumpinomap = (char *)xcalloc((unsigned) mapsize, sizeof(char));
    tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);

    nonodump = iswap32(spcl.c_level) < honorlevel;

    initcache(readcache, readblksize);

    (void)signal(SIGINFO, statussig);

    msg("mapping (Pass I) [regular files]\n");
    anydirskipped = mapfiles(maxino, &tapesize, mountpoint,
                             (dirc ? argv : NULL));

    msg("mapping (Pass II) [directories]\n");
    while (anydirskipped) {
        anydirskipped = mapdirs(maxino, &tapesize);
    }

    if (pipeout || unlimited) {
        tapesize += 10;	/* 10 trailer blocks */
        msg("estimated %llu tape blocks.\n",
            (unsigned long long)tapesize);
    } else {
        double fetapes;

        if (blocksperfile)
            fetapes = (double) tapesize / blocksperfile;
        else if (cartridge) {
            /* Estimate number of tapes, assuming streaming stops at
               the end of each block written, and not in mid-block.
               Assume no erroneous blocks; this can be compensated
               for with an artificially low tape size. */
            fetapes =
                (	  (double) tapesize	/* blocks */
                      * TP_BSIZE	/* bytes/block */
                      * (1.0/density)	/* 0.1" / byte */
                      +
                      (double) tapesize	/* blocks */
                      * (1.0/ntrec)	/* streaming-stops per block */
                      * 15.48		/* 0.1" / streaming-stop */
                ) * (1.0 / tsize );	/* tape / 0.1" */
        } else {
            /* Estimate number of tapes, for old fashioned 9-track
               tape */
            int tenthsperirg = (density == 625) ? 3 : 7;
            fetapes =
                (	  tapesize	/* blocks */
                      * TP_BSIZE	/* bytes / block */
                      * (1.0/density)	/* 0.1" / byte */
                      +
                      tapesize	/* blocks */
                      * (1.0/ntrec)	/* IRG's / block */
                      * tenthsperirg	/* 0.1" / IRG */
                ) * (1.0 / tsize );	/* tape / 0.1" */
        }
        etapes = fetapes;		/* truncating assignment */
        etapes++;
        /* count the dumped inodes map on each additional tape */
        tapesize += (etapes - 1) *
                    (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
        tapesize += etapes + 10;	/* headers + 10 trailer blks */
        msg("estimated %llu tape blocks on %3.2f tape(s).\n",
            (unsigned long long)tapesize, fetapes);
    }
    /*
     * If the user only wants an estimate of the number of
     * tapes, exit now.
     */
    if (just_estimate)
        exit(X_FINOK);

    /*
     * Allocate tape buffer.
     */
    if (!alloctape())
        quit("can't allocate tape buffers - try a smaller blocking factor.\n");

    startnewtape(1);
    (void)time((time_t *)&(tstart_writing));
    xferrate = 0;
    dumpmap(usedinomap, TS_CLRI, maxino - 1);

    msg("dumping (Pass III) [directories]\n");
    dirty = 0;		/* XXX just to get gcc to shut up */
    for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
        if (((ino - 1) % NBBY) == 0)	/* map is offset by 1 */
            dirty = *map++;
        else
            dirty >>= 1;
        if ((dirty & 1) == 0)
            continue;
        /*
         * Skip directory inodes deleted and maybe reallocated
         */
        dp = getino(ino);
        if ((DIP(dp, mode) & IFMT) != IFDIR)
            continue;
        (void)dumpino(dp, ino);
    }

    msg("dumping (Pass IV) [regular files]\n");
    for (map = dumpinomap, ino = 1; ino < maxino; ino++) {
        int mode;

        if (((ino - 1) % NBBY) == 0)	/* map is offset by 1 */
            dirty = *map++;
        else
            dirty >>= 1;
        if ((dirty & 1) == 0)
            continue;
        /*
         * Skip inodes deleted and reallocated as directories.
         */
        dp = getino(ino);
        mode = DIP(dp, mode) & IFMT;
        if (mode == IFDIR)
            continue;
        (void)dumpino(dp, ino);
    }

    spcl.c_type = iswap32(TS_END);
    for (i = 0; i < ntrec; i++)
        writeheader(maxino - 1);
    if (pipeout)
        msg("%lld tape blocks\n",(long long)iswap64(spcl.c_tapea));
    else
        msg("%lld tape blocks on %d volume%s\n",
            (long long)iswap64(spcl.c_tapea), iswap32(spcl.c_volume),
            (iswap32(spcl.c_volume) == 1) ? "" : "s");
    tnow = do_stats();
    date = iswap32(spcl.c_date);
    msg("Date of this level %c dump: %s", level,
        spcl.c_date == 0 ? "the epoch\n" : ctime(&date));
    msg("Date this dump completed:  %s", ctime(&tnow));
    msg("Average transfer rate: %d KB/s\n", xferrate / tapeno);
    putdumptime();
    trewind(0);
    broadcast("DUMP IS DONE!\a\a\n");
#ifdef DUMP_LFS
    lfs_wrap_go();
#endif /* DUMP_LFS */
    msg("DUMP IS DONE\n");
    Exit(X_FINOK);
    /* NOTREACHED */
    exit(X_FINOK);		/* XXX: to satisfy gcc */
}
Пример #11
0
static int
pass2check(struct inodesc *idesc)
{
	struct direct *dirp = idesc->id_dirp;
	struct inoinfo *inp;
	struct inostat *info;
	int n, entrysize, ret = 0;
	union dinode *dp;
	const char *errmsg;
	struct direct proto;
	char namebuf[MAXPATHLEN + 1];
	char pathbuf[MAXPATHLEN + 1];

	/*
	 * If converting, set directory entry type.
	 */
	if (!is_ufs2 && doinglevel2 && iswap32(dirp->d_ino) > 0 &&
	    iswap32(dirp->d_ino) < maxino) {
		dirp->d_type = inoinfo(iswap32(dirp->d_ino))->ino_type;
		ret |= ALTERED;
	}
	/* 
	 * check for "."
	 */
	if (idesc->id_entryno != 0)
		goto chk1;
	if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
		if (iswap32(dirp->d_ino) != idesc->id_number) {
			direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
			dirp->d_ino = iswap32(idesc->id_number);
			if (reply("FIX") == 1)
				ret |= ALTERED;
			else
				markclean = 0;
		}
		if (newinofmt && dirp->d_type != DT_DIR) {
			direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
			dirp->d_type = DT_DIR;
			if (reply("FIX") == 1)
				ret |= ALTERED;
			else
				markclean = 0;
		}
		goto chk1;
	}
	direrror(idesc->id_number, "MISSING '.'");
	proto.d_ino = iswap32(idesc->id_number);
	if (newinofmt)
		proto.d_type = DT_DIR;
	else
		proto.d_type = 0;
	proto.d_namlen = 1;
	(void)strlcpy(proto.d_name, ".", sizeof(proto.d_name));
#	if BYTE_ORDER == LITTLE_ENDIAN
		if (!newinofmt && !needswap) {
#	else
		if (!newinofmt && needswap) {
#	endif
			u_char tmp;

			tmp = proto.d_type;
			proto.d_type = proto.d_namlen;
			proto.d_namlen = tmp;
		}
	entrysize = DIRSIZ(0, &proto, 0);
	if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
		pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
			dirp->d_name);
		markclean = 0;
	} else if (iswap16(dirp->d_reclen) < entrysize) {
		pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
		markclean = 0;
	} else if (iswap16(dirp->d_reclen) < 2 * entrysize) {
		proto.d_reclen = dirp->d_reclen;
		memmove(dirp, &proto, (size_t)entrysize);
		if (reply("FIX") == 1)
			ret |= ALTERED;
		else
			markclean = 0;
	} else {
		n = iswap16(dirp->d_reclen) - entrysize;
		proto.d_reclen = iswap16(entrysize);
		memmove(dirp, &proto, (size_t)entrysize);
		idesc->id_entryno++;
		inoinfo(iswap32(dirp->d_ino))->ino_linkcnt--;
		dirp = (struct direct *)((char *)(dirp) + entrysize);
		memset(dirp, 0, (size_t)n);
		dirp->d_reclen = iswap16(n);
		if (reply("FIX") == 1)
			ret |= ALTERED;
		else
			markclean = 0;
	}
chk1:
	if (idesc->id_entryno > 1)
		goto chk2;
	inp = getinoinfo(idesc->id_number);
	proto.d_ino = iswap32(inp->i_parent);
	if (newinofmt)
		proto.d_type = DT_DIR;
	else
		proto.d_type = 0;
	proto.d_namlen = 2;
	(void)strlcpy(proto.d_name, "..", sizeof(proto.d_name));
#if BYTE_ORDER == LITTLE_ENDIAN
	if (!newinofmt && !needswap) {
#else
	if (!newinofmt && needswap) {
#endif
		u_char tmp;

		tmp = proto.d_type;
		proto.d_type = proto.d_namlen;
		proto.d_namlen = tmp;
	}
	entrysize = DIRSIZ(0, &proto, 0);
	if (idesc->id_entryno == 0) {
		n = DIRSIZ(0, dirp, 0);
		if (iswap16(dirp->d_reclen) < n + entrysize)
			goto chk2;
		proto.d_reclen = iswap16(iswap16(dirp->d_reclen) - n);
		dirp->d_reclen = iswap16(n);
		idesc->id_entryno++;
		inoinfo(iswap32(dirp->d_ino))->ino_linkcnt--;
		dirp = (struct direct *)((char *)(dirp) + n);
		memset(dirp, 0, (size_t)iswap16(proto.d_reclen));
		dirp->d_reclen = proto.d_reclen;
	}
	if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
		inp->i_dotdot = iswap32(dirp->d_ino);
		if (newinofmt && dirp->d_type != DT_DIR) {
			direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
			dirp->d_type = DT_DIR;
			if (reply("FIX") == 1)
				ret |= ALTERED;
			else
				markclean = 0;
		}
		goto chk2;
	}
	if (iswap32(dirp->d_ino) != 0 && strcmp(dirp->d_name, ".") != 0) {
		fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
		pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
			dirp->d_name);
		inp->i_dotdot = (ino_t)-1;
		markclean = 0;
	} else if (iswap16(dirp->d_reclen) < entrysize) {
		fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
		pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
		inp->i_dotdot = (ino_t)-1;
		markclean = 0;
	} else if (inp->i_parent != 0) {
		/*
		 * We know the parent, so fix now.
		 */
		inp->i_dotdot = inp->i_parent;
		fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
		proto.d_reclen = dirp->d_reclen;
		memmove(dirp, &proto, (size_t)entrysize);
		if (reply("FIX") == 1)
			ret |= ALTERED;
		else
			markclean = 0;
	}
	idesc->id_entryno++;
	if (dirp->d_ino != 0)
		inoinfo(iswap32(dirp->d_ino))->ino_linkcnt--;
	return (ret|KEEPON);
chk2:
	if (dirp->d_ino == 0)
		return (ret|KEEPON);
	if (dirp->d_namlen <= 2 &&
	    dirp->d_name[0] == '.' &&
	    idesc->id_entryno >= 2) {
		if (dirp->d_namlen == 1) {
			direrror(idesc->id_number, "EXTRA '.' ENTRY");
			dirp->d_ino = 0;
			if (reply("FIX") == 1)
				ret |= ALTERED;
			else
				markclean = 0;
			return (KEEPON | ret);
		}
		if (dirp->d_name[1] == '.') {
			direrror(idesc->id_number, "EXTRA '..' ENTRY");
			dirp->d_ino = 0;
			if (reply("FIX") == 1)
				ret |= ALTERED;
			else
				markclean = 0;
			return (KEEPON | ret);
		}
	}
	idesc->id_entryno++;
	n = 0;
	if (iswap32(dirp->d_ino) > maxino) {
		fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
		n = reply("REMOVE");
		if (n == 0)
			markclean = 0;
	} else if (newinofmt &&
		   ((iswap32(dirp->d_ino) == WINO && dirp->d_type != DT_WHT) ||
		    (iswap32(dirp->d_ino) != WINO && dirp->d_type == DT_WHT))) {
		fileerror(idesc->id_number, iswap32(dirp->d_ino), "BAD WHITEOUT ENTRY");
		dirp->d_ino = iswap32(WINO);
		dirp->d_type = DT_WHT;
		if (reply("FIX") == 1)
			ret |= ALTERED;
		else
			markclean = 0;
	} else {
again:
		info = inoinfo(iswap32(dirp->d_ino));
		switch (info->ino_state) {
		case USTATE:
			if (idesc->id_entryno <= 2)
				break;
			fileerror(idesc->id_number, iswap32(dirp->d_ino), "UNALLOCATED");
			n = reply("REMOVE");
			if (n == 0)
				markclean = 0;
			break;

		case DCLEAR:
		case FCLEAR:
			if (idesc->id_entryno <= 2)
				break;
			if (info->ino_state == FCLEAR)
				errmsg = "DUP/BAD";
			else if (!preen && !usedsoftdep)
				errmsg = "ZERO LENGTH DIRECTORY";
			else {
				n = 1;
				break;
			}
			fileerror(idesc->id_number, iswap32(dirp->d_ino), errmsg);
			if ((n = reply("REMOVE")) == 1)
				break;
			dp = ginode(iswap32(dirp->d_ino));
			info->ino_state =
			    (iswap16(DIP(dp, mode)) & IFMT) == IFDIR ? DSTATE : FSTATE;
			info->ino_linkcnt = iswap16(DIP(dp, nlink));
			goto again;

		case DSTATE:
		case DFOUND:
			inp = getinoinfo(iswap32(dirp->d_ino));
			if (inp->i_parent != 0 && idesc->id_entryno > 2) {
				getpathname(pathbuf, sizeof(pathbuf),
				    idesc->id_number, idesc->id_number);
				getpathname(namebuf, sizeof(namebuf),
				    iswap32(dirp->d_ino), iswap32(dirp->d_ino));
				pwarn("%s %s %s\n", pathbuf,
				    "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
				    namebuf);
				if (preen)
					printf(" (IGNORED)\n");
				else if ((n = reply("REMOVE")) == 1)
					break;
			}
			if (idesc->id_entryno > 2)
				inp->i_parent = idesc->id_number;
			/* fall through */

		case FSTATE:
			if (newinofmt && dirp->d_type != info->ino_type) {
				fileerror(idesc->id_number, iswap32(dirp->d_ino),
				    "BAD TYPE VALUE");
				dirp->d_type = info->ino_type;
				if (reply("FIX") == 1)
					ret |= ALTERED;
				else
					markclean = 0;
			}
			info->ino_linkcnt--;
			break;

		default:
			errexit("BAD STATE %d FOR INODE I=%d",
			    info->ino_state, iswap32(dirp->d_ino));
		}
	}
	if (n == 0)
		return (ret|KEEPON);
	dirp->d_ino = 0;
	return (ret|KEEPON|ALTERED);
}

/*
 * Routine to sort disk blocks.
 */
static int
blksort(const void *arg1, const void *arg2)
{

	return ((*(const struct inoinfo *const *)arg1)->i_blks[0] -
		(*(const struct inoinfo *const *)arg2)->i_blks[0]);
}