18fae3551SRodney W. Grimes /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
48fae3551SRodney W. Grimes * Copyright (c) 1980, 1988, 1991, 1993
58fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved.
68fae3551SRodney W. Grimes *
78fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
88fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions
98fae3551SRodney W. Grimes * are met:
108fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
118fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
128fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
138fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
148fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
168fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software
178fae3551SRodney W. Grimes * without specific prior written permission.
188fae3551SRodney W. Grimes *
198fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
208fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
218fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
228fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
238fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
248fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
258fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
268fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
278fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
288fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
298fae3551SRodney W. Grimes * SUCH DAMAGE.
308fae3551SRodney W. Grimes */
318fae3551SRodney W. Grimes
328fae3551SRodney W. Grimes #include <sys/param.h>
338fae3551SRodney W. Grimes #include <sys/stat.h>
348fae3551SRodney W. Grimes
358fae3551SRodney W. Grimes #include <ufs/ufs/dir.h>
368fae3551SRodney W. Grimes #include <ufs/ufs/dinode.h>
37a37c38b8SPeter Wemm #include <ufs/ffs/fs.h>
388fae3551SRodney W. Grimes
398fae3551SRodney W. Grimes #include <protocols/dumprestore.h>
408fae3551SRodney W. Grimes
412d518c65SWarner Losh #include <assert.h>
428fae3551SRodney W. Grimes #include <ctype.h>
4337736675SWarner Losh #include <errno.h>
44617dbd3cSIan Dowse #include <inttypes.h>
4589fdc4e1SMike Barcroft #include <limits.h>
46617dbd3cSIan Dowse #include <stdio.h>
471c85e6a3SKirk McKusick #include <stdlib.h>
48617dbd3cSIan Dowse #include <string.h>
49617dbd3cSIan Dowse #include <timeconv.h>
50617dbd3cSIan Dowse #include <unistd.h>
518fae3551SRodney W. Grimes
528fae3551SRodney W. Grimes #include "dump.h"
538fae3551SRodney W. Grimes
541c85e6a3SKirk McKusick union dinode {
551c85e6a3SKirk McKusick struct ufs1_dinode dp1;
561c85e6a3SKirk McKusick struct ufs2_dinode dp2;
571c85e6a3SKirk McKusick };
581c85e6a3SKirk McKusick #define DIP(dp, field) \
591c85e6a3SKirk McKusick ((sblock->fs_magic == FS_UFS1_MAGIC) ? \
601c85e6a3SKirk McKusick (dp)->dp1.field : (dp)->dp2.field)
618518a74aSAlexander Kabaev #define DIP_SET(dp, field, val) do {\
628518a74aSAlexander Kabaev if (sblock->fs_magic == FS_UFS1_MAGIC) \
638518a74aSAlexander Kabaev (dp)->dp1.field = (val); \
648518a74aSAlexander Kabaev else \
658518a74aSAlexander Kabaev (dp)->dp2.field = (val); \
668518a74aSAlexander Kabaev } while (0)
671c85e6a3SKirk McKusick
688fae3551SRodney W. Grimes #define HASDUMPEDFILE 0x1
698fae3551SRodney W. Grimes #define HASSUBDIRS 0x2
708fae3551SRodney W. Grimes
711c85e6a3SKirk McKusick static int dirindir(ino_t ino, ufs2_daddr_t blkno, int level, long *size,
720b39291eSDavid Malone long *tapesize, int nodump, ino_t maxino);
73772ad651SKirk McKusick static void dmpindir(union dinode *dp, ino_t ino, ufs2_daddr_t blk, int level,
74772ad651SKirk McKusick off_t *size);
75772ad651SKirk McKusick static void ufs1_blksout(ufs1_daddr_t *blkp, int frags, ino_t ino);
76772ad651SKirk McKusick static void ufs2_blksout(union dinode *dp, ufs2_daddr_t *blkp, int frags,
77772ad651SKirk McKusick ino_t ino, int last);
78772ad651SKirk McKusick static int appendextdata(union dinode *dp);
79772ad651SKirk McKusick static void writeextdata(union dinode *dp, ino_t ino, int added);
801c85e6a3SKirk McKusick static int searchdir(ino_t ino, ufs2_daddr_t blkno, long size, long filesize,
810b39291eSDavid Malone long *tapesize, int nodump, ino_t maxino);
826bfd0bdcSKirk McKusick static long blockest(union dinode *dp);
838fae3551SRodney W. Grimes
848fae3551SRodney W. Grimes /*
858fae3551SRodney W. Grimes * This is an estimation of the number of TP_BSIZE blocks in the file.
868fae3551SRodney W. Grimes * It estimates the number of blocks in files with holes by assuming
878fae3551SRodney W. Grimes * that all of the blocks accounted for by di_blocks are data blocks
888fae3551SRodney W. Grimes * (when some of the blocks are usually used for indirect pointers);
898fae3551SRodney W. Grimes * hence the estimate may be high.
908fae3551SRodney W. Grimes */
916bfd0bdcSKirk McKusick static long
blockest(union dinode * dp)921c85e6a3SKirk McKusick blockest(union dinode *dp)
938fae3551SRodney W. Grimes {
948fae3551SRodney W. Grimes long blkest, sizeest;
958fae3551SRodney W. Grimes
968fae3551SRodney W. Grimes /*
978fae3551SRodney W. Grimes * dp->di_size is the size of the file in bytes.
988fae3551SRodney W. Grimes * dp->di_blocks stores the number of sectors actually in the file.
998fae3551SRodney W. Grimes * If there are more sectors than the size would indicate, this just
1008fae3551SRodney W. Grimes * means that there are indirect blocks in the file or unused
1018fae3551SRodney W. Grimes * sectors in the last file block; we can safely ignore these
1028fae3551SRodney W. Grimes * (blkest = sizeest below).
1038fae3551SRodney W. Grimes * If the file is bigger than the number of sectors would indicate,
1048fae3551SRodney W. Grimes * then the file has holes in it. In this case we must use the
1058fae3551SRodney W. Grimes * block count to estimate the number of data blocks used, but
1068fae3551SRodney W. Grimes * we use the actual size for estimating the number of indirect
1078fae3551SRodney W. Grimes * dump blocks (sizeest vs. blkest in the indirect block
1088fae3551SRodney W. Grimes * calculation).
1098fae3551SRodney W. Grimes */
1106bfd0bdcSKirk McKusick if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0)
1116bfd0bdcSKirk McKusick return (1);
1121c85e6a3SKirk McKusick blkest = howmany(dbtob(DIP(dp, di_blocks)), TP_BSIZE);
1131c85e6a3SKirk McKusick sizeest = howmany(DIP(dp, di_size), TP_BSIZE);
1148fae3551SRodney W. Grimes if (blkest > sizeest)
1158fae3551SRodney W. Grimes blkest = sizeest;
1161dc349abSEd Maste if (DIP(dp, di_size) > sblock->fs_bsize * UFS_NDADDR) {
1178fae3551SRodney W. Grimes /* calculate the number of indirect blocks on the dump tape */
1181dc349abSEd Maste blkest += howmany(sizeest -
1191dc349abSEd Maste UFS_NDADDR * sblock->fs_bsize / TP_BSIZE, TP_NINDIR);
1208fae3551SRodney W. Grimes }
1218fae3551SRodney W. Grimes return (blkest + 1);
1228fae3551SRodney W. Grimes }
1238fae3551SRodney W. Grimes
1248fae3551SRodney W. Grimes /* Auxiliary macro to pick up files changed since previous dump. */
1258fae3551SRodney W. Grimes #define CHANGEDSINCE(dp, t) \
1261c85e6a3SKirk McKusick (DIP(dp, di_mtime) >= (t) || DIP(dp, di_ctime) >= (t))
1278fae3551SRodney W. Grimes
1288fae3551SRodney W. Grimes /* The WANTTODUMP macro decides whether a file should be dumped. */
1298fae3551SRodney W. Grimes #ifdef UF_NODUMP
1308fae3551SRodney W. Grimes #define WANTTODUMP(dp) \
1318fae3551SRodney W. Grimes (CHANGEDSINCE(dp, spcl.c_ddate) && \
1321c85e6a3SKirk McKusick (nonodump || (DIP(dp, di_flags) & UF_NODUMP) != UF_NODUMP))
1338fae3551SRodney W. Grimes #else
1348fae3551SRodney W. Grimes #define WANTTODUMP(dp) CHANGEDSINCE(dp, spcl.c_ddate)
1358fae3551SRodney W. Grimes #endif
1368fae3551SRodney W. Grimes
1378fae3551SRodney W. Grimes /*
1388fae3551SRodney W. Grimes * Dump pass 1.
1398fae3551SRodney W. Grimes *
1408fae3551SRodney W. Grimes * Walk the inode list for a file system to find all allocated inodes
1418fae3551SRodney W. Grimes * that have been modified since the previous dump time. Also, find all
1428fae3551SRodney W. Grimes * the directories in the file system.
1438fae3551SRodney W. Grimes */
1448fae3551SRodney W. Grimes int
mapfiles(ino_t maxino,long * tapesize)1452db673abSWarner Losh mapfiles(ino_t maxino, long *tapesize)
1468fae3551SRodney W. Grimes {
14769becf4aSKirk McKusick int i, cg, mode, inosused;
1488fae3551SRodney W. Grimes int anydirskipped = 0;
14969becf4aSKirk McKusick union dinode *dp;
15069becf4aSKirk McKusick struct cg *cgp;
15169becf4aSKirk McKusick ino_t ino;
1520c40596cSXin LI u_char *cp;
1538fae3551SRodney W. Grimes
15469becf4aSKirk McKusick if ((cgp = malloc(sblock->fs_cgsize)) == NULL)
15569becf4aSKirk McKusick quit("mapfiles: cannot allocate memory.\n");
15669becf4aSKirk McKusick for (cg = 0; cg < sblock->fs_ncg; cg++) {
15769becf4aSKirk McKusick ino = cg * sblock->fs_ipg;
158a770ae06SKirk McKusick blkread(fsbtodb(sblock, cgtod(sblock, cg)), (char *)cgp,
15969becf4aSKirk McKusick sblock->fs_cgsize);
16069becf4aSKirk McKusick if (sblock->fs_magic == FS_UFS2_MAGIC)
16169becf4aSKirk McKusick inosused = cgp->cg_initediblk;
16269becf4aSKirk McKusick else
16369becf4aSKirk McKusick inosused = sblock->fs_ipg;
16469becf4aSKirk McKusick /*
16569becf4aSKirk McKusick * If we are using soft updates, then we can trust the
16669becf4aSKirk McKusick * cylinder group inode allocation maps to tell us which
16769becf4aSKirk McKusick * inodes are allocated. We will scan the used inode map
16869becf4aSKirk McKusick * to find the inodes that are really in use, and then
16969becf4aSKirk McKusick * read only those inodes in from disk.
17069becf4aSKirk McKusick */
17169becf4aSKirk McKusick if (sblock->fs_flags & FS_DOSOFTDEP) {
17269becf4aSKirk McKusick if (!cg_chkmagic(cgp))
17369becf4aSKirk McKusick quit("mapfiles: cg %d: bad magic number\n", cg);
17469becf4aSKirk McKusick cp = &cg_inosused(cgp)[(inosused - 1) / CHAR_BIT];
17569becf4aSKirk McKusick for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) {
17669becf4aSKirk McKusick if (*cp == 0)
17769becf4aSKirk McKusick continue;
17869becf4aSKirk McKusick for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) {
17969becf4aSKirk McKusick if (*cp & i)
18069becf4aSKirk McKusick break;
18169becf4aSKirk McKusick inosused--;
18269becf4aSKirk McKusick }
18369becf4aSKirk McKusick break;
18469becf4aSKirk McKusick }
18569becf4aSKirk McKusick if (inosused <= 0)
18669becf4aSKirk McKusick continue;
18769becf4aSKirk McKusick }
18869becf4aSKirk McKusick for (i = 0; i < inosused; i++, ino++) {
1891dc349abSEd Maste if (ino < UFS_ROOTINO ||
19007436eebSKirk McKusick (dp = getino(ino, &mode)) == NULL ||
191d8ba45e2SEd Maste (mode & IFMT) == 0)
1928fae3551SRodney W. Grimes continue;
1930b39291eSDavid Malone if (ino >= maxino) {
194e25a029eSMatthew D Fleming msg("Skipping inode %ju >= maxino %ju\n",
195e25a029eSMatthew D Fleming (uintmax_t)ino, (uintmax_t)maxino);
1960b39291eSDavid Malone continue;
1970b39291eSDavid Malone }
198801382faSDavid E. O'Brien /*
1992c8094f3SJordan K. Hubbard * Everything must go in usedinomap so that a check
2002c8094f3SJordan K. Hubbard * for "in dumpdirmap but not in usedinomap" to detect
2012c8094f3SJordan K. Hubbard * dirs with nodump set has a chance of succeeding
2022c8094f3SJordan K. Hubbard * (this is used in mapdirs()).
203801382faSDavid E. O'Brien */
2042c8094f3SJordan K. Hubbard SETINO(ino, usedinomap);
205d8ba45e2SEd Maste if (mode == IFDIR)
2068fae3551SRodney W. Grimes SETINO(ino, dumpdirmap);
2078fae3551SRodney W. Grimes if (WANTTODUMP(dp)) {
2088fae3551SRodney W. Grimes SETINO(ino, dumpinomap);
209d8ba45e2SEd Maste if (mode != IFREG &&
210d8ba45e2SEd Maste mode != IFDIR &&
211d8ba45e2SEd Maste mode != IFLNK)
2128fae3551SRodney W. Grimes *tapesize += 1;
2138fae3551SRodney W. Grimes else
2148fae3551SRodney W. Grimes *tapesize += blockest(dp);
2158fae3551SRodney W. Grimes continue;
2168fae3551SRodney W. Grimes }
217d8ba45e2SEd Maste if (mode == IFDIR) {
21869becf4aSKirk McKusick if (!nonodump &&
21969becf4aSKirk McKusick (DIP(dp, di_flags) & UF_NODUMP))
2202c8094f3SJordan K. Hubbard CLRINO(ino, usedinomap);
2218fae3551SRodney W. Grimes anydirskipped = 1;
2228fae3551SRodney W. Grimes }
2232c8094f3SJordan K. Hubbard }
22469becf4aSKirk McKusick }
2258fae3551SRodney W. Grimes /*
2268fae3551SRodney W. Grimes * Restore gets very upset if the root is not dumped,
2278fae3551SRodney W. Grimes * so ensure that it always is dumped.
2288fae3551SRodney W. Grimes */
2291dc349abSEd Maste SETINO(UFS_ROOTINO, dumpinomap);
2308fae3551SRodney W. Grimes return (anydirskipped);
2318fae3551SRodney W. Grimes }
2328fae3551SRodney W. Grimes
2338fae3551SRodney W. Grimes /*
2348fae3551SRodney W. Grimes * Dump pass 2.
2358fae3551SRodney W. Grimes *
2368fae3551SRodney W. Grimes * Scan each directory on the file system to see if it has any modified
2378fae3551SRodney W. Grimes * files in it. If it does, and has not already been added to the dump
2388fae3551SRodney W. Grimes * list (because it was itself modified), then add it. If a directory
2398fae3551SRodney W. Grimes * has not been modified itself, contains no modified files and has no
2408fae3551SRodney W. Grimes * subdirectories, then it can be deleted from the dump list and from
2418fae3551SRodney W. Grimes * the list of directories. By deleting it from the list of directories,
2428fae3551SRodney W. Grimes * its parent may now qualify for the same treatment on this or a later
2438fae3551SRodney W. Grimes * pass using this algorithm.
2448fae3551SRodney W. Grimes */
2458fae3551SRodney W. Grimes int
mapdirs(ino_t maxino,long * tapesize)2462db673abSWarner Losh mapdirs(ino_t maxino, long *tapesize)
2478fae3551SRodney W. Grimes {
2481c85e6a3SKirk McKusick union dinode *dp;
249d2334e27SIan Dowse int i, isdir, nodump;
250d2334e27SIan Dowse char *map;
251d2334e27SIan Dowse ino_t ino;
2521c85e6a3SKirk McKusick union dinode di;
2538fae3551SRodney W. Grimes long filesize;
2548fae3551SRodney W. Grimes int ret, change = 0;
2558fae3551SRodney W. Grimes
2568fae3551SRodney W. Grimes isdir = 0; /* XXX just to get gcc to shut up */
2578fae3551SRodney W. Grimes for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
25889fdc4e1SMike Barcroft if (((ino - 1) % CHAR_BIT) == 0) /* map is offset by 1 */
2598fae3551SRodney W. Grimes isdir = *map++;
2608fae3551SRodney W. Grimes else
2618fae3551SRodney W. Grimes isdir >>= 1;
262801382faSDavid E. O'Brien /*
263801382faSDavid E. O'Brien * If a directory has been removed from usedinomap, it
264801382faSDavid E. O'Brien * either has the nodump flag set, or has inherited
265801382faSDavid E. O'Brien * it. Although a directory can't be in dumpinomap if
266801382faSDavid E. O'Brien * it isn't in usedinomap, we have to go through it to
267801382faSDavid E. O'Brien * propagate the nodump flag.
268801382faSDavid E. O'Brien */
2692c8094f3SJordan K. Hubbard nodump = !nonodump && (TSTINO(ino, usedinomap) == 0);
270801382faSDavid E. O'Brien if ((isdir & 1) == 0 || (TSTINO(ino, dumpinomap) && !nodump))
2718fae3551SRodney W. Grimes continue;
27207436eebSKirk McKusick dp = getino(ino, &i);
2731c85e6a3SKirk McKusick /*
2741c85e6a3SKirk McKusick * inode buf may change in searchdir().
2751c85e6a3SKirk McKusick */
2761c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC)
2771c85e6a3SKirk McKusick di.dp1 = dp->dp1;
2781c85e6a3SKirk McKusick else
2791c85e6a3SKirk McKusick di.dp2 = dp->dp2;
2801c85e6a3SKirk McKusick filesize = DIP(&di, di_size);
2811dc349abSEd Maste for (ret = 0, i = 0; filesize > 0 && i < UFS_NDADDR; i++) {
2821c85e6a3SKirk McKusick if (DIP(&di, di_db[i]) != 0)
2831c85e6a3SKirk McKusick ret |= searchdir(ino, DIP(&di, di_db[i]),
284155ea063SIan Dowse (long)sblksize(sblock, DIP(&di, di_size),
2850b39291eSDavid Malone i), filesize, tapesize, nodump, maxino);
2868fae3551SRodney W. Grimes if (ret & HASDUMPEDFILE)
2878fae3551SRodney W. Grimes filesize = 0;
2888fae3551SRodney W. Grimes else
2898fae3551SRodney W. Grimes filesize -= sblock->fs_bsize;
2908fae3551SRodney W. Grimes }
2911dc349abSEd Maste for (i = 0; filesize > 0 && i < UFS_NIADDR; i++) {
2921c85e6a3SKirk McKusick if (DIP(&di, di_ib[i]) == 0)
2938fae3551SRodney W. Grimes continue;
2941c85e6a3SKirk McKusick ret |= dirindir(ino, DIP(&di, di_ib[i]), i, &filesize,
2950b39291eSDavid Malone tapesize, nodump, maxino);
2968fae3551SRodney W. Grimes }
2978fae3551SRodney W. Grimes if (ret & HASDUMPEDFILE) {
2988fae3551SRodney W. Grimes SETINO(ino, dumpinomap);
299155ea063SIan Dowse *tapesize += blockest(&di);
3008fae3551SRodney W. Grimes change = 1;
3018fae3551SRodney W. Grimes continue;
3028fae3551SRodney W. Grimes }
303801382faSDavid E. O'Brien if (nodump) {
304801382faSDavid E. O'Brien if (ret & HASSUBDIRS)
305801382faSDavid E. O'Brien change = 1; /* subdirs inherit nodump */
306801382faSDavid E. O'Brien CLRINO(ino, dumpdirmap);
307801382faSDavid E. O'Brien } else if ((ret & HASSUBDIRS) == 0)
3088fae3551SRodney W. Grimes if (!TSTINO(ino, dumpinomap)) {
3098fae3551SRodney W. Grimes CLRINO(ino, dumpdirmap);
3108fae3551SRodney W. Grimes change = 1;
3118fae3551SRodney W. Grimes }
3128fae3551SRodney W. Grimes }
3138fae3551SRodney W. Grimes return (change);
3148fae3551SRodney W. Grimes }
3158fae3551SRodney W. Grimes
3168fae3551SRodney W. Grimes /*
3178fae3551SRodney W. Grimes * Read indirect blocks, and pass the data blocks to be searched
3188fae3551SRodney W. Grimes * as directories. Quit as soon as any entry is found that will
3198fae3551SRodney W. Grimes * require the directory to be dumped.
3208fae3551SRodney W. Grimes */
3218fae3551SRodney W. Grimes static int
dirindir(ino_t ino,ufs2_daddr_t blkno,int ind_level,long * filesize,long * tapesize,int nodump,ino_t maxino)3221c85e6a3SKirk McKusick dirindir(
3231c85e6a3SKirk McKusick ino_t ino,
3241c85e6a3SKirk McKusick ufs2_daddr_t blkno,
3251c85e6a3SKirk McKusick int ind_level,
3261c85e6a3SKirk McKusick long *filesize,
3271c85e6a3SKirk McKusick long *tapesize,
3280b39291eSDavid Malone int nodump,
3290b39291eSDavid Malone ino_t maxino)
3308fae3551SRodney W. Grimes {
3317680e41cSIan Dowse union {
3327680e41cSIan Dowse ufs1_daddr_t ufs1[MAXBSIZE / sizeof(ufs1_daddr_t)];
3337680e41cSIan Dowse ufs2_daddr_t ufs2[MAXBSIZE / sizeof(ufs2_daddr_t)];
3347680e41cSIan Dowse } idblk;
3358fae3551SRodney W. Grimes int ret = 0;
336d2334e27SIan Dowse int i;
3378fae3551SRodney W. Grimes
338a770ae06SKirk McKusick blkread(fsbtodb(sblock, blkno), (char *)&idblk, (int)sblock->fs_bsize);
3398fae3551SRodney W. Grimes if (ind_level <= 0) {
3408fae3551SRodney W. Grimes for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
3411c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC)
3427680e41cSIan Dowse blkno = idblk.ufs1[i];
3431c85e6a3SKirk McKusick else
3447680e41cSIan Dowse blkno = idblk.ufs2[i];
3458fae3551SRodney W. Grimes if (blkno != 0)
3468fae3551SRodney W. Grimes ret |= searchdir(ino, blkno, sblock->fs_bsize,
3470b39291eSDavid Malone *filesize, tapesize, nodump, maxino);
3488fae3551SRodney W. Grimes if (ret & HASDUMPEDFILE)
3498fae3551SRodney W. Grimes *filesize = 0;
3508fae3551SRodney W. Grimes else
3518fae3551SRodney W. Grimes *filesize -= sblock->fs_bsize;
3528fae3551SRodney W. Grimes }
3538fae3551SRodney W. Grimes return (ret);
3548fae3551SRodney W. Grimes }
3558fae3551SRodney W. Grimes ind_level--;
3568fae3551SRodney W. Grimes for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
3571c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC)
3587680e41cSIan Dowse blkno = idblk.ufs1[i];
3591c85e6a3SKirk McKusick else
3607680e41cSIan Dowse blkno = idblk.ufs2[i];
3618fae3551SRodney W. Grimes if (blkno != 0)
362801382faSDavid E. O'Brien ret |= dirindir(ino, blkno, ind_level, filesize,
3630b39291eSDavid Malone tapesize, nodump, maxino);
3648fae3551SRodney W. Grimes }
3658fae3551SRodney W. Grimes return (ret);
3668fae3551SRodney W. Grimes }
3678fae3551SRodney W. Grimes
3688fae3551SRodney W. Grimes /*
3698fae3551SRodney W. Grimes * Scan a disk block containing directory information looking to see if
3708fae3551SRodney W. Grimes * any of the entries are on the dump list and to see if the directory
3718fae3551SRodney W. Grimes * contains any subdirectories.
3728fae3551SRodney W. Grimes */
3738fae3551SRodney W. Grimes static int
searchdir(ino_t ino,ufs2_daddr_t blkno,long size,long filesize,long * tapesize,int nodump,ino_t maxino)3741c85e6a3SKirk McKusick searchdir(
3751c85e6a3SKirk McKusick ino_t ino,
3761c85e6a3SKirk McKusick ufs2_daddr_t blkno,
3771c85e6a3SKirk McKusick long size,
3781c85e6a3SKirk McKusick long filesize,
3791c85e6a3SKirk McKusick long *tapesize,
3800b39291eSDavid Malone int nodump,
3810b39291eSDavid Malone ino_t maxino)
3828fae3551SRodney W. Grimes {
3831c85e6a3SKirk McKusick int mode;
384d2334e27SIan Dowse struct direct *dp;
3851c85e6a3SKirk McKusick union dinode *ip;
386d2334e27SIan Dowse long loc, ret = 0;
3871c85e6a3SKirk McKusick static caddr_t dblk;
3888fae3551SRodney W. Grimes
3891c85e6a3SKirk McKusick if (dblk == NULL && (dblk = malloc(sblock->fs_bsize)) == NULL)
3901c85e6a3SKirk McKusick quit("searchdir: cannot allocate indirect memory.\n");
391a770ae06SKirk McKusick blkread(fsbtodb(sblock, blkno), dblk, (int)size);
3928fae3551SRodney W. Grimes if (filesize < size)
3938fae3551SRodney W. Grimes size = filesize;
3948fae3551SRodney W. Grimes for (loc = 0; loc < size; ) {
3958fae3551SRodney W. Grimes dp = (struct direct *)(dblk + loc);
3968fae3551SRodney W. Grimes if (dp->d_reclen == 0) {
397e25a029eSMatthew D Fleming msg("corrupted directory, inumber %ju\n",
398e25a029eSMatthew D Fleming (uintmax_t)ino);
3998fae3551SRodney W. Grimes break;
4008fae3551SRodney W. Grimes }
4018fae3551SRodney W. Grimes loc += dp->d_reclen;
4028fae3551SRodney W. Grimes if (dp->d_ino == 0)
4038fae3551SRodney W. Grimes continue;
4040b39291eSDavid Malone if (dp->d_ino >= maxino) {
405e25a029eSMatthew D Fleming msg("corrupted directory entry, d_ino %ju >= %ju\n",
406e25a029eSMatthew D Fleming (uintmax_t)dp->d_ino, (uintmax_t)maxino);
4070b39291eSDavid Malone break;
4080b39291eSDavid Malone }
4098fae3551SRodney W. Grimes if (dp->d_name[0] == '.') {
4108fae3551SRodney W. Grimes if (dp->d_name[1] == '\0')
4118fae3551SRodney W. Grimes continue;
4128fae3551SRodney W. Grimes if (dp->d_name[1] == '.' && dp->d_name[2] == '\0')
4138fae3551SRodney W. Grimes continue;
4148fae3551SRodney W. Grimes }
415801382faSDavid E. O'Brien if (nodump) {
41607436eebSKirk McKusick ip = getino(dp->d_ino, &mode);
417801382faSDavid E. O'Brien if (TSTINO(dp->d_ino, dumpinomap)) {
418801382faSDavid E. O'Brien CLRINO(dp->d_ino, dumpinomap);
419801382faSDavid E. O'Brien *tapesize -= blockest(ip);
420801382faSDavid E. O'Brien }
42101629855SDavid E. O'Brien /*
42201629855SDavid E. O'Brien * Add back to dumpdirmap and remove from usedinomap
42301629855SDavid E. O'Brien * to propagate nodump.
42401629855SDavid E. O'Brien */
425d8ba45e2SEd Maste if (mode == IFDIR) {
426801382faSDavid E. O'Brien SETINO(dp->d_ino, dumpdirmap);
42701629855SDavid E. O'Brien CLRINO(dp->d_ino, usedinomap);
428801382faSDavid E. O'Brien ret |= HASSUBDIRS;
429801382faSDavid E. O'Brien }
430801382faSDavid E. O'Brien } else {
4318fae3551SRodney W. Grimes if (TSTINO(dp->d_ino, dumpinomap)) {
4328fae3551SRodney W. Grimes ret |= HASDUMPEDFILE;
4338fae3551SRodney W. Grimes if (ret & HASSUBDIRS)
4348fae3551SRodney W. Grimes break;
4358fae3551SRodney W. Grimes }
4368fae3551SRodney W. Grimes if (TSTINO(dp->d_ino, dumpdirmap)) {
4378fae3551SRodney W. Grimes ret |= HASSUBDIRS;
4388fae3551SRodney W. Grimes if (ret & HASDUMPEDFILE)
4398fae3551SRodney W. Grimes break;
4408fae3551SRodney W. Grimes }
4418fae3551SRodney W. Grimes }
442801382faSDavid E. O'Brien }
4438fae3551SRodney W. Grimes return (ret);
4448fae3551SRodney W. Grimes }
4458fae3551SRodney W. Grimes
4468fae3551SRodney W. Grimes /*
4478fae3551SRodney W. Grimes * Dump passes 3 and 4.
4488fae3551SRodney W. Grimes *
4498fae3551SRodney W. Grimes * Dump the contents of an inode to tape.
4508fae3551SRodney W. Grimes */
4518fae3551SRodney W. Grimes void
dumpino(union dinode * dp,ino_t ino)4521c85e6a3SKirk McKusick dumpino(union dinode *dp, ino_t ino)
4538fae3551SRodney W. Grimes {
454772ad651SKirk McKusick int ind_level, cnt, last, added;
4551c85e6a3SKirk McKusick off_t size;
4568fae3551SRodney W. Grimes char buf[TP_BSIZE];
4578fae3551SRodney W. Grimes
4588fae3551SRodney W. Grimes if (newtape) {
4598fae3551SRodney W. Grimes newtape = 0;
4608fae3551SRodney W. Grimes dumpmap(dumpinomap, TS_BITS, ino);
4618fae3551SRodney W. Grimes }
4628fae3551SRodney W. Grimes CLRINO(ino, dumpinomap);
463be5b1425SKirk McKusick /*
464be5b1425SKirk McKusick * Zero out the size of a snapshot so that it will be dumped
465be5b1425SKirk McKusick * as a zero length file.
466be5b1425SKirk McKusick */
467be5b1425SKirk McKusick if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0) {
4688518a74aSAlexander Kabaev DIP_SET(dp, di_size, 0);
4698518a74aSAlexander Kabaev DIP_SET(dp, di_flags, DIP(dp, di_flags) & ~SF_SNAPSHOT);
470be5b1425SKirk McKusick }
4711c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC) {
4721c85e6a3SKirk McKusick spcl.c_mode = dp->dp1.di_mode;
4731c85e6a3SKirk McKusick spcl.c_size = dp->dp1.di_size;
474772ad651SKirk McKusick spcl.c_extsize = 0;
4751c85e6a3SKirk McKusick spcl.c_atime = _time32_to_time(dp->dp1.di_atime);
4761c85e6a3SKirk McKusick spcl.c_atimensec = dp->dp1.di_atimensec;
4771c85e6a3SKirk McKusick spcl.c_mtime = _time32_to_time(dp->dp1.di_mtime);
4781c85e6a3SKirk McKusick spcl.c_mtimensec = dp->dp1.di_mtimensec;
479fb36a3d8SKirk McKusick spcl.c_birthtime = 0;
480fb36a3d8SKirk McKusick spcl.c_birthtimensec = 0;
4811c85e6a3SKirk McKusick spcl.c_rdev = dp->dp1.di_rdev;
4821c85e6a3SKirk McKusick spcl.c_file_flags = dp->dp1.di_flags;
4831c85e6a3SKirk McKusick spcl.c_uid = dp->dp1.di_uid;
4841c85e6a3SKirk McKusick spcl.c_gid = dp->dp1.di_gid;
4851c85e6a3SKirk McKusick } else {
4861c85e6a3SKirk McKusick spcl.c_mode = dp->dp2.di_mode;
4871c85e6a3SKirk McKusick spcl.c_size = dp->dp2.di_size;
488772ad651SKirk McKusick spcl.c_extsize = dp->dp2.di_extsize;
4891c85e6a3SKirk McKusick spcl.c_atime = _time64_to_time(dp->dp2.di_atime);
4901c85e6a3SKirk McKusick spcl.c_atimensec = dp->dp2.di_atimensec;
4911c85e6a3SKirk McKusick spcl.c_mtime = _time64_to_time(dp->dp2.di_mtime);
4921c85e6a3SKirk McKusick spcl.c_mtimensec = dp->dp2.di_mtimensec;
493fb36a3d8SKirk McKusick spcl.c_birthtime = _time64_to_time(dp->dp2.di_birthtime);
494fb36a3d8SKirk McKusick spcl.c_birthtimensec = dp->dp2.di_birthnsec;
4951c85e6a3SKirk McKusick spcl.c_rdev = dp->dp2.di_rdev;
4961c85e6a3SKirk McKusick spcl.c_file_flags = dp->dp2.di_flags;
4971c85e6a3SKirk McKusick spcl.c_uid = dp->dp2.di_uid;
4981c85e6a3SKirk McKusick spcl.c_gid = dp->dp2.di_gid;
4991c85e6a3SKirk McKusick }
5008fae3551SRodney W. Grimes spcl.c_type = TS_INODE;
5018fae3551SRodney W. Grimes spcl.c_count = 0;
5021c85e6a3SKirk McKusick switch (DIP(dp, di_mode) & S_IFMT) {
5038fae3551SRodney W. Grimes
5048fae3551SRodney W. Grimes case 0:
5058fae3551SRodney W. Grimes /*
5068fae3551SRodney W. Grimes * Freed inode.
5078fae3551SRodney W. Grimes */
5088fae3551SRodney W. Grimes return;
5098fae3551SRodney W. Grimes
5108fae3551SRodney W. Grimes case S_IFLNK:
5118fae3551SRodney W. Grimes /*
5128fae3551SRodney W. Grimes * Check for short symbolic link.
5138fae3551SRodney W. Grimes */
5141c85e6a3SKirk McKusick if (DIP(dp, di_size) > 0 &&
5151c85e6a3SKirk McKusick DIP(dp, di_size) < sblock->fs_maxsymlinklen) {
5168fae3551SRodney W. Grimes spcl.c_addr[0] = 1;
5178fae3551SRodney W. Grimes spcl.c_count = 1;
518772ad651SKirk McKusick added = appendextdata(dp);
5198fae3551SRodney W. Grimes writeheader(ino);
5205b13fa79SJessica Clarke memmove(buf, DIP(dp, di_shortlink),
5211c85e6a3SKirk McKusick (u_long)DIP(dp, di_size));
5221c85e6a3SKirk McKusick buf[DIP(dp, di_size)] = '\0';
5238fae3551SRodney W. Grimes writerec(buf, 0);
524772ad651SKirk McKusick writeextdata(dp, ino, added);
5258fae3551SRodney W. Grimes return;
5268fae3551SRodney W. Grimes }
5277fed38d0SPhilippe Charnier /* FALLTHROUGH */
5288fae3551SRodney W. Grimes
5298fae3551SRodney W. Grimes case S_IFDIR:
5308fae3551SRodney W. Grimes case S_IFREG:
5311c85e6a3SKirk McKusick if (DIP(dp, di_size) > 0)
5328fae3551SRodney W. Grimes break;
5337fed38d0SPhilippe Charnier /* FALLTHROUGH */
5348fae3551SRodney W. Grimes
5358fae3551SRodney W. Grimes case S_IFIFO:
5368fae3551SRodney W. Grimes case S_IFSOCK:
5378fae3551SRodney W. Grimes case S_IFCHR:
5388fae3551SRodney W. Grimes case S_IFBLK:
539772ad651SKirk McKusick added = appendextdata(dp);
5408fae3551SRodney W. Grimes writeheader(ino);
541772ad651SKirk McKusick writeextdata(dp, ino, added);
5428fae3551SRodney W. Grimes return;
5438fae3551SRodney W. Grimes
5448fae3551SRodney W. Grimes default:
5451c85e6a3SKirk McKusick msg("Warning: undefined file type 0%o\n",
546d8ba45e2SEd Maste DIP(dp, di_mode) & IFMT);
5478fae3551SRodney W. Grimes return;
5488fae3551SRodney W. Grimes }
5491dc349abSEd Maste if (DIP(dp, di_size) > UFS_NDADDR * sblock->fs_bsize) {
5501dc349abSEd Maste cnt = UFS_NDADDR * sblock->fs_frag;
551772ad651SKirk McKusick last = 0;
552772ad651SKirk McKusick } else {
5531c85e6a3SKirk McKusick cnt = howmany(DIP(dp, di_size), sblock->fs_fsize);
554772ad651SKirk McKusick last = 1;
555772ad651SKirk McKusick }
5561c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC)
5571c85e6a3SKirk McKusick ufs1_blksout(&dp->dp1.di_db[0], cnt, ino);
5581c85e6a3SKirk McKusick else
559772ad651SKirk McKusick ufs2_blksout(dp, &dp->dp2.di_db[0], cnt, ino, last);
5601dc349abSEd Maste if ((size = DIP(dp, di_size) - UFS_NDADDR * sblock->fs_bsize) <= 0)
5618fae3551SRodney W. Grimes return;
5621dc349abSEd Maste for (ind_level = 0; ind_level < UFS_NIADDR; ind_level++) {
563772ad651SKirk McKusick dmpindir(dp, ino, DIP(dp, di_ib[ind_level]), ind_level, &size);
5648fae3551SRodney W. Grimes if (size <= 0)
5658fae3551SRodney W. Grimes return;
5668fae3551SRodney W. Grimes }
5678fae3551SRodney W. Grimes }
5688fae3551SRodney W. Grimes
5698fae3551SRodney W. Grimes /*
5708fae3551SRodney W. Grimes * Read indirect blocks, and pass the data blocks to be dumped.
5718fae3551SRodney W. Grimes */
5728fae3551SRodney W. Grimes static void
dmpindir(union dinode * dp,ino_t ino,ufs2_daddr_t blk,int ind_level,off_t * size)573772ad651SKirk McKusick dmpindir(union dinode *dp, ino_t ino, ufs2_daddr_t blk, int ind_level,
574772ad651SKirk McKusick off_t *size)
5758fae3551SRodney W. Grimes {
5767680e41cSIan Dowse union {
5777680e41cSIan Dowse ufs1_daddr_t ufs1[MAXBSIZE / sizeof(ufs1_daddr_t)];
5787680e41cSIan Dowse ufs2_daddr_t ufs2[MAXBSIZE / sizeof(ufs2_daddr_t)];
5797680e41cSIan Dowse } idblk;
580772ad651SKirk McKusick int i, cnt, last;
5818fae3551SRodney W. Grimes
5828fae3551SRodney W. Grimes if (blk != 0)
583a770ae06SKirk McKusick blkread(fsbtodb(sblock, blk), (char *)&idblk,
5847680e41cSIan Dowse (int)sblock->fs_bsize);
5858fae3551SRodney W. Grimes else
5867680e41cSIan Dowse memset(&idblk, 0, sblock->fs_bsize);
5878fae3551SRodney W. Grimes if (ind_level <= 0) {
588772ad651SKirk McKusick if (*size > NINDIR(sblock) * sblock->fs_bsize) {
5898fae3551SRodney W. Grimes cnt = NINDIR(sblock) * sblock->fs_frag;
590772ad651SKirk McKusick last = 0;
591772ad651SKirk McKusick } else {
592772ad651SKirk McKusick cnt = howmany(*size, sblock->fs_fsize);
593772ad651SKirk McKusick last = 1;
594772ad651SKirk McKusick }
5958fae3551SRodney W. Grimes *size -= NINDIR(sblock) * sblock->fs_bsize;
5961c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC)
5977680e41cSIan Dowse ufs1_blksout(idblk.ufs1, cnt, ino);
5981c85e6a3SKirk McKusick else
599772ad651SKirk McKusick ufs2_blksout(dp, idblk.ufs2, cnt, ino, last);
6008fae3551SRodney W. Grimes return;
6018fae3551SRodney W. Grimes }
6028fae3551SRodney W. Grimes ind_level--;
6038fae3551SRodney W. Grimes for (i = 0; i < NINDIR(sblock); i++) {
6041c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC)
605772ad651SKirk McKusick dmpindir(dp, ino, idblk.ufs1[i], ind_level, size);
6061c85e6a3SKirk McKusick else
607772ad651SKirk McKusick dmpindir(dp, ino, idblk.ufs2[i], ind_level, size);
6088fae3551SRodney W. Grimes if (*size <= 0)
6098fae3551SRodney W. Grimes return;
6108fae3551SRodney W. Grimes }
6118fae3551SRodney W. Grimes }
6128fae3551SRodney W. Grimes
6138fae3551SRodney W. Grimes /*
6148fae3551SRodney W. Grimes * Collect up the data into tape record sized buffers and output them.
6158fae3551SRodney W. Grimes */
616772ad651SKirk McKusick static void
ufs1_blksout(ufs1_daddr_t * blkp,int frags,ino_t ino)6171c85e6a3SKirk McKusick ufs1_blksout(ufs1_daddr_t *blkp, int frags, ino_t ino)
6188fae3551SRodney W. Grimes {
6191c85e6a3SKirk McKusick ufs1_daddr_t *bp;
6201c85e6a3SKirk McKusick int i, j, count, blks, tbperdb;
6211c85e6a3SKirk McKusick
6221c85e6a3SKirk McKusick blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
6231c85e6a3SKirk McKusick tbperdb = sblock->fs_bsize >> tp_bshift;
6241c85e6a3SKirk McKusick for (i = 0; i < blks; i += TP_NINDIR) {
6251c85e6a3SKirk McKusick if (i + TP_NINDIR > blks)
6261c85e6a3SKirk McKusick count = blks;
6271c85e6a3SKirk McKusick else
6281c85e6a3SKirk McKusick count = i + TP_NINDIR;
6292d518c65SWarner Losh assert(count <= TP_NINDIR + i);
6301c85e6a3SKirk McKusick for (j = i; j < count; j++)
6311c85e6a3SKirk McKusick if (blkp[j / tbperdb] != 0)
6321c85e6a3SKirk McKusick spcl.c_addr[j - i] = 1;
6331c85e6a3SKirk McKusick else
6341c85e6a3SKirk McKusick spcl.c_addr[j - i] = 0;
6351c85e6a3SKirk McKusick spcl.c_count = count - i;
6361c85e6a3SKirk McKusick writeheader(ino);
6371c85e6a3SKirk McKusick bp = &blkp[i / tbperdb];
6381c85e6a3SKirk McKusick for (j = i; j < count; j += tbperdb, bp++)
6391c85e6a3SKirk McKusick if (*bp != 0) {
6401c85e6a3SKirk McKusick if (j + tbperdb <= count)
6411c85e6a3SKirk McKusick dumpblock(*bp, (int)sblock->fs_bsize);
6421c85e6a3SKirk McKusick else
6431c85e6a3SKirk McKusick dumpblock(*bp, (count - j) * TP_BSIZE);
6441c85e6a3SKirk McKusick }
6451c85e6a3SKirk McKusick spcl.c_type = TS_ADDR;
6461c85e6a3SKirk McKusick }
6471c85e6a3SKirk McKusick }
6481c85e6a3SKirk McKusick
6491c85e6a3SKirk McKusick /*
6501c85e6a3SKirk McKusick * Collect up the data into tape record sized buffers and output them.
6511c85e6a3SKirk McKusick */
652772ad651SKirk McKusick static void
ufs2_blksout(union dinode * dp,ufs2_daddr_t * blkp,int frags,ino_t ino,int last)653772ad651SKirk McKusick ufs2_blksout(union dinode *dp, ufs2_daddr_t *blkp, int frags, ino_t ino,
654772ad651SKirk McKusick int last)
6551c85e6a3SKirk McKusick {
6561c85e6a3SKirk McKusick ufs2_daddr_t *bp;
657772ad651SKirk McKusick int i, j, count, resid, blks, tbperdb, added;
658772ad651SKirk McKusick static int writingextdata = 0;
6598fae3551SRodney W. Grimes
660772ad651SKirk McKusick /*
661772ad651SKirk McKusick * Calculate the number of TP_BSIZE blocks to be dumped.
662772ad651SKirk McKusick * For filesystems with a fragment size bigger than TP_BSIZE,
663772ad651SKirk McKusick * only part of the final fragment may need to be dumped.
664772ad651SKirk McKusick */
6658fae3551SRodney W. Grimes blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
666772ad651SKirk McKusick if (last) {
667adbc0311SHiroki Sato if (writingextdata)
668adbc0311SHiroki Sato resid = howmany(fragoff(sblock, spcl.c_extsize),
669adbc0311SHiroki Sato TP_BSIZE);
670adbc0311SHiroki Sato else
671adbc0311SHiroki Sato resid = howmany(fragoff(sblock, dp->dp2.di_size),
672adbc0311SHiroki Sato TP_BSIZE);
673772ad651SKirk McKusick if (resid > 0)
674772ad651SKirk McKusick blks -= howmany(sblock->fs_fsize, TP_BSIZE) - resid;
675772ad651SKirk McKusick }
6768fae3551SRodney W. Grimes tbperdb = sblock->fs_bsize >> tp_bshift;
6778fae3551SRodney W. Grimes for (i = 0; i < blks; i += TP_NINDIR) {
6788fae3551SRodney W. Grimes if (i + TP_NINDIR > blks)
6798fae3551SRodney W. Grimes count = blks;
6808fae3551SRodney W. Grimes else
6818fae3551SRodney W. Grimes count = i + TP_NINDIR;
6822d518c65SWarner Losh assert(count <= TP_NINDIR + i);
6838fae3551SRodney W. Grimes for (j = i; j < count; j++)
6848fae3551SRodney W. Grimes if (blkp[j / tbperdb] != 0)
6858fae3551SRodney W. Grimes spcl.c_addr[j - i] = 1;
6868fae3551SRodney W. Grimes else
6878fae3551SRodney W. Grimes spcl.c_addr[j - i] = 0;
6888fae3551SRodney W. Grimes spcl.c_count = count - i;
6893ec81826SKirk McKusick if (last && count == blks && !writingextdata)
690772ad651SKirk McKusick added = appendextdata(dp);
6918fae3551SRodney W. Grimes writeheader(ino);
6928fae3551SRodney W. Grimes bp = &blkp[i / tbperdb];
6938fae3551SRodney W. Grimes for (j = i; j < count; j += tbperdb, bp++)
69416c4e408SBill Fumerola if (*bp != 0) {
6958fae3551SRodney W. Grimes if (j + tbperdb <= count)
6968fae3551SRodney W. Grimes dumpblock(*bp, (int)sblock->fs_bsize);
6978fae3551SRodney W. Grimes else
6988fae3551SRodney W. Grimes dumpblock(*bp, (count - j) * TP_BSIZE);
69916c4e408SBill Fumerola }
7008fae3551SRodney W. Grimes spcl.c_type = TS_ADDR;
701772ad651SKirk McKusick spcl.c_count = 0;
7023ec81826SKirk McKusick if (last && count == blks && !writingextdata) {
703772ad651SKirk McKusick writingextdata = 1;
704772ad651SKirk McKusick writeextdata(dp, ino, added);
705772ad651SKirk McKusick writingextdata = 0;
7068fae3551SRodney W. Grimes }
7078fae3551SRodney W. Grimes }
708772ad651SKirk McKusick }
709772ad651SKirk McKusick
710772ad651SKirk McKusick /*
711772ad651SKirk McKusick * If there is room in the current block for the extended attributes
712772ad651SKirk McKusick * as well as the file data, update the header to reflect the added
713772ad651SKirk McKusick * attribute data at the end. Attributes are placed at the end so that
714772ad651SKirk McKusick * old versions of restore will correctly restore the file and simply
715772ad651SKirk McKusick * discard the extra data at the end that it does not understand.
716772ad651SKirk McKusick * The attribute data is dumped following the file data by the
717772ad651SKirk McKusick * writeextdata() function (below).
718772ad651SKirk McKusick */
719772ad651SKirk McKusick static int
appendextdata(union dinode * dp)720772ad651SKirk McKusick appendextdata(union dinode *dp)
721772ad651SKirk McKusick {
722772ad651SKirk McKusick int i, blks, tbperdb;
723772ad651SKirk McKusick
724772ad651SKirk McKusick /*
725772ad651SKirk McKusick * If no extended attributes, there is nothing to do.
726772ad651SKirk McKusick */
727772ad651SKirk McKusick if (spcl.c_extsize == 0)
728772ad651SKirk McKusick return (0);
729772ad651SKirk McKusick /*
730772ad651SKirk McKusick * If there is not enough room at the end of this block
731772ad651SKirk McKusick * to add the extended attributes, then rather than putting
732772ad651SKirk McKusick * part of them here, we simply push them entirely into a
733772ad651SKirk McKusick * new block rather than putting some here and some later.
734772ad651SKirk McKusick */
7351dc349abSEd Maste if (spcl.c_extsize > UFS_NXADDR * sblock->fs_bsize)
7361dc349abSEd Maste blks = howmany(UFS_NXADDR * sblock->fs_bsize, TP_BSIZE);
737772ad651SKirk McKusick else
738772ad651SKirk McKusick blks = howmany(spcl.c_extsize, TP_BSIZE);
739772ad651SKirk McKusick if (spcl.c_count + blks > TP_NINDIR)
740772ad651SKirk McKusick return (0);
741772ad651SKirk McKusick /*
742772ad651SKirk McKusick * Update the block map in the header to indicate the added
743772ad651SKirk McKusick * extended attribute. They will be appended after the file
744772ad651SKirk McKusick * data by the writeextdata() routine.
745772ad651SKirk McKusick */
746772ad651SKirk McKusick tbperdb = sblock->fs_bsize >> tp_bshift;
747efe145a7SKirk McKusick assert(spcl.c_count + blks <= TP_NINDIR);
748772ad651SKirk McKusick for (i = 0; i < blks; i++)
749772ad651SKirk McKusick if (&dp->dp2.di_extb[i / tbperdb] != 0)
750772ad651SKirk McKusick spcl.c_addr[spcl.c_count + i] = 1;
751772ad651SKirk McKusick else
752772ad651SKirk McKusick spcl.c_addr[spcl.c_count + i] = 0;
753772ad651SKirk McKusick spcl.c_count += blks;
754772ad651SKirk McKusick return (blks);
755772ad651SKirk McKusick }
756772ad651SKirk McKusick
757772ad651SKirk McKusick /*
758772ad651SKirk McKusick * Dump the extended attribute data. If there was room in the file
759772ad651SKirk McKusick * header, then all we need to do is output the data blocks. If there
760772ad651SKirk McKusick * was not room in the file header, then an additional TS_ADDR header
761772ad651SKirk McKusick * is created to hold the attribute data.
762772ad651SKirk McKusick */
763772ad651SKirk McKusick static void
writeextdata(union dinode * dp,ino_t ino,int added)764772ad651SKirk McKusick writeextdata(union dinode *dp, ino_t ino, int added)
765772ad651SKirk McKusick {
766772ad651SKirk McKusick int i, frags, blks, tbperdb, last;
767772ad651SKirk McKusick ufs2_daddr_t *bp;
768772ad651SKirk McKusick off_t size;
769772ad651SKirk McKusick
770772ad651SKirk McKusick /*
771772ad651SKirk McKusick * If no extended attributes, there is nothing to do.
772772ad651SKirk McKusick */
773772ad651SKirk McKusick if (spcl.c_extsize == 0)
774772ad651SKirk McKusick return;
775772ad651SKirk McKusick /*
776772ad651SKirk McKusick * If there was no room in the file block for the attributes,
777772ad651SKirk McKusick * dump them out in a new block, otherwise just dump the data.
778772ad651SKirk McKusick */
779772ad651SKirk McKusick if (added == 0) {
7801dc349abSEd Maste if (spcl.c_extsize > UFS_NXADDR * sblock->fs_bsize) {
7811dc349abSEd Maste frags = UFS_NXADDR * sblock->fs_frag;
782772ad651SKirk McKusick last = 0;
783772ad651SKirk McKusick } else {
784772ad651SKirk McKusick frags = howmany(spcl.c_extsize, sblock->fs_fsize);
785772ad651SKirk McKusick last = 1;
786772ad651SKirk McKusick }
787772ad651SKirk McKusick ufs2_blksout(dp, &dp->dp2.di_extb[0], frags, ino, last);
788772ad651SKirk McKusick } else {
7891dc349abSEd Maste if (spcl.c_extsize > UFS_NXADDR * sblock->fs_bsize)
7901dc349abSEd Maste blks = howmany(UFS_NXADDR * sblock->fs_bsize, TP_BSIZE);
791772ad651SKirk McKusick else
792772ad651SKirk McKusick blks = howmany(spcl.c_extsize, TP_BSIZE);
793772ad651SKirk McKusick tbperdb = sblock->fs_bsize >> tp_bshift;
794772ad651SKirk McKusick for (i = 0; i < blks; i += tbperdb) {
795772ad651SKirk McKusick bp = &dp->dp2.di_extb[i / tbperdb];
796772ad651SKirk McKusick if (*bp != 0) {
797772ad651SKirk McKusick if (i + tbperdb <= blks)
798772ad651SKirk McKusick dumpblock(*bp, (int)sblock->fs_bsize);
799772ad651SKirk McKusick else
800772ad651SKirk McKusick dumpblock(*bp, (blks - i) * TP_BSIZE);
801772ad651SKirk McKusick }
802772ad651SKirk McKusick }
803772ad651SKirk McKusick
804772ad651SKirk McKusick }
805772ad651SKirk McKusick /*
806772ad651SKirk McKusick * If an indirect block is added for extended attributes, then
807772ad651SKirk McKusick * di_exti below should be changed to the structure element
808772ad651SKirk McKusick * that references the extended attribute indirect block. This
809772ad651SKirk McKusick * definition is here only to make it compile without complaint.
810772ad651SKirk McKusick */
811772ad651SKirk McKusick #define di_exti di_spare[0]
812772ad651SKirk McKusick /*
813772ad651SKirk McKusick * If the extended attributes fall into an indirect block,
814772ad651SKirk McKusick * dump it as well.
815772ad651SKirk McKusick */
8161dc349abSEd Maste if ((size = spcl.c_extsize - UFS_NXADDR * sblock->fs_bsize) > 0)
817772ad651SKirk McKusick dmpindir(dp, ino, dp->dp2.di_exti, 0, &size);
818772ad651SKirk McKusick }
8198fae3551SRodney W. Grimes
8208fae3551SRodney W. Grimes /*
8218fae3551SRodney W. Grimes * Dump a map to the tape.
8228fae3551SRodney W. Grimes */
8238fae3551SRodney W. Grimes void
dumpmap(char * map,int type,ino_t ino)8242db673abSWarner Losh dumpmap(char *map, int type, ino_t ino)
8258fae3551SRodney W. Grimes {
826d2334e27SIan Dowse int i;
8278fae3551SRodney W. Grimes char *cp;
8288fae3551SRodney W. Grimes
8298fae3551SRodney W. Grimes spcl.c_type = type;
8308fae3551SRodney W. Grimes spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE);
8318fae3551SRodney W. Grimes writeheader(ino);
8328fae3551SRodney W. Grimes for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE)
8338fae3551SRodney W. Grimes writerec(cp, 0);
8348fae3551SRodney W. Grimes }
8358fae3551SRodney W. Grimes
8368fae3551SRodney W. Grimes /*
8378fae3551SRodney W. Grimes * Write a header record to the dump tape.
8388fae3551SRodney W. Grimes */
8398fae3551SRodney W. Grimes void
writeheader(ino_t ino)8402db673abSWarner Losh writeheader(ino_t ino)
8418fae3551SRodney W. Grimes {
842d2334e27SIan Dowse int32_t sum, cnt, *lp;
8438fae3551SRodney W. Grimes
844693c40a3SKirk McKusick if (rsync_friendly >= 2) {
845693c40a3SKirk McKusick /* don't track changes to access time */
846693c40a3SKirk McKusick spcl.c_atime = spcl.c_mtime;
847693c40a3SKirk McKusick spcl.c_atimensec = spcl.c_mtimensec;
848693c40a3SKirk McKusick }
8498fae3551SRodney W. Grimes spcl.c_inumber = ino;
8501c85e6a3SKirk McKusick spcl.c_magic = FS_UFS2_MAGIC;
8518fae3551SRodney W. Grimes spcl.c_checksum = 0;
85297b465b1SDima Ruban lp = (int32_t *)&spcl;
8538fae3551SRodney W. Grimes sum = 0;
85497b465b1SDima Ruban cnt = sizeof(union u_spcl) / (4 * sizeof(int32_t));
8558fae3551SRodney W. Grimes while (--cnt >= 0) {
8568fae3551SRodney W. Grimes sum += *lp++;
8578fae3551SRodney W. Grimes sum += *lp++;
8588fae3551SRodney W. Grimes sum += *lp++;
8598fae3551SRodney W. Grimes sum += *lp++;
8608fae3551SRodney W. Grimes }
8618fae3551SRodney W. Grimes spcl.c_checksum = CHECKSUM - sum;
8628fae3551SRodney W. Grimes writerec((char *)&spcl, 1);
8638fae3551SRodney W. Grimes }
8648fae3551SRodney W. Grimes
8651c85e6a3SKirk McKusick union dinode *
getino(ino_t inum,int * modep)86607436eebSKirk McKusick getino(ino_t inum, int *modep)
8678fae3551SRodney W. Grimes {
8681c85e6a3SKirk McKusick static ino_t minino, maxino;
8691c85e6a3SKirk McKusick static caddr_t inoblock;
8701c85e6a3SKirk McKusick struct ufs1_dinode *dp1;
8711c85e6a3SKirk McKusick struct ufs2_dinode *dp2;
8728fae3551SRodney W. Grimes
8731c85e6a3SKirk McKusick if (inoblock == NULL && (inoblock = malloc(sblock->fs_bsize)) == NULL)
8741c85e6a3SKirk McKusick quit("cannot allocate inode memory.\n");
8758fae3551SRodney W. Grimes curino = inum;
8768fae3551SRodney W. Grimes if (inum >= minino && inum < maxino)
8771c85e6a3SKirk McKusick goto gotit;
878a770ae06SKirk McKusick blkread(fsbtodb(sblock, ino_to_fsba(sblock, inum)), inoblock,
8798fae3551SRodney W. Grimes (int)sblock->fs_bsize);
8808fae3551SRodney W. Grimes minino = inum - (inum % INOPB(sblock));
8818fae3551SRodney W. Grimes maxino = minino + INOPB(sblock);
8821c85e6a3SKirk McKusick gotit:
8831c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC) {
8841c85e6a3SKirk McKusick dp1 = &((struct ufs1_dinode *)inoblock)[inum - minino];
885d8ba45e2SEd Maste *modep = (dp1->di_mode & IFMT);
8861c85e6a3SKirk McKusick return ((union dinode *)dp1);
8871c85e6a3SKirk McKusick }
8881c85e6a3SKirk McKusick dp2 = &((struct ufs2_dinode *)inoblock)[inum - minino];
889d8ba45e2SEd Maste *modep = (dp2->di_mode & IFMT);
8901c85e6a3SKirk McKusick return ((union dinode *)dp2);
8918fae3551SRodney W. Grimes }
8928fae3551SRodney W. Grimes
8938fae3551SRodney W. Grimes /*
8948fae3551SRodney W. Grimes * Read a chunk of data from the disk.
8958fae3551SRodney W. Grimes * Try to recover from hard errors by reading in sector sized pieces.
8968fae3551SRodney W. Grimes * Error recovery is attempted at most BREADEMAX times before seeking
8978fae3551SRodney W. Grimes * consent from the operator to continue.
8988fae3551SRodney W. Grimes */
8998fae3551SRodney W. Grimes int breaderrors = 0;
9008fae3551SRodney W. Grimes #define BREADEMAX 32
9018fae3551SRodney W. Grimes
9028fae3551SRodney W. Grimes void
blkread(ufs2_daddr_t blkno,char * buf,int size)903a770ae06SKirk McKusick blkread(ufs2_daddr_t blkno, char *buf, int size)
9048fae3551SRodney W. Grimes {
905924a7003SKirk McKusick int secsize, bytes, resid, xfer, base, cnt, i;
906924a7003SKirk McKusick static char *tmpbuf;
907924a7003SKirk McKusick off_t offset;
9088fae3551SRodney W. Grimes
9098fae3551SRodney W. Grimes loop:
910924a7003SKirk McKusick offset = blkno << dev_bshift;
911924a7003SKirk McKusick secsize = sblock->fs_fsize;
912924a7003SKirk McKusick base = offset % secsize;
913924a7003SKirk McKusick resid = size % secsize;
914924a7003SKirk McKusick /*
915924a7003SKirk McKusick * If the transfer request starts or ends on a non-sector
916924a7003SKirk McKusick * boundary, we must read the entire sector and copy out
917924a7003SKirk McKusick * just the part that we need.
918924a7003SKirk McKusick */
919924a7003SKirk McKusick if (base == 0 && resid == 0) {
920924a7003SKirk McKusick cnt = cread(diskfd, buf, size, offset);
9215941e412SMatthew Dillon if (cnt == size)
9228fae3551SRodney W. Grimes return;
923924a7003SKirk McKusick } else {
9240b410d9cSMarcelo Araujo if (tmpbuf == NULL && (tmpbuf = malloc(secsize)) == NULL)
925924a7003SKirk McKusick quit("buffer malloc failed\n");
926924a7003SKirk McKusick xfer = 0;
927924a7003SKirk McKusick bytes = size;
928924a7003SKirk McKusick if (base != 0) {
929924a7003SKirk McKusick cnt = cread(diskfd, tmpbuf, secsize, offset - base);
930924a7003SKirk McKusick if (cnt != secsize)
931924a7003SKirk McKusick goto bad;
932993425eeSThomas Quinot xfer = MIN(secsize - base, size);
933924a7003SKirk McKusick offset += xfer;
934924a7003SKirk McKusick bytes -= xfer;
935924a7003SKirk McKusick resid = bytes % secsize;
936924a7003SKirk McKusick memcpy(buf, &tmpbuf[base], xfer);
937924a7003SKirk McKusick }
938924a7003SKirk McKusick if (bytes >= secsize) {
939924a7003SKirk McKusick cnt = cread(diskfd, &buf[xfer], bytes - resid, offset);
940924a7003SKirk McKusick if (cnt != bytes - resid)
941924a7003SKirk McKusick goto bad;
942924a7003SKirk McKusick xfer += cnt;
943924a7003SKirk McKusick offset += cnt;
944924a7003SKirk McKusick }
945924a7003SKirk McKusick if (resid == 0)
946924a7003SKirk McKusick return;
947924a7003SKirk McKusick cnt = cread(diskfd, tmpbuf, secsize, offset);
948924a7003SKirk McKusick if (cnt == secsize) {
949924a7003SKirk McKusick memcpy(&buf[xfer], tmpbuf, resid);
950924a7003SKirk McKusick return;
951924a7003SKirk McKusick }
952924a7003SKirk McKusick }
953924a7003SKirk McKusick bad:
9548fae3551SRodney W. Grimes if (blkno + (size / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) {
9558fae3551SRodney W. Grimes /*
9568fae3551SRodney W. Grimes * Trying to read the final fragment.
9578fae3551SRodney W. Grimes *
9588fae3551SRodney W. Grimes * NB - dump only works in TP_BSIZE blocks, hence
9598fae3551SRodney W. Grimes * rounds `dev_bsize' fragments up to TP_BSIZE pieces.
9608fae3551SRodney W. Grimes * It should be smarter about not actually trying to
9618fae3551SRodney W. Grimes * read more than it can get, but for the time being
9628fae3551SRodney W. Grimes * we punt and scale back the read only when it gets
9638fae3551SRodney W. Grimes * us into trouble. (mkm 9/25/83)
9648fae3551SRodney W. Grimes */
9658fae3551SRodney W. Grimes size -= dev_bsize;
9668fae3551SRodney W. Grimes goto loop;
9678fae3551SRodney W. Grimes }
9688fae3551SRodney W. Grimes if (cnt == -1)
969617dbd3cSIan Dowse msg("read error from %s: %s: [block %jd]: count=%d\n",
970617dbd3cSIan Dowse disk, strerror(errno), (intmax_t)blkno, size);
9718fae3551SRodney W. Grimes else
972617dbd3cSIan Dowse msg("short read error from %s: [block %jd]: count=%d, got=%d\n",
973617dbd3cSIan Dowse disk, (intmax_t)blkno, size, cnt);
9748fae3551SRodney W. Grimes if (++breaderrors > BREADEMAX) {
975325167c3SIan Dowse msg("More than %d block read errors from %s\n",
9768fae3551SRodney W. Grimes BREADEMAX, disk);
9778fae3551SRodney W. Grimes broadcast("DUMP IS AILING!\n");
9788fae3551SRodney W. Grimes msg("This is an unrecoverable error.\n");
9798fae3551SRodney W. Grimes if (!query("Do you want to attempt to continue?")){
9808fae3551SRodney W. Grimes dumpabort(0);
9818fae3551SRodney W. Grimes /*NOTREACHED*/
9828fae3551SRodney W. Grimes } else
9838fae3551SRodney W. Grimes breaderrors = 0;
9848fae3551SRodney W. Grimes }
9858fae3551SRodney W. Grimes /*
9865941e412SMatthew Dillon * Zero buffer, then try to read each sector of buffer separately,
9875941e412SMatthew Dillon * and bypass the cache.
9888fae3551SRodney W. Grimes */
989a37c38b8SPeter Wemm memset(buf, 0, size);
9908fae3551SRodney W. Grimes for (i = 0; i < size; i += dev_bsize, buf += dev_bsize, blkno++) {
991be1bf707SMike Heffner if ((cnt = pread(diskfd, buf, (int)dev_bsize,
992be1bf707SMike Heffner ((off_t)blkno << dev_bshift))) == dev_bsize)
9938fae3551SRodney W. Grimes continue;
9948fae3551SRodney W. Grimes if (cnt == -1) {
995617dbd3cSIan Dowse msg("read error from %s: %s: [sector %jd]: count=%ld\n",
996617dbd3cSIan Dowse disk, strerror(errno), (intmax_t)blkno, dev_bsize);
9978fae3551SRodney W. Grimes continue;
9988fae3551SRodney W. Grimes }
999617dbd3cSIan Dowse msg("short read from %s: [sector %jd]: count=%ld, got=%d\n",
1000617dbd3cSIan Dowse disk, (intmax_t)blkno, dev_bsize, cnt);
10018fae3551SRodney W. Grimes }
10028fae3551SRodney W. Grimes }
1003