1/* $NetBSD: traverse.c,v 1.47 2006/06/24 05:28:54 perseant Exp $ */ 2 3/*- 4 * Copyright (c) 1980, 1988, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#ifndef lint 34#if 0 35static char sccsid[] = "@(#)traverse.c 8.7 (Berkeley) 6/15/95"; 36#else 37__RCSID("$NetBSD: traverse.c,v 1.47 2006/06/24 05:28:54 perseant Exp $"); 38#endif 39#endif /* not lint */ 40 41#include <sys/param.h> 42#include <sys/time.h> 43#include <sys/stat.h> 44#include <ufs/ufs/dir.h> 45#include <ufs/ufs/dinode.h> 46#include <ufs/ffs/fs.h> 47#include <ufs/ffs/ffs_extern.h> 48 49#include <protocols/dumprestore.h> 50 51#include <ctype.h> 52#include <errno.h> 53#include <fts.h> 54#include <stdio.h> 55#include <stdlib.h> 56#include <string.h> 57#include <unistd.h> 58 59#include "dump.h" 60 61#define HASDUMPEDFILE 0x1 62#define HASSUBDIRS 0x2 63 64static int dirindir(ino_t, daddr_t, int, off_t *, u_int64_t *, int); 65static void dmpindir(ino_t, daddr_t, int, off_t *); 66static int searchdir(ino_t, daddr_t, long, off_t, u_int64_t *, int); 67 68/* 69 * This is an estimation of the number of TP_BSIZE blocks in the file. 70 * It estimates the number of blocks in files with holes by assuming 71 * that all of the blocks accounted for by di_blocks are data blocks 72 * (when some of the blocks are usually used for indirect pointers); 73 * hence the estimate may be high. 74 */ 75int64_t 76blockest(union dinode *dp) 77{ 78 int64_t blkest, sizeest; 79 80 /* 81 * dp->di_size is the size of the file in bytes. 82 * dp->di_blocks stores the number of sectors actually in the file. 83 * If there are more sectors than the size would indicate, this just 84 * means that there are indirect blocks in the file or unused 85 * sectors in the last file block; we can safely ignore these 86 * (blkest = sizeest below). 87 * If the file is bigger than the number of sectors would indicate, 88 * then the file has holes in it. In this case we must use the 89 * block count to estimate the number of data blocks used, but 90 * we use the actual size for estimating the number of indirect 91 * dump blocks (sizeest vs. blkest in the indirect block 92 * calculation). 93 */ 94 if (DIP(dp, flags) & SF_SNAPSHOT) 95 return (1); 96 blkest = howmany(ufs_fragroundup(ufsib, 97 dbtob((u_int64_t)DIP(dp, blocks))), TP_BSIZE); 98 sizeest = howmany(ufs_fragroundup(ufsib, DIP(dp, size)), TP_BSIZE); 99 if (blkest > sizeest) 100 blkest = sizeest; 101 if (DIP(dp, size) > ufsib->ufs_bsize * NDADDR) { 102 /* calculate the number of indirect blocks on the dump tape */ 103 blkest += 104 howmany(sizeest - NDADDR * ufsib->ufs_bsize / TP_BSIZE, 105 TP_NINDIR); 106 } 107 return (blkest + 1); 108} 109 110/* Auxiliary macro to pick up files changed since previous dump. */ 111#define CHANGEDSINCE(dp, t) \ 112 (DIP((dp), mtime) >= (t) || DIP((dp), ctime) >= (t)) 113 114/* The WANTTODUMP macro decides whether a file should be dumped. */ 115#ifdef UF_NODUMP 116#define WANTTODUMP(dp) \ 117 (CHANGEDSINCE(dp, iswap64(spcl.c_ddate)) && \ 118 (nonodump || (DIP((dp), flags) & UF_NODUMP) != UF_NODUMP)) 119#else 120#define WANTTODUMP(dp) CHANGEDSINCE(dp, iswap64(spcl.c_ddate)) 121#endif 122 123/* 124 * Determine if given inode should be dumped 125 */ 126void 127mapfileino(ino_t ino, u_int64_t *tape_size, int *dirskipped) 128{ 129 int mode; 130 union dinode *dp; 131 132 /* 133 * Skip inode if we've already marked it for dumping 134 */ 135 if (TSTINO(ino, usedinomap)) 136 return; 137 dp = getino(ino); 138 if (dp == NULL || (mode = (DIP(dp, mode) & IFMT)) == 0) 139 return; 140 /* 141 * Skip WAPBL log file inodes. 142 */ 143 if (DIP(dp, flags) & SF_LOG) 144 return; 145 /* 146 * Put all dirs in dumpdirmap, inodes that are to be dumped in the 147 * used map. All inode but dirs who have the nodump attribute go 148 * to the usedinomap. 149 */ 150 SETINO(ino, usedinomap); 151 if (mode == IFDIR) 152 SETINO(ino, dumpdirmap); 153 if (WANTTODUMP(dp)) { 154 SETINO(ino, dumpinomap); 155 if (mode != IFREG && mode != IFDIR && mode != IFLNK) 156 *tape_size += 1; 157 else 158 *tape_size += blockest(dp); 159 return; 160 } 161 if (mode == IFDIR) { 162#ifdef UF_NODUMP 163 if (!nonodump && (DIP(dp, flags) & UF_NODUMP)) 164 CLRINO(ino, usedinomap); 165#endif 166 *dirskipped = 1; 167 } 168} 169 170/* 171 * Dump pass 1. 172 * 173 * Walk the inode list for a file system to find all allocated inodes 174 * that have been modified since the previous dump time. Also, find all 175 * the directories in the file system. 176 * disk may be NULL if dirv is NULL. 177 */ 178int 179mapfiles(ino_t maxino, u_int64_t *tape_size, char *diskname, char * const *dirv) 180{ 181 int anydirskipped = 0; 182 183 if (dirv != NULL) { 184 char curdir[MAXPATHLEN]; 185 FTS *dirh; 186 FTSENT *entry; 187 int d; 188 189 if (getcwd(curdir, sizeof(curdir)) == NULL) { 190 msg("Can't determine cwd: %s\n", strerror(errno)); 191 dumpabort(0); 192 } 193 if ((dirh = fts_open(dirv, FTS_PHYSICAL|FTS_SEEDOT|FTS_XDEV, 194 NULL)) == NULL) { 195 msg("fts_open failed: %s\n", strerror(errno)); 196 dumpabort(0); 197 } 198 while ((entry = fts_read(dirh)) != NULL) { 199 switch (entry->fts_info) { 200 case FTS_DNR: /* an error */ 201 case FTS_ERR: 202 case FTS_NS: 203 msg("Can't fts_read %s: %s\n", entry->fts_path, 204 strerror(errno)); 205 case FTS_DP: /* already seen dir */ 206 continue; 207 } 208 mapfileino(entry->fts_statp->st_ino, tape_size, 209 &anydirskipped); 210 } 211 (void)fts_close(dirh); 212 213 /* 214 * Add any parent directories 215 */ 216 for (d = 0 ; dirv[d] != NULL ; d++) { 217 char path[MAXPATHLEN]; 218 219 if (dirv[d][0] != '/') 220 (void)snprintf(path, sizeof(path), "%s/%s", 221 curdir, dirv[d]); 222 else 223 (void)snprintf(path, sizeof(path), "%s", 224 dirv[d]); 225 while (strcmp(path, diskname) != 0) { 226 char *p; 227 struct stat sb; 228 229 if (*path == '\0') 230 break; 231 if ((p = strrchr(path, '/')) == NULL) 232 break; 233 if (p == path) 234 break; 235 *p = '\0'; 236 if (stat(path, &sb) == -1) { 237 msg("Can't stat %s: %s\n", path, 238 strerror(errno)); 239 break; 240 } 241 mapfileino(sb.st_ino, tape_size, &anydirskipped); 242 } 243 } 244 245 /* 246 * Ensure that the root inode actually appears in the 247 * file list for a subdir 248 */ 249 mapfileino(ROOTINO, tape_size, &anydirskipped); 250 } else { 251 fs_mapinodes(maxino, tape_size, &anydirskipped); 252 } 253 /* 254 * Restore gets very upset if the root is not dumped, 255 * so ensure that it always is dumped. 256 */ 257 SETINO(ROOTINO, dumpinomap); 258 return (anydirskipped); 259} 260 261/* 262 * Dump pass 2. 263 * 264 * Scan each directory on the file system to see if it has any modified 265 * files in it. If it does, and has not already been added to the dump 266 * list (because it was itself modified), then add it. If a directory 267 * has not been modified itself, contains no modified files and has no 268 * subdirectories, then it can be deleted from the dump list and from 269 * the list of directories. By deleting it from the list of directories, 270 * its parent may now qualify for the same treatment on this or a later 271 * pass using this algorithm. 272 */ 273int 274mapdirs(ino_t maxino, u_int64_t *tape_size) 275{ 276 union dinode *dp, di; 277 int i, isdir, nodump; 278 char *map; 279 ino_t ino; 280 off_t filesize; 281 int ret, change = 0; 282 daddr_t blk; 283 284 isdir = 0; /* XXX just to get gcc to shut up */ 285 for (map = dumpdirmap, ino = 1; ino < maxino; ino++) { 286 if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */ 287 isdir = *map++; 288 else 289 isdir >>= 1; 290 /* 291 * If dir has been removed from the used map, it's either 292 * because it had the nodump flag, or it inherited it from 293 * its parent. A directory can't be in dumpinomap if 294 * not in usedinomap, but we have to go throuh it anyway 295 * to propagate the nodump attribute. 296 */ 297 nodump = (TSTINO(ino, usedinomap) == 0); 298 if ((isdir & 1) == 0 || 299 (TSTINO(ino, dumpinomap) && nodump == 0)) 300 continue; 301 302 dp = getino(ino); 303 /* 304 * inode buf may be changed in searchdir(). 305 */ 306 if (is_ufs2) 307 di.dp2 = dp->dp2; 308 else 309 di.dp1 = dp->dp1; 310 filesize = DIP(&di, size); 311 for (ret = 0, i = 0; filesize > 0 && i < NDADDR; i++) { 312 if (is_ufs2) 313 blk = iswap64(di.dp2.di_db[i]); 314 else 315 blk = iswap32(di.dp1.di_db[i]); 316 if (blk != 0) 317 ret |= searchdir(ino, blk, 318 (long)ufs_dblksize(ufsib, &di, i), 319 filesize, tape_size, nodump); 320 if (ret & HASDUMPEDFILE) 321 filesize = 0; 322 else 323 filesize -= ufsib->ufs_bsize; 324 } 325 for (i = 0; filesize > 0 && i < NIADDR; i++) { 326 if (is_ufs2) 327 blk = iswap64(di.dp2.di_ib[i]); 328 else 329 blk = iswap32(di.dp1.di_ib[i]); 330 if (blk == 0) 331 continue; 332 ret |= dirindir(ino, blk, i, &filesize, 333 tape_size, nodump); 334 } 335 if (ret & HASDUMPEDFILE) { 336 SETINO(ino, dumpinomap); 337 *tape_size += blockest(&di); 338 change = 1; 339 continue; 340 } 341 if (nodump) { 342 if (ret & HASSUBDIRS) 343 change = 1; /* subdirs have inherited nodump */ 344 CLRINO(ino, dumpdirmap); 345 } else if ((ret & HASSUBDIRS) == 0) { 346 if (!TSTINO(ino, dumpinomap)) { 347 CLRINO(ino, dumpdirmap); 348 change = 1; 349 } 350 } 351 } 352 return (change); 353} 354 355/* 356 * Read indirect blocks, and pass the data blocks to be searched 357 * as directories. Quit as soon as any entry is found that will 358 * require the directory to be dumped. 359 */ 360static int 361dirindir(ino_t ino, daddr_t blkno, int ind_level, off_t *filesize, 362 u_int64_t *tape_size, int nodump) 363{ 364 int ret = 0; 365 int i; 366 union { 367 int64_t i64[MAXBSIZE / sizeof (int64_t)]; 368 int32_t i32[MAXBSIZE / sizeof (int32_t)]; 369 } idblk; 370 371 bread(fsatoda(ufsib, blkno), (char *)&idblk, (int)ufsib->ufs_bsize); 372 if (ind_level <= 0) { 373 for (i = 0; *filesize > 0 && i < ufsib->ufs_nindir; i++) { 374 if (is_ufs2) 375 blkno = iswap64(idblk.i64[i]); 376 else 377 blkno = iswap32(idblk.i32[i]); 378 if (blkno != 0) 379 ret |= searchdir(ino, blkno, 380 ufsib->ufs_bsize, *filesize, 381 tape_size, nodump); 382 if (ret & HASDUMPEDFILE) 383 *filesize = 0; 384 else 385 *filesize -= ufsib->ufs_bsize; 386 } 387 return (ret); 388 } 389 ind_level--; 390 for (i = 0; *filesize > 0 && i < ufsib->ufs_nindir; i++) { 391 if (is_ufs2) 392 blkno = iswap64(idblk.i64[i]); 393 else 394 blkno = iswap32(idblk.i32[i]); 395 if (blkno != 0) 396 ret |= dirindir(ino, blkno, ind_level, filesize, 397 tape_size, nodump); 398 } 399 return (ret); 400} 401 402/* 403 * Scan a disk block containing directory information looking to see if 404 * any of the entries are on the dump list and to see if the directory 405 * contains any subdirectories. 406 */ 407static int 408searchdir(ino_t dino, daddr_t blkno, long size, off_t filesize, 409 u_int64_t *tape_size, int nodump) 410{ 411 struct direct *dp; 412 union dinode *ip; 413 long loc, ret = 0; 414 char *dblk; 415 ino_t ino; 416 417 dblk = malloc(size); 418 if (dblk == NULL) 419 quit("searchdir: cannot allocate directory memory.\n"); 420 bread(fsatoda(ufsib, blkno), dblk, (int)size); 421 if (filesize < size) 422 size = filesize; 423 for (loc = 0; loc < size; ) { 424 dp = (struct direct *)(dblk + loc); 425 if (dp->d_reclen == 0) { 426 msg("corrupted directory, inumber %llu\n", 427 (unsigned long long)dino); 428 break; 429 } 430 loc += iswap16(dp->d_reclen); 431 if (dp->d_ino == 0) 432 continue; 433 if (dp->d_name[0] == '.') { 434 if (dp->d_name[1] == '\0') 435 continue; 436 if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') 437 continue; 438 } 439 ino = iswap32(dp->d_ino); 440 if (nodump) { 441 ip = getino(ino); 442 if (TSTINO(ino, dumpinomap)) { 443 CLRINO(ino, dumpinomap); 444 *tape_size -= blockest(ip); 445 } 446 /* 447 * Add back to dumpdirmap and remove from usedinomap 448 * to propagate nodump. 449 */ 450 if ((DIP(ip, mode) & IFMT) == IFDIR) { 451 SETINO(ino, dumpdirmap); 452 CLRINO(ino, usedinomap); 453 ret |= HASSUBDIRS; 454 } 455 } else { 456 if (TSTINO(ino, dumpinomap)) { 457 ret |= HASDUMPEDFILE; 458 if (ret & HASSUBDIRS) 459 break; 460 } 461 if (TSTINO(ino, dumpdirmap)) { 462 ret |= HASSUBDIRS; 463 if (ret & HASDUMPEDFILE) 464 break; 465 } 466 } 467 } 468 free(dblk); 469 return (ret); 470} 471 472/* 473 * Dump passes 3 and 4. 474 * 475 * Dump the contents of an inode to tape. 476 */ 477void 478dumpino(union dinode *dp, ino_t ino) 479{ 480 int ind_level, cnt; 481 off_t size; 482 char buf[TP_BSIZE]; 483 daddr_t blk; 484 void *shortlink; 485 486 if (newtape) { 487 newtape = 0; 488 dumpmap(dumpinomap, TS_BITS, ino); 489 } 490 CLRINO(ino, dumpinomap); 491 /* 492 * Zero out the size of a snapshot so that it will be dumped 493 * as a zero length file. 494 */ 495 if (DIP(dp, flags) & SF_SNAPSHOT) { 496 DIP_SET(dp, size, 0); 497 DIP_SET(dp, flags, DIP(dp, flags) & ~SF_SNAPSHOT); 498 } 499 if (!is_ufs2) { 500 if (needswap) 501 ffs_dinode1_swap(&dp->dp1, &spcl.c_dinode); 502 else 503 spcl.c_dinode = dp->dp1; 504 } else { 505 if (needswap) 506 ffs_dinode2_swap(&dp->dp2, &dp->dp2); 507 spcl.c_mode = dp->dp2.di_mode; 508 spcl.c_size = dp->dp2.di_size; 509 spcl.c_atime = dp->dp2.di_atime; 510 spcl.c_atimensec = dp->dp2.di_atimensec; 511 spcl.c_mtime = dp->dp2.di_mtime; 512 spcl.c_mtimensec = dp->dp2.di_mtimensec; 513 spcl.c_birthtime = dp->dp2.di_birthtime; 514 spcl.c_birthtimensec = dp->dp2.di_birthnsec; 515 spcl.c_rdev = dp->dp2.di_rdev; 516 spcl.c_file_flags = dp->dp2.di_flags; 517 spcl.c_uid = dp->dp2.di_uid; 518 spcl.c_gid = dp->dp2.di_gid; 519 } 520 spcl.c_type = iswap32(TS_INODE); 521 spcl.c_count = 0; 522 switch (DIP(dp, mode) & IFMT) { 523 524 case 0: 525 /* 526 * Freed inode. 527 */ 528 return; 529 530 case IFLNK: 531 /* 532 * Check for short symbolic link. 533 */ 534 if (DIP(dp, size) > 0 && 535#ifdef FS_44INODEFMT 536 (DIP(dp, size) < ufsib->ufs_maxsymlinklen || 537 (ufsib->ufs_maxsymlinklen == 0 && DIP(dp, blocks) == 0)) 538#else 539 DIP(dp, blocks) == 0 540#endif 541 ) { 542 spcl.c_addr[0] = 1; 543 spcl.c_count = iswap32(1); 544 writeheader(ino); 545 if (is_ufs2) 546 shortlink = dp->dp2.di_db; 547 else 548 shortlink = dp->dp1.di_db; 549 memmove(buf, shortlink, DIP(dp, size)); 550 buf[DIP(dp, size)] = '\0'; 551 writerec(buf, 0); 552 return; 553 } 554 /* fall through */ 555 556 case IFDIR: 557 case IFREG: 558 if (DIP(dp, size) > 0) 559 break; 560 /* fall through */ 561 562 case IFIFO: 563 case IFSOCK: 564 case IFCHR: 565 case IFBLK: 566 writeheader(ino); 567 return; 568 569 default: 570 msg("Warning: undefined file type 0%o\n", DIP(dp, mode) & IFMT); 571 return; 572 } 573 if (DIP(dp, size) > NDADDR * ufsib->ufs_bsize) 574 cnt = NDADDR * ufsib->ufs_frag; 575 else 576 cnt = howmany(DIP(dp, size), ufsib->ufs_fsize); 577 if (is_ufs2) 578 blksout64(&dp->dp2.di_db[0], cnt, ino); 579 else 580 blksout32(&dp->dp1.di_db[0], cnt, ino); 581 582 if ((size = DIP(dp, size) - NDADDR * ufsib->ufs_bsize) <= 0) 583 return; 584 for (ind_level = 0; ind_level < NIADDR; ind_level++) { 585 if (is_ufs2) 586 blk = iswap64(dp->dp2.di_ib[ind_level]); 587 else 588 blk = iswap32(dp->dp1.di_ib[ind_level]); 589 dmpindir(ino, blk, ind_level, &size); 590 if (size <= 0) 591 return; 592 } 593} 594 595/* 596 * Read indirect blocks, and pass the data blocks to be dumped. 597 */ 598static void 599dmpindir(ino_t ino, daddr_t blk, int ind_level, off_t *size) 600{ 601 int i, cnt; 602 union { 603 int32_t i32[MAXBSIZE / sizeof (int32_t)]; 604 int64_t i64[MAXBSIZE / sizeof (int64_t)]; 605 } idblk; 606 daddr_t iblk; 607 608 609 if (blk != 0) 610 bread(fsatoda(ufsib, blk), (char *)&idblk, 611 (int) ufsib->ufs_bsize); 612 else 613 memset(&idblk, 0, (int)ufsib->ufs_bsize); 614 if (ind_level <= 0) { 615 if (*size < ufsib->ufs_nindir * ufsib->ufs_bsize) 616 cnt = howmany(*size, ufsib->ufs_fsize); 617 else 618 cnt = ufsib->ufs_nindir * ufsib->ufs_frag; 619 *size -= ufsib->ufs_nindir * ufsib->ufs_bsize; 620 if (is_ufs2) 621 blksout64(&idblk.i64[0], cnt, ino); 622 else 623 blksout32(&idblk.i32[0], cnt, ino); 624 return; 625 } 626 ind_level--; 627 for (i = 0; i < ufsib->ufs_nindir; i++) { 628 if (is_ufs2) 629 iblk = iswap64(idblk.i64[i]); 630 else 631 iblk = iswap32(idblk.i32[i]); 632 dmpindir(ino, iblk, ind_level, size); 633 if (*size <= 0) 634 return; 635 } 636} 637 638/* 639 * Collect up the data into tape record sized buffers and output them. 640 */ 641void 642blksout32(int32_t *blkp, int frags, ino_t ino) 643{ 644 int32_t *bp; 645 int i, j, count, blks, tbperdb; 646 647 blks = howmany(frags * ufsib->ufs_fsize, TP_BSIZE); 648 tbperdb = ufsib->ufs_bsize >> tp_bshift; 649 for (i = 0; i < blks; i += TP_NINDIR) { 650 if (i + TP_NINDIR > blks) 651 count = blks; 652 else 653 count = i + TP_NINDIR; 654 for (j = i; j < count; j++) 655 if (blkp[j / tbperdb] != 0) 656 spcl.c_addr[j - i] = 1; 657 else 658 spcl.c_addr[j - i] = 0; 659 spcl.c_count = iswap32(count - i); 660 writeheader(ino); 661 bp = &blkp[i / tbperdb]; 662 for (j = i; j < count; j += tbperdb, bp++) 663 if (*bp != 0) { 664 if (j + tbperdb <= count) 665 dumpblock(iswap32(*bp), (int)ufsib->ufs_bsize); 666 else 667 dumpblock(iswap32(*bp), (count - j) * TP_BSIZE); 668 } 669 spcl.c_type = iswap32(TS_ADDR); 670 } 671} 672 673void 674blksout64(int64_t *blkp, int frags, ino_t ino) 675{ 676 int64_t *bp; 677 int i, j, count, blks, tbperdb; 678 679 blks = howmany(frags * ufsib->ufs_fsize, TP_BSIZE); 680 tbperdb = ufsib->ufs_bsize >> tp_bshift; 681 for (i = 0; i < blks; i += TP_NINDIR) { 682 if (i + TP_NINDIR > blks) 683 count = blks; 684 else 685 count = i + TP_NINDIR; 686 for (j = i; j < count; j++) 687 if (blkp[j / tbperdb] != 0) 688 spcl.c_addr[j - i] = 1; 689 else 690 spcl.c_addr[j - i] = 0; 691 spcl.c_count = iswap32(count - i); 692 writeheader(ino); 693 bp = &blkp[i / tbperdb]; 694 for (j = i; j < count; j += tbperdb, bp++) 695 if (*bp != 0) { 696 if (j + tbperdb <= count) 697 dumpblock(iswap64(*bp), (int)ufsib->ufs_bsize); 698 else 699 dumpblock(iswap64(*bp), (count - j) * TP_BSIZE); 700 } 701 spcl.c_type = iswap32(TS_ADDR); 702 } 703} 704 705/* 706 * Dump a map to the tape. 707 */ 708void 709dumpmap(char *map, int type, ino_t ino) 710{ 711 int i; 712 char *cp; 713 714 spcl.c_type = iswap32(type); 715 spcl.c_count = iswap32(howmany(mapsize * sizeof(char), TP_BSIZE)); 716 writeheader(ino); 717 for (i = 0, cp = map; i < iswap32(spcl.c_count); i++, cp += TP_BSIZE) 718 writerec(cp, 0); 719} 720 721/* 722 * Write a header record to the dump tape. 723 */ 724void 725writeheader(ino_t ino) 726{ 727 int32_t sum, cnt, *lp; 728 729 spcl.c_inumber = iswap32(ino); 730 if (is_ufs2) 731 spcl.c_magic = iswap32(FS_UFS2_MAGIC); 732 else { 733 spcl.c_magic = iswap32(NFS_MAGIC); 734 spcl.c_old_date = iswap32(iswap64(spcl.c_date)); 735 spcl.c_old_ddate = iswap32(iswap64(spcl.c_ddate)); 736 spcl.c_old_tapea = iswap32(iswap64(spcl.c_tapea)); 737 spcl.c_old_firstrec = iswap32(iswap64(spcl.c_firstrec)); 738 } 739 spcl.c_checksum = 0; 740 lp = (int32_t *)&spcl; 741 sum = 0; 742 cnt = sizeof(union u_spcl) / (4 * sizeof(int32_t)); 743 while (--cnt >= 0) { 744 sum += iswap32(*lp++); 745 sum += iswap32(*lp++); 746 sum += iswap32(*lp++); 747 sum += iswap32(*lp++); 748 } 749 spcl.c_checksum = iswap32(CHECKSUM - sum); 750 writerec((char *)&spcl, 1); 751} 752