dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fs.d / udfs / fsck / pass1.c
blobf04e7c97f48eafc2b5eae7a05ae465b9d4833134
1 /*
2 * Copyright 1999 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
9 /*
10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11 * All rights reserved.
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.
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>
44 * for each large file ( size > MAXOFF_T) this global counter
45 * gets incremented here.
48 extern unsigned int largefile_count;
49 extern void pwarn(char *, ...);
50 extern void pfatal(char *, ...);
51 extern void errexit(char *, ...);
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 *);
65 extern void dump16(char *, char *);
67 static void adjust(struct fileinfo *);
68 static void opndir(struct file_entry *);
69 static int32_t getdir(struct file_entry *, struct bufarea **,
70 uoff_t *, struct file_id **);
71 static void ckinode(struct file_entry *);
72 struct bufarea *getfilentry();
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;
81 /* Keep track of where we are in the directory */
82 static uoff_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;
88 #define MAXFIDSIZE 2048
90 static uint8_t fidbuf[MAXFIDSIZE];
92 void
93 pass1()
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;
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 uoff_t offset, end;
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;
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;
123 if (fip->fe_block == rootblock &&
124 fip->fe_type != FTYPE_DIRECTORY)
125 errexit(gettext("Root file entry is not a "
126 "directory\n"));
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);
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;
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);
156 if (dirbuf) {
157 free(dirbuf);
158 dirbuf = NULL;
160 if (fbp)
161 fbp->b_flags &= ~B_INUSE;
162 if (debug)
163 (void) printf("Done %x\n", fip->fe_block);
164 break;
166 case FTYPE_FILE:
167 case FTYPE_SYMLINK:
168 ckinode(fp);
169 default:
170 n_files++;
171 break;
173 putfilentry(bp);
174 bp->b_flags &= ~B_INUSE;
175 next:
176 /* At end of this set of fips, get the next set */
177 if ((++fip)->fe_block == (uint32_t)-1)
178 fip = fip->fe_nexthash;
181 /* Find bad link counts */
182 fip = &inphead[0];
183 while (fip->fe_block) {
184 if (fip->fe_lcount != fip->fe_lseen)
185 adjust(fip);
186 /* At end of this set of fips, get the next set */
187 if ((++fip)->fe_block == (uint32_t)-1)
188 fip = fip->fe_nexthash;
192 static void
193 opndir(struct file_entry *fp)
195 if (dirbuf) {
196 free(dirbuf);
197 dirbuf = NULL;
199 if (extbuf) {
200 free(extbuf);
201 extbuf = NULL;
204 dir_baseoff = 0;
205 dir_basesize = 0;
206 dir_adrindx = 0;
208 switch (fp->fe_icb_tag.itag_flags & 0x3) {
209 case ICB_FLAG_SHORT_AD:
210 dir_adrsize = sizeof (short_ad_t);
211 dir_naddrs = fp->fe_len_adesc / sizeof (short_ad_t);
212 dir_adrlist = (uint8_t *)(fp->fe_spec + fp->fe_len_ear);
213 break;
214 case ICB_FLAG_LONG_AD:
215 dir_adrsize = sizeof (long_ad_t);
216 dir_naddrs = fp->fe_len_adesc / sizeof (long_ad_t);
217 dir_adrlist = (uint8_t *)(fp->fe_spec + fp->fe_len_ear);
218 break;
219 case ICB_FLAG_EXT_AD:
220 errexit(gettext("Can't handle ext_ads in directories/n"));
221 break;
222 case ICB_FLAG_ONE_AD:
223 dir_adrsize = 0;
224 dir_naddrs = 0;
225 dir_adrlist = NULL;
226 dir_basesize = fp->fe_len_adesc;
227 dir_fidp = (uint8_t *)(fp->fe_spec + fp->fe_len_ear);
228 baseblock = fp->fe_tag.tag_loc;
229 break;
233 /* Allocate and read in an allocation extent */
234 /* ARGSUSED */
236 getallocext(struct file_entry *fp, uint32_t loc, uint32_t len)
238 uint32_t nb;
239 uint8_t *ap;
240 int i;
241 int err;
242 struct alloc_ext_desc *aep;
244 if (debug)
245 (void) printf(" allocext loc %x len %x\n", loc, len);
246 nb = roundup(len, secsize);
247 free(extbuf);
248 extbuf = (uint8_t *)malloc(nb);
249 if (extbuf == NULL)
250 errexit(gettext("Can't allocate directory extent buffer\n"));
251 if (bread(fsreadfd, (char *)extbuf,
252 fsbtodb(loc + part_start), nb) != 0) {
253 (void) fprintf(stderr,
254 gettext("Can't read allocation extent\n"));
255 return (1);
257 /* LINTED */
258 aep = (struct alloc_ext_desc *)extbuf;
259 err = verifytag(&aep->aed_tag, loc, &aep->aed_tag, UD_ALLOC_EXT_DESC);
260 if (err) {
261 (void) printf(
262 gettext("Bad tag on alloc extent: %s\n"), tagerrs[err]);
263 free(extbuf);
264 return (1);
266 dir_adrlist = (uint8_t *)(aep + 1);
267 dir_naddrs = aep->aed_len_aed / dir_adrsize;
268 dir_adrindx = 0;
270 /* Swap the descriptors */
271 for (i = 0, ap = dir_adrlist; i < dir_naddrs; i++, ap += dir_adrsize) {
272 if (dir_adrsize == sizeof (short_ad_t)) {
273 /* LINTED */
274 ud_swap_short_ad((short_ad_t *)ap);
275 } else if (dir_adrsize == sizeof (long_ad_t)) {
276 /* LINTED */
277 ud_swap_long_ad((long_ad_t *)ap);
281 return (0);
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
296 /* ARGSUSED1 */
297 static int32_t
298 getdir(struct file_entry *fp, struct bufarea **fbp,
299 uoff_t *poffset, struct file_id **fidpp)
301 /* LINTED */
302 register struct file_id *fidp = (struct file_id *)fidbuf;
303 register struct short_ad *sap;
304 register struct long_ad *lap;
305 register int i, newoff, xoff = 0;
306 uint32_t block = 0, nb, len, left;
307 uoff_t offset;
308 int err, type;
311 again:
312 offset = *poffset;
313 again2:
314 if (debug)
315 (void) printf("getdir %llx\n", offset);
316 newoff = offset - dir_baseoff;
317 if (newoff >= dir_basesize) {
318 if (dirbuf) {
319 free(dirbuf);
320 dirbuf = NULL;
322 } else {
323 if (block == 0)
324 block = baseblock + (newoff / secsize);
325 goto nextone;
328 again3:
329 switch (fp->fe_icb_tag.itag_flags & 0x3) {
330 case ICB_FLAG_SHORT_AD:
331 /* LINTED */
332 sap = &((short_ad_t *)dir_adrlist)[dir_adrindx];
333 for (i = dir_adrindx; i < dir_naddrs; i++, sap++) {
334 len = EXTLEN(sap->sad_ext_len);
335 type = EXTYPE(sap->sad_ext_len);
336 if (type == 3) {
337 if (i < dir_naddrs - 1)
338 errexit(gettext("Allocation extent not "
339 "at end of list\n"));
340 markbusy(sap->sad_ext_loc, len);
341 if (getallocext(fp, sap->sad_ext_loc, len))
342 return (1);
343 goto again3;
345 if (newoff < len)
346 break;
347 newoff -= len;
348 dir_baseoff += len;
349 if (debug)
350 (void) printf(
351 " loc %x len %x\n", sap->sad_ext_loc,
352 len);
354 dir_adrindx = i;
355 if (debug)
356 (void) printf(" loc %x len %x\n", sap->sad_ext_loc,
357 sap->sad_ext_len);
358 baseblock = sap->sad_ext_loc;
359 if (block == 0)
360 block = baseblock;
361 dir_basesize = len;
362 if (type < 2)
363 markbusy(sap->sad_ext_loc, len);
364 if (type != 0) {
365 *poffset += dir_basesize;
366 goto again;
368 nb = roundup(len, secsize);
369 dirbuf = (uint8_t *)malloc(nb);
370 if (dirbuf == NULL)
371 errexit(gettext("Can't allocate directory extent "
372 "buffer\n"));
373 if (bread(fsreadfd, (char *)dirbuf,
374 fsbtodb(baseblock + part_start), nb) != 0) {
375 errexit(gettext("Can't read directory extent\n"));
377 dir_fidp = dirbuf;
378 break;
379 case ICB_FLAG_LONG_AD:
380 /* LINTED */
381 lap = &((long_ad_t *)dir_adrlist)[dir_adrindx];
382 for (i = dir_adrindx; i < dir_naddrs; i++, lap++) {
383 len = EXTLEN(lap->lad_ext_len);
384 type = EXTYPE(lap->lad_ext_len);
385 if (type == 3) {
386 if (i < dir_naddrs - 1)
387 errexit(gettext("Allocation extent not "
388 "at end of list\n"));
389 markbusy(lap->lad_ext_loc, len);
390 if (getallocext(fp, lap->lad_ext_loc, len))
391 return (1);
392 goto again3;
394 if (newoff < len)
395 break;
396 newoff -= len;
397 dir_baseoff += len;
398 if (debug)
399 (void) printf(
400 " loc %x len %x\n", lap->lad_ext_loc,
401 len);
403 dir_adrindx = i;
404 if (debug)
405 (void) printf(" loc %x len %x\n", lap->lad_ext_loc,
406 lap->lad_ext_len);
407 baseblock = lap->lad_ext_loc;
408 if (block == 0)
409 block = baseblock;
410 dir_basesize = len;
411 if (type < 2)
412 markbusy(lap->lad_ext_loc, len);
413 if (type != 0) {
414 *poffset += dir_basesize;
415 goto again;
417 nb = roundup(len, secsize);
418 dirbuf = (uint8_t *)malloc(nb);
419 if (dirbuf == NULL)
420 errexit(gettext("Can't allocate directory extent "
421 "buffer\n"));
422 if (bread(fsreadfd, (char *)dirbuf,
423 fsbtodb(baseblock + part_start), nb) != 0) {
424 errexit(gettext("Can't read directory extent\n"));
426 dir_fidp = dirbuf;
427 break;
428 case ICB_FLAG_EXT_AD:
429 break;
430 case ICB_FLAG_ONE_AD:
431 errexit(gettext("Logic error in getdir - at ICB_FLAG_ONE_AD "
432 "case\n"));
433 break;
435 nextone:
436 if (debug)
437 (void) printf("getdirend blk %x dir_baseoff %llx newoff %x\n",
438 block, dir_baseoff, newoff);
439 left = dir_basesize - newoff;
440 if (xoff + left > MAXFIDSIZE)
441 left = MAXFIDSIZE - xoff;
442 bcopy((char *)dir_fidp + newoff, (char *)fidbuf + xoff, left);
443 xoff += left;
445 * If we have a fid that crosses an extent boundary, then force
446 * a read of the next extent, and fill up the rest of the fid.
448 if (xoff < sizeof (fidp->fid_tag) ||
449 xoff < sizeof (fidp->fid_tag) + SWAP16(fidp->fid_tag.tag_crc_len)) {
450 offset += left;
451 if (debug)
452 (void) printf("block crossing at offset %llx\n",
453 offset);
454 goto again2;
456 err = verifytag(&fidp->fid_tag, block, &fidp->fid_tag, UD_FILE_ID_DESC);
457 if (debug) {
458 dump16((char *)fidp, "\n");
460 if (err) {
461 pwarn(gettext("Bad directory tag: %s\n"), tagerrs[err]);
462 return (err);
464 *fidpp = fidp;
465 return (0);
468 static void
469 ckinode(struct file_entry *fp)
471 register struct short_ad *sap;
472 register struct long_ad *lap;
473 register int i, type, len;
475 switch (fp->fe_icb_tag.itag_flags & 0x3) {
476 case ICB_FLAG_SHORT_AD:
477 dir_adrsize = sizeof (short_ad_t);
478 dir_naddrs = fp->fe_len_adesc / sizeof (short_ad_t);
479 /* LINTED */
480 sap = (short_ad_t *)(fp->fe_spec + fp->fe_len_ear);
481 again1:
482 for (i = 0; i < dir_naddrs; i++, sap++) {
483 len = EXTLEN(sap->sad_ext_len);
484 type = EXTYPE(sap->sad_ext_len);
485 if (type < 2)
486 markbusy(sap->sad_ext_loc, len);
487 if (debug)
488 (void) printf(
489 " loc %x len %x\n", sap->sad_ext_loc,
490 sap->sad_ext_len);
491 if (type == 3) {
492 markbusy(sap->sad_ext_loc, len);
493 /* This changes dir_naddrs and dir_adrlist */
494 if (getallocext(fp, sap->sad_ext_loc, len))
495 break;
496 /* LINTED */
497 sap = (short_ad_t *)dir_adrlist;
498 goto again1;
501 break;
502 case ICB_FLAG_LONG_AD:
503 dir_adrsize = sizeof (long_ad_t);
504 dir_naddrs = fp->fe_len_adesc / sizeof (long_ad_t);
505 /* LINTED */
506 lap = (long_ad_t *)(fp->fe_spec + fp->fe_len_ear);
507 again2:
508 for (i = 0; i < dir_naddrs; i++, lap++) {
509 len = EXTLEN(lap->lad_ext_len);
510 type = EXTYPE(lap->lad_ext_len);
511 if (type < 2)
512 markbusy(lap->lad_ext_loc, len);
513 if (debug)
514 (void) printf(
515 " loc %x len %x\n", lap->lad_ext_loc,
516 lap->lad_ext_len);
517 if (type == 3) {
518 markbusy(sap->sad_ext_loc, len);
519 /* This changes dir_naddrs and dir_adrlist */
520 if (getallocext(fp, lap->lad_ext_loc, len))
521 break;
522 /* LINTED */
523 lap = (long_ad_t *)dir_adrlist;
524 goto again2;
527 break;
528 case ICB_FLAG_EXT_AD:
529 break;
530 case ICB_FLAG_ONE_AD:
531 break;
535 static void
536 adjust(struct fileinfo *fip)
538 register struct file_entry *fp;
539 register struct bufarea *bp;
541 bp = getfilentry(fip->fe_block, fip->fe_len);
542 if (bp == NULL)
543 errexit(gettext("Unable to read file entry at %x\n"),
544 fip->fe_block);
545 /* LINTED */
546 fp = (struct file_entry *)bp->b_un.b_buf;
547 pwarn(gettext("LINK COUNT %s I=%x"),
548 fip->fe_type == FTYPE_DIRECTORY ? "DIR" :
549 fip->fe_type == FTYPE_SYMLINK ? "SYM" :
550 fip->fe_type == FTYPE_FILE ? "FILE" : "???", fip->fe_block);
551 (void) printf(gettext(" COUNT %d SHOULD BE %d"),
552 fip->fe_lcount, fip->fe_lseen);
553 if (preen) {
554 if (fip->fe_lseen > fip->fe_lcount) {
555 (void) printf("\n");
556 pfatal(gettext("LINK COUNT INCREASING"));
558 (void) printf(gettext(" (ADJUSTED)\n"));
560 if (preen || reply(gettext("ADJUST")) == 1) {
561 fp->fe_lcount = fip->fe_lseen;
562 putfilentry(bp);
563 dirty(bp);
564 flush(fswritefd, bp);
566 bp->b_flags &= ~B_INUSE;
569 void
570 dofreemap()
572 register int i;
573 register char *bp, *fp;
574 struct inodesc idesc;
576 if (freemap == NULL)
577 return;
579 /* Flip bits in the busy map */
580 bp = busymap;
581 for (i = 0, bp = busymap; i < part_bmp_bytes; i++, bp++)
582 *bp = ~*bp;
584 /* Mark leftovers in byte as allocated */
585 if (part_len % NBBY)
586 bp[-1] &= (unsigned)0xff >> (NBBY - part_len % NBBY);
587 bp = busymap;
588 fp = freemap;
589 bzero((char *)&idesc, sizeof (struct inodesc));
590 idesc.id_type = ADDR;
591 if (bcmp(bp, fp, part_bmp_bytes) != 0 &&
592 dofix(&idesc, gettext("BLK(S) MISSING IN FREE BITMAP"))) {
593 bcopy(bp, fp, part_bmp_bytes);
594 maketag(&spacep->sbd_tag, &spacep->sbd_tag);
595 bwrite(fswritefd, (char *)spacep, fsbtodb(part_bmp_loc),
596 part_bmp_sectors * secsize);
600 void
601 dolvint()
603 struct lvid_iu *lviup;
604 struct inodesc idesc;
606 bzero((char *)&idesc, sizeof (struct inodesc));
607 idesc.id_type = ADDR;
608 lviup = (struct lvid_iu *)&lvintp->lvid_fst[2];
609 if ((lvintp->lvid_fst[0] != part_len - n_blks ||
610 lvintp->lvid_int_type != LVI_CLOSE ||
611 lviup->lvidiu_nfiles != n_files ||
612 lviup->lvidiu_ndirs != n_dirs ||
613 lvintp->lvid_uniqid < maxuniqid) &&
614 dofix(&idesc, gettext("LOGICAL VOLUME INTEGRITY COUNTS WRONG"))) {
615 lvintp->lvid_int_type = LVI_CLOSE;
616 lvintp->lvid_fst[0] = part_len - n_blks;
617 lviup->lvidiu_nfiles = n_files;
618 lviup->lvidiu_ndirs = n_dirs;
619 lvintp->lvid_uniqid = maxuniqid;
620 maketag(&lvintp->lvid_tag, &lvintp->lvid_tag);
621 bwrite(fswritefd, (char *)lvintp, fsbtodb(lvintblock),
622 lvintlen);