2 * Copyright 1999 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
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.
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>
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
];
95 register struct file_entry
*fp
;
96 register struct fileinfo
*fip
;
97 register struct bufarea
*bp
;
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
) {
109 markbusy(fip
->fe_block
, fip
->fe_len
);
110 bp
= getfilentry(fip
->fe_block
, fip
->fe_len
);
112 pwarn(gettext("Unable to read file entry at %x\n"),
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 "
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
:
139 end
= fp
->fe_info_len
;
142 for (offset
= 0; offset
< end
;
143 offset
+= FID_LENGTH(fidp
)) {
144 err
= getdir(fp
, &fbp
, &offset
, &fidp
);
146 pwarn(gettext("Bad directory entry in "
147 "file %x at offset %llx\n"),
148 fip
->fe_block
, offset
);
151 if (fidp
->fid_flags
& FID_DELETED
)
153 (void) cachefile(fidp
->fid_icb
.lad_ext_loc
,
154 fidp
->fid_icb
.lad_ext_len
);
161 fbp
->b_flags
&= ~B_INUSE
;
163 (void) printf("Done %x\n", fip
->fe_block
);
174 bp
->b_flags
&= ~B_INUSE
;
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 */
183 while (fip
->fe_block
) {
184 if (fip
->fe_lcount
!= fip
->fe_lseen
)
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
;
193 opndir(struct file_entry
*fp
)
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
);
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
);
219 case ICB_FLAG_EXT_AD
:
220 errexit(gettext("Can't handle ext_ads in directories/n"));
222 case ICB_FLAG_ONE_AD
:
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
;
233 /* Allocate and read in an allocation extent */
236 getallocext(struct file_entry
*fp
, uint32_t loc
, uint32_t len
)
242 struct alloc_ext_desc
*aep
;
245 (void) printf(" allocext loc %x len %x\n", loc
, len
);
246 nb
= roundup(len
, secsize
);
248 extbuf
= (uint8_t *)malloc(nb
);
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"));
258 aep
= (struct alloc_ext_desc
*)extbuf
;
259 err
= verifytag(&aep
->aed_tag
, loc
, &aep
->aed_tag
, UD_ALLOC_EXT_DESC
);
262 gettext("Bad tag on alloc extent: %s\n"), tagerrs
[err
]);
266 dir_adrlist
= (uint8_t *)(aep
+ 1);
267 dir_naddrs
= aep
->aed_len_aed
/ dir_adrsize
;
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
)) {
274 ud_swap_short_ad((short_ad_t
*)ap
);
275 } else if (dir_adrsize
== sizeof (long_ad_t
)) {
277 ud_swap_long_ad((long_ad_t
*)ap
);
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
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
298 getdir(struct file_entry
*fp
, struct bufarea
**fbp
,
299 uoff_t
*poffset
, struct file_id
**fidpp
)
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
;
315 (void) printf("getdir %llx\n", offset
);
316 newoff
= offset
- dir_baseoff
;
317 if (newoff
>= dir_basesize
) {
324 block
= baseblock
+ (newoff
/ secsize
);
329 switch (fp
->fe_icb_tag
.itag_flags
& 0x3) {
330 case ICB_FLAG_SHORT_AD
:
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
);
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
))
351 " loc %x len %x\n", sap
->sad_ext_loc
,
356 (void) printf(" loc %x len %x\n", sap
->sad_ext_loc
,
358 baseblock
= sap
->sad_ext_loc
;
363 markbusy(sap
->sad_ext_loc
, len
);
365 *poffset
+= dir_basesize
;
368 nb
= roundup(len
, secsize
);
369 dirbuf
= (uint8_t *)malloc(nb
);
371 errexit(gettext("Can't allocate directory extent "
373 if (bread(fsreadfd
, (char *)dirbuf
,
374 fsbtodb(baseblock
+ part_start
), nb
) != 0) {
375 errexit(gettext("Can't read directory extent\n"));
379 case ICB_FLAG_LONG_AD
:
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
);
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
))
400 " loc %x len %x\n", lap
->lad_ext_loc
,
405 (void) printf(" loc %x len %x\n", lap
->lad_ext_loc
,
407 baseblock
= lap
->lad_ext_loc
;
412 markbusy(lap
->lad_ext_loc
, len
);
414 *poffset
+= dir_basesize
;
417 nb
= roundup(len
, secsize
);
418 dirbuf
= (uint8_t *)malloc(nb
);
420 errexit(gettext("Can't allocate directory extent "
422 if (bread(fsreadfd
, (char *)dirbuf
,
423 fsbtodb(baseblock
+ part_start
), nb
) != 0) {
424 errexit(gettext("Can't read directory extent\n"));
428 case ICB_FLAG_EXT_AD
:
430 case ICB_FLAG_ONE_AD
:
431 errexit(gettext("Logic error in getdir - at ICB_FLAG_ONE_AD "
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
);
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
)) {
452 (void) printf("block crossing at offset %llx\n",
456 err
= verifytag(&fidp
->fid_tag
, block
, &fidp
->fid_tag
, UD_FILE_ID_DESC
);
458 dump16((char *)fidp
, "\n");
461 pwarn(gettext("Bad directory tag: %s\n"), tagerrs
[err
]);
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
);
480 sap
= (short_ad_t
*)(fp
->fe_spec
+ fp
->fe_len_ear
);
482 for (i
= 0; i
< dir_naddrs
; i
++, sap
++) {
483 len
= EXTLEN(sap
->sad_ext_len
);
484 type
= EXTYPE(sap
->sad_ext_len
);
486 markbusy(sap
->sad_ext_loc
, len
);
489 " loc %x len %x\n", sap
->sad_ext_loc
,
492 markbusy(sap
->sad_ext_loc
, len
);
493 /* This changes dir_naddrs and dir_adrlist */
494 if (getallocext(fp
, sap
->sad_ext_loc
, len
))
497 sap
= (short_ad_t
*)dir_adrlist
;
502 case ICB_FLAG_LONG_AD
:
503 dir_adrsize
= sizeof (long_ad_t
);
504 dir_naddrs
= fp
->fe_len_adesc
/ sizeof (long_ad_t
);
506 lap
= (long_ad_t
*)(fp
->fe_spec
+ fp
->fe_len_ear
);
508 for (i
= 0; i
< dir_naddrs
; i
++, lap
++) {
509 len
= EXTLEN(lap
->lad_ext_len
);
510 type
= EXTYPE(lap
->lad_ext_len
);
512 markbusy(lap
->lad_ext_loc
, len
);
515 " loc %x len %x\n", lap
->lad_ext_loc
,
518 markbusy(sap
->sad_ext_loc
, len
);
519 /* This changes dir_naddrs and dir_adrlist */
520 if (getallocext(fp
, lap
->lad_ext_loc
, len
))
523 lap
= (long_ad_t
*)dir_adrlist
;
528 case ICB_FLAG_EXT_AD
:
530 case ICB_FLAG_ONE_AD
:
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
);
543 errexit(gettext("Unable to read file entry at %x\n"),
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
);
554 if (fip
->fe_lseen
> fip
->fe_lcount
) {
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
;
564 flush(fswritefd
, bp
);
566 bp
->b_flags
&= ~B_INUSE
;
573 register char *bp
, *fp
;
574 struct inodesc idesc
;
579 /* Flip bits in the busy map */
581 for (i
= 0, bp
= busymap
; i
< part_bmp_bytes
; i
++, bp
++)
584 /* Mark leftovers in byte as allocated */
586 bp
[-1] &= (unsigned)0xff >> (NBBY
- part_len
% NBBY
);
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
);
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
),