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