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 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <stdio.h> 31 #include <strings.h> 32 #include <malloc.h> 33 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <sys/sysmacros.h> 36 #include <sys/mntent.h> 37 #include <sys/vnode.h> 38 #include <sys/fs/udf_volume.h> 39 #include <sys/dkio.h> 40 #include <sys/vtoc.h> 41 #include "fsck.h" 42 #include "udfs.h" 43 #include <locale.h> 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 default: 172 n_files++; 173 break; 174 } 175 putfilentry(bp); 176 bp->b_flags &= ~B_INUSE; 177 next: 178 /* At end of this set of fips, get the next set */ 179 if ((++fip)->fe_block == (uint32_t)-1) 180 fip = fip->fe_nexthash; 181 } 182 183 /* Find bad link counts */ 184 fip = &inphead[0]; 185 while (fip->fe_block) { 186 if (fip->fe_lcount != fip->fe_lseen) 187 adjust(fip); 188 /* At end of this set of fips, get the next set */ 189 if ((++fip)->fe_block == (uint32_t)-1) 190 fip = fip->fe_nexthash; 191 } 192 } 193 194 static void 195 opndir(struct file_entry *fp) 196 { 197 if (dirbuf) { 198 free(dirbuf); 199 dirbuf = NULL; 200 } 201 if (extbuf) { 202 free(extbuf); 203 extbuf = NULL; 204 } 205 206 dir_baseoff = 0; 207 dir_basesize = 0; 208 dir_adrindx = 0; 209 210 switch (fp->fe_icb_tag.itag_flags & 0x3) { 211 case ICB_FLAG_SHORT_AD: 212 dir_adrsize = sizeof (short_ad_t); 213 dir_naddrs = fp->fe_len_adesc / sizeof (short_ad_t); 214 dir_adrlist = (uint8_t *)(fp->fe_spec + fp->fe_len_ear); 215 break; 216 case ICB_FLAG_LONG_AD: 217 dir_adrsize = sizeof (long_ad_t); 218 dir_naddrs = fp->fe_len_adesc / sizeof (long_ad_t); 219 dir_adrlist = (uint8_t *)(fp->fe_spec + fp->fe_len_ear); 220 break; 221 case ICB_FLAG_EXT_AD: 222 errexit(gettext("Can't handle ext_ads in directories/n")); 223 break; 224 case ICB_FLAG_ONE_AD: 225 dir_adrsize = 0; 226 dir_naddrs = 0; 227 dir_adrlist = NULL; 228 dir_basesize = fp->fe_len_adesc; 229 dir_fidp = (uint8_t *)(fp->fe_spec + fp->fe_len_ear); 230 baseblock = fp->fe_tag.tag_loc; 231 break; 232 } 233 } 234 235 /* Allocate and read in an allocation extent */ 236 /* ARGSUSED */ 237 int 238 getallocext(struct file_entry *fp, uint32_t loc, uint32_t len) 239 { 240 uint32_t nb; 241 uint8_t *ap; 242 int i; 243 int err; 244 struct alloc_ext_desc *aep; 245 246 if (debug) 247 (void) printf(" allocext loc %x len %x\n", loc, len); 248 nb = roundup(len, secsize); 249 if (extbuf) 250 free(extbuf); 251 extbuf = (uint8_t *)malloc(nb); 252 if (extbuf == NULL) 253 errexit(gettext("Can't allocate directory extent buffer\n")); 254 if (bread(fsreadfd, (char *)extbuf, 255 fsbtodb(loc + part_start), nb) != 0) { 256 (void) fprintf(stderr, 257 gettext("Can't read allocation extent\n")); 258 return (1); 259 } 260 /* LINTED */ 261 aep = (struct alloc_ext_desc *)extbuf; 262 err = verifytag(&aep->aed_tag, loc, &aep->aed_tag, UD_ALLOC_EXT_DESC); 263 if (err) { 264 (void) printf( 265 gettext("Bad tag on alloc extent: %s\n"), tagerrs[err]); 266 free(extbuf); 267 return (1); 268 } 269 dir_adrlist = (uint8_t *)(aep + 1); 270 dir_naddrs = aep->aed_len_aed / dir_adrsize; 271 dir_adrindx = 0; 272 273 /* Swap the descriptors */ 274 for (i = 0, ap = dir_adrlist; i < dir_naddrs; i++, ap += dir_adrsize) { 275 if (dir_adrsize == sizeof (short_ad_t)) { 276 /* LINTED */ 277 ud_swap_short_ad((short_ad_t *)ap); 278 } else if (dir_adrsize == sizeof (long_ad_t)) { 279 /* LINTED */ 280 ud_swap_long_ad((long_ad_t *)ap); 281 } 282 } 283 284 return (0); 285 } 286 287 /* 288 * Variables used in this function and their relationships: 289 * *poffset - read pointer in the directory 290 * dir_baseoff - offset at start of dirbuf 291 * dir_baselen - length of valid data in current extent 292 * dir_adrindx - index into current allocation extent for location of 293 * dir_baseoff 294 * dir_naddrs - number of entries in current allocation extent 295 * dir_fidp - pointer to dirbuf or immediate data in file entry 296 * baseblock - block address of dir_baseoff 297 * newoff - *poffset - dir_baseoff 298 */ 299 /* ARGSUSED1 */ 300 static int32_t 301 getdir(struct file_entry *fp, struct bufarea **fbp, 302 u_offset_t *poffset, struct file_id **fidpp) 303 { 304 /* LINTED */ 305 register struct file_id *fidp = (struct file_id *)fidbuf; 306 register struct short_ad *sap; 307 register struct long_ad *lap; 308 register int i, newoff, xoff = 0; 309 uint32_t block = 0, nb, len, left; 310 u_offset_t offset; 311 int err, type; 312 313 314 again: 315 offset = *poffset; 316 again2: 317 if (debug) 318 (void) printf("getdir %llx\n", offset); 319 newoff = offset - dir_baseoff; 320 if (newoff >= dir_basesize) { 321 if (dirbuf) { 322 free(dirbuf); 323 dirbuf = NULL; 324 } 325 } else { 326 if (block == 0) 327 block = baseblock + (newoff / secsize); 328 goto nextone; 329 } 330 331 again3: 332 switch (fp->fe_icb_tag.itag_flags & 0x3) { 333 case ICB_FLAG_SHORT_AD: 334 /* LINTED */ 335 sap = &((short_ad_t *)dir_adrlist)[dir_adrindx]; 336 for (i = dir_adrindx; i < dir_naddrs; i++, sap++) { 337 len = EXTLEN(sap->sad_ext_len); 338 type = EXTYPE(sap->sad_ext_len); 339 if (type == 3) { 340 if (i < dir_naddrs - 1) 341 errexit(gettext("Allocation extent not " 342 "at end of list\n")); 343 markbusy(sap->sad_ext_loc, len); 344 if (getallocext(fp, sap->sad_ext_loc, len)) 345 return (1); 346 goto again3; 347 } 348 if (newoff < len) 349 break; 350 newoff -= len; 351 dir_baseoff += len; 352 if (debug) 353 (void) printf( 354 " loc %x len %x\n", sap->sad_ext_loc, 355 len); 356 } 357 dir_adrindx = i; 358 if (debug) 359 (void) printf(" loc %x len %x\n", sap->sad_ext_loc, 360 sap->sad_ext_len); 361 baseblock = sap->sad_ext_loc; 362 if (block == 0) 363 block = baseblock; 364 dir_basesize = len; 365 if (type < 2) 366 markbusy(sap->sad_ext_loc, len); 367 if (type != 0) { 368 *poffset += dir_basesize; 369 goto again; 370 } 371 nb = roundup(len, secsize); 372 dirbuf = (uint8_t *)malloc(nb); 373 if (dirbuf == NULL) 374 errexit(gettext("Can't allocate directory extent " 375 "buffer\n")); 376 if (bread(fsreadfd, (char *)dirbuf, 377 fsbtodb(baseblock + part_start), nb) != 0) { 378 errexit(gettext("Can't read directory extent\n")); 379 } 380 dir_fidp = dirbuf; 381 break; 382 case ICB_FLAG_LONG_AD: 383 /* LINTED */ 384 lap = &((long_ad_t *)dir_adrlist)[dir_adrindx]; 385 for (i = dir_adrindx; i < dir_naddrs; i++, lap++) { 386 len = EXTLEN(lap->lad_ext_len); 387 type = EXTYPE(lap->lad_ext_len); 388 if (type == 3) { 389 if (i < dir_naddrs - 1) 390 errexit(gettext("Allocation extent not " 391 "at end of list\n")); 392 markbusy(lap->lad_ext_loc, len); 393 if (getallocext(fp, lap->lad_ext_loc, len)) 394 return (1); 395 goto again3; 396 } 397 if (newoff < len) 398 break; 399 newoff -= len; 400 dir_baseoff += len; 401 if (debug) 402 (void) printf( 403 " loc %x len %x\n", lap->lad_ext_loc, 404 len); 405 } 406 dir_adrindx = i; 407 if (debug) 408 (void) printf(" loc %x len %x\n", lap->lad_ext_loc, 409 lap->lad_ext_len); 410 baseblock = lap->lad_ext_loc; 411 if (block == 0) 412 block = baseblock; 413 dir_basesize = len; 414 if (type < 2) 415 markbusy(lap->lad_ext_loc, len); 416 if (type != 0) { 417 *poffset += dir_basesize; 418 goto again; 419 } 420 nb = roundup(len, secsize); 421 dirbuf = (uint8_t *)malloc(nb); 422 if (dirbuf == NULL) 423 errexit(gettext("Can't allocate directory extent " 424 "buffer\n")); 425 if (bread(fsreadfd, (char *)dirbuf, 426 fsbtodb(baseblock + part_start), nb) != 0) { 427 errexit(gettext("Can't read directory extent\n")); 428 } 429 dir_fidp = dirbuf; 430 break; 431 case ICB_FLAG_EXT_AD: 432 break; 433 case ICB_FLAG_ONE_AD: 434 errexit(gettext("Logic error in getdir - at ICB_FLAG_ONE_AD " 435 "case\n")); 436 break; 437 } 438 nextone: 439 if (debug) 440 (void) printf("getdirend blk %x dir_baseoff %llx newoff %x\n", 441 block, dir_baseoff, newoff); 442 left = dir_basesize - newoff; 443 if (xoff + left > MAXFIDSIZE) 444 left = MAXFIDSIZE - xoff; 445 bcopy((char *)dir_fidp + newoff, (char *)fidbuf + xoff, left); 446 xoff += left; 447 /* 448 * If we have a fid that crosses an extent boundary, then force 449 * a read of the next extent, and fill up the rest of the fid. 450 */ 451 if (xoff < sizeof (fidp->fid_tag) || 452 xoff < sizeof (fidp->fid_tag) + SWAP16(fidp->fid_tag.tag_crc_len)) { 453 offset += left; 454 if (debug) 455 (void) printf("block crossing at offset %llx\n", 456 offset); 457 goto again2; 458 } 459 err = verifytag(&fidp->fid_tag, block, &fidp->fid_tag, UD_FILE_ID_DESC); 460 if (debug) { 461 dump16((char *)fidp, "\n"); 462 } 463 if (err) { 464 pwarn(gettext("Bad directory tag: %s\n"), tagerrs[err]); 465 return (err); 466 } 467 *fidpp = fidp; 468 return (0); 469 } 470 471 static void 472 ckinode(struct file_entry *fp) 473 { 474 register struct short_ad *sap; 475 register struct long_ad *lap; 476 register int i, type, len; 477 478 switch (fp->fe_icb_tag.itag_flags & 0x3) { 479 case ICB_FLAG_SHORT_AD: 480 dir_adrsize = sizeof (short_ad_t); 481 dir_naddrs = fp->fe_len_adesc / sizeof (short_ad_t); 482 /* LINTED */ 483 sap = (short_ad_t *)(fp->fe_spec + fp->fe_len_ear); 484 again1: 485 for (i = 0; i < dir_naddrs; i++, sap++) { 486 len = EXTLEN(sap->sad_ext_len); 487 type = EXTYPE(sap->sad_ext_len); 488 if (type < 2) 489 markbusy(sap->sad_ext_loc, len); 490 if (debug) 491 (void) printf( 492 " loc %x len %x\n", sap->sad_ext_loc, 493 sap->sad_ext_len); 494 if (type == 3) { 495 markbusy(sap->sad_ext_loc, len); 496 /* This changes dir_naddrs and dir_adrlist */ 497 if (getallocext(fp, sap->sad_ext_loc, len)) 498 break; 499 /* LINTED */ 500 sap = (short_ad_t *)dir_adrlist; 501 goto again1; 502 } 503 } 504 break; 505 case ICB_FLAG_LONG_AD: 506 dir_adrsize = sizeof (long_ad_t); 507 dir_naddrs = fp->fe_len_adesc / sizeof (long_ad_t); 508 /* LINTED */ 509 lap = (long_ad_t *)(fp->fe_spec + fp->fe_len_ear); 510 again2: 511 for (i = 0; i < dir_naddrs; i++, lap++) { 512 len = EXTLEN(lap->lad_ext_len); 513 type = EXTYPE(lap->lad_ext_len); 514 if (type < 2) 515 markbusy(lap->lad_ext_loc, len); 516 if (debug) 517 (void) printf( 518 " loc %x len %x\n", lap->lad_ext_loc, 519 lap->lad_ext_len); 520 if (type == 3) { 521 markbusy(sap->sad_ext_loc, len); 522 /* This changes dir_naddrs and dir_adrlist */ 523 if (getallocext(fp, lap->lad_ext_loc, len)) 524 break; 525 /* LINTED */ 526 lap = (long_ad_t *)dir_adrlist; 527 goto again2; 528 } 529 } 530 break; 531 case ICB_FLAG_EXT_AD: 532 break; 533 case ICB_FLAG_ONE_AD: 534 break; 535 } 536 } 537 538 static void 539 adjust(struct fileinfo *fip) 540 { 541 register struct file_entry *fp; 542 register struct bufarea *bp; 543 544 bp = getfilentry(fip->fe_block, fip->fe_len); 545 if (bp == NULL) 546 errexit(gettext("Unable to read file entry at %x\n"), 547 fip->fe_block); 548 /* LINTED */ 549 fp = (struct file_entry *)bp->b_un.b_buf; 550 pwarn(gettext("LINK COUNT %s I=%x"), 551 fip->fe_type == FTYPE_DIRECTORY ? "DIR" : 552 fip->fe_type == FTYPE_SYMLINK ? "SYM" : 553 fip->fe_type == FTYPE_FILE ? "FILE" : "???", fip->fe_block); 554 (void) printf(gettext(" COUNT %d SHOULD BE %d"), 555 fip->fe_lcount, fip->fe_lseen); 556 if (preen) { 557 if (fip->fe_lseen > fip->fe_lcount) { 558 (void) printf("\n"); 559 pfatal(gettext("LINK COUNT INCREASING")); 560 } 561 (void) printf(gettext(" (ADJUSTED)\n")); 562 } 563 if (preen || reply(gettext("ADJUST")) == 1) { 564 fp->fe_lcount = fip->fe_lseen; 565 putfilentry(bp); 566 dirty(bp); 567 flush(fswritefd, bp); 568 } 569 bp->b_flags &= ~B_INUSE; 570 } 571 572 void 573 dofreemap() 574 { 575 register int i; 576 register char *bp, *fp; 577 struct inodesc idesc; 578 579 if (freemap == NULL) 580 return; 581 582 /* Flip bits in the busy map */ 583 bp = busymap; 584 for (i = 0, bp = busymap; i < part_bmp_bytes; i++, bp++) 585 *bp = ~*bp; 586 587 /* Mark leftovers in byte as allocated */ 588 if (part_len % NBBY) 589 bp[-1] &= (unsigned)0xff >> (NBBY - part_len % NBBY); 590 bp = busymap; 591 fp = freemap; 592 bzero((char *)&idesc, sizeof (struct inodesc)); 593 idesc.id_type = ADDR; 594 if (bcmp(bp, fp, part_bmp_bytes) != 0 && 595 dofix(&idesc, gettext("BLK(S) MISSING IN FREE BITMAP"))) { 596 bcopy(bp, fp, part_bmp_bytes); 597 maketag(&spacep->sbd_tag, &spacep->sbd_tag); 598 bwrite(fswritefd, (char *)spacep, fsbtodb(part_bmp_loc), 599 part_bmp_sectors * secsize); 600 } 601 } 602 603 void 604 dolvint() 605 { 606 struct lvid_iu *lviup; 607 struct inodesc idesc; 608 609 bzero((char *)&idesc, sizeof (struct inodesc)); 610 idesc.id_type = ADDR; 611 lviup = (struct lvid_iu *)&lvintp->lvid_fst[2]; 612 if ((lvintp->lvid_fst[0] != part_len - n_blks || 613 lvintp->lvid_int_type != LVI_CLOSE || 614 lviup->lvidiu_nfiles != n_files || 615 lviup->lvidiu_ndirs != n_dirs || 616 lvintp->lvid_uniqid < maxuniqid) && 617 dofix(&idesc, gettext("LOGICAL VOLUME INTEGRITY COUNTS WRONG"))) { 618 lvintp->lvid_int_type = LVI_CLOSE; 619 lvintp->lvid_fst[0] = part_len - n_blks; 620 lviup->lvidiu_nfiles = n_files; 621 lviup->lvidiu_ndirs = n_dirs; 622 lvintp->lvid_uniqid = maxuniqid; 623 maketag(&lvintp->lvid_tag, &lvintp->lvid_tag); 624 bwrite(fswritefd, (char *)lvintp, fsbtodb(lvintblock), 625 lvintlen); 626 } 627 } 628