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