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 #define DIP(dp, field) \ 551c85e6a3SKirk McKusick ((sblock->fs_magic == FS_UFS1_MAGIC) ? \ 561c85e6a3SKirk McKusick (dp)->dp1.field : (dp)->dp2.field) 578518a74aSAlexander Kabaev #define DIP_SET(dp, field, val) do {\ 588518a74aSAlexander Kabaev if (sblock->fs_magic == FS_UFS1_MAGIC) \ 598518a74aSAlexander Kabaev (dp)->dp1.field = (val); \ 608518a74aSAlexander Kabaev else \ 618518a74aSAlexander Kabaev (dp)->dp2.field = (val); \ 628518a74aSAlexander Kabaev } while (0) 631c85e6a3SKirk McKusick 648fae3551SRodney W. Grimes #define HASDUMPEDFILE 0x1 658fae3551SRodney W. Grimes #define HASSUBDIRS 0x2 668fae3551SRodney W. Grimes 671c85e6a3SKirk McKusick static int dirindir(ino_t ino, ufs2_daddr_t blkno, int level, long *size, 680b39291eSDavid Malone long *tapesize, int nodump, ino_t maxino); 69772ad651SKirk McKusick static void dmpindir(union dinode *dp, ino_t ino, ufs2_daddr_t blk, int level, 70772ad651SKirk McKusick off_t *size); 71772ad651SKirk McKusick static void ufs1_blksout(ufs1_daddr_t *blkp, int frags, ino_t ino); 72772ad651SKirk McKusick static void ufs2_blksout(union dinode *dp, ufs2_daddr_t *blkp, int frags, 73772ad651SKirk McKusick ino_t ino, int last); 74772ad651SKirk McKusick static int appendextdata(union dinode *dp); 75772ad651SKirk McKusick static void writeextdata(union dinode *dp, ino_t ino, int added); 761c85e6a3SKirk McKusick static int searchdir(ino_t ino, ufs2_daddr_t blkno, long size, long filesize, 770b39291eSDavid Malone long *tapesize, int nodump, ino_t maxino); 786bfd0bdcSKirk McKusick static long blockest(union dinode *dp); 798fae3551SRodney W. Grimes 808fae3551SRodney W. Grimes /* 818fae3551SRodney W. Grimes * This is an estimation of the number of TP_BSIZE blocks in the file. 828fae3551SRodney W. Grimes * It estimates the number of blocks in files with holes by assuming 838fae3551SRodney W. Grimes * that all of the blocks accounted for by di_blocks are data blocks 848fae3551SRodney W. Grimes * (when some of the blocks are usually used for indirect pointers); 858fae3551SRodney W. Grimes * hence the estimate may be high. 868fae3551SRodney W. Grimes */ 876bfd0bdcSKirk McKusick static long 881c85e6a3SKirk McKusick blockest(union dinode *dp) 898fae3551SRodney W. Grimes { 908fae3551SRodney W. Grimes long blkest, sizeest; 918fae3551SRodney W. Grimes 928fae3551SRodney W. Grimes /* 938fae3551SRodney W. Grimes * dp->di_size is the size of the file in bytes. 948fae3551SRodney W. Grimes * dp->di_blocks stores the number of sectors actually in the file. 958fae3551SRodney W. Grimes * If there are more sectors than the size would indicate, this just 968fae3551SRodney W. Grimes * means that there are indirect blocks in the file or unused 978fae3551SRodney W. Grimes * sectors in the last file block; we can safely ignore these 988fae3551SRodney W. Grimes * (blkest = sizeest below). 998fae3551SRodney W. Grimes * If the file is bigger than the number of sectors would indicate, 1008fae3551SRodney W. Grimes * then the file has holes in it. In this case we must use the 1018fae3551SRodney W. Grimes * block count to estimate the number of data blocks used, but 1028fae3551SRodney W. Grimes * we use the actual size for estimating the number of indirect 1038fae3551SRodney W. Grimes * dump blocks (sizeest vs. blkest in the indirect block 1048fae3551SRodney W. Grimes * calculation). 1058fae3551SRodney W. Grimes */ 1066bfd0bdcSKirk McKusick if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0) 1076bfd0bdcSKirk McKusick return (1); 1081c85e6a3SKirk McKusick blkest = howmany(dbtob(DIP(dp, di_blocks)), TP_BSIZE); 1091c85e6a3SKirk McKusick sizeest = howmany(DIP(dp, di_size), TP_BSIZE); 1108fae3551SRodney W. Grimes if (blkest > sizeest) 1118fae3551SRodney W. Grimes blkest = sizeest; 1121dc349abSEd Maste if (DIP(dp, di_size) > sblock->fs_bsize * UFS_NDADDR) { 1138fae3551SRodney W. Grimes /* calculate the number of indirect blocks on the dump tape */ 1141dc349abSEd Maste blkest += howmany(sizeest - 1151dc349abSEd Maste UFS_NDADDR * sblock->fs_bsize / TP_BSIZE, TP_NINDIR); 1168fae3551SRodney W. Grimes } 1178fae3551SRodney W. Grimes return (blkest + 1); 1188fae3551SRodney W. Grimes } 1198fae3551SRodney W. Grimes 1208fae3551SRodney W. Grimes /* Auxiliary macro to pick up files changed since previous dump. */ 1218fae3551SRodney W. Grimes #define CHANGEDSINCE(dp, t) \ 1221c85e6a3SKirk McKusick (DIP(dp, di_mtime) >= (t) || DIP(dp, di_ctime) >= (t)) 1238fae3551SRodney W. Grimes 1248fae3551SRodney W. Grimes /* The WANTTODUMP macro decides whether a file should be dumped. */ 1258fae3551SRodney W. Grimes #ifdef UF_NODUMP 1268fae3551SRodney W. Grimes #define WANTTODUMP(dp) \ 1278fae3551SRodney W. Grimes (CHANGEDSINCE(dp, spcl.c_ddate) && \ 1281c85e6a3SKirk McKusick (nonodump || (DIP(dp, di_flags) & UF_NODUMP) != UF_NODUMP)) 1298fae3551SRodney W. Grimes #else 1308fae3551SRodney W. Grimes #define WANTTODUMP(dp) CHANGEDSINCE(dp, spcl.c_ddate) 1318fae3551SRodney W. Grimes #endif 1328fae3551SRodney W. Grimes 1338fae3551SRodney W. Grimes /* 1348fae3551SRodney W. Grimes * Dump pass 1. 1358fae3551SRodney W. Grimes * 1368fae3551SRodney W. Grimes * Walk the inode list for a file system to find all allocated inodes 1378fae3551SRodney W. Grimes * that have been modified since the previous dump time. Also, find all 1388fae3551SRodney W. Grimes * the directories in the file system. 1398fae3551SRodney W. Grimes */ 1408fae3551SRodney W. Grimes int 1412db673abSWarner Losh mapfiles(ino_t maxino, long *tapesize) 1428fae3551SRodney W. Grimes { 14369becf4aSKirk McKusick int i, cg, mode, inosused; 1448fae3551SRodney W. Grimes int anydirskipped = 0; 14569becf4aSKirk McKusick union dinode *dp; 14669becf4aSKirk McKusick struct cg *cgp; 14769becf4aSKirk McKusick ino_t ino; 1480c40596cSXin LI u_char *cp; 1498fae3551SRodney W. Grimes 15069becf4aSKirk McKusick if ((cgp = malloc(sblock->fs_cgsize)) == NULL) 15169becf4aSKirk McKusick quit("mapfiles: cannot allocate memory.\n"); 15269becf4aSKirk McKusick for (cg = 0; cg < sblock->fs_ncg; cg++) { 15369becf4aSKirk McKusick ino = cg * sblock->fs_ipg; 154a770ae06SKirk McKusick blkread(fsbtodb(sblock, cgtod(sblock, cg)), (char *)cgp, 15569becf4aSKirk McKusick sblock->fs_cgsize); 15669becf4aSKirk McKusick if (sblock->fs_magic == FS_UFS2_MAGIC) 15769becf4aSKirk McKusick inosused = cgp->cg_initediblk; 15869becf4aSKirk McKusick else 15969becf4aSKirk McKusick inosused = sblock->fs_ipg; 16069becf4aSKirk McKusick /* 16169becf4aSKirk McKusick * If we are using soft updates, then we can trust the 16269becf4aSKirk McKusick * cylinder group inode allocation maps to tell us which 16369becf4aSKirk McKusick * inodes are allocated. We will scan the used inode map 16469becf4aSKirk McKusick * to find the inodes that are really in use, and then 16569becf4aSKirk McKusick * read only those inodes in from disk. 16669becf4aSKirk McKusick */ 16769becf4aSKirk McKusick if (sblock->fs_flags & FS_DOSOFTDEP) { 16869becf4aSKirk McKusick if (!cg_chkmagic(cgp)) 16969becf4aSKirk McKusick quit("mapfiles: cg %d: bad magic number\n", cg); 17069becf4aSKirk McKusick cp = &cg_inosused(cgp)[(inosused - 1) / CHAR_BIT]; 17169becf4aSKirk McKusick for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) { 17269becf4aSKirk McKusick if (*cp == 0) 17369becf4aSKirk McKusick continue; 17469becf4aSKirk McKusick for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) { 17569becf4aSKirk McKusick if (*cp & i) 17669becf4aSKirk McKusick break; 17769becf4aSKirk McKusick inosused--; 17869becf4aSKirk McKusick } 17969becf4aSKirk McKusick break; 18069becf4aSKirk McKusick } 18169becf4aSKirk McKusick if (inosused <= 0) 18269becf4aSKirk McKusick continue; 18369becf4aSKirk McKusick } 18469becf4aSKirk McKusick for (i = 0; i < inosused; i++, ino++) { 1851dc349abSEd Maste if (ino < UFS_ROOTINO || 18607436eebSKirk McKusick (dp = getino(ino, &mode)) == NULL || 187d8ba45e2SEd Maste (mode & IFMT) == 0) 1888fae3551SRodney W. Grimes continue; 1890b39291eSDavid Malone if (ino >= maxino) { 190e25a029eSMatthew D Fleming msg("Skipping inode %ju >= maxino %ju\n", 191e25a029eSMatthew D Fleming (uintmax_t)ino, (uintmax_t)maxino); 1920b39291eSDavid Malone continue; 1930b39291eSDavid Malone } 194801382faSDavid E. O'Brien /* 1952c8094f3SJordan K. Hubbard * Everything must go in usedinomap so that a check 1962c8094f3SJordan K. Hubbard * for "in dumpdirmap but not in usedinomap" to detect 1972c8094f3SJordan K. Hubbard * dirs with nodump set has a chance of succeeding 1982c8094f3SJordan K. Hubbard * (this is used in mapdirs()). 199801382faSDavid E. O'Brien */ 2002c8094f3SJordan K. Hubbard SETINO(ino, usedinomap); 201d8ba45e2SEd Maste if (mode == IFDIR) 2028fae3551SRodney W. Grimes SETINO(ino, dumpdirmap); 2038fae3551SRodney W. Grimes if (WANTTODUMP(dp)) { 2048fae3551SRodney W. Grimes SETINO(ino, dumpinomap); 205d8ba45e2SEd Maste if (mode != IFREG && 206d8ba45e2SEd Maste mode != IFDIR && 207d8ba45e2SEd Maste mode != IFLNK) 2088fae3551SRodney W. Grimes *tapesize += 1; 2098fae3551SRodney W. Grimes else 2108fae3551SRodney W. Grimes *tapesize += blockest(dp); 2118fae3551SRodney W. Grimes continue; 2128fae3551SRodney W. Grimes } 213d8ba45e2SEd Maste if (mode == IFDIR) { 21469becf4aSKirk McKusick if (!nonodump && 21569becf4aSKirk McKusick (DIP(dp, di_flags) & UF_NODUMP)) 2162c8094f3SJordan K. Hubbard CLRINO(ino, usedinomap); 2178fae3551SRodney W. Grimes anydirskipped = 1; 2188fae3551SRodney W. Grimes } 2192c8094f3SJordan K. Hubbard } 22069becf4aSKirk McKusick } 2218fae3551SRodney W. Grimes /* 2228fae3551SRodney W. Grimes * Restore gets very upset if the root is not dumped, 2238fae3551SRodney W. Grimes * so ensure that it always is dumped. 2248fae3551SRodney W. Grimes */ 2251dc349abSEd Maste SETINO(UFS_ROOTINO, dumpinomap); 2268fae3551SRodney W. Grimes return (anydirskipped); 2278fae3551SRodney W. Grimes } 2288fae3551SRodney W. Grimes 2298fae3551SRodney W. Grimes /* 2308fae3551SRodney W. Grimes * Dump pass 2. 2318fae3551SRodney W. Grimes * 2328fae3551SRodney W. Grimes * Scan each directory on the file system to see if it has any modified 2338fae3551SRodney W. Grimes * files in it. If it does, and has not already been added to the dump 2348fae3551SRodney W. Grimes * list (because it was itself modified), then add it. If a directory 2358fae3551SRodney W. Grimes * has not been modified itself, contains no modified files and has no 2368fae3551SRodney W. Grimes * subdirectories, then it can be deleted from the dump list and from 2378fae3551SRodney W. Grimes * the list of directories. By deleting it from the list of directories, 2388fae3551SRodney W. Grimes * its parent may now qualify for the same treatment on this or a later 2398fae3551SRodney W. Grimes * pass using this algorithm. 2408fae3551SRodney W. Grimes */ 2418fae3551SRodney W. Grimes int 2422db673abSWarner Losh mapdirs(ino_t maxino, long *tapesize) 2438fae3551SRodney W. Grimes { 2441c85e6a3SKirk McKusick union dinode *dp; 245d2334e27SIan Dowse int i, isdir, nodump; 246d2334e27SIan Dowse char *map; 247d2334e27SIan Dowse ino_t ino; 2481c85e6a3SKirk McKusick union dinode di; 2498fae3551SRodney W. Grimes long filesize; 2508fae3551SRodney W. Grimes int ret, change = 0; 2518fae3551SRodney W. Grimes 2528fae3551SRodney W. Grimes isdir = 0; /* XXX just to get gcc to shut up */ 2538fae3551SRodney W. Grimes for (map = dumpdirmap, ino = 1; ino < maxino; ino++) { 25489fdc4e1SMike Barcroft if (((ino - 1) % CHAR_BIT) == 0) /* map is offset by 1 */ 2558fae3551SRodney W. Grimes isdir = *map++; 2568fae3551SRodney W. Grimes else 2578fae3551SRodney W. Grimes isdir >>= 1; 258801382faSDavid E. O'Brien /* 259801382faSDavid E. O'Brien * If a directory has been removed from usedinomap, it 260801382faSDavid E. O'Brien * either has the nodump flag set, or has inherited 261801382faSDavid E. O'Brien * it. Although a directory can't be in dumpinomap if 262801382faSDavid E. O'Brien * it isn't in usedinomap, we have to go through it to 263801382faSDavid E. O'Brien * propagate the nodump flag. 264801382faSDavid E. O'Brien */ 2652c8094f3SJordan K. Hubbard nodump = !nonodump && (TSTINO(ino, usedinomap) == 0); 266801382faSDavid E. O'Brien if ((isdir & 1) == 0 || (TSTINO(ino, dumpinomap) && !nodump)) 2678fae3551SRodney W. Grimes continue; 26807436eebSKirk McKusick dp = getino(ino, &i); 2691c85e6a3SKirk McKusick /* 2701c85e6a3SKirk McKusick * inode buf may change in searchdir(). 2711c85e6a3SKirk McKusick */ 2721c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC) 2731c85e6a3SKirk McKusick di.dp1 = dp->dp1; 2741c85e6a3SKirk McKusick else 2751c85e6a3SKirk McKusick di.dp2 = dp->dp2; 2761c85e6a3SKirk McKusick filesize = DIP(&di, di_size); 2771dc349abSEd Maste for (ret = 0, i = 0; filesize > 0 && i < UFS_NDADDR; i++) { 2781c85e6a3SKirk McKusick if (DIP(&di, di_db[i]) != 0) 2791c85e6a3SKirk McKusick ret |= searchdir(ino, DIP(&di, di_db[i]), 280155ea063SIan Dowse (long)sblksize(sblock, DIP(&di, di_size), 2810b39291eSDavid Malone i), filesize, tapesize, nodump, maxino); 2828fae3551SRodney W. Grimes if (ret & HASDUMPEDFILE) 2838fae3551SRodney W. Grimes filesize = 0; 2848fae3551SRodney W. Grimes else 2858fae3551SRodney W. Grimes filesize -= sblock->fs_bsize; 2868fae3551SRodney W. Grimes } 2871dc349abSEd Maste for (i = 0; filesize > 0 && i < UFS_NIADDR; i++) { 2881c85e6a3SKirk McKusick if (DIP(&di, di_ib[i]) == 0) 2898fae3551SRodney W. Grimes continue; 2901c85e6a3SKirk McKusick ret |= dirindir(ino, DIP(&di, di_ib[i]), i, &filesize, 2910b39291eSDavid Malone tapesize, nodump, maxino); 2928fae3551SRodney W. Grimes } 2938fae3551SRodney W. Grimes if (ret & HASDUMPEDFILE) { 2948fae3551SRodney W. Grimes SETINO(ino, dumpinomap); 295155ea063SIan Dowse *tapesize += blockest(&di); 2968fae3551SRodney W. Grimes change = 1; 2978fae3551SRodney W. Grimes continue; 2988fae3551SRodney W. Grimes } 299801382faSDavid E. O'Brien if (nodump) { 300801382faSDavid E. O'Brien if (ret & HASSUBDIRS) 301801382faSDavid E. O'Brien change = 1; /* subdirs inherit nodump */ 302801382faSDavid E. O'Brien CLRINO(ino, dumpdirmap); 303801382faSDavid E. O'Brien } else if ((ret & HASSUBDIRS) == 0) 3048fae3551SRodney W. Grimes if (!TSTINO(ino, dumpinomap)) { 3058fae3551SRodney W. Grimes CLRINO(ino, dumpdirmap); 3068fae3551SRodney W. Grimes change = 1; 3078fae3551SRodney W. Grimes } 3088fae3551SRodney W. Grimes } 3098fae3551SRodney W. Grimes return (change); 3108fae3551SRodney W. Grimes } 3118fae3551SRodney W. Grimes 3128fae3551SRodney W. Grimes /* 3138fae3551SRodney W. Grimes * Read indirect blocks, and pass the data blocks to be searched 3148fae3551SRodney W. Grimes * as directories. Quit as soon as any entry is found that will 3158fae3551SRodney W. Grimes * require the directory to be dumped. 3168fae3551SRodney W. Grimes */ 3178fae3551SRodney W. Grimes static int 3181c85e6a3SKirk McKusick dirindir( 3191c85e6a3SKirk McKusick ino_t ino, 3201c85e6a3SKirk McKusick ufs2_daddr_t blkno, 3211c85e6a3SKirk McKusick int ind_level, 3221c85e6a3SKirk McKusick long *filesize, 3231c85e6a3SKirk McKusick long *tapesize, 3240b39291eSDavid Malone int nodump, 3250b39291eSDavid Malone ino_t maxino) 3268fae3551SRodney W. Grimes { 3277680e41cSIan Dowse union { 3287680e41cSIan Dowse ufs1_daddr_t ufs1[MAXBSIZE / sizeof(ufs1_daddr_t)]; 3297680e41cSIan Dowse ufs2_daddr_t ufs2[MAXBSIZE / sizeof(ufs2_daddr_t)]; 3307680e41cSIan Dowse } idblk; 3318fae3551SRodney W. Grimes int ret = 0; 332d2334e27SIan Dowse int i; 3338fae3551SRodney W. Grimes 334a770ae06SKirk McKusick blkread(fsbtodb(sblock, blkno), (char *)&idblk, (int)sblock->fs_bsize); 3358fae3551SRodney W. Grimes if (ind_level <= 0) { 3368fae3551SRodney W. Grimes for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) { 3371c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC) 3387680e41cSIan Dowse blkno = idblk.ufs1[i]; 3391c85e6a3SKirk McKusick else 3407680e41cSIan Dowse blkno = idblk.ufs2[i]; 3418fae3551SRodney W. Grimes if (blkno != 0) 3428fae3551SRodney W. Grimes ret |= searchdir(ino, blkno, sblock->fs_bsize, 3430b39291eSDavid Malone *filesize, tapesize, nodump, maxino); 3448fae3551SRodney W. Grimes if (ret & HASDUMPEDFILE) 3458fae3551SRodney W. Grimes *filesize = 0; 3468fae3551SRodney W. Grimes else 3478fae3551SRodney W. Grimes *filesize -= sblock->fs_bsize; 3488fae3551SRodney W. Grimes } 3498fae3551SRodney W. Grimes return (ret); 3508fae3551SRodney W. Grimes } 3518fae3551SRodney W. Grimes ind_level--; 3528fae3551SRodney W. Grimes for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) { 3531c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC) 3547680e41cSIan Dowse blkno = idblk.ufs1[i]; 3551c85e6a3SKirk McKusick else 3567680e41cSIan Dowse blkno = idblk.ufs2[i]; 3578fae3551SRodney W. Grimes if (blkno != 0) 358801382faSDavid E. O'Brien ret |= dirindir(ino, blkno, ind_level, filesize, 3590b39291eSDavid Malone tapesize, nodump, maxino); 3608fae3551SRodney W. Grimes } 3618fae3551SRodney W. Grimes return (ret); 3628fae3551SRodney W. Grimes } 3638fae3551SRodney W. Grimes 3648fae3551SRodney W. Grimes /* 3658fae3551SRodney W. Grimes * Scan a disk block containing directory information looking to see if 3668fae3551SRodney W. Grimes * any of the entries are on the dump list and to see if the directory 3678fae3551SRodney W. Grimes * contains any subdirectories. 3688fae3551SRodney W. Grimes */ 3698fae3551SRodney W. Grimes static int 3701c85e6a3SKirk McKusick searchdir( 3711c85e6a3SKirk McKusick ino_t ino, 3721c85e6a3SKirk McKusick ufs2_daddr_t blkno, 3731c85e6a3SKirk McKusick long size, 3741c85e6a3SKirk McKusick long filesize, 3751c85e6a3SKirk McKusick long *tapesize, 3760b39291eSDavid Malone int nodump, 3770b39291eSDavid Malone ino_t maxino) 3788fae3551SRodney W. Grimes { 3791c85e6a3SKirk McKusick int mode; 380d2334e27SIan Dowse struct direct *dp; 3811c85e6a3SKirk McKusick union dinode *ip; 382d2334e27SIan Dowse long loc, ret = 0; 3831c85e6a3SKirk McKusick static caddr_t dblk; 3848fae3551SRodney W. Grimes 3851c85e6a3SKirk McKusick if (dblk == NULL && (dblk = malloc(sblock->fs_bsize)) == NULL) 3861c85e6a3SKirk McKusick quit("searchdir: cannot allocate indirect memory.\n"); 387a770ae06SKirk McKusick blkread(fsbtodb(sblock, blkno), dblk, (int)size); 3888fae3551SRodney W. Grimes if (filesize < size) 3898fae3551SRodney W. Grimes size = filesize; 3908fae3551SRodney W. Grimes for (loc = 0; loc < size; ) { 3918fae3551SRodney W. Grimes dp = (struct direct *)(dblk + loc); 3928fae3551SRodney W. Grimes if (dp->d_reclen == 0) { 393e25a029eSMatthew D Fleming msg("corrupted directory, inumber %ju\n", 394e25a029eSMatthew D Fleming (uintmax_t)ino); 3958fae3551SRodney W. Grimes break; 3968fae3551SRodney W. Grimes } 3978fae3551SRodney W. Grimes loc += dp->d_reclen; 3988fae3551SRodney W. Grimes if (dp->d_ino == 0) 3998fae3551SRodney W. Grimes continue; 4000b39291eSDavid Malone if (dp->d_ino >= maxino) { 401e25a029eSMatthew D Fleming msg("corrupted directory entry, d_ino %ju >= %ju\n", 402e25a029eSMatthew D Fleming (uintmax_t)dp->d_ino, (uintmax_t)maxino); 4030b39291eSDavid Malone break; 4040b39291eSDavid Malone } 4058fae3551SRodney W. Grimes if (dp->d_name[0] == '.') { 4068fae3551SRodney W. Grimes if (dp->d_name[1] == '\0') 4078fae3551SRodney W. Grimes continue; 4088fae3551SRodney W. Grimes if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') 4098fae3551SRodney W. Grimes continue; 4108fae3551SRodney W. Grimes } 411801382faSDavid E. O'Brien if (nodump) { 41207436eebSKirk McKusick ip = getino(dp->d_ino, &mode); 413801382faSDavid E. O'Brien if (TSTINO(dp->d_ino, dumpinomap)) { 414801382faSDavid E. O'Brien CLRINO(dp->d_ino, dumpinomap); 415801382faSDavid E. O'Brien *tapesize -= blockest(ip); 416801382faSDavid E. O'Brien } 41701629855SDavid E. O'Brien /* 41801629855SDavid E. O'Brien * Add back to dumpdirmap and remove from usedinomap 41901629855SDavid E. O'Brien * to propagate nodump. 42001629855SDavid E. O'Brien */ 421d8ba45e2SEd Maste if (mode == IFDIR) { 422801382faSDavid E. O'Brien SETINO(dp->d_ino, dumpdirmap); 42301629855SDavid E. O'Brien CLRINO(dp->d_ino, usedinomap); 424801382faSDavid E. O'Brien ret |= HASSUBDIRS; 425801382faSDavid E. O'Brien } 426801382faSDavid E. O'Brien } else { 4278fae3551SRodney W. Grimes if (TSTINO(dp->d_ino, dumpinomap)) { 4288fae3551SRodney W. Grimes ret |= HASDUMPEDFILE; 4298fae3551SRodney W. Grimes if (ret & HASSUBDIRS) 4308fae3551SRodney W. Grimes break; 4318fae3551SRodney W. Grimes } 4328fae3551SRodney W. Grimes if (TSTINO(dp->d_ino, dumpdirmap)) { 4338fae3551SRodney W. Grimes ret |= HASSUBDIRS; 4348fae3551SRodney W. Grimes if (ret & HASDUMPEDFILE) 4358fae3551SRodney W. Grimes break; 4368fae3551SRodney W. Grimes } 4378fae3551SRodney W. Grimes } 438801382faSDavid E. O'Brien } 4398fae3551SRodney W. Grimes return (ret); 4408fae3551SRodney W. Grimes } 4418fae3551SRodney W. Grimes 4428fae3551SRodney W. Grimes /* 4438fae3551SRodney W. Grimes * Dump passes 3 and 4. 4448fae3551SRodney W. Grimes * 4458fae3551SRodney W. Grimes * Dump the contents of an inode to tape. 4468fae3551SRodney W. Grimes */ 4478fae3551SRodney W. Grimes void 4481c85e6a3SKirk McKusick dumpino(union dinode *dp, ino_t ino) 4498fae3551SRodney W. Grimes { 450772ad651SKirk McKusick int ind_level, cnt, last, added; 4511c85e6a3SKirk McKusick off_t size; 4528fae3551SRodney W. Grimes char buf[TP_BSIZE]; 4538fae3551SRodney W. Grimes 4548fae3551SRodney W. Grimes if (newtape) { 4558fae3551SRodney W. Grimes newtape = 0; 4568fae3551SRodney W. Grimes dumpmap(dumpinomap, TS_BITS, ino); 4578fae3551SRodney W. Grimes } 4588fae3551SRodney W. Grimes CLRINO(ino, dumpinomap); 459be5b1425SKirk McKusick /* 460be5b1425SKirk McKusick * Zero out the size of a snapshot so that it will be dumped 461be5b1425SKirk McKusick * as a zero length file. 462be5b1425SKirk McKusick */ 463be5b1425SKirk McKusick if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0) { 4648518a74aSAlexander Kabaev DIP_SET(dp, di_size, 0); 4658518a74aSAlexander Kabaev DIP_SET(dp, di_flags, DIP(dp, di_flags) & ~SF_SNAPSHOT); 466be5b1425SKirk McKusick } 4671c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC) { 4681c85e6a3SKirk McKusick spcl.c_mode = dp->dp1.di_mode; 4691c85e6a3SKirk McKusick spcl.c_size = dp->dp1.di_size; 470772ad651SKirk McKusick spcl.c_extsize = 0; 4711c85e6a3SKirk McKusick spcl.c_atime = _time32_to_time(dp->dp1.di_atime); 4721c85e6a3SKirk McKusick spcl.c_atimensec = dp->dp1.di_atimensec; 4731c85e6a3SKirk McKusick spcl.c_mtime = _time32_to_time(dp->dp1.di_mtime); 4741c85e6a3SKirk McKusick spcl.c_mtimensec = dp->dp1.di_mtimensec; 475fb36a3d8SKirk McKusick spcl.c_birthtime = 0; 476fb36a3d8SKirk McKusick spcl.c_birthtimensec = 0; 4771c85e6a3SKirk McKusick spcl.c_rdev = dp->dp1.di_rdev; 4781c85e6a3SKirk McKusick spcl.c_file_flags = dp->dp1.di_flags; 4791c85e6a3SKirk McKusick spcl.c_uid = dp->dp1.di_uid; 4801c85e6a3SKirk McKusick spcl.c_gid = dp->dp1.di_gid; 4811c85e6a3SKirk McKusick } else { 4821c85e6a3SKirk McKusick spcl.c_mode = dp->dp2.di_mode; 4831c85e6a3SKirk McKusick spcl.c_size = dp->dp2.di_size; 484772ad651SKirk McKusick spcl.c_extsize = dp->dp2.di_extsize; 4851c85e6a3SKirk McKusick spcl.c_atime = _time64_to_time(dp->dp2.di_atime); 4861c85e6a3SKirk McKusick spcl.c_atimensec = dp->dp2.di_atimensec; 4871c85e6a3SKirk McKusick spcl.c_mtime = _time64_to_time(dp->dp2.di_mtime); 4881c85e6a3SKirk McKusick spcl.c_mtimensec = dp->dp2.di_mtimensec; 489fb36a3d8SKirk McKusick spcl.c_birthtime = _time64_to_time(dp->dp2.di_birthtime); 490fb36a3d8SKirk McKusick spcl.c_birthtimensec = dp->dp2.di_birthnsec; 4911c85e6a3SKirk McKusick spcl.c_rdev = dp->dp2.di_rdev; 4921c85e6a3SKirk McKusick spcl.c_file_flags = dp->dp2.di_flags; 4931c85e6a3SKirk McKusick spcl.c_uid = dp->dp2.di_uid; 4941c85e6a3SKirk McKusick spcl.c_gid = dp->dp2.di_gid; 4951c85e6a3SKirk McKusick } 4968fae3551SRodney W. Grimes spcl.c_type = TS_INODE; 4978fae3551SRodney W. Grimes spcl.c_count = 0; 4981c85e6a3SKirk McKusick switch (DIP(dp, di_mode) & S_IFMT) { 4998fae3551SRodney W. Grimes 5008fae3551SRodney W. Grimes case 0: 5018fae3551SRodney W. Grimes /* 5028fae3551SRodney W. Grimes * Freed inode. 5038fae3551SRodney W. Grimes */ 5048fae3551SRodney W. Grimes return; 5058fae3551SRodney W. Grimes 5068fae3551SRodney W. Grimes case S_IFLNK: 5078fae3551SRodney W. Grimes /* 5088fae3551SRodney W. Grimes * Check for short symbolic link. 5098fae3551SRodney W. Grimes */ 5101c85e6a3SKirk McKusick if (DIP(dp, di_size) > 0 && 5111c85e6a3SKirk McKusick DIP(dp, di_size) < sblock->fs_maxsymlinklen) { 5128fae3551SRodney W. Grimes spcl.c_addr[0] = 1; 5138fae3551SRodney W. Grimes spcl.c_count = 1; 514772ad651SKirk McKusick added = appendextdata(dp); 5158fae3551SRodney W. Grimes writeheader(ino); 516*5b13fa79SJessica Clarke memmove(buf, DIP(dp, di_shortlink), 5171c85e6a3SKirk McKusick (u_long)DIP(dp, di_size)); 5181c85e6a3SKirk McKusick buf[DIP(dp, di_size)] = '\0'; 5198fae3551SRodney W. Grimes writerec(buf, 0); 520772ad651SKirk McKusick writeextdata(dp, ino, added); 5218fae3551SRodney W. Grimes return; 5228fae3551SRodney W. Grimes } 5237fed38d0SPhilippe Charnier /* FALLTHROUGH */ 5248fae3551SRodney W. Grimes 5258fae3551SRodney W. Grimes case S_IFDIR: 5268fae3551SRodney W. Grimes case S_IFREG: 5271c85e6a3SKirk McKusick if (DIP(dp, di_size) > 0) 5288fae3551SRodney W. Grimes break; 5297fed38d0SPhilippe Charnier /* FALLTHROUGH */ 5308fae3551SRodney W. Grimes 5318fae3551SRodney W. Grimes case S_IFIFO: 5328fae3551SRodney W. Grimes case S_IFSOCK: 5338fae3551SRodney W. Grimes case S_IFCHR: 5348fae3551SRodney W. Grimes case S_IFBLK: 535772ad651SKirk McKusick added = appendextdata(dp); 5368fae3551SRodney W. Grimes writeheader(ino); 537772ad651SKirk McKusick writeextdata(dp, ino, added); 5388fae3551SRodney W. Grimes return; 5398fae3551SRodney W. Grimes 5408fae3551SRodney W. Grimes default: 5411c85e6a3SKirk McKusick msg("Warning: undefined file type 0%o\n", 542d8ba45e2SEd Maste DIP(dp, di_mode) & IFMT); 5438fae3551SRodney W. Grimes return; 5448fae3551SRodney W. Grimes } 5451dc349abSEd Maste if (DIP(dp, di_size) > UFS_NDADDR * sblock->fs_bsize) { 5461dc349abSEd Maste cnt = UFS_NDADDR * sblock->fs_frag; 547772ad651SKirk McKusick last = 0; 548772ad651SKirk McKusick } else { 5491c85e6a3SKirk McKusick cnt = howmany(DIP(dp, di_size), sblock->fs_fsize); 550772ad651SKirk McKusick last = 1; 551772ad651SKirk McKusick } 5521c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC) 5531c85e6a3SKirk McKusick ufs1_blksout(&dp->dp1.di_db[0], cnt, ino); 5541c85e6a3SKirk McKusick else 555772ad651SKirk McKusick ufs2_blksout(dp, &dp->dp2.di_db[0], cnt, ino, last); 5561dc349abSEd Maste if ((size = DIP(dp, di_size) - UFS_NDADDR * sblock->fs_bsize) <= 0) 5578fae3551SRodney W. Grimes return; 5581dc349abSEd Maste for (ind_level = 0; ind_level < UFS_NIADDR; ind_level++) { 559772ad651SKirk McKusick dmpindir(dp, ino, DIP(dp, di_ib[ind_level]), ind_level, &size); 5608fae3551SRodney W. Grimes if (size <= 0) 5618fae3551SRodney W. Grimes return; 5628fae3551SRodney W. Grimes } 5638fae3551SRodney W. Grimes } 5648fae3551SRodney W. Grimes 5658fae3551SRodney W. Grimes /* 5668fae3551SRodney W. Grimes * Read indirect blocks, and pass the data blocks to be dumped. 5678fae3551SRodney W. Grimes */ 5688fae3551SRodney W. Grimes static void 569772ad651SKirk McKusick dmpindir(union dinode *dp, ino_t ino, ufs2_daddr_t blk, int ind_level, 570772ad651SKirk McKusick off_t *size) 5718fae3551SRodney W. Grimes { 5727680e41cSIan Dowse union { 5737680e41cSIan Dowse ufs1_daddr_t ufs1[MAXBSIZE / sizeof(ufs1_daddr_t)]; 5747680e41cSIan Dowse ufs2_daddr_t ufs2[MAXBSIZE / sizeof(ufs2_daddr_t)]; 5757680e41cSIan Dowse } idblk; 576772ad651SKirk McKusick int i, cnt, last; 5778fae3551SRodney W. Grimes 5788fae3551SRodney W. Grimes if (blk != 0) 579a770ae06SKirk McKusick blkread(fsbtodb(sblock, blk), (char *)&idblk, 5807680e41cSIan Dowse (int)sblock->fs_bsize); 5818fae3551SRodney W. Grimes else 5827680e41cSIan Dowse memset(&idblk, 0, sblock->fs_bsize); 5838fae3551SRodney W. Grimes if (ind_level <= 0) { 584772ad651SKirk McKusick if (*size > NINDIR(sblock) * sblock->fs_bsize) { 5858fae3551SRodney W. Grimes cnt = NINDIR(sblock) * sblock->fs_frag; 586772ad651SKirk McKusick last = 0; 587772ad651SKirk McKusick } else { 588772ad651SKirk McKusick cnt = howmany(*size, sblock->fs_fsize); 589772ad651SKirk McKusick last = 1; 590772ad651SKirk McKusick } 5918fae3551SRodney W. Grimes *size -= NINDIR(sblock) * sblock->fs_bsize; 5921c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC) 5937680e41cSIan Dowse ufs1_blksout(idblk.ufs1, cnt, ino); 5941c85e6a3SKirk McKusick else 595772ad651SKirk McKusick ufs2_blksout(dp, idblk.ufs2, cnt, ino, last); 5968fae3551SRodney W. Grimes return; 5978fae3551SRodney W. Grimes } 5988fae3551SRodney W. Grimes ind_level--; 5998fae3551SRodney W. Grimes for (i = 0; i < NINDIR(sblock); i++) { 6001c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC) 601772ad651SKirk McKusick dmpindir(dp, ino, idblk.ufs1[i], ind_level, size); 6021c85e6a3SKirk McKusick else 603772ad651SKirk McKusick dmpindir(dp, ino, idblk.ufs2[i], ind_level, size); 6048fae3551SRodney W. Grimes if (*size <= 0) 6058fae3551SRodney W. Grimes return; 6068fae3551SRodney W. Grimes } 6078fae3551SRodney W. Grimes } 6088fae3551SRodney W. Grimes 6098fae3551SRodney W. Grimes /* 6108fae3551SRodney W. Grimes * Collect up the data into tape record sized buffers and output them. 6118fae3551SRodney W. Grimes */ 612772ad651SKirk McKusick static void 6131c85e6a3SKirk McKusick ufs1_blksout(ufs1_daddr_t *blkp, int frags, ino_t ino) 6148fae3551SRodney W. Grimes { 6151c85e6a3SKirk McKusick ufs1_daddr_t *bp; 6161c85e6a3SKirk McKusick int i, j, count, blks, tbperdb; 6171c85e6a3SKirk McKusick 6181c85e6a3SKirk McKusick blks = howmany(frags * sblock->fs_fsize, TP_BSIZE); 6191c85e6a3SKirk McKusick tbperdb = sblock->fs_bsize >> tp_bshift; 6201c85e6a3SKirk McKusick for (i = 0; i < blks; i += TP_NINDIR) { 6211c85e6a3SKirk McKusick if (i + TP_NINDIR > blks) 6221c85e6a3SKirk McKusick count = blks; 6231c85e6a3SKirk McKusick else 6241c85e6a3SKirk McKusick count = i + TP_NINDIR; 6252d518c65SWarner Losh assert(count <= TP_NINDIR + i); 6261c85e6a3SKirk McKusick for (j = i; j < count; j++) 6271c85e6a3SKirk McKusick if (blkp[j / tbperdb] != 0) 6281c85e6a3SKirk McKusick spcl.c_addr[j - i] = 1; 6291c85e6a3SKirk McKusick else 6301c85e6a3SKirk McKusick spcl.c_addr[j - i] = 0; 6311c85e6a3SKirk McKusick spcl.c_count = count - i; 6321c85e6a3SKirk McKusick writeheader(ino); 6331c85e6a3SKirk McKusick bp = &blkp[i / tbperdb]; 6341c85e6a3SKirk McKusick for (j = i; j < count; j += tbperdb, bp++) 6351c85e6a3SKirk McKusick if (*bp != 0) { 6361c85e6a3SKirk McKusick if (j + tbperdb <= count) 6371c85e6a3SKirk McKusick dumpblock(*bp, (int)sblock->fs_bsize); 6381c85e6a3SKirk McKusick else 6391c85e6a3SKirk McKusick dumpblock(*bp, (count - j) * TP_BSIZE); 6401c85e6a3SKirk McKusick } 6411c85e6a3SKirk McKusick spcl.c_type = TS_ADDR; 6421c85e6a3SKirk McKusick } 6431c85e6a3SKirk McKusick } 6441c85e6a3SKirk McKusick 6451c85e6a3SKirk McKusick /* 6461c85e6a3SKirk McKusick * Collect up the data into tape record sized buffers and output them. 6471c85e6a3SKirk McKusick */ 648772ad651SKirk McKusick static void 649772ad651SKirk McKusick ufs2_blksout(union dinode *dp, ufs2_daddr_t *blkp, int frags, ino_t ino, 650772ad651SKirk McKusick int last) 6511c85e6a3SKirk McKusick { 6521c85e6a3SKirk McKusick ufs2_daddr_t *bp; 653772ad651SKirk McKusick int i, j, count, resid, blks, tbperdb, added; 654772ad651SKirk McKusick static int writingextdata = 0; 6558fae3551SRodney W. Grimes 656772ad651SKirk McKusick /* 657772ad651SKirk McKusick * Calculate the number of TP_BSIZE blocks to be dumped. 658772ad651SKirk McKusick * For filesystems with a fragment size bigger than TP_BSIZE, 659772ad651SKirk McKusick * only part of the final fragment may need to be dumped. 660772ad651SKirk McKusick */ 6618fae3551SRodney W. Grimes blks = howmany(frags * sblock->fs_fsize, TP_BSIZE); 662772ad651SKirk McKusick if (last) { 663adbc0311SHiroki Sato if (writingextdata) 664adbc0311SHiroki Sato resid = howmany(fragoff(sblock, spcl.c_extsize), 665adbc0311SHiroki Sato TP_BSIZE); 666adbc0311SHiroki Sato else 667adbc0311SHiroki Sato resid = howmany(fragoff(sblock, dp->dp2.di_size), 668adbc0311SHiroki Sato TP_BSIZE); 669772ad651SKirk McKusick if (resid > 0) 670772ad651SKirk McKusick blks -= howmany(sblock->fs_fsize, TP_BSIZE) - resid; 671772ad651SKirk McKusick } 6728fae3551SRodney W. Grimes tbperdb = sblock->fs_bsize >> tp_bshift; 6738fae3551SRodney W. Grimes for (i = 0; i < blks; i += TP_NINDIR) { 6748fae3551SRodney W. Grimes if (i + TP_NINDIR > blks) 6758fae3551SRodney W. Grimes count = blks; 6768fae3551SRodney W. Grimes else 6778fae3551SRodney W. Grimes count = i + TP_NINDIR; 6782d518c65SWarner Losh assert(count <= TP_NINDIR + i); 6798fae3551SRodney W. Grimes for (j = i; j < count; j++) 6808fae3551SRodney W. Grimes if (blkp[j / tbperdb] != 0) 6818fae3551SRodney W. Grimes spcl.c_addr[j - i] = 1; 6828fae3551SRodney W. Grimes else 6838fae3551SRodney W. Grimes spcl.c_addr[j - i] = 0; 6848fae3551SRodney W. Grimes spcl.c_count = count - i; 6853ec81826SKirk McKusick if (last && count == blks && !writingextdata) 686772ad651SKirk McKusick added = appendextdata(dp); 6878fae3551SRodney W. Grimes writeheader(ino); 6888fae3551SRodney W. Grimes bp = &blkp[i / tbperdb]; 6898fae3551SRodney W. Grimes for (j = i; j < count; j += tbperdb, bp++) 69016c4e408SBill Fumerola if (*bp != 0) { 6918fae3551SRodney W. Grimes if (j + tbperdb <= count) 6928fae3551SRodney W. Grimes dumpblock(*bp, (int)sblock->fs_bsize); 6938fae3551SRodney W. Grimes else 6948fae3551SRodney W. Grimes dumpblock(*bp, (count - j) * TP_BSIZE); 69516c4e408SBill Fumerola } 6968fae3551SRodney W. Grimes spcl.c_type = TS_ADDR; 697772ad651SKirk McKusick spcl.c_count = 0; 6983ec81826SKirk McKusick if (last && count == blks && !writingextdata) { 699772ad651SKirk McKusick writingextdata = 1; 700772ad651SKirk McKusick writeextdata(dp, ino, added); 701772ad651SKirk McKusick writingextdata = 0; 7028fae3551SRodney W. Grimes } 7038fae3551SRodney W. Grimes } 704772ad651SKirk McKusick } 705772ad651SKirk McKusick 706772ad651SKirk McKusick /* 707772ad651SKirk McKusick * If there is room in the current block for the extended attributes 708772ad651SKirk McKusick * as well as the file data, update the header to reflect the added 709772ad651SKirk McKusick * attribute data at the end. Attributes are placed at the end so that 710772ad651SKirk McKusick * old versions of restore will correctly restore the file and simply 711772ad651SKirk McKusick * discard the extra data at the end that it does not understand. 712772ad651SKirk McKusick * The attribute data is dumped following the file data by the 713772ad651SKirk McKusick * writeextdata() function (below). 714772ad651SKirk McKusick */ 715772ad651SKirk McKusick static int 716772ad651SKirk McKusick appendextdata(union dinode *dp) 717772ad651SKirk McKusick { 718772ad651SKirk McKusick int i, blks, tbperdb; 719772ad651SKirk McKusick 720772ad651SKirk McKusick /* 721772ad651SKirk McKusick * If no extended attributes, there is nothing to do. 722772ad651SKirk McKusick */ 723772ad651SKirk McKusick if (spcl.c_extsize == 0) 724772ad651SKirk McKusick return (0); 725772ad651SKirk McKusick /* 726772ad651SKirk McKusick * If there is not enough room at the end of this block 727772ad651SKirk McKusick * to add the extended attributes, then rather than putting 728772ad651SKirk McKusick * part of them here, we simply push them entirely into a 729772ad651SKirk McKusick * new block rather than putting some here and some later. 730772ad651SKirk McKusick */ 7311dc349abSEd Maste if (spcl.c_extsize > UFS_NXADDR * sblock->fs_bsize) 7321dc349abSEd Maste blks = howmany(UFS_NXADDR * sblock->fs_bsize, TP_BSIZE); 733772ad651SKirk McKusick else 734772ad651SKirk McKusick blks = howmany(spcl.c_extsize, TP_BSIZE); 735772ad651SKirk McKusick if (spcl.c_count + blks > TP_NINDIR) 736772ad651SKirk McKusick return (0); 737772ad651SKirk McKusick /* 738772ad651SKirk McKusick * Update the block map in the header to indicate the added 739772ad651SKirk McKusick * extended attribute. They will be appended after the file 740772ad651SKirk McKusick * data by the writeextdata() routine. 741772ad651SKirk McKusick */ 742772ad651SKirk McKusick tbperdb = sblock->fs_bsize >> tp_bshift; 743efe145a7SKirk McKusick assert(spcl.c_count + blks <= TP_NINDIR); 744772ad651SKirk McKusick for (i = 0; i < blks; i++) 745772ad651SKirk McKusick if (&dp->dp2.di_extb[i / tbperdb] != 0) 746772ad651SKirk McKusick spcl.c_addr[spcl.c_count + i] = 1; 747772ad651SKirk McKusick else 748772ad651SKirk McKusick spcl.c_addr[spcl.c_count + i] = 0; 749772ad651SKirk McKusick spcl.c_count += blks; 750772ad651SKirk McKusick return (blks); 751772ad651SKirk McKusick } 752772ad651SKirk McKusick 753772ad651SKirk McKusick /* 754772ad651SKirk McKusick * Dump the extended attribute data. If there was room in the file 755772ad651SKirk McKusick * header, then all we need to do is output the data blocks. If there 756772ad651SKirk McKusick * was not room in the file header, then an additional TS_ADDR header 757772ad651SKirk McKusick * is created to hold the attribute data. 758772ad651SKirk McKusick */ 759772ad651SKirk McKusick static void 760772ad651SKirk McKusick writeextdata(union dinode *dp, ino_t ino, int added) 761772ad651SKirk McKusick { 762772ad651SKirk McKusick int i, frags, blks, tbperdb, last; 763772ad651SKirk McKusick ufs2_daddr_t *bp; 764772ad651SKirk McKusick off_t size; 765772ad651SKirk McKusick 766772ad651SKirk McKusick /* 767772ad651SKirk McKusick * If no extended attributes, there is nothing to do. 768772ad651SKirk McKusick */ 769772ad651SKirk McKusick if (spcl.c_extsize == 0) 770772ad651SKirk McKusick return; 771772ad651SKirk McKusick /* 772772ad651SKirk McKusick * If there was no room in the file block for the attributes, 773772ad651SKirk McKusick * dump them out in a new block, otherwise just dump the data. 774772ad651SKirk McKusick */ 775772ad651SKirk McKusick if (added == 0) { 7761dc349abSEd Maste if (spcl.c_extsize > UFS_NXADDR * sblock->fs_bsize) { 7771dc349abSEd Maste frags = UFS_NXADDR * sblock->fs_frag; 778772ad651SKirk McKusick last = 0; 779772ad651SKirk McKusick } else { 780772ad651SKirk McKusick frags = howmany(spcl.c_extsize, sblock->fs_fsize); 781772ad651SKirk McKusick last = 1; 782772ad651SKirk McKusick } 783772ad651SKirk McKusick ufs2_blksout(dp, &dp->dp2.di_extb[0], frags, ino, last); 784772ad651SKirk McKusick } else { 7851dc349abSEd Maste if (spcl.c_extsize > UFS_NXADDR * sblock->fs_bsize) 7861dc349abSEd Maste blks = howmany(UFS_NXADDR * sblock->fs_bsize, TP_BSIZE); 787772ad651SKirk McKusick else 788772ad651SKirk McKusick blks = howmany(spcl.c_extsize, TP_BSIZE); 789772ad651SKirk McKusick tbperdb = sblock->fs_bsize >> tp_bshift; 790772ad651SKirk McKusick for (i = 0; i < blks; i += tbperdb) { 791772ad651SKirk McKusick bp = &dp->dp2.di_extb[i / tbperdb]; 792772ad651SKirk McKusick if (*bp != 0) { 793772ad651SKirk McKusick if (i + tbperdb <= blks) 794772ad651SKirk McKusick dumpblock(*bp, (int)sblock->fs_bsize); 795772ad651SKirk McKusick else 796772ad651SKirk McKusick dumpblock(*bp, (blks - i) * TP_BSIZE); 797772ad651SKirk McKusick } 798772ad651SKirk McKusick } 799772ad651SKirk McKusick 800772ad651SKirk McKusick } 801772ad651SKirk McKusick /* 802772ad651SKirk McKusick * If an indirect block is added for extended attributes, then 803772ad651SKirk McKusick * di_exti below should be changed to the structure element 804772ad651SKirk McKusick * that references the extended attribute indirect block. This 805772ad651SKirk McKusick * definition is here only to make it compile without complaint. 806772ad651SKirk McKusick */ 807772ad651SKirk McKusick #define di_exti di_spare[0] 808772ad651SKirk McKusick /* 809772ad651SKirk McKusick * If the extended attributes fall into an indirect block, 810772ad651SKirk McKusick * dump it as well. 811772ad651SKirk McKusick */ 8121dc349abSEd Maste if ((size = spcl.c_extsize - UFS_NXADDR * sblock->fs_bsize) > 0) 813772ad651SKirk McKusick dmpindir(dp, ino, dp->dp2.di_exti, 0, &size); 814772ad651SKirk McKusick } 8158fae3551SRodney W. Grimes 8168fae3551SRodney W. Grimes /* 8178fae3551SRodney W. Grimes * Dump a map to the tape. 8188fae3551SRodney W. Grimes */ 8198fae3551SRodney W. Grimes void 8202db673abSWarner Losh dumpmap(char *map, int type, ino_t ino) 8218fae3551SRodney W. Grimes { 822d2334e27SIan Dowse int i; 8238fae3551SRodney W. Grimes char *cp; 8248fae3551SRodney W. Grimes 8258fae3551SRodney W. Grimes spcl.c_type = type; 8268fae3551SRodney W. Grimes spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE); 8278fae3551SRodney W. Grimes writeheader(ino); 8288fae3551SRodney W. Grimes for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE) 8298fae3551SRodney W. Grimes writerec(cp, 0); 8308fae3551SRodney W. Grimes } 8318fae3551SRodney W. Grimes 8328fae3551SRodney W. Grimes /* 8338fae3551SRodney W. Grimes * Write a header record to the dump tape. 8348fae3551SRodney W. Grimes */ 8358fae3551SRodney W. Grimes void 8362db673abSWarner Losh writeheader(ino_t ino) 8378fae3551SRodney W. Grimes { 838d2334e27SIan Dowse int32_t sum, cnt, *lp; 8398fae3551SRodney W. Grimes 840693c40a3SKirk McKusick if (rsync_friendly >= 2) { 841693c40a3SKirk McKusick /* don't track changes to access time */ 842693c40a3SKirk McKusick spcl.c_atime = spcl.c_mtime; 843693c40a3SKirk McKusick spcl.c_atimensec = spcl.c_mtimensec; 844693c40a3SKirk McKusick } 8458fae3551SRodney W. Grimes spcl.c_inumber = ino; 8461c85e6a3SKirk McKusick spcl.c_magic = FS_UFS2_MAGIC; 8478fae3551SRodney W. Grimes spcl.c_checksum = 0; 84897b465b1SDima Ruban lp = (int32_t *)&spcl; 8498fae3551SRodney W. Grimes sum = 0; 85097b465b1SDima Ruban cnt = sizeof(union u_spcl) / (4 * sizeof(int32_t)); 8518fae3551SRodney W. Grimes while (--cnt >= 0) { 8528fae3551SRodney W. Grimes sum += *lp++; 8538fae3551SRodney W. Grimes sum += *lp++; 8548fae3551SRodney W. Grimes sum += *lp++; 8558fae3551SRodney W. Grimes sum += *lp++; 8568fae3551SRodney W. Grimes } 8578fae3551SRodney W. Grimes spcl.c_checksum = CHECKSUM - sum; 8588fae3551SRodney W. Grimes writerec((char *)&spcl, 1); 8598fae3551SRodney W. Grimes } 8608fae3551SRodney W. Grimes 8611c85e6a3SKirk McKusick union dinode * 86207436eebSKirk McKusick getino(ino_t inum, int *modep) 8638fae3551SRodney W. Grimes { 8641c85e6a3SKirk McKusick static ino_t minino, maxino; 8651c85e6a3SKirk McKusick static caddr_t inoblock; 8661c85e6a3SKirk McKusick struct ufs1_dinode *dp1; 8671c85e6a3SKirk McKusick struct ufs2_dinode *dp2; 8688fae3551SRodney W. Grimes 8691c85e6a3SKirk McKusick if (inoblock == NULL && (inoblock = malloc(sblock->fs_bsize)) == NULL) 8701c85e6a3SKirk McKusick quit("cannot allocate inode memory.\n"); 8718fae3551SRodney W. Grimes curino = inum; 8728fae3551SRodney W. Grimes if (inum >= minino && inum < maxino) 8731c85e6a3SKirk McKusick goto gotit; 874a770ae06SKirk McKusick blkread(fsbtodb(sblock, ino_to_fsba(sblock, inum)), inoblock, 8758fae3551SRodney W. Grimes (int)sblock->fs_bsize); 8768fae3551SRodney W. Grimes minino = inum - (inum % INOPB(sblock)); 8778fae3551SRodney W. Grimes maxino = minino + INOPB(sblock); 8781c85e6a3SKirk McKusick gotit: 8791c85e6a3SKirk McKusick if (sblock->fs_magic == FS_UFS1_MAGIC) { 8801c85e6a3SKirk McKusick dp1 = &((struct ufs1_dinode *)inoblock)[inum - minino]; 881d8ba45e2SEd Maste *modep = (dp1->di_mode & IFMT); 8821c85e6a3SKirk McKusick return ((union dinode *)dp1); 8831c85e6a3SKirk McKusick } 8841c85e6a3SKirk McKusick dp2 = &((struct ufs2_dinode *)inoblock)[inum - minino]; 885d8ba45e2SEd Maste *modep = (dp2->di_mode & IFMT); 8861c85e6a3SKirk McKusick return ((union dinode *)dp2); 8878fae3551SRodney W. Grimes } 8888fae3551SRodney W. Grimes 8898fae3551SRodney W. Grimes /* 8908fae3551SRodney W. Grimes * Read a chunk of data from the disk. 8918fae3551SRodney W. Grimes * Try to recover from hard errors by reading in sector sized pieces. 8928fae3551SRodney W. Grimes * Error recovery is attempted at most BREADEMAX times before seeking 8938fae3551SRodney W. Grimes * consent from the operator to continue. 8948fae3551SRodney W. Grimes */ 8958fae3551SRodney W. Grimes int breaderrors = 0; 8968fae3551SRodney W. Grimes #define BREADEMAX 32 8978fae3551SRodney W. Grimes 8988fae3551SRodney W. Grimes void 899a770ae06SKirk McKusick blkread(ufs2_daddr_t blkno, char *buf, int size) 9008fae3551SRodney W. Grimes { 901924a7003SKirk McKusick int secsize, bytes, resid, xfer, base, cnt, i; 902924a7003SKirk McKusick static char *tmpbuf; 903924a7003SKirk McKusick off_t offset; 9048fae3551SRodney W. Grimes 9058fae3551SRodney W. Grimes loop: 906924a7003SKirk McKusick offset = blkno << dev_bshift; 907924a7003SKirk McKusick secsize = sblock->fs_fsize; 908924a7003SKirk McKusick base = offset % secsize; 909924a7003SKirk McKusick resid = size % secsize; 910924a7003SKirk McKusick /* 911924a7003SKirk McKusick * If the transfer request starts or ends on a non-sector 912924a7003SKirk McKusick * boundary, we must read the entire sector and copy out 913924a7003SKirk McKusick * just the part that we need. 914924a7003SKirk McKusick */ 915924a7003SKirk McKusick if (base == 0 && resid == 0) { 916924a7003SKirk McKusick cnt = cread(diskfd, buf, size, offset); 9175941e412SMatthew Dillon if (cnt == size) 9188fae3551SRodney W. Grimes return; 919924a7003SKirk McKusick } else { 9200b410d9cSMarcelo Araujo if (tmpbuf == NULL && (tmpbuf = malloc(secsize)) == NULL) 921924a7003SKirk McKusick quit("buffer malloc failed\n"); 922924a7003SKirk McKusick xfer = 0; 923924a7003SKirk McKusick bytes = size; 924924a7003SKirk McKusick if (base != 0) { 925924a7003SKirk McKusick cnt = cread(diskfd, tmpbuf, secsize, offset - base); 926924a7003SKirk McKusick if (cnt != secsize) 927924a7003SKirk McKusick goto bad; 928993425eeSThomas Quinot xfer = MIN(secsize - base, size); 929924a7003SKirk McKusick offset += xfer; 930924a7003SKirk McKusick bytes -= xfer; 931924a7003SKirk McKusick resid = bytes % secsize; 932924a7003SKirk McKusick memcpy(buf, &tmpbuf[base], xfer); 933924a7003SKirk McKusick } 934924a7003SKirk McKusick if (bytes >= secsize) { 935924a7003SKirk McKusick cnt = cread(diskfd, &buf[xfer], bytes - resid, offset); 936924a7003SKirk McKusick if (cnt != bytes - resid) 937924a7003SKirk McKusick goto bad; 938924a7003SKirk McKusick xfer += cnt; 939924a7003SKirk McKusick offset += cnt; 940924a7003SKirk McKusick } 941924a7003SKirk McKusick if (resid == 0) 942924a7003SKirk McKusick return; 943924a7003SKirk McKusick cnt = cread(diskfd, tmpbuf, secsize, offset); 944924a7003SKirk McKusick if (cnt == secsize) { 945924a7003SKirk McKusick memcpy(&buf[xfer], tmpbuf, resid); 946924a7003SKirk McKusick return; 947924a7003SKirk McKusick } 948924a7003SKirk McKusick } 949924a7003SKirk McKusick bad: 9508fae3551SRodney W. Grimes if (blkno + (size / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) { 9518fae3551SRodney W. Grimes /* 9528fae3551SRodney W. Grimes * Trying to read the final fragment. 9538fae3551SRodney W. Grimes * 9548fae3551SRodney W. Grimes * NB - dump only works in TP_BSIZE blocks, hence 9558fae3551SRodney W. Grimes * rounds `dev_bsize' fragments up to TP_BSIZE pieces. 9568fae3551SRodney W. Grimes * It should be smarter about not actually trying to 9578fae3551SRodney W. Grimes * read more than it can get, but for the time being 9588fae3551SRodney W. Grimes * we punt and scale back the read only when it gets 9598fae3551SRodney W. Grimes * us into trouble. (mkm 9/25/83) 9608fae3551SRodney W. Grimes */ 9618fae3551SRodney W. Grimes size -= dev_bsize; 9628fae3551SRodney W. Grimes goto loop; 9638fae3551SRodney W. Grimes } 9648fae3551SRodney W. Grimes if (cnt == -1) 965617dbd3cSIan Dowse msg("read error from %s: %s: [block %jd]: count=%d\n", 966617dbd3cSIan Dowse disk, strerror(errno), (intmax_t)blkno, size); 9678fae3551SRodney W. Grimes else 968617dbd3cSIan Dowse msg("short read error from %s: [block %jd]: count=%d, got=%d\n", 969617dbd3cSIan Dowse disk, (intmax_t)blkno, size, cnt); 9708fae3551SRodney W. Grimes if (++breaderrors > BREADEMAX) { 971325167c3SIan Dowse msg("More than %d block read errors from %s\n", 9728fae3551SRodney W. Grimes BREADEMAX, disk); 9738fae3551SRodney W. Grimes broadcast("DUMP IS AILING!\n"); 9748fae3551SRodney W. Grimes msg("This is an unrecoverable error.\n"); 9758fae3551SRodney W. Grimes if (!query("Do you want to attempt to continue?")){ 9768fae3551SRodney W. Grimes dumpabort(0); 9778fae3551SRodney W. Grimes /*NOTREACHED*/ 9788fae3551SRodney W. Grimes } else 9798fae3551SRodney W. Grimes breaderrors = 0; 9808fae3551SRodney W. Grimes } 9818fae3551SRodney W. Grimes /* 9825941e412SMatthew Dillon * Zero buffer, then try to read each sector of buffer separately, 9835941e412SMatthew Dillon * and bypass the cache. 9848fae3551SRodney W. Grimes */ 985a37c38b8SPeter Wemm memset(buf, 0, size); 9868fae3551SRodney W. Grimes for (i = 0; i < size; i += dev_bsize, buf += dev_bsize, blkno++) { 987be1bf707SMike Heffner if ((cnt = pread(diskfd, buf, (int)dev_bsize, 988be1bf707SMike Heffner ((off_t)blkno << dev_bshift))) == dev_bsize) 9898fae3551SRodney W. Grimes continue; 9908fae3551SRodney W. Grimes if (cnt == -1) { 991617dbd3cSIan Dowse msg("read error from %s: %s: [sector %jd]: count=%ld\n", 992617dbd3cSIan Dowse disk, strerror(errno), (intmax_t)blkno, dev_bsize); 9938fae3551SRodney W. Grimes continue; 9948fae3551SRodney W. Grimes } 995617dbd3cSIan Dowse msg("short read from %s: [sector %jd]: count=%ld, got=%d\n", 996617dbd3cSIan Dowse disk, (intmax_t)blkno, dev_bsize, cnt); 9978fae3551SRodney W. Grimes } 9988fae3551SRodney W. Grimes } 999