1 /* $NetBSD: traverse.c,v 1.52 2019/03/01 16:42:11 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.52 2019/03/01 16:42:11 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 /* FALLTHROUGH */ 203 case FTS_DP: /* already seen dir */ 204 continue; 205 } 206 mapfileino(entry->fts_statp->st_ino, tape_size, 207 &anydirskipped); 208 } 209 (void)fts_close(dirh); 210 211 /* 212 * Add any parent directories 213 */ 214 for (d = 0 ; dirv[d] != NULL ; d++) { 215 char path[MAXPATHLEN]; 216 217 if (dirv[d][0] != '/') 218 (void)snprintf(path, sizeof(path), "%s/%s", 219 curdir, dirv[d]); 220 else 221 (void)snprintf(path, sizeof(path), "%s", 222 dirv[d]); 223 while (strcmp(path, diskname) != 0) { 224 char *p; 225 struct stat sb; 226 227 if (*path == '\0') 228 break; 229 if ((p = strrchr(path, '/')) == NULL) 230 break; 231 if (p == path) 232 break; 233 *p = '\0'; 234 if (stat(path, &sb) == -1) { 235 msg("Can't stat %s: %s\n", path, 236 strerror(errno)); 237 break; 238 } 239 mapfileino(sb.st_ino, tape_size, &anydirskipped); 240 } 241 } 242 243 /* 244 * Ensure that the root inode actually appears in the 245 * file list for a subdir 246 */ 247 mapfileino(UFS_ROOTINO, tape_size, &anydirskipped); 248 } else { 249 fs_mapinodes(maxino, tape_size, &anydirskipped); 250 } 251 /* 252 * Restore gets very upset if the root is not dumped, 253 * so ensure that it always is dumped. 254 */ 255 SETINO(UFS_ROOTINO, dumpinomap); 256 return (anydirskipped); 257 } 258 259 /* 260 * Dump pass 2. 261 * 262 * Scan each directory on the file system to see if it has any modified 263 * files in it. If it does, and has not already been added to the dump 264 * list (because it was itself modified), then add it. If a directory 265 * has not been modified itself, contains no modified files and has no 266 * subdirectories, then it can be deleted from the dump list and from 267 * the list of directories. By deleting it from the list of directories, 268 * its parent may now qualify for the same treatment on this or a later 269 * pass using this algorithm. 270 */ 271 int 272 mapdirs(ino_t maxino, u_int64_t *tape_size) 273 { 274 union dinode *dp, di; 275 int i, isdir, nodump; 276 char *map; 277 ino_t ino; 278 off_t filesize; 279 int ret, change = 0; 280 daddr_t blk; 281 282 isdir = 0; /* XXX just to get gcc to shut up */ 283 for (map = dumpdirmap, ino = 1; ino < maxino; ino++) { 284 if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */ 285 isdir = *map++; 286 else 287 isdir >>= 1; 288 /* 289 * If dir has been removed from the used map, it's either 290 * because it had the nodump flag, or it inherited it from 291 * its parent. A directory can't be in dumpinomap if 292 * not in usedinomap, but we have to go throuh it anyway 293 * to propagate the nodump attribute. 294 */ 295 nodump = (TSTINO(ino, usedinomap) == 0); 296 if ((isdir & 1) == 0 || 297 (TSTINO(ino, dumpinomap) && nodump == 0)) 298 continue; 299 300 dp = getino(ino); 301 /* 302 * inode buf may be changed in searchdir(). 303 */ 304 if (is_ufs2) 305 di.dp2 = dp->dp2; 306 else 307 di.dp1 = dp->dp1; 308 filesize = DIP(&di, size); 309 for (ret = 0, i = 0; filesize > 0 && i < UFS_NDADDR; i++) { 310 if (is_ufs2) 311 blk = iswap64(di.dp2.di_db[i]); 312 else 313 blk = iswap32(di.dp1.di_db[i]); 314 if (blk != 0) 315 ret |= searchdir(ino, blk, 316 (long)ufs_dblksize(ufsib, &di, i), 317 filesize, tape_size, nodump); 318 if (ret & HASDUMPEDFILE) 319 filesize = 0; 320 else 321 filesize -= ufsib->ufs_bsize; 322 } 323 for (i = 0; filesize > 0 && i < UFS_NIADDR; i++) { 324 if (is_ufs2) 325 blk = iswap64(di.dp2.di_ib[i]); 326 else 327 blk = iswap32(di.dp1.di_ib[i]); 328 if (blk == 0) 329 continue; 330 ret |= dirindir(ino, blk, i, &filesize, 331 tape_size, nodump); 332 } 333 if (ret & HASDUMPEDFILE) { 334 SETINO(ino, dumpinomap); 335 *tape_size += blockest(&di); 336 change = 1; 337 continue; 338 } 339 if (nodump) { 340 if (ret & HASSUBDIRS) 341 change = 1; /* subdirs have inherited nodump */ 342 CLRINO(ino, dumpdirmap); 343 } else if ((ret & HASSUBDIRS) == 0) { 344 if (!TSTINO(ino, dumpinomap)) { 345 CLRINO(ino, dumpdirmap); 346 change = 1; 347 } 348 } 349 } 350 return (change); 351 } 352 353 /* 354 * Read indirect blocks, and pass the data blocks to be searched 355 * as directories. Quit as soon as any entry is found that will 356 * require the directory to be dumped. 357 */ 358 static int 359 dirindir(ino_t ino, daddr_t blkno, int ind_level, off_t *filesize, 360 u_int64_t *tape_size, int nodump) 361 { 362 int ret = 0; 363 int i; 364 union { 365 int64_t i64[MAXBSIZE / sizeof (int64_t)]; 366 int32_t i32[MAXBSIZE / sizeof (int32_t)]; 367 } idblk; 368 369 bread(fsatoda(ufsib, blkno), (char *)&idblk, (int)ufsib->ufs_bsize); 370 if (ind_level <= 0) { 371 for (i = 0; *filesize > 0 && i < ufsib->ufs_nindir; i++) { 372 if (is_ufs2) 373 blkno = iswap64(idblk.i64[i]); 374 else 375 blkno = iswap32(idblk.i32[i]); 376 if (blkno != 0) 377 ret |= searchdir(ino, blkno, 378 ufsib->ufs_bsize, *filesize, 379 tape_size, nodump); 380 if (ret & HASDUMPEDFILE) 381 *filesize = 0; 382 else 383 *filesize -= ufsib->ufs_bsize; 384 } 385 return (ret); 386 } 387 ind_level--; 388 for (i = 0; *filesize > 0 && i < ufsib->ufs_nindir; i++) { 389 if (is_ufs2) 390 blkno = iswap64(idblk.i64[i]); 391 else 392 blkno = iswap32(idblk.i32[i]); 393 if (blkno != 0) 394 ret |= dirindir(ino, blkno, ind_level, filesize, 395 tape_size, nodump); 396 } 397 return (ret); 398 } 399 400 /* 401 * Scan a disk block containing directory information looking to see if 402 * any of the entries are on the dump list and to see if the directory 403 * contains any subdirectories. 404 */ 405 static int 406 searchdir(ino_t dino, daddr_t blkno, long size, off_t filesize, 407 u_int64_t *tape_size, int nodump) 408 { 409 struct direct *dp; 410 union dinode *ip; 411 long loc, ret = 0; 412 char *dblk; 413 ino_t ino; 414 415 dblk = malloc(size); 416 if (dblk == NULL) 417 quit("%s: cannot allocate directory memory", __func__); 418 bread(fsatoda(ufsib, blkno), dblk, (int)size); 419 if (filesize < size) 420 size = filesize; 421 for (loc = 0; loc < size; ) { 422 dp = (struct direct *)(dblk + loc); 423 if (dp->d_reclen == 0) { 424 msg("corrupted directory, inumber %llu\n", 425 (unsigned long long)dino); 426 break; 427 } 428 loc += iswap16(dp->d_reclen); 429 if (dp->d_ino == 0) 430 continue; 431 if (dp->d_name[0] == '.') { 432 if (dp->d_name[1] == '\0') 433 continue; 434 if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') 435 continue; 436 } 437 ino = iswap32(dp->d_ino); 438 if (nodump) { 439 ip = getino(ino); 440 if (TSTINO(ino, dumpinomap)) { 441 CLRINO(ino, dumpinomap); 442 *tape_size -= blockest(ip); 443 } 444 /* 445 * Add back to dumpdirmap and remove from usedinomap 446 * to propagate nodump. 447 */ 448 if ((DIP(ip, mode) & IFMT) == IFDIR) { 449 SETINO(ino, dumpdirmap); 450 CLRINO(ino, usedinomap); 451 ret |= HASSUBDIRS; 452 } 453 } else { 454 if (TSTINO(ino, dumpinomap)) { 455 ret |= HASDUMPEDFILE; 456 if (ret & HASSUBDIRS) 457 break; 458 } 459 if (TSTINO(ino, dumpdirmap)) { 460 ret |= HASSUBDIRS; 461 if (ret & HASDUMPEDFILE) 462 break; 463 } 464 } 465 } 466 free(dblk); 467 return (ret); 468 } 469 470 /* 471 * Dump passes 3 and 4. 472 * 473 * Dump the contents of an inode to tape. 474 */ 475 void 476 dumpino(union dinode *dp, ino_t ino) 477 { 478 int ind_level, cnt; 479 off_t size; 480 char buf[TP_BSIZE]; 481 daddr_t blk; 482 void *shortlink; 483 484 if (newtape) { 485 newtape = 0; 486 dumpmap(dumpinomap, TS_BITS, ino); 487 } 488 CLRINO(ino, dumpinomap); 489 /* 490 * Zero out the size of a snapshot so that it will be dumped 491 * as a zero length file. 492 */ 493 if (DIP(dp, flags) & SF_SNAPSHOT) { 494 DIP_SET(dp, size, 0); 495 DIP_SET(dp, flags, DIP(dp, flags) & ~SF_SNAPSHOT); 496 } 497 if (!is_ufs2) { 498 if (needswap) 499 ffs_dinode1_swap(&dp->dp1, &spcl.c_dinode); 500 else 501 spcl.c_dinode = dp->dp1; 502 } else { 503 if (needswap) 504 ffs_dinode2_swap(&dp->dp2, &dp->dp2); 505 spcl.c_mode = dp->dp2.di_mode; 506 spcl.c_size = dp->dp2.di_size; 507 spcl.c_atime = dp->dp2.di_atime; 508 spcl.c_atimensec = dp->dp2.di_atimensec; 509 spcl.c_mtime = dp->dp2.di_mtime; 510 spcl.c_mtimensec = dp->dp2.di_mtimensec; 511 spcl.c_birthtime = dp->dp2.di_birthtime; 512 spcl.c_birthtimensec = dp->dp2.di_birthnsec; 513 spcl.c_rdev = dp->dp2.di_rdev; 514 spcl.c_file_flags = dp->dp2.di_flags; 515 spcl.c_uid = dp->dp2.di_uid; 516 spcl.c_gid = dp->dp2.di_gid; 517 } 518 spcl.c_type = iswap32(TS_INODE); 519 spcl.c_count = 0; 520 switch (DIP(dp, mode) & IFMT) { 521 522 case 0: 523 /* 524 * Freed inode. 525 */ 526 return; 527 528 case IFLNK: 529 /* 530 * Check for short symbolic link. 531 */ 532 if (DIP(dp, size) > 0 && 533 #ifdef FS_44INODEFMT 534 (DIP(dp, size) < ufsib->ufs_maxsymlinklen || 535 (ufsib->ufs_maxsymlinklen == 0 && DIP(dp, blocks) == 0)) 536 #else 537 DIP(dp, blocks) == 0 538 #endif 539 ) { 540 spcl.c_addr[0] = 1; 541 spcl.c_count = iswap32(1); 542 writeheader(ino); 543 if (is_ufs2) 544 shortlink = dp->dp2.di_db; 545 else 546 shortlink = dp->dp1.di_db; 547 memmove(buf, shortlink, DIP(dp, size)); 548 buf[DIP(dp, size)] = '\0'; 549 writerec(buf, 0); 550 return; 551 } 552 /* fall through */ 553 554 case IFDIR: 555 case IFREG: 556 if (DIP(dp, size) > 0) 557 break; 558 /* fall through */ 559 560 case IFIFO: 561 case IFSOCK: 562 case IFCHR: 563 case IFBLK: 564 writeheader(ino); 565 return; 566 567 default: 568 msg("Warning: undefined file type 0%o\n", DIP(dp, mode) & IFMT); 569 return; 570 } 571 if (DIP(dp, size) > UFS_NDADDR * ufsib->ufs_bsize) 572 cnt = UFS_NDADDR * ufsib->ufs_frag; 573 else 574 cnt = howmany(DIP(dp, size), ufsib->ufs_fsize); 575 if (is_ufs2) 576 blksout64(&dp->dp2.di_db[0], cnt, ino); 577 else 578 blksout32(&dp->dp1.di_db[0], cnt, ino); 579 580 if ((size = DIP(dp, size) - UFS_NDADDR * ufsib->ufs_bsize) <= 0) 581 return; 582 for (ind_level = 0; ind_level < UFS_NIADDR; ind_level++) { 583 if (is_ufs2) 584 blk = iswap64(dp->dp2.di_ib[ind_level]); 585 else 586 blk = iswap32(dp->dp1.di_ib[ind_level]); 587 dmpindir(ino, blk, ind_level, &size); 588 if (size <= 0) 589 return; 590 } 591 } 592 593 /* 594 * Read indirect blocks, and pass the data blocks to be dumped. 595 */ 596 static void 597 dmpindir(ino_t ino, daddr_t blk, int ind_level, off_t *size) 598 { 599 int i, cnt; 600 union { 601 int32_t i32[MAXBSIZE / sizeof (int32_t)]; 602 int64_t i64[MAXBSIZE / sizeof (int64_t)]; 603 } idblk; 604 daddr_t iblk; 605 606 607 if (blk != 0) 608 bread(fsatoda(ufsib, blk), (char *)&idblk, 609 (int) ufsib->ufs_bsize); 610 else 611 memset(&idblk, 0, (int)ufsib->ufs_bsize); 612 if (ind_level <= 0) { 613 if (*size < ufsib->ufs_nindir * ufsib->ufs_bsize) 614 cnt = howmany(*size, ufsib->ufs_fsize); 615 else 616 cnt = ufsib->ufs_nindir * ufsib->ufs_frag; 617 *size -= ufsib->ufs_nindir * ufsib->ufs_bsize; 618 if (is_ufs2) 619 blksout64(&idblk.i64[0], cnt, ino); 620 else 621 blksout32(&idblk.i32[0], cnt, ino); 622 return; 623 } 624 ind_level--; 625 for (i = 0; i < ufsib->ufs_nindir; i++) { 626 if (is_ufs2) 627 iblk = iswap64(idblk.i64[i]); 628 else 629 iblk = iswap32(idblk.i32[i]); 630 dmpindir(ino, iblk, ind_level, size); 631 if (*size <= 0) 632 return; 633 } 634 } 635 636 /* 637 * Collect up the data into tape record sized buffers and output them. 638 */ 639 void 640 blksout32(int32_t *blkp, int frags, ino_t ino) 641 { 642 int32_t *bp; 643 int i, j, count, blks, tbperdb; 644 645 blks = howmany(frags * ufsib->ufs_fsize, TP_BSIZE); 646 tbperdb = ufsib->ufs_bsize >> tp_bshift; 647 for (i = 0; i < blks; i += TP_NINDIR) { 648 if (i + TP_NINDIR > blks) 649 count = blks; 650 else 651 count = i + TP_NINDIR; 652 for (j = i; j < count; j++) 653 if (blkp[j / tbperdb] != 0) 654 spcl.c_addr[j - i] = 1; 655 else 656 spcl.c_addr[j - i] = 0; 657 spcl.c_count = iswap32(count - i); 658 writeheader(ino); 659 bp = &blkp[i / tbperdb]; 660 for (j = i; j < count; j += tbperdb, bp++) 661 if (*bp != 0) { 662 if (j + tbperdb <= count) 663 dumpblock(iswap32(*bp), (int)ufsib->ufs_bsize); 664 else 665 dumpblock(iswap32(*bp), (count - j) * TP_BSIZE); 666 } 667 spcl.c_type = iswap32(TS_ADDR); 668 } 669 } 670 671 void 672 blksout64(int64_t *blkp, int frags, ino_t ino) 673 { 674 int64_t *bp; 675 int i, j, count, blks, tbperdb; 676 677 blks = howmany(frags * ufsib->ufs_fsize, TP_BSIZE); 678 tbperdb = ufsib->ufs_bsize >> tp_bshift; 679 for (i = 0; i < blks; i += TP_NINDIR) { 680 if (i + TP_NINDIR > blks) 681 count = blks; 682 else 683 count = i + TP_NINDIR; 684 for (j = i; j < count; j++) 685 if (blkp[j / tbperdb] != 0) 686 spcl.c_addr[j - i] = 1; 687 else 688 spcl.c_addr[j - i] = 0; 689 spcl.c_count = iswap32(count - i); 690 writeheader(ino); 691 bp = &blkp[i / tbperdb]; 692 for (j = i; j < count; j += tbperdb, bp++) 693 if (*bp != 0) { 694 if (j + tbperdb <= count) 695 dumpblock(iswap64(*bp), (int)ufsib->ufs_bsize); 696 else 697 dumpblock(iswap64(*bp), (count - j) * TP_BSIZE); 698 } 699 spcl.c_type = iswap32(TS_ADDR); 700 } 701 } 702 703 /* 704 * Dump a map to the tape. 705 */ 706 void 707 dumpmap(char *map, int type, ino_t ino) 708 { 709 int i; 710 char *cp; 711 712 spcl.c_type = iswap32(type); 713 spcl.c_count = iswap32(howmany(mapsize * sizeof(char), TP_BSIZE)); 714 writeheader(ino); 715 for (i = 0, cp = map; i < iswap32(spcl.c_count); i++, cp += TP_BSIZE) 716 writerec(cp, 0); 717 } 718 719 /* 720 * Write a header record to the dump tape. 721 */ 722 void 723 writeheader(ino_t ino) 724 { 725 int32_t sum, cnt, *lp; 726 727 spcl.c_inumber = iswap32(ino); 728 if (is_ufs2) 729 spcl.c_magic = iswap32(FS_UFS2_MAGIC); 730 else { 731 spcl.c_magic = iswap32(NFS_MAGIC); 732 spcl.c_old_date = iswap32(iswap64(spcl.c_date)); 733 spcl.c_old_ddate = iswap32(iswap64(spcl.c_ddate)); 734 spcl.c_old_tapea = iswap32(iswap64(spcl.c_tapea)); 735 spcl.c_old_firstrec = iswap32(iswap64(spcl.c_firstrec)); 736 } 737 spcl.c_checksum = 0; 738 lp = (int32_t *)&spcl; 739 sum = 0; 740 cnt = sizeof(union u_spcl) / (4 * sizeof(int32_t)); 741 while (--cnt >= 0) { 742 sum += iswap32(*lp++); 743 sum += iswap32(*lp++); 744 sum += iswap32(*lp++); 745 sum += iswap32(*lp++); 746 } 747 spcl.c_checksum = iswap32(CHECKSUM - sum); 748 writerec((char *)&spcl, 1); 749 } 750