11558Srgrimes/*- 21558Srgrimes * Copyright (c) 1980, 1988, 1991, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 301558Srgrimes#ifndef lint 3136997Scharnier#if 0 3223672Speterstatic char sccsid[] = "@(#)traverse.c 8.7 (Berkeley) 6/15/95"; 3336997Scharnier#endif 3436997Scharnierstatic const char rcsid[] = 3550476Speter "$FreeBSD$"; 361558Srgrimes#endif /* not lint */ 371558Srgrimes 381558Srgrimes#include <sys/param.h> 391558Srgrimes#include <sys/stat.h> 401558Srgrimes 411558Srgrimes#include <ufs/ufs/dir.h> 421558Srgrimes#include <ufs/ufs/dinode.h> 4323672Speter#include <ufs/ffs/fs.h> 441558Srgrimes 451558Srgrimes#include <protocols/dumprestore.h> 461558Srgrimes 471558Srgrimes#include <ctype.h> 4899562Siedowse#include <errno.h> 4999562Siedowse#include <inttypes.h> 50103949Smike#include <limits.h> 511558Srgrimes#include <stdio.h> 5299562Siedowse#include <stdlib.h> 531558Srgrimes#include <string.h> 5499562Siedowse#include <timeconv.h> 551558Srgrimes#include <unistd.h> 561558Srgrimes 571558Srgrimes#include "dump.h" 581558Srgrimes 5998542Smckusickunion dinode { 6098542Smckusick struct ufs1_dinode dp1; 6198542Smckusick struct ufs2_dinode dp2; 6298542Smckusick}; 6398542Smckusick#define DIP(dp, field) \ 6498542Smckusick ((sblock->fs_magic == FS_UFS1_MAGIC) ? \ 6598542Smckusick (dp)->dp1.field : (dp)->dp2.field) 66132762Skan#define DIP_SET(dp, field, val) do {\ 67132762Skan if (sblock->fs_magic == FS_UFS1_MAGIC) \ 68132762Skan (dp)->dp1.field = (val); \ 69132762Skan else \ 70132762Skan (dp)->dp2.field = (val); \ 71132762Skan } while (0) 7298542Smckusick 731558Srgrimes#define HASDUMPEDFILE 0x1 741558Srgrimes#define HASSUBDIRS 0x2 751558Srgrimes 7698542Smckusickstatic int dirindir(ino_t ino, ufs2_daddr_t blkno, int level, long *size, 77157660Sdwmalone long *tapesize, int nodump, ino_t maxino); 78167011Smckusickstatic void dmpindir(union dinode *dp, ino_t ino, ufs2_daddr_t blk, int level, 79167011Smckusick off_t *size); 80167011Smckusickstatic void ufs1_blksout(ufs1_daddr_t *blkp, int frags, ino_t ino); 81167011Smckusickstatic void ufs2_blksout(union dinode *dp, ufs2_daddr_t *blkp, int frags, 82167011Smckusick ino_t ino, int last); 83167011Smckusickstatic int appendextdata(union dinode *dp); 84167011Smckusickstatic void writeextdata(union dinode *dp, ino_t ino, int added); 8598542Smckusickstatic int searchdir(ino_t ino, ufs2_daddr_t blkno, long size, long filesize, 86157660Sdwmalone long *tapesize, int nodump, ino_t maxino); 87107542Smckusickstatic long blockest(union dinode *dp); 881558Srgrimes 891558Srgrimes/* 901558Srgrimes * This is an estimation of the number of TP_BSIZE blocks in the file. 911558Srgrimes * It estimates the number of blocks in files with holes by assuming 921558Srgrimes * that all of the blocks accounted for by di_blocks are data blocks 931558Srgrimes * (when some of the blocks are usually used for indirect pointers); 941558Srgrimes * hence the estimate may be high. 951558Srgrimes */ 96107542Smckusickstatic long 9798542Smckusickblockest(union dinode *dp) 981558Srgrimes{ 991558Srgrimes long blkest, sizeest; 1001558Srgrimes 1011558Srgrimes /* 1021558Srgrimes * dp->di_size is the size of the file in bytes. 1031558Srgrimes * dp->di_blocks stores the number of sectors actually in the file. 1041558Srgrimes * If there are more sectors than the size would indicate, this just 1051558Srgrimes * means that there are indirect blocks in the file or unused 1061558Srgrimes * sectors in the last file block; we can safely ignore these 1071558Srgrimes * (blkest = sizeest below). 1081558Srgrimes * If the file is bigger than the number of sectors would indicate, 1091558Srgrimes * then the file has holes in it. In this case we must use the 1101558Srgrimes * block count to estimate the number of data blocks used, but 1111558Srgrimes * we use the actual size for estimating the number of indirect 1121558Srgrimes * dump blocks (sizeest vs. blkest in the indirect block 1131558Srgrimes * calculation). 1141558Srgrimes */ 115107542Smckusick if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0) 116107542Smckusick return (1); 11798542Smckusick blkest = howmany(dbtob(DIP(dp, di_blocks)), TP_BSIZE); 11898542Smckusick sizeest = howmany(DIP(dp, di_size), TP_BSIZE); 1191558Srgrimes if (blkest > sizeest) 1201558Srgrimes blkest = sizeest; 12198542Smckusick if (DIP(dp, di_size) > sblock->fs_bsize * NDADDR) { 1221558Srgrimes /* calculate the number of indirect blocks on the dump tape */ 1231558Srgrimes blkest += 1241558Srgrimes howmany(sizeest - NDADDR * sblock->fs_bsize / TP_BSIZE, 1251558Srgrimes TP_NINDIR); 1261558Srgrimes } 1271558Srgrimes return (blkest + 1); 1281558Srgrimes} 1291558Srgrimes 1301558Srgrimes/* Auxiliary macro to pick up files changed since previous dump. */ 1311558Srgrimes#define CHANGEDSINCE(dp, t) \ 13298542Smckusick (DIP(dp, di_mtime) >= (t) || DIP(dp, di_ctime) >= (t)) 1331558Srgrimes 1341558Srgrimes/* The WANTTODUMP macro decides whether a file should be dumped. */ 1351558Srgrimes#ifdef UF_NODUMP 1361558Srgrimes#define WANTTODUMP(dp) \ 1371558Srgrimes (CHANGEDSINCE(dp, spcl.c_ddate) && \ 13898542Smckusick (nonodump || (DIP(dp, di_flags) & UF_NODUMP) != UF_NODUMP)) 1391558Srgrimes#else 1401558Srgrimes#define WANTTODUMP(dp) CHANGEDSINCE(dp, spcl.c_ddate) 1411558Srgrimes#endif 1421558Srgrimes 1431558Srgrimes/* 1441558Srgrimes * Dump pass 1. 1451558Srgrimes * 146102231Strhodes * Walk the inode list for a file system to find all allocated inodes 1471558Srgrimes * that have been modified since the previous dump time. Also, find all 148102231Strhodes * the directories in the file system. 1491558Srgrimes */ 1501558Srgrimesint 15192837Simpmapfiles(ino_t maxino, long *tapesize) 1521558Srgrimes{ 153107541Smckusick int i, cg, mode, inosused; 154107541Smckusick int anydirskipped = 0; 155107541Smckusick union dinode *dp; 156107541Smckusick struct cg *cgp; 15786473Siedowse ino_t ino; 158145794Sdelphij u_char *cp; 1591558Srgrimes 160107541Smckusick if ((cgp = malloc(sblock->fs_cgsize)) == NULL) 161107541Smckusick quit("mapfiles: cannot allocate memory.\n"); 162107541Smckusick for (cg = 0; cg < sblock->fs_ncg; cg++) { 163107541Smckusick ino = cg * sblock->fs_ipg; 164107541Smckusick bread(fsbtodb(sblock, cgtod(sblock, cg)), (char *)cgp, 165107541Smckusick sblock->fs_cgsize); 166107541Smckusick if (sblock->fs_magic == FS_UFS2_MAGIC) 167107541Smckusick inosused = cgp->cg_initediblk; 168107541Smckusick else 169107541Smckusick inosused = sblock->fs_ipg; 17073375Sobrien /* 171107541Smckusick * If we are using soft updates, then we can trust the 172107541Smckusick * cylinder group inode allocation maps to tell us which 173107541Smckusick * inodes are allocated. We will scan the used inode map 174107541Smckusick * to find the inodes that are really in use, and then 175107541Smckusick * read only those inodes in from disk. 17673375Sobrien */ 177107541Smckusick if (sblock->fs_flags & FS_DOSOFTDEP) { 178107541Smckusick if (!cg_chkmagic(cgp)) 179107541Smckusick quit("mapfiles: cg %d: bad magic number\n", cg); 180107541Smckusick cp = &cg_inosused(cgp)[(inosused - 1) / CHAR_BIT]; 181107541Smckusick for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) { 182107541Smckusick if (*cp == 0) 183107541Smckusick continue; 184107541Smckusick for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) { 185107541Smckusick if (*cp & i) 186107541Smckusick break; 187107541Smckusick inosused--; 188107541Smckusick } 189107541Smckusick break; 190107541Smckusick } 191107541Smckusick if (inosused <= 0) 192107541Smckusick continue; 1931558Srgrimes } 194107541Smckusick for (i = 0; i < inosused; i++, ino++) { 195107541Smckusick if (ino < ROOTINO || 196107541Smckusick (dp = getino(ino, &mode)) == NULL || 197107541Smckusick (mode & IFMT) == 0) 198107541Smckusick continue; 199157660Sdwmalone if (ino >= maxino) { 200241013Smdf msg("Skipping inode %ju >= maxino %ju\n", 201241013Smdf (uintmax_t)ino, (uintmax_t)maxino); 202157660Sdwmalone continue; 203157660Sdwmalone } 204107541Smckusick /* 205107541Smckusick * Everything must go in usedinomap so that a check 206107541Smckusick * for "in dumpdirmap but not in usedinomap" to detect 207107541Smckusick * dirs with nodump set has a chance of succeeding 208107541Smckusick * (this is used in mapdirs()). 209107541Smckusick */ 210107541Smckusick SETINO(ino, usedinomap); 211107541Smckusick if (mode == IFDIR) 212107541Smckusick SETINO(ino, dumpdirmap); 213107541Smckusick if (WANTTODUMP(dp)) { 214107541Smckusick SETINO(ino, dumpinomap); 215107541Smckusick if (mode != IFREG && 216107541Smckusick mode != IFDIR && 217107541Smckusick mode != IFLNK) 218107541Smckusick *tapesize += 1; 219107541Smckusick else 220107541Smckusick *tapesize += blockest(dp); 221107541Smckusick continue; 222107541Smckusick } 223107541Smckusick if (mode == IFDIR) { 224107541Smckusick if (!nonodump && 225107541Smckusick (DIP(dp, di_flags) & UF_NODUMP)) 226107541Smckusick CLRINO(ino, usedinomap); 227107541Smckusick anydirskipped = 1; 228107541Smckusick } 22975689Sjkh } 2301558Srgrimes } 2311558Srgrimes /* 2321558Srgrimes * Restore gets very upset if the root is not dumped, 2331558Srgrimes * so ensure that it always is dumped. 2341558Srgrimes */ 2351558Srgrimes SETINO(ROOTINO, dumpinomap); 2361558Srgrimes return (anydirskipped); 2371558Srgrimes} 2381558Srgrimes 2391558Srgrimes/* 2401558Srgrimes * Dump pass 2. 2411558Srgrimes * 242102231Strhodes * Scan each directory on the file system to see if it has any modified 2431558Srgrimes * files in it. If it does, and has not already been added to the dump 2441558Srgrimes * list (because it was itself modified), then add it. If a directory 2451558Srgrimes * has not been modified itself, contains no modified files and has no 2461558Srgrimes * subdirectories, then it can be deleted from the dump list and from 2471558Srgrimes * the list of directories. By deleting it from the list of directories, 2481558Srgrimes * its parent may now qualify for the same treatment on this or a later 2491558Srgrimes * pass using this algorithm. 2501558Srgrimes */ 2511558Srgrimesint 25292837Simpmapdirs(ino_t maxino, long *tapesize) 2531558Srgrimes{ 25498542Smckusick union dinode *dp; 25586473Siedowse int i, isdir, nodump; 25686473Siedowse char *map; 25786473Siedowse ino_t ino; 25898542Smckusick union dinode di; 2591558Srgrimes long filesize; 2601558Srgrimes int ret, change = 0; 2611558Srgrimes 2621558Srgrimes isdir = 0; /* XXX just to get gcc to shut up */ 2631558Srgrimes for (map = dumpdirmap, ino = 1; ino < maxino; ino++) { 264103949Smike if (((ino - 1) % CHAR_BIT) == 0) /* map is offset by 1 */ 2651558Srgrimes isdir = *map++; 2661558Srgrimes else 2671558Srgrimes isdir >>= 1; 26873375Sobrien /* 26973375Sobrien * If a directory has been removed from usedinomap, it 27073375Sobrien * either has the nodump flag set, or has inherited 27173375Sobrien * it. Although a directory can't be in dumpinomap if 27273375Sobrien * it isn't in usedinomap, we have to go through it to 27373375Sobrien * propagate the nodump flag. 27473375Sobrien */ 27575689Sjkh nodump = !nonodump && (TSTINO(ino, usedinomap) == 0); 27673375Sobrien if ((isdir & 1) == 0 || (TSTINO(ino, dumpinomap) && !nodump)) 2771558Srgrimes continue; 27898542Smckusick dp = getino(ino, &i); 27998542Smckusick /* 28098542Smckusick * inode buf may change in searchdir(). 28198542Smckusick */ 28298542Smckusick if (sblock->fs_magic == FS_UFS1_MAGIC) 28398542Smckusick di.dp1 = dp->dp1; 28498542Smckusick else 28598542Smckusick di.dp2 = dp->dp2; 28698542Smckusick filesize = DIP(&di, di_size); 2871558Srgrimes for (ret = 0, i = 0; filesize > 0 && i < NDADDR; i++) { 28898542Smckusick if (DIP(&di, di_db[i]) != 0) 28998542Smckusick ret |= searchdir(ino, DIP(&di, di_db[i]), 290122060Siedowse (long)sblksize(sblock, DIP(&di, di_size), 291157660Sdwmalone i), filesize, tapesize, nodump, maxino); 2921558Srgrimes if (ret & HASDUMPEDFILE) 2931558Srgrimes filesize = 0; 2941558Srgrimes else 2951558Srgrimes filesize -= sblock->fs_bsize; 2961558Srgrimes } 2971558Srgrimes for (i = 0; filesize > 0 && i < NIADDR; i++) { 29898542Smckusick if (DIP(&di, di_ib[i]) == 0) 2991558Srgrimes continue; 30098542Smckusick ret |= dirindir(ino, DIP(&di, di_ib[i]), i, &filesize, 301157660Sdwmalone tapesize, nodump, maxino); 3021558Srgrimes } 3031558Srgrimes if (ret & HASDUMPEDFILE) { 3041558Srgrimes SETINO(ino, dumpinomap); 305122060Siedowse *tapesize += blockest(&di); 3061558Srgrimes change = 1; 3071558Srgrimes continue; 3081558Srgrimes } 30973375Sobrien if (nodump) { 31073375Sobrien if (ret & HASSUBDIRS) 31173375Sobrien change = 1; /* subdirs inherit nodump */ 31273375Sobrien CLRINO(ino, dumpdirmap); 31373375Sobrien } else if ((ret & HASSUBDIRS) == 0) 3141558Srgrimes if (!TSTINO(ino, dumpinomap)) { 3151558Srgrimes CLRINO(ino, dumpdirmap); 3161558Srgrimes change = 1; 3171558Srgrimes } 3181558Srgrimes } 3191558Srgrimes return (change); 3201558Srgrimes} 3211558Srgrimes 3221558Srgrimes/* 3231558Srgrimes * Read indirect blocks, and pass the data blocks to be searched 3241558Srgrimes * as directories. Quit as soon as any entry is found that will 3251558Srgrimes * require the directory to be dumped. 3261558Srgrimes */ 3271558Srgrimesstatic int 32898542Smckusickdirindir( 32998542Smckusick ino_t ino, 33098542Smckusick ufs2_daddr_t blkno, 33198542Smckusick int ind_level, 33298542Smckusick long *filesize, 33398542Smckusick long *tapesize, 334157660Sdwmalone int nodump, 335157660Sdwmalone ino_t maxino) 3361558Srgrimes{ 33799626Siedowse union { 33899626Siedowse ufs1_daddr_t ufs1[MAXBSIZE / sizeof(ufs1_daddr_t)]; 33999626Siedowse ufs2_daddr_t ufs2[MAXBSIZE / sizeof(ufs2_daddr_t)]; 34099626Siedowse } idblk; 3411558Srgrimes int ret = 0; 34286473Siedowse int i; 3431558Srgrimes 34499626Siedowse bread(fsbtodb(sblock, blkno), (char *)&idblk, (int)sblock->fs_bsize); 3451558Srgrimes if (ind_level <= 0) { 3461558Srgrimes for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) { 34798542Smckusick if (sblock->fs_magic == FS_UFS1_MAGIC) 34899626Siedowse blkno = idblk.ufs1[i]; 34998542Smckusick else 35099626Siedowse blkno = idblk.ufs2[i]; 3511558Srgrimes if (blkno != 0) 3521558Srgrimes ret |= searchdir(ino, blkno, sblock->fs_bsize, 353157660Sdwmalone *filesize, tapesize, nodump, maxino); 3541558Srgrimes if (ret & HASDUMPEDFILE) 3551558Srgrimes *filesize = 0; 3561558Srgrimes else 3571558Srgrimes *filesize -= sblock->fs_bsize; 3581558Srgrimes } 3591558Srgrimes return (ret); 3601558Srgrimes } 3611558Srgrimes ind_level--; 3621558Srgrimes for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) { 36398542Smckusick if (sblock->fs_magic == FS_UFS1_MAGIC) 36499626Siedowse blkno = idblk.ufs1[i]; 36598542Smckusick else 36699626Siedowse blkno = idblk.ufs2[i]; 3671558Srgrimes if (blkno != 0) 36873375Sobrien ret |= dirindir(ino, blkno, ind_level, filesize, 369157660Sdwmalone tapesize, nodump, maxino); 3701558Srgrimes } 3711558Srgrimes return (ret); 3721558Srgrimes} 3731558Srgrimes 3741558Srgrimes/* 3751558Srgrimes * Scan a disk block containing directory information looking to see if 3761558Srgrimes * any of the entries are on the dump list and to see if the directory 3771558Srgrimes * contains any subdirectories. 3781558Srgrimes */ 3791558Srgrimesstatic int 38098542Smckusicksearchdir( 38198542Smckusick ino_t ino, 38298542Smckusick ufs2_daddr_t blkno, 38398542Smckusick long size, 38498542Smckusick long filesize, 38598542Smckusick long *tapesize, 386157660Sdwmalone int nodump, 387157660Sdwmalone ino_t maxino) 3881558Srgrimes{ 38998542Smckusick int mode; 39086473Siedowse struct direct *dp; 39198542Smckusick union dinode *ip; 39286473Siedowse long loc, ret = 0; 39398542Smckusick static caddr_t dblk; 3941558Srgrimes 39598542Smckusick if (dblk == NULL && (dblk = malloc(sblock->fs_bsize)) == NULL) 39698542Smckusick quit("searchdir: cannot allocate indirect memory.\n"); 3971558Srgrimes bread(fsbtodb(sblock, blkno), dblk, (int)size); 3981558Srgrimes if (filesize < size) 3991558Srgrimes size = filesize; 4001558Srgrimes for (loc = 0; loc < size; ) { 4011558Srgrimes dp = (struct direct *)(dblk + loc); 4021558Srgrimes if (dp->d_reclen == 0) { 403241013Smdf msg("corrupted directory, inumber %ju\n", 404241013Smdf (uintmax_t)ino); 4051558Srgrimes break; 4061558Srgrimes } 4071558Srgrimes loc += dp->d_reclen; 4081558Srgrimes if (dp->d_ino == 0) 4091558Srgrimes continue; 410157660Sdwmalone if (dp->d_ino >= maxino) { 411241013Smdf msg("corrupted directory entry, d_ino %ju >= %ju\n", 412241013Smdf (uintmax_t)dp->d_ino, (uintmax_t)maxino); 413157660Sdwmalone break; 414157660Sdwmalone } 4151558Srgrimes if (dp->d_name[0] == '.') { 4161558Srgrimes if (dp->d_name[1] == '\0') 4171558Srgrimes continue; 4181558Srgrimes if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') 4191558Srgrimes continue; 4201558Srgrimes } 42173375Sobrien if (nodump) { 42298542Smckusick ip = getino(dp->d_ino, &mode); 42373375Sobrien if (TSTINO(dp->d_ino, dumpinomap)) { 42473375Sobrien CLRINO(dp->d_ino, dumpinomap); 42573375Sobrien *tapesize -= blockest(ip); 42673375Sobrien } 42787413Sobrien /* 42887413Sobrien * Add back to dumpdirmap and remove from usedinomap 42987413Sobrien * to propagate nodump. 43087413Sobrien */ 43198542Smckusick if (mode == IFDIR) { 43273375Sobrien SETINO(dp->d_ino, dumpdirmap); 43387413Sobrien CLRINO(dp->d_ino, usedinomap); 43473375Sobrien ret |= HASSUBDIRS; 43573375Sobrien } 43673375Sobrien } else { 43773375Sobrien if (TSTINO(dp->d_ino, dumpinomap)) { 43873375Sobrien ret |= HASDUMPEDFILE; 43973375Sobrien if (ret & HASSUBDIRS) 44073375Sobrien break; 44173375Sobrien } 44273375Sobrien if (TSTINO(dp->d_ino, dumpdirmap)) { 44373375Sobrien ret |= HASSUBDIRS; 44473375Sobrien if (ret & HASDUMPEDFILE) 44573375Sobrien break; 44673375Sobrien } 4471558Srgrimes } 4481558Srgrimes } 4491558Srgrimes return (ret); 4501558Srgrimes} 4511558Srgrimes 4521558Srgrimes/* 4531558Srgrimes * Dump passes 3 and 4. 4541558Srgrimes * 4551558Srgrimes * Dump the contents of an inode to tape. 4561558Srgrimes */ 4571558Srgrimesvoid 45898542Smckusickdumpino(union dinode *dp, ino_t ino) 4591558Srgrimes{ 460167011Smckusick int ind_level, cnt, last, added; 46198542Smckusick off_t size; 4621558Srgrimes char buf[TP_BSIZE]; 4631558Srgrimes 4641558Srgrimes if (newtape) { 4651558Srgrimes newtape = 0; 4661558Srgrimes dumpmap(dumpinomap, TS_BITS, ino); 4671558Srgrimes } 4681558Srgrimes CLRINO(ino, dumpinomap); 469107430Smckusick /* 470107430Smckusick * Zero out the size of a snapshot so that it will be dumped 471107430Smckusick * as a zero length file. 472107430Smckusick */ 473107430Smckusick if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0) { 474132762Skan DIP_SET(dp, di_size, 0); 475132762Skan DIP_SET(dp, di_flags, DIP(dp, di_flags) & ~SF_SNAPSHOT); 476107430Smckusick } 47798542Smckusick if (sblock->fs_magic == FS_UFS1_MAGIC) { 47898542Smckusick spcl.c_mode = dp->dp1.di_mode; 47998542Smckusick spcl.c_size = dp->dp1.di_size; 480167011Smckusick spcl.c_extsize = 0; 48198542Smckusick spcl.c_atime = _time32_to_time(dp->dp1.di_atime); 48298542Smckusick spcl.c_atimensec = dp->dp1.di_atimensec; 48398542Smckusick spcl.c_mtime = _time32_to_time(dp->dp1.di_mtime); 48498542Smckusick spcl.c_mtimensec = dp->dp1.di_mtimensec; 485100207Smckusick spcl.c_birthtime = 0; 486100207Smckusick spcl.c_birthtimensec = 0; 48798542Smckusick spcl.c_rdev = dp->dp1.di_rdev; 48898542Smckusick spcl.c_file_flags = dp->dp1.di_flags; 48998542Smckusick spcl.c_uid = dp->dp1.di_uid; 49098542Smckusick spcl.c_gid = dp->dp1.di_gid; 49198542Smckusick } else { 49298542Smckusick spcl.c_mode = dp->dp2.di_mode; 49398542Smckusick spcl.c_size = dp->dp2.di_size; 494167011Smckusick spcl.c_extsize = dp->dp2.di_extsize; 49598542Smckusick spcl.c_atime = _time64_to_time(dp->dp2.di_atime); 49698542Smckusick spcl.c_atimensec = dp->dp2.di_atimensec; 49798542Smckusick spcl.c_mtime = _time64_to_time(dp->dp2.di_mtime); 49898542Smckusick spcl.c_mtimensec = dp->dp2.di_mtimensec; 499100207Smckusick spcl.c_birthtime = _time64_to_time(dp->dp2.di_birthtime); 500100207Smckusick spcl.c_birthtimensec = dp->dp2.di_birthnsec; 50198542Smckusick spcl.c_rdev = dp->dp2.di_rdev; 50298542Smckusick spcl.c_file_flags = dp->dp2.di_flags; 50398542Smckusick spcl.c_uid = dp->dp2.di_uid; 50498542Smckusick spcl.c_gid = dp->dp2.di_gid; 50598542Smckusick } 5061558Srgrimes spcl.c_type = TS_INODE; 5071558Srgrimes spcl.c_count = 0; 50898542Smckusick switch (DIP(dp, di_mode) & S_IFMT) { 5091558Srgrimes 5101558Srgrimes case 0: 5111558Srgrimes /* 5121558Srgrimes * Freed inode. 5131558Srgrimes */ 5141558Srgrimes return; 5151558Srgrimes 5161558Srgrimes case S_IFLNK: 5171558Srgrimes /* 5181558Srgrimes * Check for short symbolic link. 5191558Srgrimes */ 52098542Smckusick if (DIP(dp, di_size) > 0 && 52198542Smckusick DIP(dp, di_size) < sblock->fs_maxsymlinklen) { 5221558Srgrimes spcl.c_addr[0] = 1; 5231558Srgrimes spcl.c_count = 1; 524167011Smckusick added = appendextdata(dp); 5251558Srgrimes writeheader(ino); 52698542Smckusick if (sblock->fs_magic == FS_UFS1_MAGIC) 52798542Smckusick memmove(buf, (caddr_t)dp->dp1.di_db, 52898542Smckusick (u_long)DIP(dp, di_size)); 52998542Smckusick else 53098542Smckusick memmove(buf, (caddr_t)dp->dp2.di_db, 53198542Smckusick (u_long)DIP(dp, di_size)); 53298542Smckusick buf[DIP(dp, di_size)] = '\0'; 5331558Srgrimes writerec(buf, 0); 534167011Smckusick writeextdata(dp, ino, added); 5351558Srgrimes return; 5361558Srgrimes } 537102411Scharnier /* FALLTHROUGH */ 5381558Srgrimes 5391558Srgrimes case S_IFDIR: 5401558Srgrimes case S_IFREG: 54198542Smckusick if (DIP(dp, di_size) > 0) 5421558Srgrimes break; 543102411Scharnier /* FALLTHROUGH */ 5441558Srgrimes 5451558Srgrimes case S_IFIFO: 5461558Srgrimes case S_IFSOCK: 5471558Srgrimes case S_IFCHR: 5481558Srgrimes case S_IFBLK: 549167011Smckusick added = appendextdata(dp); 5501558Srgrimes writeheader(ino); 551167011Smckusick writeextdata(dp, ino, added); 5521558Srgrimes return; 5531558Srgrimes 5541558Srgrimes default: 55598542Smckusick msg("Warning: undefined file type 0%o\n", 55698542Smckusick DIP(dp, di_mode) & IFMT); 5571558Srgrimes return; 5581558Srgrimes } 559167011Smckusick if (DIP(dp, di_size) > NDADDR * sblock->fs_bsize) { 5601558Srgrimes cnt = NDADDR * sblock->fs_frag; 561167011Smckusick last = 0; 562167011Smckusick } else { 56398542Smckusick cnt = howmany(DIP(dp, di_size), sblock->fs_fsize); 564167011Smckusick last = 1; 565167011Smckusick } 56698542Smckusick if (sblock->fs_magic == FS_UFS1_MAGIC) 56798542Smckusick ufs1_blksout(&dp->dp1.di_db[0], cnt, ino); 56898542Smckusick else 569167011Smckusick ufs2_blksout(dp, &dp->dp2.di_db[0], cnt, ino, last); 57098542Smckusick if ((size = DIP(dp, di_size) - NDADDR * sblock->fs_bsize) <= 0) 5711558Srgrimes return; 5721558Srgrimes for (ind_level = 0; ind_level < NIADDR; ind_level++) { 573167011Smckusick dmpindir(dp, ino, DIP(dp, di_ib[ind_level]), ind_level, &size); 5741558Srgrimes if (size <= 0) 5751558Srgrimes return; 5761558Srgrimes } 5771558Srgrimes} 5781558Srgrimes 5791558Srgrimes/* 5801558Srgrimes * Read indirect blocks, and pass the data blocks to be dumped. 5811558Srgrimes */ 5821558Srgrimesstatic void 583167011Smckusickdmpindir(union dinode *dp, ino_t ino, ufs2_daddr_t blk, int ind_level, 584167011Smckusick off_t *size) 5851558Srgrimes{ 58699626Siedowse union { 58799626Siedowse ufs1_daddr_t ufs1[MAXBSIZE / sizeof(ufs1_daddr_t)]; 58899626Siedowse ufs2_daddr_t ufs2[MAXBSIZE / sizeof(ufs2_daddr_t)]; 58999626Siedowse } idblk; 590167011Smckusick int i, cnt, last; 5911558Srgrimes 5921558Srgrimes if (blk != 0) 59399626Siedowse bread(fsbtodb(sblock, blk), (char *)&idblk, 59499626Siedowse (int)sblock->fs_bsize); 5951558Srgrimes else 59699626Siedowse memset(&idblk, 0, sblock->fs_bsize); 5971558Srgrimes if (ind_level <= 0) { 598167011Smckusick if (*size > NINDIR(sblock) * sblock->fs_bsize) { 599167011Smckusick cnt = NINDIR(sblock) * sblock->fs_frag; 600167011Smckusick last = 0; 601167011Smckusick } else { 6021558Srgrimes cnt = howmany(*size, sblock->fs_fsize); 603167011Smckusick last = 1; 604167011Smckusick } 6051558Srgrimes *size -= NINDIR(sblock) * sblock->fs_bsize; 60698542Smckusick if (sblock->fs_magic == FS_UFS1_MAGIC) 60799626Siedowse ufs1_blksout(idblk.ufs1, cnt, ino); 60898542Smckusick else 609167011Smckusick ufs2_blksout(dp, idblk.ufs2, cnt, ino, last); 6101558Srgrimes return; 6111558Srgrimes } 6121558Srgrimes ind_level--; 6131558Srgrimes for (i = 0; i < NINDIR(sblock); i++) { 61498542Smckusick if (sblock->fs_magic == FS_UFS1_MAGIC) 615167011Smckusick dmpindir(dp, ino, idblk.ufs1[i], ind_level, size); 61698542Smckusick else 617167011Smckusick dmpindir(dp, ino, idblk.ufs2[i], ind_level, size); 6181558Srgrimes if (*size <= 0) 6191558Srgrimes return; 6201558Srgrimes } 6211558Srgrimes} 6221558Srgrimes 6231558Srgrimes/* 6241558Srgrimes * Collect up the data into tape record sized buffers and output them. 6251558Srgrimes */ 626167011Smckusickstatic void 62798542Smckusickufs1_blksout(ufs1_daddr_t *blkp, int frags, ino_t ino) 6281558Srgrimes{ 62998542Smckusick ufs1_daddr_t *bp; 6301558Srgrimes int i, j, count, blks, tbperdb; 6311558Srgrimes 6321558Srgrimes blks = howmany(frags * sblock->fs_fsize, TP_BSIZE); 6331558Srgrimes tbperdb = sblock->fs_bsize >> tp_bshift; 6341558Srgrimes for (i = 0; i < blks; i += TP_NINDIR) { 6351558Srgrimes if (i + TP_NINDIR > blks) 6361558Srgrimes count = blks; 6371558Srgrimes else 6381558Srgrimes count = i + TP_NINDIR; 6391558Srgrimes for (j = i; j < count; j++) 6401558Srgrimes if (blkp[j / tbperdb] != 0) 6411558Srgrimes spcl.c_addr[j - i] = 1; 6421558Srgrimes else 6431558Srgrimes spcl.c_addr[j - i] = 0; 6441558Srgrimes spcl.c_count = count - i; 6451558Srgrimes writeheader(ino); 6461558Srgrimes bp = &blkp[i / tbperdb]; 6471558Srgrimes for (j = i; j < count; j += tbperdb, bp++) 64848688Sbillf if (*bp != 0) { 6491558Srgrimes if (j + tbperdb <= count) 6501558Srgrimes dumpblock(*bp, (int)sblock->fs_bsize); 6511558Srgrimes else 6521558Srgrimes dumpblock(*bp, (count - j) * TP_BSIZE); 65348688Sbillf } 6541558Srgrimes spcl.c_type = TS_ADDR; 6551558Srgrimes } 6561558Srgrimes} 6571558Srgrimes 6581558Srgrimes/* 65998542Smckusick * Collect up the data into tape record sized buffers and output them. 66098542Smckusick */ 661167011Smckusickstatic void 662167011Smckusickufs2_blksout(union dinode *dp, ufs2_daddr_t *blkp, int frags, ino_t ino, 663167011Smckusick int last) 66498542Smckusick{ 66598542Smckusick ufs2_daddr_t *bp; 666167011Smckusick int i, j, count, resid, blks, tbperdb, added; 667167011Smckusick static int writingextdata = 0; 66898542Smckusick 669167011Smckusick /* 670167011Smckusick * Calculate the number of TP_BSIZE blocks to be dumped. 671167011Smckusick * For filesystems with a fragment size bigger than TP_BSIZE, 672167011Smckusick * only part of the final fragment may need to be dumped. 673167011Smckusick */ 67498542Smckusick blks = howmany(frags * sblock->fs_fsize, TP_BSIZE); 675167011Smckusick if (last) { 676272867Shrs if (writingextdata) 677272867Shrs resid = howmany(fragoff(sblock, spcl.c_extsize), 678272867Shrs TP_BSIZE); 679272867Shrs else 680272867Shrs resid = howmany(fragoff(sblock, dp->dp2.di_size), 681272867Shrs TP_BSIZE); 682167011Smckusick if (resid > 0) 683167011Smckusick blks -= howmany(sblock->fs_fsize, TP_BSIZE) - resid; 684167011Smckusick } 68598542Smckusick tbperdb = sblock->fs_bsize >> tp_bshift; 68698542Smckusick for (i = 0; i < blks; i += TP_NINDIR) { 68798542Smckusick if (i + TP_NINDIR > blks) 68898542Smckusick count = blks; 68998542Smckusick else 69098542Smckusick count = i + TP_NINDIR; 69198542Smckusick for (j = i; j < count; j++) 69298542Smckusick if (blkp[j / tbperdb] != 0) 69398542Smckusick spcl.c_addr[j - i] = 1; 69498542Smckusick else 69598542Smckusick spcl.c_addr[j - i] = 0; 69698542Smckusick spcl.c_count = count - i; 697167055Smckusick if (last && count == blks && !writingextdata) 698167011Smckusick added = appendextdata(dp); 69998542Smckusick writeheader(ino); 70098542Smckusick bp = &blkp[i / tbperdb]; 70198542Smckusick for (j = i; j < count; j += tbperdb, bp++) 70298542Smckusick if (*bp != 0) { 70398542Smckusick if (j + tbperdb <= count) 70498542Smckusick dumpblock(*bp, (int)sblock->fs_bsize); 70598542Smckusick else 70698542Smckusick dumpblock(*bp, (count - j) * TP_BSIZE); 70798542Smckusick } 70898542Smckusick spcl.c_type = TS_ADDR; 709167011Smckusick spcl.c_count = 0; 710167055Smckusick if (last && count == blks && !writingextdata) { 711167011Smckusick writingextdata = 1; 712167011Smckusick writeextdata(dp, ino, added); 713167011Smckusick writingextdata = 0; 714167011Smckusick } 71598542Smckusick } 71698542Smckusick} 71798542Smckusick 71898542Smckusick/* 719167011Smckusick * If there is room in the current block for the extended attributes 720167011Smckusick * as well as the file data, update the header to reflect the added 721167011Smckusick * attribute data at the end. Attributes are placed at the end so that 722167011Smckusick * old versions of restore will correctly restore the file and simply 723167011Smckusick * discard the extra data at the end that it does not understand. 724167011Smckusick * The attribute data is dumped following the file data by the 725167011Smckusick * writeextdata() function (below). 726167011Smckusick */ 727167011Smckusickstatic int 728167011Smckusickappendextdata(union dinode *dp) 729167011Smckusick{ 730167011Smckusick int i, blks, tbperdb; 731167011Smckusick 732167011Smckusick /* 733167011Smckusick * If no extended attributes, there is nothing to do. 734167011Smckusick */ 735167011Smckusick if (spcl.c_extsize == 0) 736167011Smckusick return (0); 737167011Smckusick /* 738167011Smckusick * If there is not enough room at the end of this block 739167011Smckusick * to add the extended attributes, then rather than putting 740167011Smckusick * part of them here, we simply push them entirely into a 741167011Smckusick * new block rather than putting some here and some later. 742167011Smckusick */ 743167011Smckusick if (spcl.c_extsize > NXADDR * sblock->fs_bsize) 744167011Smckusick blks = howmany(NXADDR * sblock->fs_bsize, TP_BSIZE); 745167011Smckusick else 746167011Smckusick blks = howmany(spcl.c_extsize, TP_BSIZE); 747167011Smckusick if (spcl.c_count + blks > TP_NINDIR) 748167011Smckusick return (0); 749167011Smckusick /* 750167011Smckusick * Update the block map in the header to indicate the added 751167011Smckusick * extended attribute. They will be appended after the file 752167011Smckusick * data by the writeextdata() routine. 753167011Smckusick */ 754167011Smckusick tbperdb = sblock->fs_bsize >> tp_bshift; 755167011Smckusick for (i = 0; i < blks; i++) 756167011Smckusick if (&dp->dp2.di_extb[i / tbperdb] != 0) 757167011Smckusick spcl.c_addr[spcl.c_count + i] = 1; 758167011Smckusick else 759167011Smckusick spcl.c_addr[spcl.c_count + i] = 0; 760167011Smckusick spcl.c_count += blks; 761167011Smckusick return (blks); 762167011Smckusick} 763167011Smckusick 764167011Smckusick/* 765167011Smckusick * Dump the extended attribute data. If there was room in the file 766167011Smckusick * header, then all we need to do is output the data blocks. If there 767167011Smckusick * was not room in the file header, then an additional TS_ADDR header 768167011Smckusick * is created to hold the attribute data. 769167011Smckusick */ 770167011Smckusickstatic void 771167011Smckusickwriteextdata(union dinode *dp, ino_t ino, int added) 772167011Smckusick{ 773167011Smckusick int i, frags, blks, tbperdb, last; 774167011Smckusick ufs2_daddr_t *bp; 775167011Smckusick off_t size; 776167011Smckusick 777167011Smckusick /* 778167011Smckusick * If no extended attributes, there is nothing to do. 779167011Smckusick */ 780167011Smckusick if (spcl.c_extsize == 0) 781167011Smckusick return; 782167011Smckusick /* 783167011Smckusick * If there was no room in the file block for the attributes, 784167011Smckusick * dump them out in a new block, otherwise just dump the data. 785167011Smckusick */ 786167011Smckusick if (added == 0) { 787167011Smckusick if (spcl.c_extsize > NXADDR * sblock->fs_bsize) { 788167011Smckusick frags = NXADDR * sblock->fs_frag; 789167011Smckusick last = 0; 790167011Smckusick } else { 791167011Smckusick frags = howmany(spcl.c_extsize, sblock->fs_fsize); 792167011Smckusick last = 1; 793167011Smckusick } 794167011Smckusick ufs2_blksout(dp, &dp->dp2.di_extb[0], frags, ino, last); 795167011Smckusick } else { 796167011Smckusick if (spcl.c_extsize > NXADDR * sblock->fs_bsize) 797167011Smckusick blks = howmany(NXADDR * sblock->fs_bsize, TP_BSIZE); 798167011Smckusick else 799167011Smckusick blks = howmany(spcl.c_extsize, TP_BSIZE); 800167011Smckusick tbperdb = sblock->fs_bsize >> tp_bshift; 801167011Smckusick for (i = 0; i < blks; i += tbperdb) { 802167011Smckusick bp = &dp->dp2.di_extb[i / tbperdb]; 803167011Smckusick if (*bp != 0) { 804167011Smckusick if (i + tbperdb <= blks) 805167011Smckusick dumpblock(*bp, (int)sblock->fs_bsize); 806167011Smckusick else 807167011Smckusick dumpblock(*bp, (blks - i) * TP_BSIZE); 808167011Smckusick } 809167011Smckusick } 810167011Smckusick 811167011Smckusick } 812167011Smckusick /* 813167011Smckusick * If an indirect block is added for extended attributes, then 814167011Smckusick * di_exti below should be changed to the structure element 815167011Smckusick * that references the extended attribute indirect block. This 816167011Smckusick * definition is here only to make it compile without complaint. 817167011Smckusick */ 818167011Smckusick#define di_exti di_spare[0] 819167011Smckusick /* 820167011Smckusick * If the extended attributes fall into an indirect block, 821167011Smckusick * dump it as well. 822167011Smckusick */ 823167011Smckusick if ((size = spcl.c_extsize - NXADDR * sblock->fs_bsize) > 0) 824167011Smckusick dmpindir(dp, ino, dp->dp2.di_exti, 0, &size); 825167011Smckusick} 826167011Smckusick 827167011Smckusick/* 8281558Srgrimes * Dump a map to the tape. 8291558Srgrimes */ 8301558Srgrimesvoid 83192837Simpdumpmap(char *map, int type, ino_t ino) 8321558Srgrimes{ 83386473Siedowse int i; 8341558Srgrimes char *cp; 8351558Srgrimes 8361558Srgrimes spcl.c_type = type; 8371558Srgrimes spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE); 8381558Srgrimes writeheader(ino); 8391558Srgrimes for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE) 8401558Srgrimes writerec(cp, 0); 8411558Srgrimes} 8421558Srgrimes 8431558Srgrimes/* 8441558Srgrimes * Write a header record to the dump tape. 8451558Srgrimes */ 8461558Srgrimesvoid 84792837Simpwriteheader(ino_t ino) 8481558Srgrimes{ 84986473Siedowse int32_t sum, cnt, *lp; 8501558Srgrimes 851179267Smckusick if (rsync_friendly >= 2) { 852179267Smckusick /* don't track changes to access time */ 853179267Smckusick spcl.c_atime = spcl.c_mtime; 854179267Smckusick spcl.c_atimensec = spcl.c_mtimensec; 855179267Smckusick } 8561558Srgrimes spcl.c_inumber = ino; 85798542Smckusick spcl.c_magic = FS_UFS2_MAGIC; 8581558Srgrimes spcl.c_checksum = 0; 85940668Sdima lp = (int32_t *)&spcl; 8601558Srgrimes sum = 0; 86140668Sdima cnt = sizeof(union u_spcl) / (4 * sizeof(int32_t)); 8621558Srgrimes while (--cnt >= 0) { 8631558Srgrimes sum += *lp++; 8641558Srgrimes sum += *lp++; 8651558Srgrimes sum += *lp++; 8661558Srgrimes sum += *lp++; 8671558Srgrimes } 8681558Srgrimes spcl.c_checksum = CHECKSUM - sum; 8691558Srgrimes writerec((char *)&spcl, 1); 8701558Srgrimes} 8711558Srgrimes 87298542Smckusickunion dinode * 87398542Smckusickgetino(ino_t inum, int *modep) 8741558Srgrimes{ 87598542Smckusick static ino_t minino, maxino; 87698542Smckusick static caddr_t inoblock; 87798542Smckusick struct ufs1_dinode *dp1; 87898542Smckusick struct ufs2_dinode *dp2; 8791558Srgrimes 88098542Smckusick if (inoblock == NULL && (inoblock = malloc(sblock->fs_bsize)) == NULL) 88198542Smckusick quit("cannot allocate inode memory.\n"); 8821558Srgrimes curino = inum; 8831558Srgrimes if (inum >= minino && inum < maxino) 88498542Smckusick goto gotit; 88598542Smckusick bread(fsbtodb(sblock, ino_to_fsba(sblock, inum)), inoblock, 8861558Srgrimes (int)sblock->fs_bsize); 8871558Srgrimes minino = inum - (inum % INOPB(sblock)); 8881558Srgrimes maxino = minino + INOPB(sblock); 88998542Smckusickgotit: 89098542Smckusick if (sblock->fs_magic == FS_UFS1_MAGIC) { 89198542Smckusick dp1 = &((struct ufs1_dinode *)inoblock)[inum - minino]; 89298542Smckusick *modep = (dp1->di_mode & IFMT); 89398542Smckusick return ((union dinode *)dp1); 89498542Smckusick } 89598542Smckusick dp2 = &((struct ufs2_dinode *)inoblock)[inum - minino]; 89698542Smckusick *modep = (dp2->di_mode & IFMT); 89798542Smckusick return ((union dinode *)dp2); 8981558Srgrimes} 8991558Srgrimes 9001558Srgrimes/* 9011558Srgrimes * Read a chunk of data from the disk. 9021558Srgrimes * Try to recover from hard errors by reading in sector sized pieces. 9031558Srgrimes * Error recovery is attempted at most BREADEMAX times before seeking 9041558Srgrimes * consent from the operator to continue. 9051558Srgrimes */ 9068871Srgrimesint breaderrors = 0; 9071558Srgrimes#define BREADEMAX 32 9081558Srgrimes 9091558Srgrimesvoid 91098542Smckusickbread(ufs2_daddr_t blkno, char *buf, int size) 9111558Srgrimes{ 912114810Smckusick int secsize, bytes, resid, xfer, base, cnt, i; 913114810Smckusick static char *tmpbuf; 914114810Smckusick off_t offset; 9151558Srgrimes 9161558Srgrimesloop: 917114810Smckusick offset = blkno << dev_bshift; 918114810Smckusick secsize = sblock->fs_fsize; 919114810Smckusick base = offset % secsize; 920114810Smckusick resid = size % secsize; 921114810Smckusick /* 922114810Smckusick * If the transfer request starts or ends on a non-sector 923114810Smckusick * boundary, we must read the entire sector and copy out 924114810Smckusick * just the part that we need. 925114810Smckusick */ 926114810Smckusick if (base == 0 && resid == 0) { 927114810Smckusick cnt = cread(diskfd, buf, size, offset); 928114810Smckusick if (cnt == size) 929114810Smckusick return; 930114810Smckusick } else { 931114810Smckusick if (tmpbuf == NULL && (tmpbuf = malloc(secsize)) == 0) 932114810Smckusick quit("buffer malloc failed\n"); 933114810Smckusick xfer = 0; 934114810Smckusick bytes = size; 935114810Smckusick if (base != 0) { 936114810Smckusick cnt = cread(diskfd, tmpbuf, secsize, offset - base); 937114810Smckusick if (cnt != secsize) 938114810Smckusick goto bad; 939168392Sthomas xfer = MIN(secsize - base, size); 940114810Smckusick offset += xfer; 941114810Smckusick bytes -= xfer; 942114810Smckusick resid = bytes % secsize; 943114810Smckusick memcpy(buf, &tmpbuf[base], xfer); 944114810Smckusick } 945114810Smckusick if (bytes >= secsize) { 946114810Smckusick cnt = cread(diskfd, &buf[xfer], bytes - resid, offset); 947114810Smckusick if (cnt != bytes - resid) 948114810Smckusick goto bad; 949114810Smckusick xfer += cnt; 950114810Smckusick offset += cnt; 951114810Smckusick } 952114810Smckusick if (resid == 0) 953114810Smckusick return; 954114810Smckusick cnt = cread(diskfd, tmpbuf, secsize, offset); 955114810Smckusick if (cnt == secsize) { 956114810Smckusick memcpy(&buf[xfer], tmpbuf, resid); 957114810Smckusick return; 958114810Smckusick } 959114810Smckusick } 960114810Smckusickbad: 9611558Srgrimes if (blkno + (size / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) { 9621558Srgrimes /* 9631558Srgrimes * Trying to read the final fragment. 9641558Srgrimes * 9651558Srgrimes * NB - dump only works in TP_BSIZE blocks, hence 9661558Srgrimes * rounds `dev_bsize' fragments up to TP_BSIZE pieces. 9671558Srgrimes * It should be smarter about not actually trying to 9681558Srgrimes * read more than it can get, but for the time being 9691558Srgrimes * we punt and scale back the read only when it gets 9701558Srgrimes * us into trouble. (mkm 9/25/83) 9711558Srgrimes */ 9721558Srgrimes size -= dev_bsize; 9731558Srgrimes goto loop; 9741558Srgrimes } 9751558Srgrimes if (cnt == -1) 97699562Siedowse msg("read error from %s: %s: [block %jd]: count=%d\n", 97799562Siedowse disk, strerror(errno), (intmax_t)blkno, size); 9781558Srgrimes else 97999562Siedowse msg("short read error from %s: [block %jd]: count=%d, got=%d\n", 98099562Siedowse disk, (intmax_t)blkno, size, cnt); 9811558Srgrimes if (++breaderrors > BREADEMAX) { 98299530Siedowse msg("More than %d block read errors from %s\n", 9831558Srgrimes BREADEMAX, disk); 9841558Srgrimes broadcast("DUMP IS AILING!\n"); 9851558Srgrimes msg("This is an unrecoverable error.\n"); 9861558Srgrimes if (!query("Do you want to attempt to continue?")){ 9871558Srgrimes dumpabort(0); 9881558Srgrimes /*NOTREACHED*/ 9891558Srgrimes } else 9901558Srgrimes breaderrors = 0; 9911558Srgrimes } 9921558Srgrimes /* 993109187Sdillon * Zero buffer, then try to read each sector of buffer separately, 994109187Sdillon * and bypass the cache. 9951558Srgrimes */ 99623672Speter memset(buf, 0, size); 9971558Srgrimes for (i = 0; i < size; i += dev_bsize, buf += dev_bsize, blkno++) { 99879039Smikeh if ((cnt = pread(diskfd, buf, (int)dev_bsize, 99979039Smikeh ((off_t)blkno << dev_bshift))) == dev_bsize) 10001558Srgrimes continue; 10011558Srgrimes if (cnt == -1) { 100299562Siedowse msg("read error from %s: %s: [sector %jd]: count=%ld\n", 100399562Siedowse disk, strerror(errno), (intmax_t)blkno, dev_bsize); 10041558Srgrimes continue; 10051558Srgrimes } 100699562Siedowse msg("short read from %s: [sector %jd]: count=%ld, got=%d\n", 100799562Siedowse disk, (intmax_t)blkno, dev_bsize, cnt); 10081558Srgrimes } 10091558Srgrimes} 1010