1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 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 #ifndef lint 33 #endif /* not lint */ 34 35 #include <sys/param.h> 36 #include <sys/stat.h> 37 38 #include <ufs/ufs/dir.h> 39 #include <ufs/ufs/dinode.h> 40 #include <ufs/ffs/fs.h> 41 42 #include <protocols/dumprestore.h> 43 44 #include <assert.h> 45 #include <ctype.h> 46 #include <errno.h> 47 #include <inttypes.h> 48 #include <limits.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <timeconv.h> 53 #include <unistd.h> 54 55 #include "dump.h" 56 57 union dinode { 58 struct ufs1_dinode dp1; 59 struct ufs2_dinode dp2; 60 }; 61 #define DIP(dp, field) \ 62 ((sblock->fs_magic == FS_UFS1_MAGIC) ? \ 63 (dp)->dp1.field : (dp)->dp2.field) 64 #define DIP_SET(dp, field, val) do {\ 65 if (sblock->fs_magic == FS_UFS1_MAGIC) \ 66 (dp)->dp1.field = (val); \ 67 else \ 68 (dp)->dp2.field = (val); \ 69 } while (0) 70 71 #define HASDUMPEDFILE 0x1 72 #define HASSUBDIRS 0x2 73 74 static int dirindir(ino_t ino, ufs2_daddr_t blkno, int level, long *size, 75 long *tapesize, int nodump, ino_t maxino); 76 static void dmpindir(union dinode *dp, ino_t ino, ufs2_daddr_t blk, int level, 77 off_t *size); 78 static void ufs1_blksout(ufs1_daddr_t *blkp, int frags, ino_t ino); 79 static void ufs2_blksout(union dinode *dp, ufs2_daddr_t *blkp, int frags, 80 ino_t ino, int last); 81 static int appendextdata(union dinode *dp); 82 static void writeextdata(union dinode *dp, ino_t ino, int added); 83 static int searchdir(ino_t ino, ufs2_daddr_t blkno, long size, long filesize, 84 long *tapesize, int nodump, ino_t maxino); 85 static long blockest(union dinode *dp); 86 87 /* 88 * This is an estimation of the number of TP_BSIZE blocks in the file. 89 * It estimates the number of blocks in files with holes by assuming 90 * that all of the blocks accounted for by di_blocks are data blocks 91 * (when some of the blocks are usually used for indirect pointers); 92 * hence the estimate may be high. 93 */ 94 static long 95 blockest(union dinode *dp) 96 { 97 long blkest, sizeest; 98 99 /* 100 * dp->di_size is the size of the file in bytes. 101 * dp->di_blocks stores the number of sectors actually in the file. 102 * If there are more sectors than the size would indicate, this just 103 * means that there are indirect blocks in the file or unused 104 * sectors in the last file block; we can safely ignore these 105 * (blkest = sizeest below). 106 * If the file is bigger than the number of sectors would indicate, 107 * then the file has holes in it. In this case we must use the 108 * block count to estimate the number of data blocks used, but 109 * we use the actual size for estimating the number of indirect 110 * dump blocks (sizeest vs. blkest in the indirect block 111 * calculation). 112 */ 113 if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0) 114 return (1); 115 blkest = howmany(dbtob(DIP(dp, di_blocks)), TP_BSIZE); 116 sizeest = howmany(DIP(dp, di_size), TP_BSIZE); 117 if (blkest > sizeest) 118 blkest = sizeest; 119 if (DIP(dp, di_size) > sblock->fs_bsize * UFS_NDADDR) { 120 /* calculate the number of indirect blocks on the dump tape */ 121 blkest += howmany(sizeest - 122 UFS_NDADDR * sblock->fs_bsize / TP_BSIZE, TP_NINDIR); 123 } 124 return (blkest + 1); 125 } 126 127 /* Auxiliary macro to pick up files changed since previous dump. */ 128 #define CHANGEDSINCE(dp, t) \ 129 (DIP(dp, di_mtime) >= (t) || DIP(dp, di_ctime) >= (t)) 130 131 /* The WANTTODUMP macro decides whether a file should be dumped. */ 132 #ifdef UF_NODUMP 133 #define WANTTODUMP(dp) \ 134 (CHANGEDSINCE(dp, spcl.c_ddate) && \ 135 (nonodump || (DIP(dp, di_flags) & UF_NODUMP) != UF_NODUMP)) 136 #else 137 #define WANTTODUMP(dp) CHANGEDSINCE(dp, spcl.c_ddate) 138 #endif 139 140 /* 141 * Dump pass 1. 142 * 143 * Walk the inode list for a file system to find all allocated inodes 144 * that have been modified since the previous dump time. Also, find all 145 * the directories in the file system. 146 */ 147 int 148 mapfiles(ino_t maxino, long *tapesize) 149 { 150 int i, cg, mode, inosused; 151 int anydirskipped = 0; 152 union dinode *dp; 153 struct cg *cgp; 154 ino_t ino; 155 u_char *cp; 156 157 if ((cgp = malloc(sblock->fs_cgsize)) == NULL) 158 quit("mapfiles: cannot allocate memory.\n"); 159 for (cg = 0; cg < sblock->fs_ncg; cg++) { 160 ino = cg * sblock->fs_ipg; 161 blkread(fsbtodb(sblock, cgtod(sblock, cg)), (char *)cgp, 162 sblock->fs_cgsize); 163 if (sblock->fs_magic == FS_UFS2_MAGIC) 164 inosused = cgp->cg_initediblk; 165 else 166 inosused = sblock->fs_ipg; 167 /* 168 * If we are using soft updates, then we can trust the 169 * cylinder group inode allocation maps to tell us which 170 * inodes are allocated. We will scan the used inode map 171 * to find the inodes that are really in use, and then 172 * read only those inodes in from disk. 173 */ 174 if (sblock->fs_flags & FS_DOSOFTDEP) { 175 if (!cg_chkmagic(cgp)) 176 quit("mapfiles: cg %d: bad magic number\n", cg); 177 cp = &cg_inosused(cgp)[(inosused - 1) / CHAR_BIT]; 178 for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) { 179 if (*cp == 0) 180 continue; 181 for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) { 182 if (*cp & i) 183 break; 184 inosused--; 185 } 186 break; 187 } 188 if (inosused <= 0) 189 continue; 190 } 191 for (i = 0; i < inosused; i++, ino++) { 192 if (ino < UFS_ROOTINO || 193 (dp = getino(ino, &mode)) == NULL || 194 (mode & IFMT) == 0) 195 continue; 196 if (ino >= maxino) { 197 msg("Skipping inode %ju >= maxino %ju\n", 198 (uintmax_t)ino, (uintmax_t)maxino); 199 continue; 200 } 201 /* 202 * Everything must go in usedinomap so that a check 203 * for "in dumpdirmap but not in usedinomap" to detect 204 * dirs with nodump set has a chance of succeeding 205 * (this is used in mapdirs()). 206 */ 207 SETINO(ino, usedinomap); 208 if (mode == IFDIR) 209 SETINO(ino, dumpdirmap); 210 if (WANTTODUMP(dp)) { 211 SETINO(ino, dumpinomap); 212 if (mode != IFREG && 213 mode != IFDIR && 214 mode != IFLNK) 215 *tapesize += 1; 216 else 217 *tapesize += blockest(dp); 218 continue; 219 } 220 if (mode == IFDIR) { 221 if (!nonodump && 222 (DIP(dp, di_flags) & UF_NODUMP)) 223 CLRINO(ino, usedinomap); 224 anydirskipped = 1; 225 } 226 } 227 } 228 /* 229 * Restore gets very upset if the root is not dumped, 230 * so ensure that it always is dumped. 231 */ 232 SETINO(UFS_ROOTINO, dumpinomap); 233 return (anydirskipped); 234 } 235 236 /* 237 * Dump pass 2. 238 * 239 * Scan each directory on the file system to see if it has any modified 240 * files in it. If it does, and has not already been added to the dump 241 * list (because it was itself modified), then add it. If a directory 242 * has not been modified itself, contains no modified files and has no 243 * subdirectories, then it can be deleted from the dump list and from 244 * the list of directories. By deleting it from the list of directories, 245 * its parent may now qualify for the same treatment on this or a later 246 * pass using this algorithm. 247 */ 248 int 249 mapdirs(ino_t maxino, long *tapesize) 250 { 251 union dinode *dp; 252 int i, isdir, nodump; 253 char *map; 254 ino_t ino; 255 union dinode di; 256 long filesize; 257 int ret, change = 0; 258 259 isdir = 0; /* XXX just to get gcc to shut up */ 260 for (map = dumpdirmap, ino = 1; ino < maxino; ino++) { 261 if (((ino - 1) % CHAR_BIT) == 0) /* map is offset by 1 */ 262 isdir = *map++; 263 else 264 isdir >>= 1; 265 /* 266 * If a directory has been removed from usedinomap, it 267 * either has the nodump flag set, or has inherited 268 * it. Although a directory can't be in dumpinomap if 269 * it isn't in usedinomap, we have to go through it to 270 * propagate the nodump flag. 271 */ 272 nodump = !nonodump && (TSTINO(ino, usedinomap) == 0); 273 if ((isdir & 1) == 0 || (TSTINO(ino, dumpinomap) && !nodump)) 274 continue; 275 dp = getino(ino, &i); 276 /* 277 * inode buf may change in searchdir(). 278 */ 279 if (sblock->fs_magic == FS_UFS1_MAGIC) 280 di.dp1 = dp->dp1; 281 else 282 di.dp2 = dp->dp2; 283 filesize = DIP(&di, di_size); 284 for (ret = 0, i = 0; filesize > 0 && i < UFS_NDADDR; i++) { 285 if (DIP(&di, di_db[i]) != 0) 286 ret |= searchdir(ino, DIP(&di, di_db[i]), 287 (long)sblksize(sblock, DIP(&di, di_size), 288 i), filesize, tapesize, nodump, maxino); 289 if (ret & HASDUMPEDFILE) 290 filesize = 0; 291 else 292 filesize -= sblock->fs_bsize; 293 } 294 for (i = 0; filesize > 0 && i < UFS_NIADDR; i++) { 295 if (DIP(&di, di_ib[i]) == 0) 296 continue; 297 ret |= dirindir(ino, DIP(&di, di_ib[i]), i, &filesize, 298 tapesize, nodump, maxino); 299 } 300 if (ret & HASDUMPEDFILE) { 301 SETINO(ino, dumpinomap); 302 *tapesize += blockest(&di); 303 change = 1; 304 continue; 305 } 306 if (nodump) { 307 if (ret & HASSUBDIRS) 308 change = 1; /* subdirs inherit nodump */ 309 CLRINO(ino, dumpdirmap); 310 } else if ((ret & HASSUBDIRS) == 0) 311 if (!TSTINO(ino, dumpinomap)) { 312 CLRINO(ino, dumpdirmap); 313 change = 1; 314 } 315 } 316 return (change); 317 } 318 319 /* 320 * Read indirect blocks, and pass the data blocks to be searched 321 * as directories. Quit as soon as any entry is found that will 322 * require the directory to be dumped. 323 */ 324 static int 325 dirindir( 326 ino_t ino, 327 ufs2_daddr_t blkno, 328 int ind_level, 329 long *filesize, 330 long *tapesize, 331 int nodump, 332 ino_t maxino) 333 { 334 union { 335 ufs1_daddr_t ufs1[MAXBSIZE / sizeof(ufs1_daddr_t)]; 336 ufs2_daddr_t ufs2[MAXBSIZE / sizeof(ufs2_daddr_t)]; 337 } idblk; 338 int ret = 0; 339 int i; 340 341 blkread(fsbtodb(sblock, blkno), (char *)&idblk, (int)sblock->fs_bsize); 342 if (ind_level <= 0) { 343 for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) { 344 if (sblock->fs_magic == FS_UFS1_MAGIC) 345 blkno = idblk.ufs1[i]; 346 else 347 blkno = idblk.ufs2[i]; 348 if (blkno != 0) 349 ret |= searchdir(ino, blkno, sblock->fs_bsize, 350 *filesize, tapesize, nodump, maxino); 351 if (ret & HASDUMPEDFILE) 352 *filesize = 0; 353 else 354 *filesize -= sblock->fs_bsize; 355 } 356 return (ret); 357 } 358 ind_level--; 359 for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) { 360 if (sblock->fs_magic == FS_UFS1_MAGIC) 361 blkno = idblk.ufs1[i]; 362 else 363 blkno = idblk.ufs2[i]; 364 if (blkno != 0) 365 ret |= dirindir(ino, blkno, ind_level, filesize, 366 tapesize, nodump, maxino); 367 } 368 return (ret); 369 } 370 371 /* 372 * Scan a disk block containing directory information looking to see if 373 * any of the entries are on the dump list and to see if the directory 374 * contains any subdirectories. 375 */ 376 static int 377 searchdir( 378 ino_t ino, 379 ufs2_daddr_t blkno, 380 long size, 381 long filesize, 382 long *tapesize, 383 int nodump, 384 ino_t maxino) 385 { 386 int mode; 387 struct direct *dp; 388 union dinode *ip; 389 long loc, ret = 0; 390 static caddr_t dblk; 391 392 if (dblk == NULL && (dblk = malloc(sblock->fs_bsize)) == NULL) 393 quit("searchdir: cannot allocate indirect memory.\n"); 394 blkread(fsbtodb(sblock, blkno), dblk, (int)size); 395 if (filesize < size) 396 size = filesize; 397 for (loc = 0; loc < size; ) { 398 dp = (struct direct *)(dblk + loc); 399 if (dp->d_reclen == 0) { 400 msg("corrupted directory, inumber %ju\n", 401 (uintmax_t)ino); 402 break; 403 } 404 loc += dp->d_reclen; 405 if (dp->d_ino == 0) 406 continue; 407 if (dp->d_ino >= maxino) { 408 msg("corrupted directory entry, d_ino %ju >= %ju\n", 409 (uintmax_t)dp->d_ino, (uintmax_t)maxino); 410 break; 411 } 412 if (dp->d_name[0] == '.') { 413 if (dp->d_name[1] == '\0') 414 continue; 415 if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') 416 continue; 417 } 418 if (nodump) { 419 ip = getino(dp->d_ino, &mode); 420 if (TSTINO(dp->d_ino, dumpinomap)) { 421 CLRINO(dp->d_ino, dumpinomap); 422 *tapesize -= blockest(ip); 423 } 424 /* 425 * Add back to dumpdirmap and remove from usedinomap 426 * to propagate nodump. 427 */ 428 if (mode == IFDIR) { 429 SETINO(dp->d_ino, dumpdirmap); 430 CLRINO(dp->d_ino, usedinomap); 431 ret |= HASSUBDIRS; 432 } 433 } else { 434 if (TSTINO(dp->d_ino, dumpinomap)) { 435 ret |= HASDUMPEDFILE; 436 if (ret & HASSUBDIRS) 437 break; 438 } 439 if (TSTINO(dp->d_ino, dumpdirmap)) { 440 ret |= HASSUBDIRS; 441 if (ret & HASDUMPEDFILE) 442 break; 443 } 444 } 445 } 446 return (ret); 447 } 448 449 /* 450 * Dump passes 3 and 4. 451 * 452 * Dump the contents of an inode to tape. 453 */ 454 void 455 dumpino(union dinode *dp, ino_t ino) 456 { 457 int ind_level, cnt, last, added; 458 off_t size; 459 char buf[TP_BSIZE]; 460 461 if (newtape) { 462 newtape = 0; 463 dumpmap(dumpinomap, TS_BITS, ino); 464 } 465 CLRINO(ino, dumpinomap); 466 /* 467 * Zero out the size of a snapshot so that it will be dumped 468 * as a zero length file. 469 */ 470 if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0) { 471 DIP_SET(dp, di_size, 0); 472 DIP_SET(dp, di_flags, DIP(dp, di_flags) & ~SF_SNAPSHOT); 473 } 474 if (sblock->fs_magic == FS_UFS1_MAGIC) { 475 spcl.c_mode = dp->dp1.di_mode; 476 spcl.c_size = dp->dp1.di_size; 477 spcl.c_extsize = 0; 478 spcl.c_atime = _time32_to_time(dp->dp1.di_atime); 479 spcl.c_atimensec = dp->dp1.di_atimensec; 480 spcl.c_mtime = _time32_to_time(dp->dp1.di_mtime); 481 spcl.c_mtimensec = dp->dp1.di_mtimensec; 482 spcl.c_birthtime = 0; 483 spcl.c_birthtimensec = 0; 484 spcl.c_rdev = dp->dp1.di_rdev; 485 spcl.c_file_flags = dp->dp1.di_flags; 486 spcl.c_uid = dp->dp1.di_uid; 487 spcl.c_gid = dp->dp1.di_gid; 488 } else { 489 spcl.c_mode = dp->dp2.di_mode; 490 spcl.c_size = dp->dp2.di_size; 491 spcl.c_extsize = dp->dp2.di_extsize; 492 spcl.c_atime = _time64_to_time(dp->dp2.di_atime); 493 spcl.c_atimensec = dp->dp2.di_atimensec; 494 spcl.c_mtime = _time64_to_time(dp->dp2.di_mtime); 495 spcl.c_mtimensec = dp->dp2.di_mtimensec; 496 spcl.c_birthtime = _time64_to_time(dp->dp2.di_birthtime); 497 spcl.c_birthtimensec = dp->dp2.di_birthnsec; 498 spcl.c_rdev = dp->dp2.di_rdev; 499 spcl.c_file_flags = dp->dp2.di_flags; 500 spcl.c_uid = dp->dp2.di_uid; 501 spcl.c_gid = dp->dp2.di_gid; 502 } 503 spcl.c_type = TS_INODE; 504 spcl.c_count = 0; 505 switch (DIP(dp, di_mode) & S_IFMT) { 506 507 case 0: 508 /* 509 * Freed inode. 510 */ 511 return; 512 513 case S_IFLNK: 514 /* 515 * Check for short symbolic link. 516 */ 517 if (DIP(dp, di_size) > 0 && 518 DIP(dp, di_size) < sblock->fs_maxsymlinklen) { 519 spcl.c_addr[0] = 1; 520 spcl.c_count = 1; 521 added = appendextdata(dp); 522 writeheader(ino); 523 memmove(buf, DIP(dp, di_shortlink), 524 (u_long)DIP(dp, di_size)); 525 buf[DIP(dp, di_size)] = '\0'; 526 writerec(buf, 0); 527 writeextdata(dp, ino, added); 528 return; 529 } 530 /* FALLTHROUGH */ 531 532 case S_IFDIR: 533 case S_IFREG: 534 if (DIP(dp, di_size) > 0) 535 break; 536 /* FALLTHROUGH */ 537 538 case S_IFIFO: 539 case S_IFSOCK: 540 case S_IFCHR: 541 case S_IFBLK: 542 added = appendextdata(dp); 543 writeheader(ino); 544 writeextdata(dp, ino, added); 545 return; 546 547 default: 548 msg("Warning: undefined file type 0%o\n", 549 DIP(dp, di_mode) & IFMT); 550 return; 551 } 552 if (DIP(dp, di_size) > UFS_NDADDR * sblock->fs_bsize) { 553 cnt = UFS_NDADDR * sblock->fs_frag; 554 last = 0; 555 } else { 556 cnt = howmany(DIP(dp, di_size), sblock->fs_fsize); 557 last = 1; 558 } 559 if (sblock->fs_magic == FS_UFS1_MAGIC) 560 ufs1_blksout(&dp->dp1.di_db[0], cnt, ino); 561 else 562 ufs2_blksout(dp, &dp->dp2.di_db[0], cnt, ino, last); 563 if ((size = DIP(dp, di_size) - UFS_NDADDR * sblock->fs_bsize) <= 0) 564 return; 565 for (ind_level = 0; ind_level < UFS_NIADDR; ind_level++) { 566 dmpindir(dp, ino, DIP(dp, di_ib[ind_level]), ind_level, &size); 567 if (size <= 0) 568 return; 569 } 570 } 571 572 /* 573 * Read indirect blocks, and pass the data blocks to be dumped. 574 */ 575 static void 576 dmpindir(union dinode *dp, ino_t ino, ufs2_daddr_t blk, int ind_level, 577 off_t *size) 578 { 579 union { 580 ufs1_daddr_t ufs1[MAXBSIZE / sizeof(ufs1_daddr_t)]; 581 ufs2_daddr_t ufs2[MAXBSIZE / sizeof(ufs2_daddr_t)]; 582 } idblk; 583 int i, cnt, last; 584 585 if (blk != 0) 586 blkread(fsbtodb(sblock, blk), (char *)&idblk, 587 (int)sblock->fs_bsize); 588 else 589 memset(&idblk, 0, sblock->fs_bsize); 590 if (ind_level <= 0) { 591 if (*size > NINDIR(sblock) * sblock->fs_bsize) { 592 cnt = NINDIR(sblock) * sblock->fs_frag; 593 last = 0; 594 } else { 595 cnt = howmany(*size, sblock->fs_fsize); 596 last = 1; 597 } 598 *size -= NINDIR(sblock) * sblock->fs_bsize; 599 if (sblock->fs_magic == FS_UFS1_MAGIC) 600 ufs1_blksout(idblk.ufs1, cnt, ino); 601 else 602 ufs2_blksout(dp, idblk.ufs2, cnt, ino, last); 603 return; 604 } 605 ind_level--; 606 for (i = 0; i < NINDIR(sblock); i++) { 607 if (sblock->fs_magic == FS_UFS1_MAGIC) 608 dmpindir(dp, ino, idblk.ufs1[i], ind_level, size); 609 else 610 dmpindir(dp, ino, idblk.ufs2[i], ind_level, size); 611 if (*size <= 0) 612 return; 613 } 614 } 615 616 /* 617 * Collect up the data into tape record sized buffers and output them. 618 */ 619 static void 620 ufs1_blksout(ufs1_daddr_t *blkp, int frags, ino_t ino) 621 { 622 ufs1_daddr_t *bp; 623 int i, j, count, blks, tbperdb; 624 625 blks = howmany(frags * sblock->fs_fsize, TP_BSIZE); 626 tbperdb = sblock->fs_bsize >> tp_bshift; 627 for (i = 0; i < blks; i += TP_NINDIR) { 628 if (i + TP_NINDIR > blks) 629 count = blks; 630 else 631 count = i + TP_NINDIR; 632 assert(count <= TP_NINDIR + i); 633 for (j = i; j < count; j++) 634 if (blkp[j / tbperdb] != 0) 635 spcl.c_addr[j - i] = 1; 636 else 637 spcl.c_addr[j - i] = 0; 638 spcl.c_count = count - i; 639 writeheader(ino); 640 bp = &blkp[i / tbperdb]; 641 for (j = i; j < count; j += tbperdb, bp++) 642 if (*bp != 0) { 643 if (j + tbperdb <= count) 644 dumpblock(*bp, (int)sblock->fs_bsize); 645 else 646 dumpblock(*bp, (count - j) * TP_BSIZE); 647 } 648 spcl.c_type = TS_ADDR; 649 } 650 } 651 652 /* 653 * Collect up the data into tape record sized buffers and output them. 654 */ 655 static void 656 ufs2_blksout(union dinode *dp, ufs2_daddr_t *blkp, int frags, ino_t ino, 657 int last) 658 { 659 ufs2_daddr_t *bp; 660 int i, j, count, resid, blks, tbperdb, added; 661 static int writingextdata = 0; 662 663 /* 664 * Calculate the number of TP_BSIZE blocks to be dumped. 665 * For filesystems with a fragment size bigger than TP_BSIZE, 666 * only part of the final fragment may need to be dumped. 667 */ 668 blks = howmany(frags * sblock->fs_fsize, TP_BSIZE); 669 if (last) { 670 if (writingextdata) 671 resid = howmany(fragoff(sblock, spcl.c_extsize), 672 TP_BSIZE); 673 else 674 resid = howmany(fragoff(sblock, dp->dp2.di_size), 675 TP_BSIZE); 676 if (resid > 0) 677 blks -= howmany(sblock->fs_fsize, TP_BSIZE) - resid; 678 } 679 tbperdb = sblock->fs_bsize >> tp_bshift; 680 for (i = 0; i < blks; i += TP_NINDIR) { 681 if (i + TP_NINDIR > blks) 682 count = blks; 683 else 684 count = i + TP_NINDIR; 685 assert(count <= TP_NINDIR + i); 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 = count - i; 692 if (last && count == blks && !writingextdata) 693 added = appendextdata(dp); 694 writeheader(ino); 695 bp = &blkp[i / tbperdb]; 696 for (j = i; j < count; j += tbperdb, bp++) 697 if (*bp != 0) { 698 if (j + tbperdb <= count) 699 dumpblock(*bp, (int)sblock->fs_bsize); 700 else 701 dumpblock(*bp, (count - j) * TP_BSIZE); 702 } 703 spcl.c_type = TS_ADDR; 704 spcl.c_count = 0; 705 if (last && count == blks && !writingextdata) { 706 writingextdata = 1; 707 writeextdata(dp, ino, added); 708 writingextdata = 0; 709 } 710 } 711 } 712 713 /* 714 * If there is room in the current block for the extended attributes 715 * as well as the file data, update the header to reflect the added 716 * attribute data at the end. Attributes are placed at the end so that 717 * old versions of restore will correctly restore the file and simply 718 * discard the extra data at the end that it does not understand. 719 * The attribute data is dumped following the file data by the 720 * writeextdata() function (below). 721 */ 722 static int 723 appendextdata(union dinode *dp) 724 { 725 int i, blks, tbperdb; 726 727 /* 728 * If no extended attributes, there is nothing to do. 729 */ 730 if (spcl.c_extsize == 0) 731 return (0); 732 /* 733 * If there is not enough room at the end of this block 734 * to add the extended attributes, then rather than putting 735 * part of them here, we simply push them entirely into a 736 * new block rather than putting some here and some later. 737 */ 738 if (spcl.c_extsize > UFS_NXADDR * sblock->fs_bsize) 739 blks = howmany(UFS_NXADDR * sblock->fs_bsize, TP_BSIZE); 740 else 741 blks = howmany(spcl.c_extsize, TP_BSIZE); 742 if (spcl.c_count + blks > TP_NINDIR) 743 return (0); 744 /* 745 * Update the block map in the header to indicate the added 746 * extended attribute. They will be appended after the file 747 * data by the writeextdata() routine. 748 */ 749 tbperdb = sblock->fs_bsize >> tp_bshift; 750 assert(spcl.c_count + blks <= TP_NINDIR); 751 for (i = 0; i < blks; i++) 752 if (&dp->dp2.di_extb[i / tbperdb] != 0) 753 spcl.c_addr[spcl.c_count + i] = 1; 754 else 755 spcl.c_addr[spcl.c_count + i] = 0; 756 spcl.c_count += blks; 757 return (blks); 758 } 759 760 /* 761 * Dump the extended attribute data. If there was room in the file 762 * header, then all we need to do is output the data blocks. If there 763 * was not room in the file header, then an additional TS_ADDR header 764 * is created to hold the attribute data. 765 */ 766 static void 767 writeextdata(union dinode *dp, ino_t ino, int added) 768 { 769 int i, frags, blks, tbperdb, last; 770 ufs2_daddr_t *bp; 771 off_t size; 772 773 /* 774 * If no extended attributes, there is nothing to do. 775 */ 776 if (spcl.c_extsize == 0) 777 return; 778 /* 779 * If there was no room in the file block for the attributes, 780 * dump them out in a new block, otherwise just dump the data. 781 */ 782 if (added == 0) { 783 if (spcl.c_extsize > UFS_NXADDR * sblock->fs_bsize) { 784 frags = UFS_NXADDR * sblock->fs_frag; 785 last = 0; 786 } else { 787 frags = howmany(spcl.c_extsize, sblock->fs_fsize); 788 last = 1; 789 } 790 ufs2_blksout(dp, &dp->dp2.di_extb[0], frags, ino, last); 791 } else { 792 if (spcl.c_extsize > UFS_NXADDR * sblock->fs_bsize) 793 blks = howmany(UFS_NXADDR * sblock->fs_bsize, TP_BSIZE); 794 else 795 blks = howmany(spcl.c_extsize, TP_BSIZE); 796 tbperdb = sblock->fs_bsize >> tp_bshift; 797 for (i = 0; i < blks; i += tbperdb) { 798 bp = &dp->dp2.di_extb[i / tbperdb]; 799 if (*bp != 0) { 800 if (i + tbperdb <= blks) 801 dumpblock(*bp, (int)sblock->fs_bsize); 802 else 803 dumpblock(*bp, (blks - i) * TP_BSIZE); 804 } 805 } 806 807 } 808 /* 809 * If an indirect block is added for extended attributes, then 810 * di_exti below should be changed to the structure element 811 * that references the extended attribute indirect block. This 812 * definition is here only to make it compile without complaint. 813 */ 814 #define di_exti di_spare[0] 815 /* 816 * If the extended attributes fall into an indirect block, 817 * dump it as well. 818 */ 819 if ((size = spcl.c_extsize - UFS_NXADDR * sblock->fs_bsize) > 0) 820 dmpindir(dp, ino, dp->dp2.di_exti, 0, &size); 821 } 822 823 /* 824 * Dump a map to the tape. 825 */ 826 void 827 dumpmap(char *map, int type, ino_t ino) 828 { 829 int i; 830 char *cp; 831 832 spcl.c_type = type; 833 spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE); 834 writeheader(ino); 835 for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE) 836 writerec(cp, 0); 837 } 838 839 /* 840 * Write a header record to the dump tape. 841 */ 842 void 843 writeheader(ino_t ino) 844 { 845 int32_t sum, cnt, *lp; 846 847 if (rsync_friendly >= 2) { 848 /* don't track changes to access time */ 849 spcl.c_atime = spcl.c_mtime; 850 spcl.c_atimensec = spcl.c_mtimensec; 851 } 852 spcl.c_inumber = ino; 853 spcl.c_magic = FS_UFS2_MAGIC; 854 spcl.c_checksum = 0; 855 lp = (int32_t *)&spcl; 856 sum = 0; 857 cnt = sizeof(union u_spcl) / (4 * sizeof(int32_t)); 858 while (--cnt >= 0) { 859 sum += *lp++; 860 sum += *lp++; 861 sum += *lp++; 862 sum += *lp++; 863 } 864 spcl.c_checksum = CHECKSUM - sum; 865 writerec((char *)&spcl, 1); 866 } 867 868 union dinode * 869 getino(ino_t inum, int *modep) 870 { 871 static ino_t minino, maxino; 872 static caddr_t inoblock; 873 struct ufs1_dinode *dp1; 874 struct ufs2_dinode *dp2; 875 876 if (inoblock == NULL && (inoblock = malloc(sblock->fs_bsize)) == NULL) 877 quit("cannot allocate inode memory.\n"); 878 curino = inum; 879 if (inum >= minino && inum < maxino) 880 goto gotit; 881 blkread(fsbtodb(sblock, ino_to_fsba(sblock, inum)), inoblock, 882 (int)sblock->fs_bsize); 883 minino = inum - (inum % INOPB(sblock)); 884 maxino = minino + INOPB(sblock); 885 gotit: 886 if (sblock->fs_magic == FS_UFS1_MAGIC) { 887 dp1 = &((struct ufs1_dinode *)inoblock)[inum - minino]; 888 *modep = (dp1->di_mode & IFMT); 889 return ((union dinode *)dp1); 890 } 891 dp2 = &((struct ufs2_dinode *)inoblock)[inum - minino]; 892 *modep = (dp2->di_mode & IFMT); 893 return ((union dinode *)dp2); 894 } 895 896 /* 897 * Read a chunk of data from the disk. 898 * Try to recover from hard errors by reading in sector sized pieces. 899 * Error recovery is attempted at most BREADEMAX times before seeking 900 * consent from the operator to continue. 901 */ 902 int breaderrors = 0; 903 #define BREADEMAX 32 904 905 void 906 blkread(ufs2_daddr_t blkno, char *buf, int size) 907 { 908 int secsize, bytes, resid, xfer, base, cnt, i; 909 static char *tmpbuf; 910 off_t offset; 911 912 loop: 913 offset = blkno << dev_bshift; 914 secsize = sblock->fs_fsize; 915 base = offset % secsize; 916 resid = size % secsize; 917 /* 918 * If the transfer request starts or ends on a non-sector 919 * boundary, we must read the entire sector and copy out 920 * just the part that we need. 921 */ 922 if (base == 0 && resid == 0) { 923 cnt = cread(diskfd, buf, size, offset); 924 if (cnt == size) 925 return; 926 } else { 927 if (tmpbuf == NULL && (tmpbuf = malloc(secsize)) == NULL) 928 quit("buffer malloc failed\n"); 929 xfer = 0; 930 bytes = size; 931 if (base != 0) { 932 cnt = cread(diskfd, tmpbuf, secsize, offset - base); 933 if (cnt != secsize) 934 goto bad; 935 xfer = MIN(secsize - base, size); 936 offset += xfer; 937 bytes -= xfer; 938 resid = bytes % secsize; 939 memcpy(buf, &tmpbuf[base], xfer); 940 } 941 if (bytes >= secsize) { 942 cnt = cread(diskfd, &buf[xfer], bytes - resid, offset); 943 if (cnt != bytes - resid) 944 goto bad; 945 xfer += cnt; 946 offset += cnt; 947 } 948 if (resid == 0) 949 return; 950 cnt = cread(diskfd, tmpbuf, secsize, offset); 951 if (cnt == secsize) { 952 memcpy(&buf[xfer], tmpbuf, resid); 953 return; 954 } 955 } 956 bad: 957 if (blkno + (size / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) { 958 /* 959 * Trying to read the final fragment. 960 * 961 * NB - dump only works in TP_BSIZE blocks, hence 962 * rounds `dev_bsize' fragments up to TP_BSIZE pieces. 963 * It should be smarter about not actually trying to 964 * read more than it can get, but for the time being 965 * we punt and scale back the read only when it gets 966 * us into trouble. (mkm 9/25/83) 967 */ 968 size -= dev_bsize; 969 goto loop; 970 } 971 if (cnt == -1) 972 msg("read error from %s: %s: [block %jd]: count=%d\n", 973 disk, strerror(errno), (intmax_t)blkno, size); 974 else 975 msg("short read error from %s: [block %jd]: count=%d, got=%d\n", 976 disk, (intmax_t)blkno, size, cnt); 977 if (++breaderrors > BREADEMAX) { 978 msg("More than %d block read errors from %s\n", 979 BREADEMAX, disk); 980 broadcast("DUMP IS AILING!\n"); 981 msg("This is an unrecoverable error.\n"); 982 if (!query("Do you want to attempt to continue?")){ 983 dumpabort(0); 984 /*NOTREACHED*/ 985 } else 986 breaderrors = 0; 987 } 988 /* 989 * Zero buffer, then try to read each sector of buffer separately, 990 * and bypass the cache. 991 */ 992 memset(buf, 0, size); 993 for (i = 0; i < size; i += dev_bsize, buf += dev_bsize, blkno++) { 994 if ((cnt = pread(diskfd, buf, (int)dev_bsize, 995 ((off_t)blkno << dev_bshift))) == dev_bsize) 996 continue; 997 if (cnt == -1) { 998 msg("read error from %s: %s: [sector %jd]: count=%ld\n", 999 disk, strerror(errno), (intmax_t)blkno, dev_bsize); 1000 continue; 1001 } 1002 msg("short read from %s: [sector %jd]: count=%ld, got=%d\n", 1003 disk, (intmax_t)blkno, dev_bsize, cnt); 1004 } 1005 } 1006