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