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