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
pass1(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
opndir(struct file_entry * fp)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
getallocext(struct file_entry * fp,uint32_t loc,uint32_t len)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
getdir(struct file_entry * fp,struct bufarea ** fbp,u_offset_t * poffset,struct file_id ** fidpp)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
ckinode(struct file_entry * fp)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
adjust(struct fileinfo * fip)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
dofreemap(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
dolvint(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