xref: /netbsd-src/sbin/dump/traverse.c (revision 4008e3978a45954ac003ce17e71d782cd93efeed)
1*4008e397Smrg /*	$NetBSD: traverse.c,v 1.56 2023/08/07 23:26:40 mrg Exp $	*/
20114e805Scgd 
3108d8947Scgd /*-
4ccfa3742Smycroft  * Copyright (c) 1980, 1988, 1991, 1993
5ccfa3742Smycroft  *	The Regents of the University of California.  All rights reserved.
6108d8947Scgd  *
7108d8947Scgd  * Redistribution and use in source and binary forms, with or without
8108d8947Scgd  * modification, are permitted provided that the following conditions
9108d8947Scgd  * are met:
10108d8947Scgd  * 1. Redistributions of source code must retain the above copyright
11108d8947Scgd  *    notice, this list of conditions and the following disclaimer.
12108d8947Scgd  * 2. Redistributions in binary form must reproduce the above copyright
13108d8947Scgd  *    notice, this list of conditions and the following disclaimer in the
14108d8947Scgd  *    documentation and/or other materials provided with the distribution.
15bf07c871Sagc  * 3. Neither the name of the University nor the names of its contributors
16108d8947Scgd  *    may be used to endorse or promote products derived from this software
17108d8947Scgd  *    without specific prior written permission.
18108d8947Scgd  *
19108d8947Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20108d8947Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21108d8947Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22108d8947Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23108d8947Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24108d8947Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25108d8947Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26108d8947Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27108d8947Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28108d8947Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29108d8947Scgd  * SUCH DAMAGE.
30108d8947Scgd  */
31108d8947Scgd 
32a84bab53Slukem #include <sys/cdefs.h>
33108d8947Scgd #ifndef lint
340114e805Scgd #if 0
35919c9246Slukem static char sccsid[] = "@(#)traverse.c	8.7 (Berkeley) 6/15/95";
360114e805Scgd #else
37*4008e397Smrg __RCSID("$NetBSD: traverse.c,v 1.56 2023/08/07 23:26:40 mrg Exp $");
380114e805Scgd #endif
39108d8947Scgd #endif /* not lint */
40108d8947Scgd 
41108d8947Scgd #include <sys/param.h>
42108d8947Scgd #include <sys/time.h>
43108d8947Scgd #include <sys/stat.h>
44ccfa3742Smycroft #include <ufs/ufs/dir.h>
45919c9246Slukem #include <ufs/ffs/fs.h>
4634ccbd43Sbouyer #include <ufs/ffs/ffs_extern.h>
47ccfa3742Smycroft 
48e2325e1fSchristos #include <assert.h>
49ccfa3742Smycroft #include <ctype.h>
504c54f5b7Slukem #include <errno.h>
514c54f5b7Slukem #include <fts.h>
52ccfa3742Smycroft #include <stdio.h>
5342614ed3Sfvdl #include <stdlib.h>
54ccfa3742Smycroft #include <string.h>
55ccfa3742Smycroft #include <unistd.h>
56ccfa3742Smycroft 
57108d8947Scgd #include "dump.h"
58108d8947Scgd 
59108d8947Scgd #define	HASDUMPEDFILE	0x1
60108d8947Scgd #define	HASSUBDIRS	0x2
61108d8947Scgd 
62e2325e1fSchristos static	int appendextdata(union dinode *dp);
63e2325e1fSchristos static	void writeextdata(union dinode *dp, ino_t ino, int added);
6442614ed3Sfvdl static	int dirindir(ino_t, daddr_t, int, off_t *, u_int64_t *, int);
65e2325e1fSchristos static	void dmpindir(union dinode *dp, ino_t, daddr_t, int, off_t *);
6642614ed3Sfvdl static	int searchdir(ino_t, daddr_t, long, off_t, u_int64_t *, int);
67ccfa3742Smycroft 
68108d8947Scgd /*
69108d8947Scgd  * This is an estimation of the number of TP_BSIZE blocks in the file.
70108d8947Scgd  * It estimates the number of blocks in files with holes by assuming
71108d8947Scgd  * that all of the blocks accounted for by di_blocks are data blocks
72108d8947Scgd  * (when some of the blocks are usually used for indirect pointers);
73108d8947Scgd  * hence the estimate may be high.
74108d8947Scgd  */
7542614ed3Sfvdl int64_t
blockest(union dinode * dp)7642614ed3Sfvdl blockest(union dinode *dp)
77108d8947Scgd {
7842614ed3Sfvdl 	int64_t blkest, sizeest;
79108d8947Scgd 
80108d8947Scgd 	/*
81108d8947Scgd 	 * dp->di_size is the size of the file in bytes.
82108d8947Scgd 	 * dp->di_blocks stores the number of sectors actually in the file.
83108d8947Scgd 	 * If there are more sectors than the size would indicate, this just
84108d8947Scgd 	 *	means that there are indirect blocks in the file or unused
85108d8947Scgd 	 *	sectors in the last file block; we can safely ignore these
86108d8947Scgd 	 *	(blkest = sizeest below).
87108d8947Scgd 	 * If the file is bigger than the number of sectors would indicate,
88108d8947Scgd 	 *	then the file has holes in it.	In this case we must use the
89108d8947Scgd 	 *	block count to estimate the number of data blocks used, but
90108d8947Scgd 	 *	we use the actual size for estimating the number of indirect
91108d8947Scgd 	 *	dump blocks (sizeest vs. blkest in the indirect block
92108d8947Scgd 	 *	calculation).
93108d8947Scgd 	 */
948c21bc62Shannken 	if (DIP(dp, flags) & SF_SNAPSHOT)
958c21bc62Shannken 		return (1);
967deceea3Shannken 	blkest = howmany(ufs_fragroundup(ufsib,
977deceea3Shannken 	    dbtob((u_int64_t)DIP(dp, blocks))), TP_BSIZE);
987deceea3Shannken 	sizeest = howmany(ufs_fragroundup(ufsib, DIP(dp, size)), TP_BSIZE);
99108d8947Scgd 	if (blkest > sizeest)
100108d8947Scgd 		blkest = sizeest;
101dcd34a91Sdholland 	if (DIP(dp, size) > ufsib->ufs_bsize * UFS_NDADDR) {
102108d8947Scgd 		/* calculate the number of indirect blocks on the dump tape */
103108d8947Scgd 		blkest +=
104dcd34a91Sdholland 			howmany(sizeest - UFS_NDADDR * ufsib->ufs_bsize / TP_BSIZE,
105108d8947Scgd 			TP_NINDIR);
106108d8947Scgd 	}
107108d8947Scgd 	return (blkest + 1);
108108d8947Scgd }
109108d8947Scgd 
110ccfa3742Smycroft /* Auxiliary macro to pick up files changed since previous dump. */
111ccfa3742Smycroft #define	CHANGEDSINCE(dp, t) \
11242614ed3Sfvdl 	(DIP((dp), mtime) >= (t) || DIP((dp), ctime) >= (t))
113ccfa3742Smycroft 
114ccfa3742Smycroft /* The WANTTODUMP macro decides whether a file should be dumped. */
115ccfa3742Smycroft #ifdef UF_NODUMP
116ccfa3742Smycroft #define	WANTTODUMP(dp) \
11742614ed3Sfvdl 	(CHANGEDSINCE(dp, iswap64(spcl.c_ddate)) && \
11842614ed3Sfvdl 	 (nonodump || (DIP((dp), flags) & UF_NODUMP) != UF_NODUMP))
119ccfa3742Smycroft #else
12042614ed3Sfvdl #define	WANTTODUMP(dp) CHANGEDSINCE(dp, iswap64(spcl.c_ddate))
121ccfa3742Smycroft #endif
122ccfa3742Smycroft 
123108d8947Scgd /*
1244c54f5b7Slukem  * Determine if given inode should be dumped
125108d8947Scgd  */
1264c54f5b7Slukem void
mapfileino(ino_t ino,u_int64_t * tape_size,int * dirskipped)12742614ed3Sfvdl mapfileino(ino_t ino, u_int64_t *tape_size, int *dirskipped)
128108d8947Scgd {
12993da79deSlukem 	int mode;
13042614ed3Sfvdl 	union dinode *dp;
131108d8947Scgd 
1325f22ea3aSlukem 	/*
1335f22ea3aSlukem 	 * Skip inode if we've already marked it for dumping
1345f22ea3aSlukem 	 */
1355f22ea3aSlukem 	if (TSTINO(ino, usedinomap))
1365f22ea3aSlukem 		return;
137108d8947Scgd 	dp = getino(ino);
1381c57171fSperseant 	if (dp == NULL || (mode = (DIP(dp, mode) & IFMT)) == 0)
1394c54f5b7Slukem 		return;
1401746034bSbouyer 	/*
14189943600Ssimonb 	 * Skip WAPBL log file inodes.
14289943600Ssimonb 	 */
14389943600Ssimonb 	if (DIP(dp, flags) & SF_LOG)
14489943600Ssimonb 		return;
14589943600Ssimonb 	/*
1461746034bSbouyer 	 * Put all dirs in dumpdirmap, inodes that are to be dumped in the
1471746034bSbouyer 	 * used map. All inode but dirs who have the nodump attribute go
1481746034bSbouyer 	 * to the usedinomap.
1491746034bSbouyer 	 */
150108d8947Scgd 	SETINO(ino, usedinomap);
151108d8947Scgd 	if (mode == IFDIR)
152108d8947Scgd 		SETINO(ino, dumpdirmap);
153ccfa3742Smycroft 	if (WANTTODUMP(dp)) {
154108d8947Scgd 		SETINO(ino, dumpinomap);
155ccfa3742Smycroft 		if (mode != IFREG && mode != IFDIR && mode != IFLNK)
1564c4307e3Slukem 			*tape_size += 1;
157ccfa3742Smycroft 		else
1584c4307e3Slukem 			*tape_size += blockest(dp);
1594c54f5b7Slukem 		return;
160108d8947Scgd 	}
1611746034bSbouyer 	if (mode == IFDIR) {
1621746034bSbouyer #ifdef UF_NODUMP
16342614ed3Sfvdl 		if (!nonodump && (DIP(dp, flags) & UF_NODUMP))
1641746034bSbouyer 			CLRINO(ino, usedinomap);
1651746034bSbouyer #endif
1664c54f5b7Slukem 		*dirskipped = 1;
1674c54f5b7Slukem 	}
1681746034bSbouyer }
1694c54f5b7Slukem 
1704c54f5b7Slukem /*
1714c54f5b7Slukem  * Dump pass 1.
1724c54f5b7Slukem  *
1734c54f5b7Slukem  * Walk the inode list for a file system to find all allocated inodes
1744c54f5b7Slukem  * that have been modified since the previous dump time. Also, find all
1754c54f5b7Slukem  * the directories in the file system.
1769af1692eSlukem  * disk may be NULL if dirv is NULL.
1774c54f5b7Slukem  */
1784c54f5b7Slukem int
mapfiles(ino_t maxino,u_int64_t * tape_size,char * diskname,char * const * dirv)17942614ed3Sfvdl mapfiles(ino_t maxino, u_int64_t *tape_size, char *diskname, char * const *dirv)
1804c54f5b7Slukem {
1814c54f5b7Slukem 	int anydirskipped = 0;
1824c54f5b7Slukem 
1834c54f5b7Slukem 	if (dirv != NULL) {
1844c54f5b7Slukem 		char	 curdir[MAXPATHLEN];
1854c54f5b7Slukem 		FTS	*dirh;
1864c54f5b7Slukem 		FTSENT	*entry;
1874c54f5b7Slukem 		int	 d;
1884c54f5b7Slukem 
1894c54f5b7Slukem 		if (getcwd(curdir, sizeof(curdir)) == NULL) {
1904c54f5b7Slukem 			msg("Can't determine cwd: %s\n", strerror(errno));
1914c54f5b7Slukem 			dumpabort(0);
1924c54f5b7Slukem 		}
1934c54f5b7Slukem 		if ((dirh = fts_open(dirv, FTS_PHYSICAL|FTS_SEEDOT|FTS_XDEV,
194a84bab53Slukem 		    		    NULL)) == NULL) {
1954c54f5b7Slukem 			msg("fts_open failed: %s\n", strerror(errno));
1964c54f5b7Slukem 			dumpabort(0);
1974c54f5b7Slukem 		}
1984c54f5b7Slukem 		while ((entry = fts_read(dirh)) != NULL) {
1994c54f5b7Slukem 			switch (entry->fts_info) {
2004c54f5b7Slukem 			case FTS_DNR:		/* an error */
2014c54f5b7Slukem 			case FTS_ERR:
2024c54f5b7Slukem 			case FTS_NS:
2034c54f5b7Slukem 				msg("Can't fts_read %s: %s\n", entry->fts_path,
2044c54f5b7Slukem 				    strerror(errno));
205272df19fSmrg 				/* FALLTHROUGH */
2064c54f5b7Slukem 			case FTS_DP:		/* already seen dir */
2074c54f5b7Slukem 				continue;
2084c54f5b7Slukem 			}
2094c4307e3Slukem 			mapfileino(entry->fts_statp->st_ino, tape_size,
2104c54f5b7Slukem 			    &anydirskipped);
2114c54f5b7Slukem 		}
2124c54f5b7Slukem 		(void)fts_close(dirh);
2134c54f5b7Slukem 
2144c54f5b7Slukem 		/*
2154c54f5b7Slukem 		 * Add any parent directories
2164c54f5b7Slukem 		 */
2174c54f5b7Slukem 		for (d = 0 ; dirv[d] != NULL ; d++) {
2184c54f5b7Slukem 			char path[MAXPATHLEN];
2194c54f5b7Slukem 
2204c54f5b7Slukem 			if (dirv[d][0] != '/')
2214c54f5b7Slukem 				(void)snprintf(path, sizeof(path), "%s/%s",
2224c54f5b7Slukem 				    curdir, dirv[d]);
2234c54f5b7Slukem 			else
2244c54f5b7Slukem 				(void)snprintf(path, sizeof(path), "%s",
2254c54f5b7Slukem 				    dirv[d]);
2264c4307e3Slukem 			while (strcmp(path, diskname) != 0) {
2274c54f5b7Slukem 				char *p;
2284c54f5b7Slukem 				struct stat sb;
2294c54f5b7Slukem 
2304c54f5b7Slukem 				if (*path == '\0')
2314c54f5b7Slukem 					break;
2324c54f5b7Slukem 				if ((p = strrchr(path, '/')) == NULL)
2334c54f5b7Slukem 					break;
2344c54f5b7Slukem 				if (p == path)
2354c54f5b7Slukem 					break;
2364c54f5b7Slukem 				*p = '\0';
2374c54f5b7Slukem 				if (stat(path, &sb) == -1) {
2384c54f5b7Slukem 					msg("Can't stat %s: %s\n", path,
2394c54f5b7Slukem 					    strerror(errno));
2404c54f5b7Slukem 					break;
2414c54f5b7Slukem 				}
2424c4307e3Slukem 				mapfileino(sb.st_ino, tape_size, &anydirskipped);
2434c54f5b7Slukem 			}
2444c54f5b7Slukem 		}
2454c54f5b7Slukem 
2464c54f5b7Slukem 		/*
2474c54f5b7Slukem 		 * Ensure that the root inode actually appears in the
2484c54f5b7Slukem 		 * file list for a subdir
2494c54f5b7Slukem 		 */
250dcd34a91Sdholland 		mapfileino(UFS_ROOTINO, tape_size, &anydirskipped);
2514c54f5b7Slukem 	} else {
25242614ed3Sfvdl 		fs_mapinodes(maxino, tape_size, &anydirskipped);
253108d8947Scgd 	}
254108d8947Scgd 	/*
255108d8947Scgd 	 * Restore gets very upset if the root is not dumped,
256108d8947Scgd 	 * so ensure that it always is dumped.
257108d8947Scgd 	 */
258dcd34a91Sdholland 	SETINO(UFS_ROOTINO, dumpinomap);
259108d8947Scgd 	return (anydirskipped);
260108d8947Scgd }
261108d8947Scgd 
262108d8947Scgd /*
263108d8947Scgd  * Dump pass 2.
264108d8947Scgd  *
265108d8947Scgd  * Scan each directory on the file system to see if it has any modified
266108d8947Scgd  * files in it. If it does, and has not already been added to the dump
267108d8947Scgd  * list (because it was itself modified), then add it. If a directory
268108d8947Scgd  * has not been modified itself, contains no modified files and has no
269108d8947Scgd  * subdirectories, then it can be deleted from the dump list and from
270108d8947Scgd  * the list of directories. By deleting it from the list of directories,
271108d8947Scgd  * its parent may now qualify for the same treatment on this or a later
272108d8947Scgd  * pass using this algorithm.
273108d8947Scgd  */
274ccfa3742Smycroft int
mapdirs(ino_t maxino,u_int64_t * tape_size)27542614ed3Sfvdl mapdirs(ino_t maxino, u_int64_t *tape_size)
276108d8947Scgd {
27742614ed3Sfvdl 	union dinode *dp, di;
2781746034bSbouyer 	int i, isdir, nodump;
27993da79deSlukem 	char *map;
28093da79deSlukem 	ino_t ino;
28142614ed3Sfvdl 	off_t filesize;
282108d8947Scgd 	int ret, change = 0;
28342614ed3Sfvdl 	daddr_t blk;
284108d8947Scgd 
285ccfa3742Smycroft 	isdir = 0;		/* XXX just to get gcc to shut up */
286ccfa3742Smycroft 	for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
287ccfa3742Smycroft 		if (((ino - 1) % NBBY) == 0)	/* map is offset by 1 */
288108d8947Scgd 			isdir = *map++;
289108d8947Scgd 		else
290108d8947Scgd 			isdir >>= 1;
2911746034bSbouyer 		/*
2921746034bSbouyer 		 * If dir has been removed from the used map, it's either
2930835d456Sfvdl 		 * because it had the nodump flag, or it inherited it from
2941746034bSbouyer 		 * its parent. A directory can't be in dumpinomap if
2951746034bSbouyer 		 * not in usedinomap, but we have to go throuh it anyway
2961746034bSbouyer 		 * to propagate the nodump attribute.
2971746034bSbouyer 		 */
2981746034bSbouyer 		nodump = (TSTINO(ino, usedinomap) == 0);
2991746034bSbouyer 		if ((isdir & 1) == 0 ||
3001746034bSbouyer 		    (TSTINO(ino, dumpinomap) && nodump == 0))
301108d8947Scgd 			continue;
3021746034bSbouyer 
303108d8947Scgd 		dp = getino(ino);
30442614ed3Sfvdl 		/*
30542614ed3Sfvdl 		 * inode buf may be changed in searchdir().
30642614ed3Sfvdl 		 */
30742614ed3Sfvdl 		if (is_ufs2)
30842614ed3Sfvdl 			di.dp2 = dp->dp2;
30942614ed3Sfvdl 		else
31042614ed3Sfvdl 			di.dp1 = dp->dp1;
31142614ed3Sfvdl 		filesize = DIP(&di, size);
312dcd34a91Sdholland 		for (ret = 0, i = 0; filesize > 0 && i < UFS_NDADDR; i++) {
31342614ed3Sfvdl 			if (is_ufs2)
31442614ed3Sfvdl 				blk = iswap64(di.dp2.di_db[i]);
31542614ed3Sfvdl 			else
31642614ed3Sfvdl 				blk = iswap32(di.dp1.di_db[i]);
31742614ed3Sfvdl 			if (blk != 0)
31842614ed3Sfvdl 				ret |= searchdir(ino, blk,
3192763cc19Sperseant 					(long)ufs_dblksize(ufsib, &di, i),
3204c4307e3Slukem 					filesize, tape_size, nodump);
321108d8947Scgd 			if (ret & HASDUMPEDFILE)
322108d8947Scgd 				filesize = 0;
323108d8947Scgd 			else
3242763cc19Sperseant 				filesize -= ufsib->ufs_bsize;
325108d8947Scgd 		}
326dcd34a91Sdholland 		for (i = 0; filesize > 0 && i < UFS_NIADDR; i++) {
32742614ed3Sfvdl 			if (is_ufs2)
32842614ed3Sfvdl 				blk = iswap64(di.dp2.di_ib[i]);
32942614ed3Sfvdl 			else
330161b371dSfvdl 				blk = iswap32(di.dp1.di_ib[i]);
33142614ed3Sfvdl 			if (blk == 0)
332108d8947Scgd 				continue;
33342614ed3Sfvdl 			ret |= dirindir(ino, blk, i, &filesize,
3344c4307e3Slukem 			    tape_size, nodump);
335108d8947Scgd 		}
336108d8947Scgd 		if (ret & HASDUMPEDFILE) {
337108d8947Scgd 			SETINO(ino, dumpinomap);
3384c4307e3Slukem 			*tape_size += blockest(&di);
339108d8947Scgd 			change = 1;
340108d8947Scgd 			continue;
341108d8947Scgd 		}
3421746034bSbouyer 		if (nodump) {
3431746034bSbouyer 			if (ret & HASSUBDIRS)
3441746034bSbouyer 				change = 1; /* subdirs have inherited nodump */
3451746034bSbouyer 			CLRINO(ino, dumpdirmap);
3461746034bSbouyer 		} else if ((ret & HASSUBDIRS) == 0) {
347108d8947Scgd 			if (!TSTINO(ino, dumpinomap)) {
348108d8947Scgd 				CLRINO(ino, dumpdirmap);
349108d8947Scgd 				change = 1;
350108d8947Scgd 			}
351108d8947Scgd 		}
352108d8947Scgd 	}
353108d8947Scgd 	return (change);
354108d8947Scgd }
355108d8947Scgd 
356108d8947Scgd /*
357108d8947Scgd  * Read indirect blocks, and pass the data blocks to be searched
358108d8947Scgd  * as directories. Quit as soon as any entry is found that will
359108d8947Scgd  * require the directory to be dumped.
360108d8947Scgd  */
361ccfa3742Smycroft static int
dirindir(ino_t ino,daddr_t blkno,int ind_level,off_t * filesize,u_int64_t * tape_size,int nodump)36242614ed3Sfvdl dirindir(ino_t ino, daddr_t blkno, int ind_level, off_t *filesize,
36342614ed3Sfvdl 	u_int64_t *tape_size, int nodump)
364108d8947Scgd {
365108d8947Scgd 	int ret = 0;
36693da79deSlukem 	int i;
36742614ed3Sfvdl 	union {
36842614ed3Sfvdl 		int64_t i64[MAXBSIZE / sizeof (int64_t)];
36942614ed3Sfvdl 		int32_t i32[MAXBSIZE / sizeof (int32_t)];
37042614ed3Sfvdl 	} idblk;
371108d8947Scgd 
37242614ed3Sfvdl 	bread(fsatoda(ufsib, blkno), (char *)&idblk, (int)ufsib->ufs_bsize);
373108d8947Scgd 	if (ind_level <= 0) {
3742763cc19Sperseant 		for (i = 0; *filesize > 0 && i < ufsib->ufs_nindir; i++) {
37542614ed3Sfvdl 			if (is_ufs2)
376617c9472Sfvdl 				blkno = iswap64(idblk.i64[i]);
37742614ed3Sfvdl 			else
378617c9472Sfvdl 				blkno = iswap32(idblk.i32[i]);
379108d8947Scgd 			if (blkno != 0)
380617c9472Sfvdl 				ret |= searchdir(ino, blkno,
3812763cc19Sperseant 				    ufsib->ufs_bsize, *filesize,
3824c4307e3Slukem 				    tape_size, nodump);
383108d8947Scgd 			if (ret & HASDUMPEDFILE)
384108d8947Scgd 				*filesize = 0;
385108d8947Scgd 			else
3862763cc19Sperseant 				*filesize -= ufsib->ufs_bsize;
387108d8947Scgd 		}
388108d8947Scgd 		return (ret);
389108d8947Scgd 	}
390108d8947Scgd 	ind_level--;
3912763cc19Sperseant 	for (i = 0; *filesize > 0 && i < ufsib->ufs_nindir; i++) {
39242614ed3Sfvdl 		if (is_ufs2)
393617c9472Sfvdl 			blkno = iswap64(idblk.i64[i]);
39442614ed3Sfvdl 		else
395617c9472Sfvdl 			blkno = iswap32(idblk.i32[i]);
396108d8947Scgd 		if (blkno != 0)
3971746034bSbouyer 			ret |= dirindir(ino, blkno, ind_level, filesize,
3984c4307e3Slukem 			    tape_size, nodump);
399108d8947Scgd 	}
400108d8947Scgd 	return (ret);
401108d8947Scgd }
402108d8947Scgd 
403108d8947Scgd /*
404108d8947Scgd  * Scan a disk block containing directory information looking to see if
405108d8947Scgd  * any of the entries are on the dump list and to see if the directory
406108d8947Scgd  * contains any subdirectories.
407108d8947Scgd  */
408ccfa3742Smycroft static int
searchdir(ino_t dino,daddr_t blkno,long size,off_t filesize,u_int64_t * tape_size,int nodump)40942614ed3Sfvdl searchdir(ino_t dino, daddr_t blkno, long size, off_t filesize,
41042614ed3Sfvdl 	u_int64_t *tape_size, int nodump)
411108d8947Scgd {
41293da79deSlukem 	struct direct *dp;
41342614ed3Sfvdl 	union dinode *ip;
41493da79deSlukem 	long loc, ret = 0;
4152812e7d8Sfvdl 	char *dblk;
4161746034bSbouyer 	ino_t ino;
417108d8947Scgd 
4182812e7d8Sfvdl 	dblk = malloc(size);
4192812e7d8Sfvdl 	if (dblk == NULL)
420c8d11eb8Schristos 		quit("%s: cannot allocate directory memory", __func__);
4212763cc19Sperseant 	bread(fsatoda(ufsib, blkno), dblk, (int)size);
422108d8947Scgd 	if (filesize < size)
423108d8947Scgd 		size = filesize;
424108d8947Scgd 	for (loc = 0; loc < size; ) {
425108d8947Scgd 		dp = (struct direct *)(dblk + loc);
426108d8947Scgd 		if (dp->d_reclen == 0) {
427c4ee9f6dSchristos 			msg("corrupted directory, inumber %llu\n",
428c4ee9f6dSchristos 			    (unsigned long long)dino);
429108d8947Scgd 			break;
430108d8947Scgd 		}
43134ccbd43Sbouyer 		loc += iswap16(dp->d_reclen);
432108d8947Scgd 		if (dp->d_ino == 0)
433108d8947Scgd 			continue;
434108d8947Scgd 		if (dp->d_name[0] == '.') {
435108d8947Scgd 			if (dp->d_name[1] == '\0')
436108d8947Scgd 				continue;
437108d8947Scgd 			if (dp->d_name[1] == '.' && dp->d_name[2] == '\0')
438108d8947Scgd 				continue;
439108d8947Scgd 		}
4401746034bSbouyer 		ino = iswap32(dp->d_ino);
4411746034bSbouyer 		if (nodump) {
4421746034bSbouyer 			ip = getino(ino);
4431746034bSbouyer 			if (TSTINO(ino, dumpinomap)) {
4441746034bSbouyer 				CLRINO(ino, dumpinomap);
4454c4307e3Slukem 				*tape_size -= blockest(ip);
4461746034bSbouyer 			}
44719eb88dfSlukem 			/*
44819eb88dfSlukem 			 * Add back to dumpdirmap and remove from usedinomap
44919eb88dfSlukem 			 * to propagate nodump.
45019eb88dfSlukem 			 */
45142614ed3Sfvdl 			if ((DIP(ip, mode) & IFMT) == IFDIR) {
4521746034bSbouyer 				SETINO(ino, dumpdirmap);
45319eb88dfSlukem 				CLRINO(ino, usedinomap);
4541746034bSbouyer 				ret |= HASSUBDIRS;
4551746034bSbouyer 			}
4561746034bSbouyer 		} else {
4571746034bSbouyer 			if (TSTINO(ino, dumpinomap)) {
458108d8947Scgd 				ret |= HASDUMPEDFILE;
459108d8947Scgd 				if (ret & HASSUBDIRS)
460108d8947Scgd 					break;
461108d8947Scgd 			}
4621746034bSbouyer 			if (TSTINO(ino, dumpdirmap)) {
463108d8947Scgd 				ret |= HASSUBDIRS;
464108d8947Scgd 				if (ret & HASDUMPEDFILE)
465108d8947Scgd 					break;
466108d8947Scgd 			}
467108d8947Scgd 		}
4681746034bSbouyer 	}
4692812e7d8Sfvdl 	free(dblk);
470108d8947Scgd 	return (ret);
471108d8947Scgd }
472108d8947Scgd 
473108d8947Scgd /*
474108d8947Scgd  * Dump passes 3 and 4.
475108d8947Scgd  *
476108d8947Scgd  * Dump the contents of an inode to tape.
477108d8947Scgd  */
478108d8947Scgd void
dumpino(union dinode * dp,ino_t ino)47942614ed3Sfvdl dumpino(union dinode *dp, ino_t ino)
480108d8947Scgd {
481e2325e1fSchristos 	int ind_level, cnt, last, added;
48242614ed3Sfvdl 	off_t size;
483108d8947Scgd 	char buf[TP_BSIZE];
48442614ed3Sfvdl 	daddr_t blk;
48542614ed3Sfvdl 	void *shortlink;
486108d8947Scgd 
487108d8947Scgd 	if (newtape) {
488108d8947Scgd 		newtape = 0;
489108d8947Scgd 		dumpmap(dumpinomap, TS_BITS, ino);
490108d8947Scgd 	}
491108d8947Scgd 	CLRINO(ino, dumpinomap);
4928c21bc62Shannken 	/*
4938c21bc62Shannken 	 * Zero out the size of a snapshot so that it will be dumped
4948c21bc62Shannken 	 * as a zero length file.
4958c21bc62Shannken 	 */
4968c21bc62Shannken 	if (DIP(dp, flags) & SF_SNAPSHOT) {
4977ba7efe1Sskrll 		DIP_SET(dp, size, 0);
4987ba7efe1Sskrll 		DIP_SET(dp, flags, DIP(dp, flags) & ~SF_SNAPSHOT);
4998c21bc62Shannken 	}
50042614ed3Sfvdl 	if (!is_ufs2) {
50134ccbd43Sbouyer 		if (needswap)
50242614ed3Sfvdl 			ffs_dinode1_swap(&dp->dp1, &spcl.c_dinode);
50334ccbd43Sbouyer 		else
50442614ed3Sfvdl 			spcl.c_dinode = dp->dp1;
505d66b0477Schristos 		spcl.c_extsize = 0;
50642614ed3Sfvdl 	} else {
50742614ed3Sfvdl 		if (needswap)
50842614ed3Sfvdl 			ffs_dinode2_swap(&dp->dp2, &dp->dp2);
50942614ed3Sfvdl 		spcl.c_mode = dp->dp2.di_mode;
51042614ed3Sfvdl 		spcl.c_size = dp->dp2.di_size;
511e2325e1fSchristos 		spcl.c_extsize = dp->dp2.di_extsize;
51242614ed3Sfvdl 		spcl.c_atime = dp->dp2.di_atime;
51342614ed3Sfvdl 		spcl.c_atimensec = dp->dp2.di_atimensec;
51442614ed3Sfvdl 		spcl.c_mtime = dp->dp2.di_mtime;
51542614ed3Sfvdl 		spcl.c_mtimensec = dp->dp2.di_mtimensec;
51642614ed3Sfvdl 		spcl.c_birthtime = dp->dp2.di_birthtime;
51742614ed3Sfvdl 		spcl.c_birthtimensec = dp->dp2.di_birthnsec;
51842614ed3Sfvdl 		spcl.c_rdev = dp->dp2.di_rdev;
51942614ed3Sfvdl 		spcl.c_file_flags = dp->dp2.di_flags;
52042614ed3Sfvdl 		spcl.c_uid = dp->dp2.di_uid;
52142614ed3Sfvdl 		spcl.c_gid = dp->dp2.di_gid;
52242614ed3Sfvdl 	}
52334ccbd43Sbouyer 	spcl.c_type = iswap32(TS_INODE);
524108d8947Scgd 	spcl.c_count = 0;
52542614ed3Sfvdl 	switch (DIP(dp, mode) & IFMT) {
526108d8947Scgd 
527ccfa3742Smycroft 	case 0:
528108d8947Scgd 		/*
529108d8947Scgd 		 * Freed inode.
530108d8947Scgd 		 */
531108d8947Scgd 		return;
532108d8947Scgd 
5330c1f0c97Smycroft 	case IFLNK:
534108d8947Scgd 		/*
535108d8947Scgd 		 * Check for short symbolic link.
536108d8947Scgd 		 */
53742614ed3Sfvdl 		if (DIP(dp, size) > 0 &&
538eadb2ad5Smycroft #ifdef FS_44INODEFMT
53942614ed3Sfvdl 		    (DIP(dp, size) < ufsib->ufs_maxsymlinklen ||
54042614ed3Sfvdl 		     (ufsib->ufs_maxsymlinklen == 0 && DIP(dp, blocks) == 0))
541eadb2ad5Smycroft #else
54242614ed3Sfvdl 		    DIP(dp, blocks) == 0
543eadb2ad5Smycroft #endif
54499feaf5bSlukem 			) {
545108d8947Scgd 			spcl.c_addr[0] = 1;
54634ccbd43Sbouyer 			spcl.c_count = iswap32(1);
547e2325e1fSchristos 			added = appendextdata(dp);
548108d8947Scgd 			writeheader(ino);
54942614ed3Sfvdl 			if (is_ufs2)
55042614ed3Sfvdl 				shortlink = dp->dp2.di_db;
55142614ed3Sfvdl 			else
55242614ed3Sfvdl 				shortlink = dp->dp1.di_db;
55342614ed3Sfvdl 			memmove(buf, shortlink, DIP(dp, size));
55442614ed3Sfvdl 			buf[DIP(dp, size)] = '\0';
555108d8947Scgd 			writerec(buf, 0);
556e2325e1fSchristos 			writeextdata(dp, ino, added);
557108d8947Scgd 			return;
558108d8947Scgd 		}
559108d8947Scgd 		/* fall through */
560108d8947Scgd 
5610c1f0c97Smycroft 	case IFDIR:
5620c1f0c97Smycroft 	case IFREG:
56342614ed3Sfvdl 		if (DIP(dp, size) > 0)
564108d8947Scgd 			break;
565108d8947Scgd 		/* fall through */
566108d8947Scgd 
5670c1f0c97Smycroft 	case IFIFO:
5680c1f0c97Smycroft 	case IFSOCK:
5690c1f0c97Smycroft 	case IFCHR:
5700c1f0c97Smycroft 	case IFBLK:
571e2325e1fSchristos 		added = appendextdata(dp);
572108d8947Scgd 		writeheader(ino);
573e2325e1fSchristos 		writeextdata(dp, ino, added);
574108d8947Scgd 		return;
575108d8947Scgd 
576108d8947Scgd 	default:
57742614ed3Sfvdl 		msg("Warning: undefined file type 0%o\n", DIP(dp, mode) & IFMT);
578108d8947Scgd 		return;
579108d8947Scgd 	}
580e2325e1fSchristos 	if (DIP(dp, size) > UFS_NDADDR * ufsib->ufs_bsize) {
581dcd34a91Sdholland 		cnt = UFS_NDADDR * ufsib->ufs_frag;
582e2325e1fSchristos 		last = 0;
583e2325e1fSchristos 	} else {
58442614ed3Sfvdl 		cnt = howmany(DIP(dp, size), ufsib->ufs_fsize);
585e2325e1fSchristos 		last = 1;
586e2325e1fSchristos 	}
58742614ed3Sfvdl 	if (is_ufs2)
588e2325e1fSchristos 		blksout64(dp, &dp->dp2.di_db[0], cnt, ino, last);
58942614ed3Sfvdl 	else
59042614ed3Sfvdl 		blksout32(&dp->dp1.di_db[0], cnt, ino);
59142614ed3Sfvdl 
592dcd34a91Sdholland 	if ((size = DIP(dp, size) - UFS_NDADDR * ufsib->ufs_bsize) <= 0)
593108d8947Scgd 		return;
594dcd34a91Sdholland 	for (ind_level = 0; ind_level < UFS_NIADDR; ind_level++) {
59542614ed3Sfvdl 		if (is_ufs2)
59642614ed3Sfvdl 			blk = iswap64(dp->dp2.di_ib[ind_level]);
59742614ed3Sfvdl 		else
59842614ed3Sfvdl 			blk = iswap32(dp->dp1.di_ib[ind_level]);
599e2325e1fSchristos 		dmpindir(dp, ino, blk, ind_level, &size);
600108d8947Scgd 		if (size <= 0)
601108d8947Scgd 			return;
602108d8947Scgd 	}
603108d8947Scgd }
604108d8947Scgd 
605108d8947Scgd /*
606108d8947Scgd  * Read indirect blocks, and pass the data blocks to be dumped.
607108d8947Scgd  */
608ccfa3742Smycroft static void
dmpindir(union dinode * dp,ino_t ino,daddr_t blk,int ind_level,off_t * size)609e2325e1fSchristos dmpindir(union dinode *dp, ino_t ino, daddr_t blk, int ind_level, off_t *size)
610108d8947Scgd {
611e2325e1fSchristos 	int i, cnt, last;
61242614ed3Sfvdl 	union {
61342614ed3Sfvdl 		int32_t i32[MAXBSIZE / sizeof (int32_t)];
61442614ed3Sfvdl 		int64_t i64[MAXBSIZE / sizeof (int64_t)];
61542614ed3Sfvdl 	} idblk;
61642614ed3Sfvdl 	daddr_t iblk;
61742614ed3Sfvdl 
618108d8947Scgd 
619108d8947Scgd 	if (blk != 0)
62042614ed3Sfvdl 		bread(fsatoda(ufsib, blk), (char *)&idblk,
6212763cc19Sperseant 			(int) ufsib->ufs_bsize);
622108d8947Scgd 	else
62342614ed3Sfvdl 		memset(&idblk, 0, (int)ufsib->ufs_bsize);
624108d8947Scgd 	if (ind_level <= 0) {
625e2325e1fSchristos 		if (*size < ufsib->ufs_nindir * ufsib->ufs_bsize) {
6262763cc19Sperseant 			cnt = howmany(*size, ufsib->ufs_fsize);
627e2325e1fSchristos 			last = 0;
628e2325e1fSchristos 		} else {
6292763cc19Sperseant 			cnt = ufsib->ufs_nindir * ufsib->ufs_frag;
630e2325e1fSchristos 			last = 1;
631e2325e1fSchristos 		}
6322763cc19Sperseant 		*size -= ufsib->ufs_nindir * ufsib->ufs_bsize;
63342614ed3Sfvdl 		if (is_ufs2)
634e2325e1fSchristos 			blksout64(dp, &idblk.i64[0], cnt, ino, last);
63542614ed3Sfvdl 		else
63642614ed3Sfvdl 			blksout32(&idblk.i32[0], cnt, ino);
637108d8947Scgd 		return;
638108d8947Scgd 	}
639108d8947Scgd 	ind_level--;
6402763cc19Sperseant 	for (i = 0; i < ufsib->ufs_nindir; i++) {
64142614ed3Sfvdl 		if (is_ufs2)
64242614ed3Sfvdl 			iblk = iswap64(idblk.i64[i]);
64342614ed3Sfvdl 		else
64442614ed3Sfvdl 			iblk = iswap32(idblk.i32[i]);
645e2325e1fSchristos 		dmpindir(dp, ino, iblk, ind_level, size);
646108d8947Scgd 		if (*size <= 0)
647108d8947Scgd 			return;
648108d8947Scgd 	}
649108d8947Scgd }
650108d8947Scgd 
651108d8947Scgd /*
652108d8947Scgd  * Collect up the data into tape record sized buffers and output them.
653108d8947Scgd  */
654108d8947Scgd void
blksout32(int32_t * blkp,int frags,ino_t ino)65542614ed3Sfvdl blksout32(int32_t *blkp, int frags, ino_t ino)
656108d8947Scgd {
657a3ff3a30Sfvdl 	int32_t *bp;
658108d8947Scgd 	int i, j, count, blks, tbperdb;
659108d8947Scgd 
6602763cc19Sperseant 	blks = howmany(frags * ufsib->ufs_fsize, TP_BSIZE);
6612763cc19Sperseant 	tbperdb = ufsib->ufs_bsize >> tp_bshift;
662108d8947Scgd 	for (i = 0; i < blks; i += TP_NINDIR) {
663108d8947Scgd 		if (i + TP_NINDIR > blks)
664108d8947Scgd 			count = blks;
665108d8947Scgd 		else
666108d8947Scgd 			count = i + TP_NINDIR;
667108d8947Scgd 		for (j = i; j < count; j++)
668108d8947Scgd 			if (blkp[j / tbperdb] != 0)
669108d8947Scgd 				spcl.c_addr[j - i] = 1;
670108d8947Scgd 			else
671108d8947Scgd 				spcl.c_addr[j - i] = 0;
67234ccbd43Sbouyer 		spcl.c_count = iswap32(count - i);
673108d8947Scgd 		writeheader(ino);
674108d8947Scgd 		bp = &blkp[i / tbperdb];
675108d8947Scgd 		for (j = i; j < count; j += tbperdb, bp++)
676029a64ccSross 			if (*bp != 0) {
677108d8947Scgd 				if (j + tbperdb <= count)
6782763cc19Sperseant 					dumpblock(iswap32(*bp), (int)ufsib->ufs_bsize);
679108d8947Scgd 				else
68034ccbd43Sbouyer 					dumpblock(iswap32(*bp), (count - j) * TP_BSIZE);
681029a64ccSross 			}
68234ccbd43Sbouyer 		spcl.c_type = iswap32(TS_ADDR);
683108d8947Scgd 	}
684108d8947Scgd }
685108d8947Scgd 
68642614ed3Sfvdl void
blksout64(union dinode * dp,int64_t * blkp,int frags,ino_t ino,int last)687e2325e1fSchristos blksout64(union dinode *dp, int64_t *blkp, int frags, ino_t ino, int last)
68842614ed3Sfvdl {
68942614ed3Sfvdl 	int64_t *bp;
690e2325e1fSchristos 	int i, j, count, blks, tbperdb, added = 0;
691e2325e1fSchristos 	static int writingextdata = 0;
69242614ed3Sfvdl 
69342614ed3Sfvdl 	blks = howmany(frags * ufsib->ufs_fsize, TP_BSIZE);
694873fd608Schristos #if 0
695e2325e1fSchristos 	if (last) {
696e2325e1fSchristos 		int resid;
697e2325e1fSchristos 		int extsize = iswap32(spcl.c_extsize);
698e2325e1fSchristos 		if (writingextdata)
699e2325e1fSchristos 			resid = howmany(ufsib->ufs_qfmask & extsize,
700e2325e1fSchristos 			    TP_BSIZE);
701e2325e1fSchristos 		else
702e2325e1fSchristos 			resid = howmany(ufsib->ufs_qfmask & dp->dp2.di_size,
703e2325e1fSchristos 			    TP_BSIZE);
704e2325e1fSchristos 		if (resid > 0)
705e2325e1fSchristos 			blks -= howmany(ufsib->ufs_fsize, TP_BSIZE) - resid;
706e2325e1fSchristos 	}
707873fd608Schristos #endif
70842614ed3Sfvdl 	tbperdb = ufsib->ufs_bsize >> tp_bshift;
70942614ed3Sfvdl 	for (i = 0; i < blks; i += TP_NINDIR) {
71042614ed3Sfvdl 		if (i + TP_NINDIR > blks)
71142614ed3Sfvdl 			count = blks;
71242614ed3Sfvdl 		else
71342614ed3Sfvdl 			count = i + TP_NINDIR;
714e2325e1fSchristos 		assert(count <= TP_NINDIR + i);
71542614ed3Sfvdl 		for (j = i; j < count; j++)
71642614ed3Sfvdl 			if (blkp[j / tbperdb] != 0)
71742614ed3Sfvdl 				spcl.c_addr[j - i] = 1;
71842614ed3Sfvdl 			else
71942614ed3Sfvdl 				spcl.c_addr[j - i] = 0;
72042614ed3Sfvdl 		spcl.c_count = iswap32(count - i);
721e2325e1fSchristos 		if (last && count == blks && !writingextdata)
722e2325e1fSchristos 			added = appendextdata(dp);
72342614ed3Sfvdl 		writeheader(ino);
72442614ed3Sfvdl 		bp = &blkp[i / tbperdb];
72542614ed3Sfvdl 		for (j = i; j < count; j += tbperdb, bp++)
72642614ed3Sfvdl 			if (*bp != 0) {
72742614ed3Sfvdl 				if (j + tbperdb <= count)
72842614ed3Sfvdl 					dumpblock(iswap64(*bp), (int)ufsib->ufs_bsize);
72942614ed3Sfvdl 				else
73042614ed3Sfvdl 					dumpblock(iswap64(*bp), (count - j) * TP_BSIZE);
73142614ed3Sfvdl 			}
73242614ed3Sfvdl 		spcl.c_type = iswap32(TS_ADDR);
733e2325e1fSchristos 		spcl.c_count = 0;
734e2325e1fSchristos 		if (last && count == blks && !writingextdata) {
735e2325e1fSchristos 			writingextdata = 1;
736e2325e1fSchristos 			writeextdata(dp, ino, added);
737e2325e1fSchristos 			writingextdata = 0;
73842614ed3Sfvdl 		}
73942614ed3Sfvdl 	}
740e2325e1fSchristos }
741e2325e1fSchristos 
742e2325e1fSchristos /*
743e2325e1fSchristos  * If there is room in the current block for the extended attributes
744e2325e1fSchristos  * as well as the file data, update the header to reflect the added
745e2325e1fSchristos  * attribute data at the end. Attributes are placed at the end so that
746e2325e1fSchristos  * old versions of restore will correctly restore the file and simply
747e2325e1fSchristos  * discard the extra data at the end that it does not understand.
748e2325e1fSchristos  * The attribute data is dumped following the file data by the
749e2325e1fSchristos  * writeextdata() function (below).
750e2325e1fSchristos  */
751e2325e1fSchristos static int
appendextdata(union dinode * dp)752e2325e1fSchristos appendextdata(union dinode *dp)
753e2325e1fSchristos {
754e2325e1fSchristos 	int i, blks, tbperdb, count, extsize;
755e2325e1fSchristos 
756e2325e1fSchristos 	count = iswap32(spcl.c_count);
757e2325e1fSchristos 	extsize = iswap32(spcl.c_extsize);
758e2325e1fSchristos 	/*
759e2325e1fSchristos 	 * If no extended attributes, there is nothing to do.
760e2325e1fSchristos 	 */
761e2325e1fSchristos 	if (extsize == 0)
762e2325e1fSchristos 		return (0);
763e2325e1fSchristos 	/*
764e2325e1fSchristos 	 * If there is not enough room at the end of this block
765e2325e1fSchristos 	 * to add the extended attributes, then rather than putting
766e2325e1fSchristos 	 * part of them here, we simply push them entirely into a
767e2325e1fSchristos 	 * new block rather than putting some here and some later.
768e2325e1fSchristos 	 */
769e2325e1fSchristos 	if (extsize > UFS_NXADDR * ufsib->ufs_bsize)
770e2325e1fSchristos 		blks = howmany(UFS_NXADDR * ufsib->ufs_bsize, TP_BSIZE);
771e2325e1fSchristos 	else
772e2325e1fSchristos 		blks = howmany(extsize, TP_BSIZE);
773e2325e1fSchristos 	if (count + blks > TP_NINDIR)
774e2325e1fSchristos 		return (0);
775e2325e1fSchristos 	/*
776e2325e1fSchristos 	 * Update the block map in the header to indicate the added
777e2325e1fSchristos 	 * extended attribute. They will be appended after the file
778e2325e1fSchristos 	 * data by the writeextdata() routine.
779e2325e1fSchristos 	 */
780e2325e1fSchristos 	tbperdb = ufsib->ufs_bsize >> tp_bshift;
781e2325e1fSchristos 	assert(count + blks < TP_NINDIR);
782e2325e1fSchristos 	for (i = 0; i < blks; i++)
783*4008e397Smrg 		if (dp->dp2.di_extb[i / tbperdb] != 0)
784e2325e1fSchristos 				spcl.c_addr[count + i] = 1;
785e2325e1fSchristos 			else
786e2325e1fSchristos 				spcl.c_addr[count + i] = 0;
787e2325e1fSchristos 	spcl.c_count = iswap32(count + blks);
788e2325e1fSchristos 	return (blks);
789e2325e1fSchristos }
790e2325e1fSchristos 
791e2325e1fSchristos /*
792e2325e1fSchristos  * Dump the extended attribute data. If there was room in the file
793e2325e1fSchristos  * header, then all we need to do is output the data blocks. If there
794e2325e1fSchristos  * was not room in the file header, then an additional TS_ADDR header
795e2325e1fSchristos  * is created to hold the attribute data.
796e2325e1fSchristos  */
797e2325e1fSchristos static void
writeextdata(union dinode * dp,ino_t ino,int added)798e2325e1fSchristos writeextdata(union dinode *dp, ino_t ino, int added)
799e2325e1fSchristos {
800e2325e1fSchristos 	int i, frags, blks, tbperdb, last, extsize;
801e2325e1fSchristos 	int64_t *bp;
802e2325e1fSchristos 	off_t size;
803e2325e1fSchristos 
804e2325e1fSchristos 	extsize = iswap32(spcl.c_extsize);
805e2325e1fSchristos 
806e2325e1fSchristos 	/*
807e2325e1fSchristos 	 * If no extended attributes, there is nothing to do.
808e2325e1fSchristos 	 */
809e2325e1fSchristos 	if (extsize == 0)
810e2325e1fSchristos 		return;
811e2325e1fSchristos 	/*
812e2325e1fSchristos 	 * If there was no room in the file block for the attributes,
813e2325e1fSchristos 	 * dump them out in a new block, otherwise just dump the data.
814e2325e1fSchristos 	 */
815e2325e1fSchristos 	if (added == 0) {
816e2325e1fSchristos 		if (extsize > UFS_NXADDR * ufsib->ufs_bsize) {
817e2325e1fSchristos 			frags = UFS_NXADDR * ufsib->ufs_frag;
818e2325e1fSchristos 			last = 0;
819e2325e1fSchristos 		} else {
820e2325e1fSchristos 			frags = howmany(extsize, ufsib->ufs_fsize);
821e2325e1fSchristos 			last = 1;
822e2325e1fSchristos 		}
823e2325e1fSchristos 		blksout64(dp, &dp->dp2.di_extb[0], frags, ino, last);
824e2325e1fSchristos 	} else {
825e2325e1fSchristos 		if (extsize > UFS_NXADDR * ufsib->ufs_bsize)
826e2325e1fSchristos 			blks = howmany(UFS_NXADDR * ufsib->ufs_bsize, TP_BSIZE);
827e2325e1fSchristos 		else
828e2325e1fSchristos 			blks = howmany(extsize, TP_BSIZE);
829e2325e1fSchristos 		tbperdb = ufsib->ufs_bsize >> tp_bshift;
830e2325e1fSchristos 		for (i = 0; i < blks; i += tbperdb) {
831e2325e1fSchristos 			bp = &dp->dp2.di_extb[i / tbperdb];
832e2325e1fSchristos 			if (*bp != 0) {
833e2325e1fSchristos 				if (i + tbperdb <= blks)
834e2325e1fSchristos 					dumpblock(iswap64(*bp), (int)ufsib->ufs_bsize);
835e2325e1fSchristos 				else
836e2325e1fSchristos 					dumpblock(iswap64(*bp), (blks - i) * TP_BSIZE);
837e2325e1fSchristos 			}
838e2325e1fSchristos 		}
839e2325e1fSchristos 
840e2325e1fSchristos 	}
841e2325e1fSchristos 	/*
842e2325e1fSchristos 	 * If an indirect block is added for extended attributes, then
843e2325e1fSchristos 	 * di_exti below should be changed to the structure element
844e2325e1fSchristos 	 * that references the extended attribute indirect block. This
845e2325e1fSchristos 	 * definition is here only to make it compile without complaint.
846e2325e1fSchristos 	 */
847e2325e1fSchristos #define di_exti di_spare[0]
848e2325e1fSchristos 	/*
849e2325e1fSchristos 	 * If the extended attributes fall into an indirect block,
850e2325e1fSchristos 	 * dump it as well.
851e2325e1fSchristos 	 */
852e2325e1fSchristos 	if ((size = extsize - UFS_NXADDR * ufsib->ufs_bsize) > 0)
853e2325e1fSchristos 		dmpindir(dp, ino, dp->dp2.di_exti, 0, &size);
854e2325e1fSchristos }
85542614ed3Sfvdl 
856108d8947Scgd /*
857108d8947Scgd  * Dump a map to the tape.
858108d8947Scgd  */
859108d8947Scgd void
dumpmap(char * map,int type,ino_t ino)86099feaf5bSlukem dumpmap(char *map, int type, ino_t ino)
861108d8947Scgd {
86293da79deSlukem 	int i;
863108d8947Scgd 	char *cp;
864108d8947Scgd 
86534ccbd43Sbouyer 	spcl.c_type = iswap32(type);
86634ccbd43Sbouyer 	spcl.c_count = iswap32(howmany(mapsize * sizeof(char), TP_BSIZE));
867108d8947Scgd 	writeheader(ino);
86834ccbd43Sbouyer 	for (i = 0, cp = map; i < iswap32(spcl.c_count); i++, cp += TP_BSIZE)
869108d8947Scgd 		writerec(cp, 0);
870108d8947Scgd }
871108d8947Scgd 
872108d8947Scgd /*
873108d8947Scgd  * Write a header record to the dump tape.
874108d8947Scgd  */
875108d8947Scgd void
writeheader(ino_t ino)87699feaf5bSlukem writeheader(ino_t ino)
877108d8947Scgd {
87893da79deSlukem 	int32_t sum, cnt, *lp;
879108d8947Scgd 
88034ccbd43Sbouyer 	spcl.c_inumber = iswap32(ino);
88142614ed3Sfvdl 	if (is_ufs2)
88242614ed3Sfvdl 		spcl.c_magic = iswap32(FS_UFS2_MAGIC);
88342614ed3Sfvdl 	else {
88434ccbd43Sbouyer 		spcl.c_magic = iswap32(NFS_MAGIC);
88542614ed3Sfvdl 		spcl.c_old_date = iswap32(iswap64(spcl.c_date));
88642614ed3Sfvdl 		spcl.c_old_ddate = iswap32(iswap64(spcl.c_ddate));
88742614ed3Sfvdl 		spcl.c_old_tapea = iswap32(iswap64(spcl.c_tapea));
88842614ed3Sfvdl 		spcl.c_old_firstrec = iswap32(iswap64(spcl.c_firstrec));
88942614ed3Sfvdl 	}
890108d8947Scgd 	spcl.c_checksum = 0;
891a0c5caa0Scgd 	lp = (int32_t *)&spcl;
892108d8947Scgd 	sum = 0;
893a0c5caa0Scgd 	cnt = sizeof(union u_spcl) / (4 * sizeof(int32_t));
894108d8947Scgd 	while (--cnt >= 0) {
89534ccbd43Sbouyer 		sum += iswap32(*lp++);
89634ccbd43Sbouyer 		sum += iswap32(*lp++);
89734ccbd43Sbouyer 		sum += iswap32(*lp++);
89834ccbd43Sbouyer 		sum += iswap32(*lp++);
899108d8947Scgd 	}
90034ccbd43Sbouyer 	spcl.c_checksum = iswap32(CHECKSUM - sum);
901108d8947Scgd 	writerec((char *)&spcl, 1);
902108d8947Scgd }
903