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, uoff_t
*);
23 static void indir(daddr32_t
, int, uoff_t
*);
24 static void lf_blksout(daddr32_t
*, uoff_t
);
25 static void lf_dumpinode(struct dinode
*);
26 static void dsrch(daddr32_t
, ulong_t
, uoff_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 */
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
)
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)
323 /* xxx sanity check sblock contents before trusting them */
324 bread(fsbtodb(sblock
, d
), (uchar_t
*)idblk
, (size_t)sblock
->fs_bsize
);
326 for (i
= 0; i
< NINDIR(sblock
); i
++) {
329 dsrch(d
, (ulong_t
)(uint32_t)sblock
->fs_bsize
,
331 *filesize
-= (unsigned)(sblock
->fs_bsize
);
335 for (i
= 0; i
< NINDIR(sblock
); i
++) {
338 indir(d
, n
, filesize
);
347 /* watchout for dir inodes deleted and maybe reallocated */
348 if (((ip
->di_mode
& IFMT
) != IFDIR
&&
349 (ip
->di_mode
& IFMT
) != IFATTRDIR
) || ip
->di_nlink
< 2) {
350 (void) snprintf(msgbuf
, sizeof (msgbuf
), gettext(
351 "Warning - directory at inode `%lu' vanished!\n"),
359 static uoff_t loffset
; /* current offset in file (ufsdump) */
365 if ((ip
->di_shadow
== 0) || shortmeta
)
368 lf_dumpinode(getino((ino_t
)(unsigned)(ip
->di_shadow
)));
378 if ((*ip
)->di_shadow
== 0)
381 *ip
= getino((ino_t
)(unsigned)((*ip
)->di_shadow
));
382 rc
= ((*ip
)->di_size
<= sizeof (union u_shadow
));
383 *ip
= getino(ino
= savino
);
394 i
= ip
->di_mode
& IFMT
;
396 if (i
== 0 || ip
->di_nlink
<= 0)
402 if ((i
!= IFDIR
&& i
!= IFATTRDIR
&& i
!= IFREG
&& i
!= IFLNK
&&
403 i
!= IFSHAD
) || ip
->di_size
== 0) {
404 toslave(dospcl
, ino
);
408 size
= NDADDR
* (unsigned)(sblock
->fs_bsize
);
409 if (size
> ip
->di_size
)
412 lf_blksout(&ip
->di_db
[0], size
);
414 size
= ip
->di_size
- size
;
416 for (i
= 0; i
< NIADDR
; i
++) {
417 lf_dmpindir(ip
->di_ib
[i
], i
, &size
);
429 if ((!BIT(ino
, nodmap
)) && (!BIT(ino
, shamap
)))
432 shortmeta
= hasshortmeta(&ip
);
434 ip
= getino((ino_t
)(unsigned)(ip
->di_shadow
));
435 /* assume spcl.c_shadow is smaller than 1 block */
436 bread(fsbtodb(sblock
, ip
->di_db
[0]),
437 (uchar_t
*)spcl
.c_shadow
.c_shadow
, sizeof (spcl
.c_shadow
));
438 spcl
.c_flags
|= DR_HASMETA
;
440 spcl
.c_flags
&= ~DR_HASMETA
;
447 spcl
.c_type
= TS_TAPE
;
449 spcl
.c_type
= TS_ADDR
;
451 spcl
.c_type
= TS_INODE
;
460 lf_dmpindir(blk
, lvl
, size
)
467 daddr32_t idblk
[MAXNINDIR
];
469 if ((unsigned)(sblock
->fs_bsize
) > sizeof (idblk
)) {
471 "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
476 if ((unsigned)NINDIR(sblock
) > MAXNINDIR
) {
478 "Inconsistency detected: inode has more indirect \
479 blocks than valid maximum.\n"));
485 bread(fsbtodb(sblock
, blk
), (uchar_t
*)idblk
,
486 (size_t)sblock
->fs_bsize
);
488 bzero((char *)idblk
, (size_t)sblock
->fs_bsize
);
490 cnt
= (uoff_t
)(unsigned)NINDIR(sblock
) *
491 (uoff_t
)(unsigned)(sblock
->fs_bsize
);
495 lf_blksout(&idblk
[0], cnt
);
499 for (i
= 0; i
< NINDIR(sblock
); i
++) {
500 lf_dmpindir(idblk
[i
], lvl
, size
);
507 lf_blksout(blkp
, bytes
)
512 uoff_t tbperfsb
= (unsigned)(sblock
->fs_bsize
/ tp_bsize
);
516 uoff_t bytepos
, diff
;
518 off_t byteoff
= 0; /* bytes to skip within first f/s block */
519 off_t fragoff
= 0; /* frags to skip within first f/s block */
521 uoff_t tpblkoff
= 0; /* tape blocks to skip in first f/s block */
522 uoff_t tpblkskip
= 0; /* total tape blocks to skip */
523 uoff_t skip
; /* tape blocks to skip this pass */
527 * We get here if a slave throws a signal to the
528 * master indicating a partially dumped file.
529 * Begin by figuring out what was undone.
531 bytepos
= (offset_t
)pos
* tp_bsize
;
533 if ((loffset
+ bytes
) <= bytepos
) {
534 /* This stuff was dumped already, forget it. */
535 loffset
+= (uoff_t
)tp_bsize
*
536 /* LINTED: spurious complaint on sign-extending */
537 d_howmany(bytes
, (uoff_t
)tp_bsize
);
541 if (loffset
< bytepos
) {
543 * Some of this was dumped, some wasn't.
544 * Figure out what was done and skip it.
546 diff
= bytepos
- loffset
;
547 /* LINTED: spurious complaint on sign-extending */
548 tpblkskip
= d_howmany(diff
, (uoff_t
)tp_bsize
);
549 /* LINTED room after EOT is only a few MB */
550 blkp
+= (int)(diff
/ sblock
->fs_bsize
);
552 bytecnt
= diff
% (unsigned)(sblock
->fs_bsize
);
553 /* LINTED: result fits, due to modulus */
554 byteoff
= bytecnt
% (off_t
)(sblock
->fs_fsize
);
555 /* LINTED: spurious complaint on sign-extending */
556 tpblkoff
= d_howmany(bytecnt
,
557 (uoff_t
)(unsigned)tp_bsize
);
558 /* LINTED: result fits, due to modulus */
559 fragoff
= bytecnt
/ (off_t
)(sblock
->fs_fsize
);
560 bytecnt
= (unsigned)(sblock
->fs_bsize
) - bytecnt
;
567 if (bytes
< TP_NINDIR
*tp_bsize
)
568 /* LINTED: spurious complaint on sign-extending */
569 count
= d_howmany(bytes
, (uoff_t
)tp_bsize
);
573 if (tpblkskip
< TP_NINDIR
) {
574 bytes
-= (tpblkskip
* (uoff_t
)tp_bsize
);
578 bytes
-= (offset_t
)TP_NINDIR
*tp_bsize
;
579 tpblkskip
-= TP_NINDIR
;
584 assert(tbperfsb
>= tpblkoff
);
585 assert((count
- skip
) <= TP_NINDIR
);
586 for (j
= 0, k
= 0; j
< count
- skip
; j
++, k
++) {
587 spcl
.c_addr
[j
] = (blkp
[k
] != 0);
588 for (i
= tbperfsb
- tpblkoff
; --i
> 0; j
++)
589 spcl
.c_addr
[j
+1] = spcl
.c_addr
[j
];
592 /* LINTED (count - skip) will always fit into an int32_t */
593 spcl
.c_count
= count
- skip
;
594 toslave(dospcl
, ino
);
595 bytecnt
= MIN(bytes
, bytecnt
?
596 bytecnt
: (unsigned)(sblock
->fs_bsize
));
598 while (j
< count
- skip
) {
600 /* LINTED: fragoff fits into 32 bits */
601 dmpblk(*blkp
+(int32_t)fragoff
,
602 /* LINTED: bytecnt fits into 32 bits */
603 (size_t)bytecnt
, byteoff
);
607 /* LINTED: spurious complaint on sign-extending */
608 j
+= d_howmany(bytecnt
, (uoff_t
)tp_bsize
);
609 bytecnt
= MIN(bytes
, (unsigned)(sblock
->fs_bsize
));
613 spcl
.c_type
= TS_ADDR
;
632 for (i
= 0; i
< TP_NINDIR
; i
++)
634 /* LINTED: spurious complaint on sign-extending */
635 count
= d_howmany(msiz
* sizeof (map
[0]), tp_bsize
) - pos
;
636 for (cp
= &map
[pos
* tp_bsize
]; count
> 0;
637 count
-= (uoff_t
)(unsigned)spcl
.c_count
) {
639 spcl
.c_count
= leftover
;
642 /* LINTED value always less than INT32_MAX */
643 spcl
.c_count
= count
> TP_NINDIR
? TP_NINDIR
: count
;
646 for (i
= 0; i
< spcl
.c_count
; i
++, cp
+= tp_bsize
)
647 taprec(cp
, 0, tp_bsize
);
648 spcl
.c_type
= TS_ADDR
;
653 dsrch(d
, size
, filesize
)
655 ulong_t size
; /* block size */
663 if (dadded
|| filesize
== 0)
665 if (filesize
> (uoff_t
)size
)
666 filesize
= (uoff_t
)size
;
667 if (sizeof (dblk
) < roundup(filesize
, DEV_BSIZE
)) {
669 "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
675 /* LINTED ufs disk addresses always fit into 32 bits */
676 bread(fsbtodb(sblock
, d
), (uchar_t
*)dblk
,
677 /* LINTED from sizeof check above, roundup() <= max(size_t) */
678 (size_t)(roundup(filesize
, DEV_BSIZE
)));
680 while ((uoff_t
)loc
< filesize
) {
681 /*LINTED [dblk is char[], loc (dp->d_reclen) % 4 == 0]*/
682 dp
= (struct direct
*)(dblk
+ loc
);
683 if (dp
->d_reclen
== 0) {
684 (void) snprintf(msgbuf
, sizeof (msgbuf
), gettext(
685 "Warning - directory at inode `%lu' is corrupted\n"),
693 if (dp
->d_name
[0] == '.') {
694 if (dp
->d_name
[1] == '\0') {
695 if ((ino_t
)(dp
->d_ino
) != ino
) {
696 (void) snprintf(msgbuf
, sizeof (msgbuf
),
698 "Warning - directory at inode `%lu' is corrupted:\n\
699 \t\".\" points to inode `%lu' - run fsck\n"),
705 if (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0') {
706 if (!BIT(dp
->d_ino
, dirmap
) &&
707 ((ip
= getino(ino
)) == NULL
||
708 (ip
->di_mode
& IFMT
) != IFATTRDIR
)) {
709 (void) snprintf(msgbuf
, sizeof (msgbuf
),
711 "Warning - directory at inode `%lu' is corrupted:\n\
712 \t\"..\" points to non-directory inode `%lu' - run fsck\n"),
719 if (BIT(dp
->d_ino
, nodmap
)) {
723 if (BIT(dp
->d_ino
, dirmap
))
734 static ino_t minino
, maxino
;
735 static struct dinode itab
[MAXINOPB
];
736 static struct dinode icache
[CACHESIZE
];
737 static ino_t icacheval
[CACHESIZE
], lasti
= 0;
738 static int cacheoff
= 0;
741 if (ino
>= minino
&& ino
< maxino
) {
743 return (&itab
[ino
- minino
]);
746 /* before we do major i/o, check for a secondary cache hit */
747 for (i
= 0; i
< CACHESIZE
; i
++)
748 if (icacheval
[i
] == ino
)
751 /* we need to do major i/o. throw the last inode retrieved into */
752 /* the cache. note: this copies garbage the first time it is */
753 /* used, but no harm done. */
754 icacheval
[cacheoff
] = lasti
;
755 bcopy(itab
+ (lasti
- minino
), icache
+ cacheoff
, sizeof (itab
[0]));
757 if (++cacheoff
>= CACHESIZE
)
760 #define INOPERDB (DEV_BSIZE / sizeof (struct dinode))
761 minino
= ino
&~ (INOPERDB
- 1);
762 maxino
= ((itog(sblock
, ino
) + 1) * (unsigned)(sblock
->fs_ipg
));
763 if (maxino
> minino
+ MAXINOPB
)
764 maxino
= minino
+ MAXINOPB
;
766 /* LINTED: can't make up for broken system macros here */
767 (fsbtodb(sblock
, itod(sblock
, ino
)) + itoo(sblock
, ino
) / INOPERDB
),
768 /* LINTED: (max - min) * size fits into a size_t */
769 (uchar_t
*)itab
, (size_t)((maxino
- minino
) * sizeof (*itab
)));
770 return (&itab
[ino
- minino
]);
775 #ifdef NO__LONGLONG__
776 #define DEV_LSEEK(fd, offset, whence) \
777 lseek((fd), (((off_t)(offset))*DEV_BSIZE), (whence))
779 #define DEV_LSEEK(fd, offset, whence) \
780 llseek((fd), (((offset_t)((offset)))*DEV_BSIZE), (whence))
783 #define BREAD_FAIL(buf, size) { \
785 bzero(buf, (size_t)size); \
803 off64_t displacement
;
805 static size_t pagesize
= 0;
806 static int breaderrors
= 0;
808 /* mechanics for caching small bread requests. these are */
809 /* often small ACLs that are used over and over. */
810 static uchar_t bcache
[DEV_BSIZE
* CACHESIZE
];
811 static diskaddr_t bcacheval
[CACHESIZE
];
812 static int cacheoff
= 0;
815 if ((cnt
>= DEV_BSIZE
) && (mapfd
!= -1)) {
817 pagesize
= getpagesize();
819 * We depend on mmap(2)'s guarantee that mapping a
820 * partial page will cause the remainder of the page
823 filoff
= ((off64_t
)da
) * DEV_BSIZE
;
824 displacement
= filoff
& (pagesize
- 1);
825 mapoff
= filoff
- displacement
;
826 /* LINTED offset will fit into 32 bits */
827 len
= (size_t)roundup(cnt
+ (filoff
- mapoff
), pagesize
);
828 maddr
= mmap64(NULL
, len
, PROT_READ
, MAP_SHARED
, mapfd
, mapoff
);
829 if (maddr
!= MAP_FAILED
) {
830 (void) memcpy(ba
, maddr
+ displacement
, cnt
);
831 (void) munmap(maddr
, len
);
836 if (DEV_LSEEK(fi
, da
, L_SET
) < 0) {
838 msg(gettext("bread: dev_seek error: %s\n"), strerror(saverr
));
839 /* Don't know where we are, return the least-harmful data */
844 if (read(fi
, ba
, (size_t)cnt
) == (size_t)cnt
)
849 if (da
>= fsbtodb(sblock
, sblock
->fs_size
)) {
851 "Warning - block %llu is beyond the end of `%s'\n"),
857 if (DEV_LSEEK(fi
, da
, L_SET
) < 0) {
858 msg(gettext("%s: %s error\n"), "bread", "DEV_LSEEK2");
863 if (cnt
< DEV_BSIZE
) {
864 /* small read. check for cache hit. */
865 for (i
= 0; i
< CACHESIZE
; i
++)
866 if (bcacheval
[i
] == da
) {
867 bcopy(bcache
+ (i
* DEV_BSIZE
),
872 /* no cache hit; throw this one into the cache... */
874 dest
= bcache
+ (cacheoff
* DEV_BSIZE
);
875 bcacheval
[cacheoff
] = da
;
876 if (++cacheoff
>= CACHESIZE
)
883 n
= read(fi
, dest
, DEV_BSIZE
);
884 if (n
!= DEV_BSIZE
) {
886 bzero(dest
+n
, DEV_BSIZE
-n
);
889 "Warning - cannot read sector %llu of `%s'\n"),
893 bcopy(dest
, ba
, len
);
896 /* LINTED character pointers aren't signed */
901 if (breaderrors
> BREADEMAX
) {
903 "More than %d block read errors from dump device `%s'\n"),