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