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