1 /* 2 * Copyright 1999 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms are permitted 14 * provided that: (1) source distributions retain this entire copyright 15 * notice and comment, and (2) distributions including binaries display 16 * the following acknowledgement: ``This product includes software 17 * developed by the University of California, Berkeley and its contributors'' 18 * in the documentation or other materials provided with the distribution 19 * and in all advertising materials mentioning features or use of this 20 * software. Neither the name of the University nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26 */ 27 28 #include <stdio.h> 29 #include <strings.h> 30 #include <malloc.h> 31 #include <sys/param.h> 32 #include <sys/types.h> 33 #include <sys/sysmacros.h> 34 #include <sys/mntent.h> 35 #include <sys/vnode.h> 36 #include <sys/fs/udf_volume.h> 37 #include <sys/dkio.h> 38 #include <sys/vtoc.h> 39 #include "fsck.h" 40 #include "udfs.h" 41 #include <locale.h> 42 43 uint64_t maxuniqid; /* maximum unique id on medium */ 44 45 /* 46 * for each large file ( size > MAXOFF_T) this global counter 47 * gets incremented here. 48 */ 49 50 extern unsigned int largefile_count; 51 extern void pwarn(char *, ...); 52 extern void pfatal(char *, ...); 53 extern void errexit(char *, ...); 54 55 extern int32_t verifytag(struct tag *, uint32_t, struct tag *, int); 56 extern char *tagerrs[]; 57 extern void maketag(struct tag *, struct tag *); 58 extern void flush(int32_t, struct bufarea *); 59 extern void putfilentry(struct bufarea *); 60 extern int32_t bread(int32_t, char *, daddr_t, long); 61 extern void bwrite(int, char *, daddr_t, long); 62 extern int32_t dofix(struct inodesc *, char *); 63 extern int32_t reply(char *); 64 extern void ud_swap_short_ad(short_ad_t *); 65 extern void ud_swap_long_ad(long_ad_t *); 66 67 extern void dump16(char *, char *); 68 69 static void adjust(struct fileinfo *); 70 static void opndir(struct file_entry *); 71 static int32_t getdir(struct file_entry *, struct bufarea **, 72 u_offset_t *, struct file_id **); 73 static void ckinode(struct file_entry *); 74 struct bufarea *getfilentry(); 75 76 /* Fields for traversing an allocation extent */ 77 static uint32_t dir_adrsize; 78 static uint32_t dir_adrindx; 79 static uint32_t dir_naddrs; 80 static uint8_t *extbuf; 81 static uint8_t *dir_adrlist; 82 83 /* Keep track of where we are in the directory */ 84 static u_offset_t dir_baseoff; 85 static uint32_t dir_basesize; 86 static uint8_t *dirbuf; 87 static uint8_t *dir_fidp; 88 static uint32_t baseblock; 89 90 #define MAXFIDSIZE 2048 91 92 static uint8_t fidbuf[MAXFIDSIZE]; 93 94 void 95 pass1() 96 { 97 register struct file_entry *fp; 98 register struct fileinfo *fip; 99 register struct bufarea *bp; 100 struct file_id *fidp; 101 struct bufarea *fbp; 102 int err; 103 104 (void) cachefile(rootblock, rootlen); 105 fip = &inphead[0]; /* The root */ 106 fip->fe_lseen = 0; /* Didn't get here through directory */ 107 n_files = n_dirs = 0; 108 while (fip->fe_block) { 109 u_offset_t offset, end; 110 111 markbusy(fip->fe_block, fip->fe_len); 112 bp = getfilentry(fip->fe_block, fip->fe_len); 113 if (bp == NULL) { 114 pwarn(gettext("Unable to read file entry at %x\n"), 115 fip->fe_block); 116 goto next; 117 } 118 /* LINTED */ 119 fp = (struct file_entry *)bp->b_un.b_buf; 120 fip->fe_lcount = fp->fe_lcount; 121 fip->fe_type = fp->fe_icb_tag.itag_ftype; 122 if (fp->fe_uniq_id >= maxuniqid) 123 maxuniqid = fp->fe_uniq_id + 1; 124 125 if (fip->fe_block == rootblock && 126 fip->fe_type != FTYPE_DIRECTORY) 127 errexit(gettext("Root file entry is not a " 128 "directory\n")); 129 130 if (debug) { 131 (void) printf("do %x len %d type %d lcount %d" 132 " lseen %d end %llx\n", 133 fip->fe_block, fip->fe_len, 134 fip->fe_type, fip->fe_lcount, 135 fip->fe_lseen, fp->fe_info_len); 136 } 137 switch (fip->fe_type) { 138 case FTYPE_DIRECTORY: 139 n_dirs++; 140 offset = 0; 141 end = fp->fe_info_len; 142 fbp = NULL; 143 opndir(fp); 144 for (offset = 0; offset < end; 145 offset += FID_LENGTH(fidp)) { 146 err = getdir(fp, &fbp, &offset, &fidp); 147 if (err) { 148 pwarn(gettext("Bad directory entry in " 149 "file %x at offset %llx\n"), 150 fip->fe_block, offset); 151 offset = end; 152 } 153 if (fidp->fid_flags & FID_DELETED) 154 continue; 155 (void) cachefile(fidp->fid_icb.lad_ext_loc, 156 fidp->fid_icb.lad_ext_len); 157 } 158 if (dirbuf) { 159 free(dirbuf); 160 dirbuf = NULL; 161 } 162 if (fbp) 163 fbp->b_flags &= ~B_INUSE; 164 if (debug) 165 (void) printf("Done %x\n", fip->fe_block); 166 break; 167 168 case FTYPE_FILE: 169 case FTYPE_SYMLINK: 170 ckinode(fp); 171 /* FALLTHROUGH */ 172 default: 173 n_files++; 174 break; 175 } 176 putfilentry(bp); 177 bp->b_flags &= ~B_INUSE; 178 next: 179 /* At end of this set of fips, get the next set */ 180 if ((++fip)->fe_block == (uint32_t)-1) 181 fip = fip->fe_nexthash; 182 } 183 184 /* Find bad link counts */ 185 fip = &inphead[0]; 186 while (fip->fe_block) { 187 if (fip->fe_lcount != fip->fe_lseen) 188 adjust(fip); 189 /* At end of this set of fips, get the next set */ 190 if ((++fip)->fe_block == (uint32_t)-1) 191 fip = fip->fe_nexthash; 192 } 193 } 194 195 static void 196 opndir(struct file_entry *fp) 197 { 198 if (dirbuf) { 199 free(dirbuf); 200 dirbuf = NULL; 201 } 202 if (extbuf) { 203 free(extbuf); 204 extbuf = NULL; 205 } 206 207 dir_baseoff = 0; 208 dir_basesize = 0; 209 dir_adrindx = 0; 210 211 switch (fp->fe_icb_tag.itag_flags & 0x3) { 212 case ICB_FLAG_SHORT_AD: 213 dir_adrsize = sizeof (short_ad_t); 214 dir_naddrs = fp->fe_len_adesc / sizeof (short_ad_t); 215 dir_adrlist = (uint8_t *)(fp->fe_spec + fp->fe_len_ear); 216 break; 217 case ICB_FLAG_LONG_AD: 218 dir_adrsize = sizeof (long_ad_t); 219 dir_naddrs = fp->fe_len_adesc / sizeof (long_ad_t); 220 dir_adrlist = (uint8_t *)(fp->fe_spec + fp->fe_len_ear); 221 break; 222 case ICB_FLAG_EXT_AD: 223 errexit(gettext("Can't handle ext_ads in directories/n")); 224 break; 225 case ICB_FLAG_ONE_AD: 226 dir_adrsize = 0; 227 dir_naddrs = 0; 228 dir_adrlist = NULL; 229 dir_basesize = fp->fe_len_adesc; 230 dir_fidp = (uint8_t *)(fp->fe_spec + fp->fe_len_ear); 231 baseblock = fp->fe_tag.tag_loc; 232 break; 233 } 234 } 235 236 /* Allocate and read in an allocation extent */ 237 /* ARGSUSED */ 238 int 239 getallocext(struct file_entry *fp, uint32_t loc, uint32_t len) 240 { 241 uint32_t nb; 242 uint8_t *ap; 243 int i; 244 int err; 245 struct alloc_ext_desc *aep; 246 247 if (debug) 248 (void) printf(" allocext loc %x len %x\n", loc, len); 249 nb = roundup(len, secsize); 250 if (extbuf) 251 free(extbuf); 252 extbuf = (uint8_t *)malloc(nb); 253 if (extbuf == NULL) 254 errexit(gettext("Can't allocate directory extent buffer\n")); 255 if (bread(fsreadfd, (char *)extbuf, 256 fsbtodb(loc + part_start), nb) != 0) { 257 (void) fprintf(stderr, 258 gettext("Can't read allocation extent\n")); 259 return (1); 260 } 261 /* LINTED */ 262 aep = (struct alloc_ext_desc *)extbuf; 263 err = verifytag(&aep->aed_tag, loc, &aep->aed_tag, UD_ALLOC_EXT_DESC); 264 if (err) { 265 (void) printf( 266 gettext("Bad tag on alloc extent: %s\n"), tagerrs[err]); 267 free(extbuf); 268 return (1); 269 } 270 dir_adrlist = (uint8_t *)(aep + 1); 271 dir_naddrs = aep->aed_len_aed / dir_adrsize; 272 dir_adrindx = 0; 273 274 /* Swap the descriptors */ 275 for (i = 0, ap = dir_adrlist; i < dir_naddrs; i++, ap += dir_adrsize) { 276 if (dir_adrsize == sizeof (short_ad_t)) { 277 /* LINTED */ 278 ud_swap_short_ad((short_ad_t *)ap); 279 } else if (dir_adrsize == sizeof (long_ad_t)) { 280 /* LINTED */ 281 ud_swap_long_ad((long_ad_t *)ap); 282 } 283 } 284 285 return (0); 286 } 287 288 /* 289 * Variables used in this function and their relationships: 290 * *poffset - read pointer in the directory 291 * dir_baseoff - offset at start of dirbuf 292 * dir_baselen - length of valid data in current extent 293 * dir_adrindx - index into current allocation extent for location of 294 * dir_baseoff 295 * dir_naddrs - number of entries in current allocation extent 296 * dir_fidp - pointer to dirbuf or immediate data in file entry 297 * baseblock - block address of dir_baseoff 298 * newoff - *poffset - dir_baseoff 299 */ 300 /* ARGSUSED1 */ 301 static int32_t 302 getdir(struct file_entry *fp, struct bufarea **fbp, 303 u_offset_t *poffset, struct file_id **fidpp) 304 { 305 /* LINTED */ 306 register struct file_id *fidp = (struct file_id *)fidbuf; 307 register struct short_ad *sap; 308 register struct long_ad *lap; 309 register int i, newoff, xoff = 0; 310 uint32_t block = 0, nb, len, left; 311 u_offset_t offset; 312 int err, type; 313 314 315 again: 316 offset = *poffset; 317 again2: 318 if (debug) 319 (void) printf("getdir %llx\n", offset); 320 newoff = offset - dir_baseoff; 321 if (newoff >= dir_basesize) { 322 if (dirbuf) { 323 free(dirbuf); 324 dirbuf = NULL; 325 } 326 } else { 327 if (block == 0) 328 block = baseblock + (newoff / secsize); 329 goto nextone; 330 } 331 332 again3: 333 switch (fp->fe_icb_tag.itag_flags & 0x3) { 334 case ICB_FLAG_SHORT_AD: 335 /* LINTED */ 336 sap = &((short_ad_t *)dir_adrlist)[dir_adrindx]; 337 for (i = dir_adrindx; i < dir_naddrs; i++, sap++) { 338 len = EXTLEN(sap->sad_ext_len); 339 type = EXTYPE(sap->sad_ext_len); 340 if (type == 3) { 341 if (i < dir_naddrs - 1) 342 errexit(gettext("Allocation extent not " 343 "at end of list\n")); 344 markbusy(sap->sad_ext_loc, len); 345 if (getallocext(fp, sap->sad_ext_loc, len)) 346 return (1); 347 goto again3; 348 } 349 if (newoff < len) 350 break; 351 newoff -= len; 352 dir_baseoff += len; 353 if (debug) 354 (void) printf( 355 " loc %x len %x\n", sap->sad_ext_loc, 356 len); 357 } 358 dir_adrindx = i; 359 if (debug) 360 (void) printf(" loc %x len %x\n", sap->sad_ext_loc, 361 sap->sad_ext_len); 362 baseblock = sap->sad_ext_loc; 363 if (block == 0) 364 block = baseblock; 365 dir_basesize = len; 366 if (type < 2) 367 markbusy(sap->sad_ext_loc, len); 368 if (type != 0) { 369 *poffset += dir_basesize; 370 goto again; 371 } 372 nb = roundup(len, secsize); 373 dirbuf = (uint8_t *)malloc(nb); 374 if (dirbuf == NULL) 375 errexit(gettext("Can't allocate directory extent " 376 "buffer\n")); 377 if (bread(fsreadfd, (char *)dirbuf, 378 fsbtodb(baseblock + part_start), nb) != 0) { 379 errexit(gettext("Can't read directory extent\n")); 380 } 381 dir_fidp = dirbuf; 382 break; 383 case ICB_FLAG_LONG_AD: 384 /* LINTED */ 385 lap = &((long_ad_t *)dir_adrlist)[dir_adrindx]; 386 for (i = dir_adrindx; i < dir_naddrs; i++, lap++) { 387 len = EXTLEN(lap->lad_ext_len); 388 type = EXTYPE(lap->lad_ext_len); 389 if (type == 3) { 390 if (i < dir_naddrs - 1) 391 errexit(gettext("Allocation extent not " 392 "at end of list\n")); 393 markbusy(lap->lad_ext_loc, len); 394 if (getallocext(fp, lap->lad_ext_loc, len)) 395 return (1); 396 goto again3; 397 } 398 if (newoff < len) 399 break; 400 newoff -= len; 401 dir_baseoff += len; 402 if (debug) 403 (void) printf( 404 " loc %x len %x\n", lap->lad_ext_loc, 405 len); 406 } 407 dir_adrindx = i; 408 if (debug) 409 (void) printf(" loc %x len %x\n", lap->lad_ext_loc, 410 lap->lad_ext_len); 411 baseblock = lap->lad_ext_loc; 412 if (block == 0) 413 block = baseblock; 414 dir_basesize = len; 415 if (type < 2) 416 markbusy(lap->lad_ext_loc, len); 417 if (type != 0) { 418 *poffset += dir_basesize; 419 goto again; 420 } 421 nb = roundup(len, secsize); 422 dirbuf = (uint8_t *)malloc(nb); 423 if (dirbuf == NULL) 424 errexit(gettext("Can't allocate directory extent " 425 "buffer\n")); 426 if (bread(fsreadfd, (char *)dirbuf, 427 fsbtodb(baseblock + part_start), nb) != 0) { 428 errexit(gettext("Can't read directory extent\n")); 429 } 430 dir_fidp = dirbuf; 431 break; 432 case ICB_FLAG_EXT_AD: 433 break; 434 case ICB_FLAG_ONE_AD: 435 errexit(gettext("Logic error in getdir - at ICB_FLAG_ONE_AD " 436 "case\n")); 437 break; 438 } 439 nextone: 440 if (debug) 441 (void) printf("getdirend blk %x dir_baseoff %llx newoff %x\n", 442 block, dir_baseoff, newoff); 443 left = dir_basesize - newoff; 444 if (xoff + left > MAXFIDSIZE) 445 left = MAXFIDSIZE - xoff; 446 bcopy((char *)dir_fidp + newoff, (char *)fidbuf + xoff, left); 447 xoff += left; 448 /* 449 * If we have a fid that crosses an extent boundary, then force 450 * a read of the next extent, and fill up the rest of the fid. 451 */ 452 if (xoff < sizeof (fidp->fid_tag) || 453 xoff < sizeof (fidp->fid_tag) + SWAP16(fidp->fid_tag.tag_crc_len)) { 454 offset += left; 455 if (debug) 456 (void) printf("block crossing at offset %llx\n", 457 offset); 458 goto again2; 459 } 460 err = verifytag(&fidp->fid_tag, block, &fidp->fid_tag, UD_FILE_ID_DESC); 461 if (debug) { 462 dump16((char *)fidp, "\n"); 463 } 464 if (err) { 465 pwarn(gettext("Bad directory tag: %s\n"), tagerrs[err]); 466 return (err); 467 } 468 *fidpp = fidp; 469 return (0); 470 } 471 472 static void 473 ckinode(struct file_entry *fp) 474 { 475 register struct short_ad *sap; 476 register struct long_ad *lap; 477 register int i, type, len; 478 479 switch (fp->fe_icb_tag.itag_flags & 0x3) { 480 case ICB_FLAG_SHORT_AD: 481 dir_adrsize = sizeof (short_ad_t); 482 dir_naddrs = fp->fe_len_adesc / sizeof (short_ad_t); 483 /* LINTED */ 484 sap = (short_ad_t *)(fp->fe_spec + fp->fe_len_ear); 485 again1: 486 for (i = 0; i < dir_naddrs; i++, sap++) { 487 len = EXTLEN(sap->sad_ext_len); 488 type = EXTYPE(sap->sad_ext_len); 489 if (type < 2) 490 markbusy(sap->sad_ext_loc, len); 491 if (debug) 492 (void) printf( 493 " loc %x len %x\n", sap->sad_ext_loc, 494 sap->sad_ext_len); 495 if (type == 3) { 496 markbusy(sap->sad_ext_loc, len); 497 /* This changes dir_naddrs and dir_adrlist */ 498 if (getallocext(fp, sap->sad_ext_loc, len)) 499 break; 500 /* LINTED */ 501 sap = (short_ad_t *)dir_adrlist; 502 goto again1; 503 } 504 } 505 break; 506 case ICB_FLAG_LONG_AD: 507 dir_adrsize = sizeof (long_ad_t); 508 dir_naddrs = fp->fe_len_adesc / sizeof (long_ad_t); 509 /* LINTED */ 510 lap = (long_ad_t *)(fp->fe_spec + fp->fe_len_ear); 511 again2: 512 for (i = 0; i < dir_naddrs; i++, lap++) { 513 len = EXTLEN(lap->lad_ext_len); 514 type = EXTYPE(lap->lad_ext_len); 515 if (type < 2) 516 markbusy(lap->lad_ext_loc, len); 517 if (debug) 518 (void) printf( 519 " loc %x len %x\n", lap->lad_ext_loc, 520 lap->lad_ext_len); 521 if (type == 3) { 522 markbusy(sap->sad_ext_loc, len); 523 /* This changes dir_naddrs and dir_adrlist */ 524 if (getallocext(fp, lap->lad_ext_loc, len)) 525 break; 526 /* LINTED */ 527 lap = (long_ad_t *)dir_adrlist; 528 goto again2; 529 } 530 } 531 break; 532 case ICB_FLAG_EXT_AD: 533 break; 534 case ICB_FLAG_ONE_AD: 535 break; 536 } 537 } 538 539 static void 540 adjust(struct fileinfo *fip) 541 { 542 register struct file_entry *fp; 543 register struct bufarea *bp; 544 545 bp = getfilentry(fip->fe_block, fip->fe_len); 546 if (bp == NULL) 547 errexit(gettext("Unable to read file entry at %x\n"), 548 fip->fe_block); 549 /* LINTED */ 550 fp = (struct file_entry *)bp->b_un.b_buf; 551 pwarn(gettext("LINK COUNT %s I=%x"), 552 fip->fe_type == FTYPE_DIRECTORY ? "DIR" : 553 fip->fe_type == FTYPE_SYMLINK ? "SYM" : 554 fip->fe_type == FTYPE_FILE ? "FILE" : "???", fip->fe_block); 555 (void) printf(gettext(" COUNT %d SHOULD BE %d"), 556 fip->fe_lcount, fip->fe_lseen); 557 if (preen) { 558 if (fip->fe_lseen > fip->fe_lcount) { 559 (void) printf("\n"); 560 pfatal(gettext("LINK COUNT INCREASING")); 561 } 562 (void) printf(gettext(" (ADJUSTED)\n")); 563 } 564 if (preen || reply(gettext("ADJUST")) == 1) { 565 fp->fe_lcount = fip->fe_lseen; 566 putfilentry(bp); 567 dirty(bp); 568 flush(fswritefd, bp); 569 } 570 bp->b_flags &= ~B_INUSE; 571 } 572 573 void 574 dofreemap() 575 { 576 register int i; 577 register char *bp, *fp; 578 struct inodesc idesc; 579 580 if (freemap == NULL) 581 return; 582 583 /* Flip bits in the busy map */ 584 bp = busymap; 585 for (i = 0, bp = busymap; i < part_bmp_bytes; i++, bp++) 586 *bp = ~*bp; 587 588 /* Mark leftovers in byte as allocated */ 589 if (part_len % NBBY) 590 bp[-1] &= (unsigned)0xff >> (NBBY - part_len % NBBY); 591 bp = busymap; 592 fp = freemap; 593 bzero((char *)&idesc, sizeof (struct inodesc)); 594 idesc.id_type = ADDR; 595 if (bcmp(bp, fp, part_bmp_bytes) != 0 && 596 dofix(&idesc, gettext("BLK(S) MISSING IN FREE BITMAP"))) { 597 bcopy(bp, fp, part_bmp_bytes); 598 maketag(&spacep->sbd_tag, &spacep->sbd_tag); 599 bwrite(fswritefd, (char *)spacep, fsbtodb(part_bmp_loc), 600 part_bmp_sectors * secsize); 601 } 602 } 603 604 void 605 dolvint() 606 { 607 struct lvid_iu *lviup; 608 struct inodesc idesc; 609 610 bzero((char *)&idesc, sizeof (struct inodesc)); 611 idesc.id_type = ADDR; 612 lviup = (struct lvid_iu *)&lvintp->lvid_fst[2]; 613 if ((lvintp->lvid_fst[0] != part_len - n_blks || 614 lvintp->lvid_int_type != LVI_CLOSE || 615 lviup->lvidiu_nfiles != n_files || 616 lviup->lvidiu_ndirs != n_dirs || 617 lvintp->lvid_uniqid < maxuniqid) && 618 dofix(&idesc, gettext("LOGICAL VOLUME INTEGRITY COUNTS WRONG"))) { 619 lvintp->lvid_int_type = LVI_CLOSE; 620 lvintp->lvid_fst[0] = part_len - n_blks; 621 lviup->lvidiu_nfiles = n_files; 622 lviup->lvidiu_ndirs = n_dirs; 623 lvintp->lvid_uniqid = maxuniqid; 624 maketag(&lvintp->lvid_tag, &lvintp->lvid_tag); 625 bwrite(fswritefd, (char *)lvintp, fsbtodb(lvintblock), 626 lvintlen); 627 } 628 } 629