2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #pragma ident "%Z%%M% %I% %E% SMI"
22 static void lf_dmpindir(daddr32_t
, int, u_offset_t
*);
23 static void indir(daddr32_t
, int, u_offset_t
*);
24 static void lf_blksout(daddr32_t
*, u_offset_t
);
25 static void lf_dumpinode(struct dinode
*);
26 static void dsrch(daddr32_t
, ulong_t
, u_offset_t
);
27 void lf_dump(struct dinode
*);
29 static void lf_dmpindir();
31 static void lf_blksout();
36 static char msgbuf
[256];
40 void (*fn
)(struct dinode
*);
46 maxino
= (unsigned)(sblock
->fs_ipg
* sblock
->fs_ncg
- 1);
48 * Handle pass restarts. We don't check for UFSROOTINO just in
49 * case we need to restart on the root inode.
54 /* LINTED: lint seems to think map is signed */
58 bits
>>= (ino
% NBBY
);
62 while (ino
< maxino
) {
63 if ((ino
% NBBY
) == 0) {
71 * Ignore any inode less than UFSROOTINO and inodes that
72 * we have already done on a previous pass.
74 if ((ino
>= UFSROOTINO
) && (bits
& 1)) {
76 * The following test is merely an optimization
77 * for common case where "add" will just return.
79 if (!(fn
== add
&& BIT(ino
, nodmap
)))
92 f
= ip
->di_mode
& IFMT
;
93 if (f
== 0 || ip
->di_nlink
<= 0) {
94 /* LINTED: 32-bit to 8-bit assignment ok */
98 /* LINTED: 32-bit to 8-bit assignment ok */
100 if (f
== IFDIR
|| f
== IFATTRDIR
) {
101 /* LINTED: 32-bit to 8-bit assignment ok */
104 if (ip
->di_ctime
>= spcl
.c_ddate
) {
107 /* LINTED: 32-bit to 8-bit assignment ok */
109 /* attribute changes impact the root */
111 BIS(UFSROOTINO
, nodmap
);
112 if (f
!= IFREG
&& f
!= IFDIR
&& f
!= IFATTRDIR
&& f
!= IFLNK
) {
126 f
= ip
->di_mode
& IFMT
;
127 if (f
== 0 || ip
->di_nlink
<= 0) {
128 /* LINTED: 32-bit to 8-bit assignment ok */
132 /* LINTED: 32-bit to 8-bit assignment ok */
134 if (f
== IFDIR
|| f
== IFATTRDIR
) {
135 /* LINTED: 32-bit to 8-bit assignment ok */
138 if (BIT(ino
, activemap
)) {
139 /* LINTED: 32-bit to 8-bit assignment ok */
141 /* attribute changes impact the root */
143 BIS(UFSROOTINO
, nodmap
);
144 if (f
!= IFREG
&& f
!= IFDIR
&& f
!= IFATTRDIR
&& f
!= IFLNK
) {
152 static struct shcount
{
153 struct shcount
*higher
, *lower
;
161 static struct shcount
*shc
= NULL
;
169 if (ip
->di_shadow
== 0)
174 shadow
= (ino_t
)(unsigned)(ip
->di_shadow
);
175 while ((shadow
> shc
->ino
) && (shc
->higher
))
177 while ((shadow
< shc
->ino
) && (shc
->lower
))
179 if (shadow
!= shc
->ino
) {
182 new = (struct shcount
*)xcalloc(1, sizeof (*new));
183 new->higher
= shc
->higher
;
184 if (shc
->higher
!= NULL
)
185 shc
->higher
->lower
= new;
192 /* LINTED: 32-bit to 8-bit assignment ok */
201 u_offset_t esizeprime
;
204 if (ip
->di_size
<= sizeof (union u_shadow
))
207 while ((ino
> shc
->ino
) && (shc
->higher
))
209 while ((ino
< shc
->ino
) && (shc
->lower
))
212 return; /* xxx panic? complain? */
214 tmpesize
= (o_esize
+ f_esize
);
215 esizeprime
= tmpesize
;
217 esizeprime
= tmpesize
- esizeprime
;
218 esizeprime
*= shc
->count
- 1;
219 f_esize
+= esizeprime
;
232 if (shc
->higher
) /* else panic? */
233 (void) free(shc
->higher
);
236 * This should be unnecessary, but do it just to be safe.
237 * Note that shc might be malloc'd or static, so can't free().
239 bzero(shc
, sizeof (*shc
));
249 if (BIT(ino
, nodmap
))
251 if ((ip
->di_mode
& IFMT
) != IFDIR
&&
252 (ip
->di_mode
& IFMT
) != IFATTRDIR
) {
253 (void) snprintf(msgbuf
, sizeof (msgbuf
), gettext(
254 "Warning - directory at inode `%lu' vanished!\n"), ino
);
256 /* LINTED: 32-bit to 8-bit assignment ok */
262 filesize
= ip
->di_size
;
263 for (i
= 0; i
< NDADDR
; i
++) {
264 if (ip
->di_db
[i
] != 0)
265 /* LINTED dblksize/blkoff does a safe cast here */
266 dsrch(ip
->di_db
[i
], (ulong_t
)dblksize(sblock
, ip
, i
),
268 filesize
-= (unsigned)(sblock
->fs_bsize
);
270 for (i
= 0; i
< NIADDR
; i
++) {
271 if (ip
->di_ib
[i
] != 0)
272 indir(ip
->di_ib
[i
], i
, &filesize
);
276 if (!BIT(ino
, nodmap
)) {
277 /* LINTED: 32-bit to 8-bit assignment ok */
279 if ((ip
->di_mode
& IFMT
) == IFATTRDIR
) {
280 /* attribute changes "auto-percolate" to root */
281 BIS(UFSROOTINO
, nodmap
);
287 if (!BIT(ino
, nodmap
)) {
288 /* LINTED: 32-bit to 8-bit assignment ok */
295 indir(d
, n
, filesize
)
298 u_offset_t
*filesize
;
301 daddr32_t idblk
[MAXNINDIR
];
303 if ((unsigned)(sblock
->fs_bsize
) > sizeof (idblk
)) {
305 "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
310 if ((unsigned)NINDIR(sblock
) > MAXNINDIR
) {
313 "Inconsistency detected: inode has more indirect \
314 blocks than valid maximum.\n"));
319 if (dadded
|| *filesize
== 0)
326 /* xxx sanity check sblock contents before trusting them */
327 bread(fsbtodb(sblock
, d
), (uchar_t
*)idblk
, (size_t)sblock
->fs_bsize
);
329 for (i
= 0; i
< NINDIR(sblock
); i
++) {
332 dsrch(d
, (ulong_t
)(uint32_t)sblock
->fs_bsize
,
334 *filesize
-= (unsigned)(sblock
->fs_bsize
);
338 for (i
= 0; i
< NINDIR(sblock
); i
++) {
341 indir(d
, n
, filesize
);
350 /* watchout for dir inodes deleted and maybe reallocated */
351 if (((ip
->di_mode
& IFMT
) != IFDIR
&&
352 (ip
->di_mode
& IFMT
) != IFATTRDIR
) || ip
->di_nlink
< 2) {
353 (void) snprintf(msgbuf
, sizeof (msgbuf
), gettext(
354 "Warning - directory at inode `%lu' vanished!\n"),
362 static u_offset_t loffset
; /* current offset in file (ufsdump) */
368 if ((ip
->di_shadow
== 0) || shortmeta
)
371 lf_dumpinode(getino((ino_t
)(unsigned)(ip
->di_shadow
)));
381 if ((*ip
)->di_shadow
== 0)
384 *ip
= getino((ino_t
)(unsigned)((*ip
)->di_shadow
));
385 rc
= ((*ip
)->di_size
<= sizeof (union u_shadow
));
386 *ip
= getino(ino
= savino
);
397 i
= ip
->di_mode
& IFMT
;
399 if (i
== 0 || ip
->di_nlink
<= 0)
405 if ((i
!= IFDIR
&& i
!= IFATTRDIR
&& i
!= IFREG
&& i
!= IFLNK
&&
406 i
!= IFSHAD
) || ip
->di_size
== 0) {
407 toslave(dospcl
, ino
);
411 size
= NDADDR
* (unsigned)(sblock
->fs_bsize
);
412 if (size
> ip
->di_size
)
415 lf_blksout(&ip
->di_db
[0], size
);
417 size
= ip
->di_size
- size
;
419 for (i
= 0; i
< NIADDR
; i
++) {
420 lf_dmpindir(ip
->di_ib
[i
], i
, &size
);
432 if ((!BIT(ino
, nodmap
)) && (!BIT(ino
, shamap
)))
435 shortmeta
= hasshortmeta(&ip
);
437 ip
= getino((ino_t
)(unsigned)(ip
->di_shadow
));
438 /* assume spcl.c_shadow is smaller than 1 block */
439 bread(fsbtodb(sblock
, ip
->di_db
[0]),
440 (uchar_t
*)spcl
.c_shadow
.c_shadow
, sizeof (spcl
.c_shadow
));
441 spcl
.c_flags
|= DR_HASMETA
;
443 spcl
.c_flags
&= ~DR_HASMETA
;
450 spcl
.c_type
= TS_TAPE
;
452 spcl
.c_type
= TS_ADDR
;
454 spcl
.c_type
= TS_INODE
;
463 lf_dmpindir(blk
, lvl
, size
)
470 daddr32_t idblk
[MAXNINDIR
];
472 if ((unsigned)(sblock
->fs_bsize
) > sizeof (idblk
)) {
474 "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
479 if ((unsigned)NINDIR(sblock
) > MAXNINDIR
) {
481 "Inconsistency detected: inode has more indirect \
482 blocks than valid maximum.\n"));
488 bread(fsbtodb(sblock
, blk
), (uchar_t
*)idblk
,
489 (size_t)sblock
->fs_bsize
);
491 bzero((char *)idblk
, (size_t)sblock
->fs_bsize
);
493 cnt
= (u_offset_t
)(unsigned)NINDIR(sblock
) *
494 (u_offset_t
)(unsigned)(sblock
->fs_bsize
);
498 lf_blksout(&idblk
[0], cnt
);
502 for (i
= 0; i
< NINDIR(sblock
); i
++) {
503 lf_dmpindir(idblk
[i
], lvl
, size
);
510 lf_blksout(blkp
, bytes
)
515 u_offset_t tbperfsb
= (unsigned)(sblock
->fs_bsize
/ tp_bsize
);
517 u_offset_t j
, k
, count
;
519 u_offset_t bytepos
, diff
;
520 u_offset_t bytecnt
= 0;
521 off_t byteoff
= 0; /* bytes to skip within first f/s block */
522 off_t fragoff
= 0; /* frags to skip within first f/s block */
524 u_offset_t tpblkoff
= 0; /* tape blocks to skip in first f/s block */
525 u_offset_t tpblkskip
= 0; /* total tape blocks to skip */
526 u_offset_t skip
; /* tape blocks to skip this pass */
530 * We get here if a slave throws a signal to the
531 * master indicating a partially dumped file.
532 * Begin by figuring out what was undone.
534 bytepos
= (offset_t
)pos
* tp_bsize
;
536 if ((loffset
+ bytes
) <= bytepos
) {
537 /* This stuff was dumped already, forget it. */
538 loffset
+= (u_offset_t
)tp_bsize
*
539 /* LINTED: spurious complaint on sign-extending */
540 d_howmany(bytes
, (u_offset_t
)tp_bsize
);
544 if (loffset
< bytepos
) {
546 * Some of this was dumped, some wasn't.
547 * Figure out what was done and skip it.
549 diff
= bytepos
- loffset
;
550 /* LINTED: spurious complaint on sign-extending */
551 tpblkskip
= d_howmany(diff
, (u_offset_t
)tp_bsize
);
552 /* LINTED room after EOT is only a few MB */
553 blkp
+= (int)(diff
/ sblock
->fs_bsize
);
555 bytecnt
= diff
% (unsigned)(sblock
->fs_bsize
);
556 /* LINTED: result fits, due to modulus */
557 byteoff
= bytecnt
% (off_t
)(sblock
->fs_fsize
);
558 /* LINTED: spurious complaint on sign-extending */
559 tpblkoff
= d_howmany(bytecnt
,
560 (u_offset_t
)(unsigned)tp_bsize
);
561 /* LINTED: result fits, due to modulus */
562 fragoff
= bytecnt
/ (off_t
)(sblock
->fs_fsize
);
563 bytecnt
= (unsigned)(sblock
->fs_bsize
) - bytecnt
;
570 if (bytes
< TP_NINDIR
*tp_bsize
)
571 /* LINTED: spurious complaint on sign-extending */
572 count
= d_howmany(bytes
, (u_offset_t
)tp_bsize
);
576 if (tpblkskip
< TP_NINDIR
) {
577 bytes
-= (tpblkskip
* (u_offset_t
)tp_bsize
);
581 bytes
-= (offset_t
)TP_NINDIR
*tp_bsize
;
582 tpblkskip
-= TP_NINDIR
;
587 assert(tbperfsb
>= tpblkoff
);
588 assert((count
- skip
) <= TP_NINDIR
);
589 for (j
= 0, k
= 0; j
< count
- skip
; j
++, k
++) {
590 spcl
.c_addr
[j
] = (blkp
[k
] != 0);
591 for (i
= tbperfsb
- tpblkoff
; --i
> 0; j
++)
592 spcl
.c_addr
[j
+1] = spcl
.c_addr
[j
];
595 /* LINTED (count - skip) will always fit into an int32_t */
596 spcl
.c_count
= count
- skip
;
597 toslave(dospcl
, ino
);
598 bytecnt
= MIN(bytes
, bytecnt
?
599 bytecnt
: (unsigned)(sblock
->fs_bsize
));
601 while (j
< count
- skip
) {
603 /* LINTED: fragoff fits into 32 bits */
604 dmpblk(*blkp
+(int32_t)fragoff
,
605 /* LINTED: bytecnt fits into 32 bits */
606 (size_t)bytecnt
, byteoff
);
610 /* LINTED: spurious complaint on sign-extending */
611 j
+= d_howmany(bytecnt
, (u_offset_t
)tp_bsize
);
612 bytecnt
= MIN(bytes
, (unsigned)(sblock
->fs_bsize
));
616 spcl
.c_type
= TS_ADDR
;
635 for (i
= 0; i
< TP_NINDIR
; i
++)
637 /* LINTED: spurious complaint on sign-extending */
638 count
= d_howmany(msiz
* sizeof (map
[0]), tp_bsize
) - pos
;
639 for (cp
= &map
[pos
* tp_bsize
]; count
> 0;
640 count
-= (u_offset_t
)(unsigned)spcl
.c_count
) {
642 spcl
.c_count
= leftover
;
645 /* LINTED value always less than INT32_MAX */
646 spcl
.c_count
= count
> TP_NINDIR
? TP_NINDIR
: count
;
649 for (i
= 0; i
< spcl
.c_count
; i
++, cp
+= tp_bsize
)
650 taprec(cp
, 0, tp_bsize
);
651 spcl
.c_type
= TS_ADDR
;
656 dsrch(d
, size
, filesize
)
658 ulong_t size
; /* block size */
666 if (dadded
|| filesize
== 0)
668 if (filesize
> (u_offset_t
)size
)
669 filesize
= (u_offset_t
)size
;
670 if (sizeof (dblk
) < roundup(filesize
, DEV_BSIZE
)) {
672 "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
681 /* LINTED ufs disk addresses always fit into 32 bits */
682 bread(fsbtodb(sblock
, d
), (uchar_t
*)dblk
,
683 /* LINTED from sizeof check above, roundup() <= max(size_t) */
684 (size_t)(roundup(filesize
, DEV_BSIZE
)));
686 while ((u_offset_t
)loc
< filesize
) {
687 /*LINTED [dblk is char[], loc (dp->d_reclen) % 4 == 0]*/
688 dp
= (struct direct
*)(dblk
+ loc
);
689 if (dp
->d_reclen
== 0) {
690 (void) snprintf(msgbuf
, sizeof (msgbuf
), gettext(
691 "Warning - directory at inode `%lu' is corrupted\n"),
699 if (dp
->d_name
[0] == '.') {
700 if (dp
->d_name
[1] == '\0') {
701 if ((ino_t
)(dp
->d_ino
) != ino
) {
702 (void) snprintf(msgbuf
, sizeof (msgbuf
),
704 "Warning - directory at inode `%lu' is corrupted:\n\
705 \t\".\" points to inode `%lu' - run fsck\n"),
711 if (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0') {
712 if (!BIT(dp
->d_ino
, dirmap
) &&
713 ((ip
= getino(ino
)) == NULL
||
714 (ip
->di_mode
& IFMT
) != IFATTRDIR
)) {
715 (void) snprintf(msgbuf
, sizeof (msgbuf
),
717 "Warning - directory at inode `%lu' is corrupted:\n\
718 \t\"..\" points to non-directory inode `%lu' - run fsck\n"),
725 if (BIT(dp
->d_ino
, nodmap
)) {
729 if (BIT(dp
->d_ino
, dirmap
))
740 static ino_t minino
, maxino
;
741 static struct dinode itab
[MAXINOPB
];
742 static struct dinode icache
[CACHESIZE
];
743 static ino_t icacheval
[CACHESIZE
], lasti
= 0;
744 static int cacheoff
= 0;
747 if (ino
>= minino
&& ino
< maxino
) {
749 return (&itab
[ino
- minino
]);
752 /* before we do major i/o, check for a secondary cache hit */
753 for (i
= 0; i
< CACHESIZE
; i
++)
754 if (icacheval
[i
] == ino
)
757 /* we need to do major i/o. throw the last inode retrieved into */
758 /* the cache. note: this copies garbage the first time it is */
759 /* used, but no harm done. */
760 icacheval
[cacheoff
] = lasti
;
761 bcopy(itab
+ (lasti
- minino
), icache
+ cacheoff
, sizeof (itab
[0]));
763 if (++cacheoff
>= CACHESIZE
)
766 #define INOPERDB (DEV_BSIZE / sizeof (struct dinode))
767 minino
= ino
&~ (INOPERDB
- 1);
768 maxino
= ((itog(sblock
, ino
) + 1) * (unsigned)(sblock
->fs_ipg
));
769 if (maxino
> minino
+ MAXINOPB
)
770 maxino
= minino
+ MAXINOPB
;
772 /* LINTED: can't make up for broken system macros here */
773 (fsbtodb(sblock
, itod(sblock
, ino
)) + itoo(sblock
, ino
) / INOPERDB
),
774 /* LINTED: (max - min) * size fits into a size_t */
775 (uchar_t
*)itab
, (size_t)((maxino
- minino
) * sizeof (*itab
)));
776 return (&itab
[ino
- minino
]);
781 #ifdef NO__LONGLONG__
782 #define DEV_LSEEK(fd, offset, whence) \
783 lseek((fd), (((off_t)(offset))*DEV_BSIZE), (whence))
785 #define DEV_LSEEK(fd, offset, whence) \
786 llseek((fd), (((offset_t)((offset)))*DEV_BSIZE), (whence))
789 #define BREAD_FAIL(buf, size) { \
791 bzero(buf, (size_t)size); \
809 off64_t displacement
;
811 static size_t pagesize
= 0;
812 static int breaderrors
= 0;
814 /* mechanics for caching small bread requests. these are */
815 /* often small ACLs that are used over and over. */
816 static uchar_t bcache
[DEV_BSIZE
* CACHESIZE
];
817 static diskaddr_t bcacheval
[CACHESIZE
];
818 static int cacheoff
= 0;
821 if ((cnt
>= DEV_BSIZE
) && (mapfd
!= -1)) {
823 pagesize
= getpagesize();
825 * We depend on mmap(2)'s guarantee that mapping a
826 * partial page will cause the remainder of the page
829 filoff
= ((off64_t
)da
) * DEV_BSIZE
;
830 displacement
= filoff
& (pagesize
- 1);
831 mapoff
= filoff
- displacement
;
832 /* LINTED offset will fit into 32 bits */
833 len
= (size_t)roundup(cnt
+ (filoff
- mapoff
), pagesize
);
834 maddr
= mmap64(NULL
, len
, PROT_READ
, MAP_SHARED
, mapfd
, mapoff
);
835 if (maddr
!= MAP_FAILED
) {
836 (void) memcpy(ba
, maddr
+ displacement
, cnt
);
837 (void) munmap(maddr
, len
);
842 if (DEV_LSEEK(fi
, da
, L_SET
) < 0) {
844 msg(gettext("bread: dev_seek error: %s\n"), strerror(saverr
));
845 /* Don't know where we are, return the least-harmful data */
850 if (read(fi
, ba
, (size_t)cnt
) == (size_t)cnt
)
855 if (da
>= fsbtodb(sblock
, sblock
->fs_size
)) {
857 "Warning - block %llu is beyond the end of `%s'\n"),
863 if (DEV_LSEEK(fi
, da
, L_SET
) < 0) {
864 msg(gettext("%s: %s error\n"), "bread", "DEV_LSEEK2");
869 if (cnt
< DEV_BSIZE
) {
870 /* small read. check for cache hit. */
871 for (i
= 0; i
< CACHESIZE
; i
++)
872 if (bcacheval
[i
] == da
) {
873 bcopy(bcache
+ (i
* DEV_BSIZE
),
878 /* no cache hit; throw this one into the cache... */
880 dest
= bcache
+ (cacheoff
* DEV_BSIZE
);
881 bcacheval
[cacheoff
] = da
;
882 if (++cacheoff
>= CACHESIZE
)
889 n
= read(fi
, dest
, DEV_BSIZE
);
890 if (n
!= DEV_BSIZE
) {
892 bzero(dest
+n
, DEV_BSIZE
-n
);
895 "Warning - cannot read sector %llu of `%s'\n"),
899 bcopy(dest
, ba
, len
);
902 /* LINTED character pointers aren't signed */
907 if (breaderrors
> BREADEMAX
) {
909 "More than %d block read errors from dump device `%s'\n"),