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(void) 96 { 97 struct file_entry *fp; 98 struct fileinfo *fip; 99 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 fp = (struct file_entry *)bp->b_un.b_buf; 119 fip->fe_lcount = fp->fe_lcount; 120 fip->fe_type = fp->fe_icb_tag.itag_ftype; 121 if (fp->fe_uniq_id >= maxuniqid) 122 maxuniqid = fp->fe_uniq_id + 1; 123 124 if (fip->fe_block == rootblock && 125 fip->fe_type != FTYPE_DIRECTORY) 126 errexit(gettext("Root file entry is not a " 127 "directory\n")); 128 129 if (debug) { 130 (void) printf("do %x len %d type %d lcount %d" 131 " lseen %d end %llx\n", 132 fip->fe_block, fip->fe_len, 133 fip->fe_type, fip->fe_lcount, 134 fip->fe_lseen, fp->fe_info_len); 135 } 136 switch (fip->fe_type) { 137 case FTYPE_DIRECTORY: 138 n_dirs++; 139 offset = 0; 140 end = fp->fe_info_len; 141 fbp = NULL; 142 opndir(fp); 143 for (offset = 0; offset < end; 144 offset += FID_LENGTH(fidp)) { 145 err = getdir(fp, &fbp, &offset, &fidp); 146 if (err) { 147 pwarn(gettext("Bad directory entry in " 148 "file %x at offset %llx\n"), 149 fip->fe_block, offset); 150 offset = end; 151 } 152 if (fidp->fid_flags & FID_DELETED) 153 continue; 154 (void) cachefile(fidp->fid_icb.lad_ext_loc, 155 fidp->fid_icb.lad_ext_len); 156 } 157 if (dirbuf) { 158 free(dirbuf); 159 dirbuf = NULL; 160 } 161 if (fbp) 162 fbp->b_flags &= ~B_INUSE; 163 if (debug) 164 (void) printf("Done %x\n", fip->fe_block); 165 break; 166 167 case FTYPE_FILE: 168 case FTYPE_SYMLINK: 169 ckinode(fp); 170 /* FALLTHROUGH */ 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 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 ud_swap_short_ad((short_ad_t *)ap); 276 } else if (dir_adrsize == sizeof (long_ad_t)) { 277 ud_swap_long_ad((long_ad_t *)ap); 278 } 279 } 280 281 return (0); 282 } 283 284 /* 285 * Variables used in this function and their relationships: 286 * *poffset - read pointer in the directory 287 * dir_baseoff - offset at start of dirbuf 288 * dir_baselen - length of valid data in current extent 289 * dir_adrindx - index into current allocation extent for location of 290 * dir_baseoff 291 * dir_naddrs - number of entries in current allocation extent 292 * dir_fidp - pointer to dirbuf or immediate data in file entry 293 * baseblock - block address of dir_baseoff 294 * newoff - *poffset - dir_baseoff 295 */ 296 /* ARGSUSED1 */ 297 static int32_t 298 getdir(struct file_entry *fp, struct bufarea **fbp, 299 u_offset_t *poffset, struct file_id **fidpp) 300 { 301 struct file_id *fidp = (struct file_id *)fidbuf; 302 struct short_ad *sap; 303 struct long_ad *lap; 304 int i, newoff, xoff = 0; 305 uint32_t block = 0, nb, len = 0, left; 306 u_offset_t offset; 307 int err, type = 0; 308 309 310 again: 311 offset = *poffset; 312 again2: 313 if (debug) 314 (void) printf("getdir %llx\n", offset); 315 newoff = offset - dir_baseoff; 316 if (newoff >= dir_basesize) { 317 if (dirbuf) { 318 free(dirbuf); 319 dirbuf = NULL; 320 } 321 } else { 322 if (block == 0) 323 block = baseblock + (newoff / secsize); 324 goto nextone; 325 } 326 327 again3: 328 switch (fp->fe_icb_tag.itag_flags & 0x3) { 329 case ICB_FLAG_SHORT_AD: 330 sap = &((short_ad_t *)dir_adrlist)[dir_adrindx]; 331 for (i = dir_adrindx; i < dir_naddrs; i++, sap++) { 332 len = EXTLEN(sap->sad_ext_len); 333 type = EXTYPE(sap->sad_ext_len); 334 if (type == 3) { 335 if (i < dir_naddrs - 1) 336 errexit(gettext("Allocation extent not " 337 "at end of list\n")); 338 markbusy(sap->sad_ext_loc, len); 339 if (getallocext(fp, sap->sad_ext_loc, len)) 340 return (1); 341 goto again3; 342 } 343 if (newoff < len) 344 break; 345 newoff -= len; 346 dir_baseoff += len; 347 if (debug) 348 (void) printf( 349 " loc %x len %x\n", sap->sad_ext_loc, 350 len); 351 } 352 dir_adrindx = i; 353 if (debug) 354 (void) printf(" loc %x len %x\n", sap->sad_ext_loc, 355 sap->sad_ext_len); 356 baseblock = sap->sad_ext_loc; 357 if (block == 0) 358 block = baseblock; 359 dir_basesize = len; 360 if (type < 2) 361 markbusy(sap->sad_ext_loc, len); 362 if (type != 0) { 363 *poffset += dir_basesize; 364 goto again; 365 } 366 nb = roundup(len, secsize); 367 dirbuf = (uint8_t *)malloc(nb); 368 if (dirbuf == NULL) 369 errexit(gettext("Can't allocate directory extent " 370 "buffer\n")); 371 if (bread(fsreadfd, (char *)dirbuf, 372 fsbtodb(baseblock + part_start), nb) != 0) { 373 errexit(gettext("Can't read directory extent\n")); 374 } 375 dir_fidp = dirbuf; 376 break; 377 case ICB_FLAG_LONG_AD: 378 lap = &((long_ad_t *)dir_adrlist)[dir_adrindx]; 379 for (i = dir_adrindx; i < dir_naddrs; i++, lap++) { 380 len = EXTLEN(lap->lad_ext_len); 381 type = EXTYPE(lap->lad_ext_len); 382 if (type == 3) { 383 if (i < dir_naddrs - 1) 384 errexit(gettext("Allocation extent not " 385 "at end of list\n")); 386 markbusy(lap->lad_ext_loc, len); 387 if (getallocext(fp, lap->lad_ext_loc, len)) 388 return (1); 389 goto again3; 390 } 391 if (newoff < len) 392 break; 393 newoff -= len; 394 dir_baseoff += len; 395 if (debug) 396 (void) printf( 397 " loc %x len %x\n", lap->lad_ext_loc, 398 len); 399 } 400 dir_adrindx = i; 401 if (debug) 402 (void) printf(" loc %x len %x\n", lap->lad_ext_loc, 403 lap->lad_ext_len); 404 baseblock = lap->lad_ext_loc; 405 if (block == 0) 406 block = baseblock; 407 dir_basesize = len; 408 if (type < 2) 409 markbusy(lap->lad_ext_loc, len); 410 if (type != 0) { 411 *poffset += dir_basesize; 412 goto again; 413 } 414 nb = roundup(len, secsize); 415 dirbuf = (uint8_t *)malloc(nb); 416 if (dirbuf == NULL) 417 errexit(gettext("Can't allocate directory extent " 418 "buffer\n")); 419 if (bread(fsreadfd, (char *)dirbuf, 420 fsbtodb(baseblock + part_start), nb) != 0) { 421 errexit(gettext("Can't read directory extent\n")); 422 } 423 dir_fidp = dirbuf; 424 break; 425 case ICB_FLAG_EXT_AD: 426 break; 427 case ICB_FLAG_ONE_AD: 428 errexit(gettext("Logic error in getdir - at ICB_FLAG_ONE_AD " 429 "case\n")); 430 break; 431 } 432 nextone: 433 if (debug) 434 (void) printf("getdirend blk %x dir_baseoff %llx newoff %x\n", 435 block, dir_baseoff, newoff); 436 left = dir_basesize - newoff; 437 if (xoff + left > MAXFIDSIZE) 438 left = MAXFIDSIZE - xoff; 439 bcopy((char *)dir_fidp + newoff, (char *)fidbuf + xoff, left); 440 xoff += left; 441 /* 442 * If we have a fid that crosses an extent boundary, then force 443 * a read of the next extent, and fill up the rest of the fid. 444 */ 445 if (xoff < sizeof (fidp->fid_tag) || 446 xoff < sizeof (fidp->fid_tag) + SWAP16(fidp->fid_tag.tag_crc_len)) { 447 offset += left; 448 if (debug) 449 (void) printf("block crossing at offset %llx\n", 450 offset); 451 goto again2; 452 } 453 err = verifytag(&fidp->fid_tag, block, &fidp->fid_tag, UD_FILE_ID_DESC); 454 if (debug) { 455 dump16((char *)fidp, "\n"); 456 } 457 if (err) { 458 pwarn(gettext("Bad directory tag: %s\n"), tagerrs[err]); 459 return (err); 460 } 461 *fidpp = fidp; 462 return (0); 463 } 464 465 static void 466 ckinode(struct file_entry *fp) 467 { 468 struct short_ad *sap = NULL; 469 struct long_ad *lap; 470 int i, type, len; 471 472 switch (fp->fe_icb_tag.itag_flags & 0x3) { 473 case ICB_FLAG_SHORT_AD: 474 dir_adrsize = sizeof (short_ad_t); 475 dir_naddrs = fp->fe_len_adesc / sizeof (short_ad_t); 476 sap = (short_ad_t *)(fp->fe_spec + fp->fe_len_ear); 477 again1: 478 for (i = 0; i < dir_naddrs; i++, sap++) { 479 len = EXTLEN(sap->sad_ext_len); 480 type = EXTYPE(sap->sad_ext_len); 481 if (type < 2) 482 markbusy(sap->sad_ext_loc, len); 483 if (debug) 484 (void) printf( 485 " loc %x len %x\n", sap->sad_ext_loc, 486 sap->sad_ext_len); 487 if (type == 3) { 488 markbusy(sap->sad_ext_loc, len); 489 /* This changes dir_naddrs and dir_adrlist */ 490 if (getallocext(fp, sap->sad_ext_loc, len)) 491 break; 492 sap = (short_ad_t *)dir_adrlist; 493 goto again1; 494 } 495 } 496 break; 497 case ICB_FLAG_LONG_AD: 498 dir_adrsize = sizeof (long_ad_t); 499 dir_naddrs = fp->fe_len_adesc / sizeof (long_ad_t); 500 lap = (long_ad_t *)(fp->fe_spec + fp->fe_len_ear); 501 again2: 502 for (i = 0; i < dir_naddrs; i++, lap++) { 503 len = EXTLEN(lap->lad_ext_len); 504 type = EXTYPE(lap->lad_ext_len); 505 if (type < 2) 506 markbusy(lap->lad_ext_loc, len); 507 if (debug) 508 (void) printf( 509 " loc %x len %x\n", lap->lad_ext_loc, 510 lap->lad_ext_len); 511 if (type == 3) { 512 markbusy(sap->sad_ext_loc, len); 513 /* This changes dir_naddrs and dir_adrlist */ 514 if (getallocext(fp, lap->lad_ext_loc, len)) 515 break; 516 lap = (long_ad_t *)dir_adrlist; 517 goto again2; 518 } 519 } 520 break; 521 case ICB_FLAG_EXT_AD: 522 break; 523 case ICB_FLAG_ONE_AD: 524 break; 525 } 526 } 527 528 static void 529 adjust(struct fileinfo *fip) 530 { 531 struct file_entry *fp; 532 struct bufarea *bp; 533 534 bp = getfilentry(fip->fe_block, fip->fe_len); 535 if (bp == NULL) 536 errexit(gettext("Unable to read file entry at %x\n"), 537 fip->fe_block); 538 fp = (struct file_entry *)bp->b_un.b_buf; 539 pwarn(gettext("LINK COUNT %s I=%x"), 540 fip->fe_type == FTYPE_DIRECTORY ? "DIR" : 541 fip->fe_type == FTYPE_SYMLINK ? "SYM" : 542 fip->fe_type == FTYPE_FILE ? "FILE" : "???", fip->fe_block); 543 (void) printf(gettext(" COUNT %d SHOULD BE %d"), 544 fip->fe_lcount, fip->fe_lseen); 545 if (preen) { 546 if (fip->fe_lseen > fip->fe_lcount) { 547 (void) printf("\n"); 548 pfatal(gettext("LINK COUNT INCREASING")); 549 } 550 (void) printf(gettext(" (ADJUSTED)\n")); 551 } 552 if (preen || reply(gettext("ADJUST")) == 1) { 553 fp->fe_lcount = fip->fe_lseen; 554 putfilentry(bp); 555 dirty(bp); 556 flush(fswritefd, bp); 557 } 558 bp->b_flags &= ~B_INUSE; 559 } 560 561 void 562 dofreemap(void) 563 { 564 int i; 565 char *bp, *fp; 566 struct inodesc idesc; 567 568 if (freemap == NULL) 569 return; 570 571 /* Flip bits in the busy map */ 572 bp = busymap; 573 for (i = 0, bp = busymap; i < part_bmp_bytes; i++, bp++) 574 *bp = ~*bp; 575 576 /* Mark leftovers in byte as allocated */ 577 if (part_len % NBBY) 578 bp[-1] &= (unsigned)0xff >> (NBBY - part_len % NBBY); 579 bp = busymap; 580 fp = freemap; 581 bzero((char *)&idesc, sizeof (struct inodesc)); 582 idesc.id_type = ADDR; 583 if (bcmp(bp, fp, part_bmp_bytes) != 0 && 584 dofix(&idesc, gettext("BLK(S) MISSING IN FREE BITMAP"))) { 585 bcopy(bp, fp, part_bmp_bytes); 586 maketag(&spacep->sbd_tag, &spacep->sbd_tag); 587 bwrite(fswritefd, (char *)spacep, fsbtodb(part_bmp_loc), 588 part_bmp_sectors * secsize); 589 } 590 } 591 592 void 593 dolvint(void) 594 { 595 struct lvid_iu *lviup; 596 struct inodesc idesc; 597 598 bzero((char *)&idesc, sizeof (struct inodesc)); 599 idesc.id_type = ADDR; 600 lviup = (struct lvid_iu *)&lvintp->lvid_fst[2]; 601 if ((lvintp->lvid_fst[0] != part_len - n_blks || 602 lvintp->lvid_int_type != LVI_CLOSE || 603 lviup->lvidiu_nfiles != n_files || 604 lviup->lvidiu_ndirs != n_dirs || 605 lvintp->lvid_uniqid < maxuniqid) && 606 dofix(&idesc, gettext("LOGICAL VOLUME INTEGRITY COUNTS WRONG"))) { 607 lvintp->lvid_int_type = LVI_CLOSE; 608 lvintp->lvid_fst[0] = part_len - n_blks; 609 lviup->lvidiu_nfiles = n_files; 610 lviup->lvidiu_ndirs = n_dirs; 611 lvintp->lvid_uniqid = maxuniqid; 612 maketag(&lvintp->lvid_tag, &lvintp->lvid_tag); 613 bwrite(fswritefd, (char *)lvintp, fsbtodb(lvintblock), 614 lvintlen); 615 } 616 } 617