* Copyright (c) 1992 The Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)library.c 5.10 (Berkeley) %G%";
#include <ufs/ufs/dinode.h>
void add_blocks
__P((FS_INFO
*, BLOCK_INFO
*, int *, SEGSUM
*, caddr_t
,
void add_inodes
__P((FS_INFO
*, BLOCK_INFO
*, int *, SEGSUM
*, caddr_t
,
int bi_compare
__P((const void *, const void *));
int bi_toss
__P((const void *, const void *, const void *));
void get_ifile
__P((FS_INFO
*, int));
int get_superblock
__P((FS_INFO
*, struct lfs
*));
int pseg_valid
__P((FS_INFO
*, SEGSUM
*));
* This function will get information on a a filesystem which matches
* the name and type given. If a "name" is in a filesystem of the given
* type, then buf is filled with that filesystem's info, and the
* a non-zero value is returned.
fs_getmntinfo(buf
, name
, type
)
/* allocate space for the filesystem info */
*buf
= (struct statfs
*)malloc(sizeof(struct statfs
));
/* grab the filesystem info */
if (statfs(name
, *buf
) < 0) {
/* check to see if it's the one we want */
if (((*buf
)->f_type
!= type
) ||
strncmp(name
, (*buf
)->f_mntonname
, MNAMELEN
)) {
/* "this is not the filesystem you're looking for */
* Get all the information available on an LFS file system.
* Returns an pointer to an FS_INFO structure, NULL on error.
get_fs_info (lstatfsp
, use_mmap
)
struct statfs
*lstatfsp
; /* IN: pointer to statfs struct */
int use_mmap
; /* IN: mmap or read */
fsp
= (FS_INFO
*)malloc(sizeof(FS_INFO
));
bzero(fsp
, sizeof(FS_INFO
));
fsp
->fi_statfsp
= lstatfsp
;
if (get_superblock (fsp
, &fsp
->fi_lfs
))
err(1, "get_fs_info: get_superblock failed");
fsp
->fi_lfs
.lfs_bshift
- fsp
->fi_lfs
.lfs_fsbtodb
;
get_ifile (fsp
, use_mmap
);
* If we are reading the ifile then we need to refresh it. Even if
* we are mmapping it, it might have grown. Finally, we need to
* refresh the file system information (statfs) info.
reread_fs_info(fsp
, use_mmap
)
FS_INFO
*fsp
; /* IN: prointer fs_infos to reread */
if (statfs(fsp
->fi_statfsp
->f_mntonname
, fsp
->fi_statfsp
))
err(0, "reread_fs_info: statfs failed");
get_ifile (fsp
, use_mmap
);
* Gets the superblock from disk (possibly in face of errors)
get_superblock (fsp
, sbp
)
FS_INFO
*fsp
; /* local file system info structure */
char mntfromname
[MNAMELEN
+1];
strcpy(mntfromname
, "/dev/r");
strcat(mntfromname
, fsp
->fi_statfsp
->f_mntfromname
+5);
if ((fid
= open(mntfromname
, O_RDONLY
, (mode_t
)0)) < 0) {
err(0, "get_superblock: bad open");
get(fid
, LFS_LABELPAD
, sbp
, sizeof(struct lfs
));
* This function will map the ifile into memory. It causes a
* fatal error on failure.
get_ifile (fsp
, use_mmap
)
ifile_name
= malloc(strlen(fsp
->fi_statfsp
->f_mntonname
) +
strcat(strcat(strcpy(ifile_name
, fsp
->fi_statfsp
->f_mntonname
), "/"),
if ((fid
= open(ifile_name
, O_RDWR
, (mode_t
)0)) < 0)
err(1, "get_ifile: bad open");
if (fstat (fid
, &file_stat
))
err(1, "get_ifile: fstat failed");
if (use_mmap
&& file_stat
.st_size
== fsp
->fi_ifile_length
) {
munmap((caddr_t
)fsp
->fi_cip
, fsp
->fi_ifile_length
);
ifp
= mmap ((caddr_t
)0, file_stat
.st_size
,
PROT_READ
|PROT_WRITE
, 0, fid
, (off_t
)0);
if (ifp
== (caddr_t
)(-1))
err(1, "get_ifile: mmap failed");
if (!(ifp
= malloc (file_stat
.st_size
)))
err (1, "get_ifile: malloc failed");
count
= read (fid
, ifp
, (size_t) file_stat
.st_size
);
err(1, "get_ifile: bad ifile read");
else if (count
< file_stat
.st_size
) {
if (lseek(fid
, 0, SEEK_SET
) < 0)
err(1, "get_ifile: bad ifile lseek");
fsp
->fi_ifile_length
= file_stat
.st_size
;
fsp
->fi_cip
= (CLEANERINFO
*)ifp
;
fsp
->fi_segusep
= (SEGUSE
*)(ifp
+ CLEANSIZE(fsp
));
fsp
->fi_ifilep
= (IFILE
*)((caddr_t
)fsp
->fi_segusep
+ SEGTABSIZE(fsp
));
* The number of ifile entries is equal to the number of blocks
* blocks in the ifile minus the ones allocated to cleaner info
* and segment usage table multiplied by the number of ifile
fsp
->fi_ifile_count
= (fsp
->fi_ifile_length
>> fsp
->fi_lfs
.lfs_bshift
-
fsp
->fi_lfs
.lfs_cleansz
- fsp
->fi_lfs
.lfs_segtabsz
) *
* This function will scan a segment and return a list of
* <inode, blocknum> pairs which indicate which blocks were
* contained as live data within the segment when the segment
* summary was read (it may have "died" since then). Any given
* pair will be listed at most once.
lfs_segmapv(fsp
, seg
, seg_buf
, blocks
, bcount
)
FS_INFO
*fsp
; /* pointer to local file system information */
int seg
; /* the segment number */
caddr_t seg_buf
; /* the buffer containing the segment's data */
BLOCK_INFO
**blocks
; /* OUT: array of block_info for live blocks */
int *bcount
; /* OUT: number of active blocks in segment */
daddr_t pseg_addr
, seg_addr
;
int i
, nelem
, nblocks
, sumsize
;
nelem
= 2 * lfsp
->lfs_ssize
;
if (!(bip
= malloc(nelem
* sizeof(BLOCK_INFO
))))
sup
= SEGUSE_ENTRY(lfsp
, fsp
->fi_segusep
, seg
);
s
= seg_buf
+ (sup
->su_flags
& SEGUSE_SUPERBLOCK
? LFS_SBPAD
: 0);
seg_addr
= sntoda(lfsp
, seg
);
pseg_addr
= seg_addr
+ (sup
->su_flags
& SEGUSE_SUPERBLOCK
? btodb(LFS_SBPAD
) : 0);
printf("\tsegment buffer at: 0x%x\tseg_addr 0x%x\n", s
, seg_addr
);
for (segend
= seg_buf
+ seg_size(lfsp
), timestamp
= 0; s
< segend
; ) {
printf("\tpartial at: 0x%x\n", pseg_addr
);
nblocks
= pseg_valid(fsp
, sp
);
/* Check if we have hit old data */
if (timestamp
> ((SEGSUM
*)s
)->ss_create
)
timestamp
= ((SEGSUM
*)s
)->ss_create
;
/* Verfiy size of summary block */
sumsize
= sizeof(SEGSUM
) +
(sp
->ss_ninos
+ INOPB(lfsp
) - 1) / INOPB(lfsp
);
for (fip
= (FINFO
*)(sp
+ 1); i
< sp
->ss_nfinfo
; ++i
) {
sumsize
+= sizeof(FINFO
) +
(fip
->fi_nblocks
- 1) * sizeof(daddr_t
);
fip
= (FINFO
*)(&fip
->fi_blocks
[fip
->fi_nblocks
]);
if (sumsize
> LFS_SUMMARY_SIZE
) {
"Segment %d summary block too big: %d\n",
if (*bcount
+ nblocks
+ sp
->ss_ninos
> nelem
) {
nelem
= *bcount
+ nblocks
+ sp
->ss_ninos
;
bip
= realloc (bip
, nelem
* sizeof(BLOCK_INFO
));
add_blocks(fsp
, bip
, bcount
, sp
, seg_buf
, seg_addr
, pseg_addr
);
add_inodes(fsp
, bip
, bcount
, sp
, seg_buf
, seg_addr
);
pseg_addr
+= fsbtodb(lfsp
, nblocks
) +
bytetoda(fsp
, LFS_SUMMARY_SIZE
);
s
+= (nblocks
<< lfsp
->lfs_bshift
) + LFS_SUMMARY_SIZE
;
qsort(bip
, *bcount
, sizeof(BLOCK_INFO
), bi_compare
);
toss(bip
, bcount
, sizeof(BLOCK_INFO
), bi_toss
, NULL
);
for (_bip
= bip
, i
=0; i
< *bcount
; ++_bip
, ++i
)
* This will parse a partial segment and fill in BLOCK_INFO structures
* for each block described in the segment summary. It will not include
* blocks or inodes from files with new version numbers.
add_blocks (fsp
, bip
, countp
, sp
, seg_buf
, segaddr
, psegaddr
)
FS_INFO
*fsp
; /* pointer to super block */
BLOCK_INFO
*bip
; /* Block info array */
int *countp
; /* IN/OUT: number of blocks in array */
SEGSUM
*sp
; /* segment summmary pointer */
caddr_t seg_buf
; /* buffer containing segment */
daddr_t segaddr
; /* address of this segment */
daddr_t psegaddr
; /* address of this partial segment */
db_per_block
= fsbtodb(&fsp
->fi_lfs
, 1);
page_size
= fsp
->fi_lfs
.lfs_bsize
;
bp
= seg_buf
+ datobyte(fsp
, psegaddr
- segaddr
) + LFS_SUMMARY_SIZE
;
psegaddr
+= bytetoda(fsp
, LFS_SUMMARY_SIZE
);
iaddrp
= (daddr_t
*)((caddr_t
)sp
+ LFS_SUMMARY_SIZE
);
for (fip
= (FINFO
*)(sp
+ 1), i
= 0; i
< sp
->ss_nfinfo
;
++i
, fip
= (FINFO
*)(&fip
->fi_blocks
[fip
->fi_nblocks
])) {
ifp
= IFILE_ENTRY(&fsp
->fi_lfs
, fsp
->fi_ifilep
, fip
->fi_ino
);
if (ifp
->if_version
> fip
->fi_version
)
dp
= &(fip
->fi_blocks
[0]);
for (j
= 0; j
< fip
->fi_nblocks
; j
++, dp
++) {
while (psegaddr
== *iaddrp
) {
psegaddr
+= db_per_block
;
bip
->bi_inode
= fip
->fi_ino
;
bip
->bi_daddr
= psegaddr
;
bip
->bi_segcreate
= (time_t)(sp
->ss_create
);
bip
->bi_version
= ifp
->if_version
;
psegaddr
+= db_per_block
;
* For a particular segment summary, reads the inode blocks and adds
* INODE_INFO structures to the array. Returns the number of inodes
add_inodes (fsp
, bip
, countp
, sp
, seg_buf
, seg_addr
)
FS_INFO
*fsp
; /* pointer to super block */
BLOCK_INFO
*bip
; /* block info array */
int *countp
; /* pointer to current number of inodes */
SEGSUM
*sp
; /* segsum pointer */
caddr_t seg_buf
; /* the buffer containing the segment's data */
daddr_t seg_addr
; /* disk address of seg_buf */
(void) printf("INODES:\n");
daddrp
= (daddr_t
*)((caddr_t
)sp
+ LFS_SUMMARY_SIZE
);
for (i
= 0; i
< sp
->ss_ninos
; ++i
) {
if (i
% INOPB(lfsp
) == 0) {
di
= (struct dinode
*)(seg_buf
+
((*daddrp
- seg_addr
) << fsp
->fi_daddr_shift
));
bp
->bi_lbn
= LFS_UNUSED_LBN
;
bp
->bi_segcreate
= sp
->ss_create
;
if (inum
== LFS_IFILE_INUM
) {
bp
->bi_version
= 1; /* Ifile version should be 1 */
ifp
= IFILE_ENTRY(lfsp
, fsp
->fi_ifilep
, inum
);
PRINT_INODE(ifp
->if_daddr
== *daddrp
, bp
);
bp
->bi_version
= ifp
->if_version
;
if (ifp
->if_daddr
== *daddrp
) {
* Checks the summary checksum and the data checksum to determine if the
* segment is valid or not. Returns the size of the partial segment if it
* is valid, * and 0 otherwise. Use dump_summary to figure out size of the
* the partial as well as whether or not the checksum is valid.
FS_INFO
*fsp
; /* pointer to file system info */
SEGSUM
*ssp
; /* pointer to segment summary block */
if ((nblocks
= dump_summary(&fsp
->fi_lfs
, ssp
, 0, NULL
)) <= 0 ||
nblocks
> fsp
->fi_lfs
.lfs_ssize
- 1)
/* check data/inode block(s) checksum too */
datap
= (u_long
*)malloc(nblocks
* sizeof(u_long
));
p
= (caddr_t
)ssp
+ LFS_SUMMARY_SIZE
;
for (i
= 0; i
< nblocks
; ++i
) {
datap
[i
] = *((u_long
*)p
);
p
+= fsp
->fi_lfs
.lfs_bsize
;
if (cksum ((void *)datap
, nblocks
* sizeof(u_long
)) != ssp
->ss_datasum
)
/* #define MMAP_SEGMENT */
* read a segment into a memory buffer
mmap_segment (fsp
, segment
, segbuf
, use_mmap
)
FS_INFO
*fsp
; /* file system information */
int segment
; /* segment number */
caddr_t
*segbuf
; /* pointer to buffer area */
int use_mmap
; /* mmap instead of read */
int fid
; /* fildes for file system device */
daddr_t seg_daddr
; /* base disk address of segment */
char mntfromname
[MNAMELEN
+2];
/* get the disk address of the beginning of the segment */
seg_daddr
= sntoda(lfsp
, segment
);
seg_byte
= datobyte(fsp
, seg_daddr
);
strcpy(mntfromname
, "/dev/r");
strcat(mntfromname
, fsp
->fi_statfsp
->f_mntfromname
+5);
if ((fid
= open(mntfromname
, O_RDONLY
, (mode_t
)0)) < 0) {
err(0, "mmap_segment: bad open");
*segbuf
= mmap ((caddr_t
)0, seg_size(lfsp
), PROT_READ
,
if (*(long *)segbuf
< 0) {
err(0, "mmap_segment: mmap failed");
printf("mmap_segment\tseg_daddr: %lu\tseg_size: %lu\tseg_offset: %qu\n",
seg_daddr
, ssize
, seg_byte
);
/* malloc the space for the buffer */
err(0, "mmap_segment: malloc failed");
/* read the segment data into the buffer */
if (lseek (fid
, seg_byte
, SEEK_SET
) != seg_byte
) {
err (0, "mmap_segment: bad lseek");
if (read (fid
, *segbuf
, ssize
) != ssize
) {
err (0, "mmap_segment: bad read");
munmap_segment (fsp
, seg_buf
, use_mmap
)
FS_INFO
*fsp
; /* file system information */
caddr_t seg_buf
; /* pointer to buffer area */
int use_mmap
; /* mmap instead of read/write */
munmap (seg_buf
, seg_size(&fsp
->fi_lfs
));
* USEFUL DEBUGGING TOOLS:
(void) dump_summary(lfsp
, p
, DUMP_ALL
, NULL
);
const BLOCK_INFO
*ba
, *bb
;
if (diff
= (int)(ba
->bi_inode
- bb
->bi_inode
))
if (diff
= (int)(ba
->bi_lbn
- bb
->bi_lbn
)) {
if (ba
->bi_lbn
== LFS_UNUSED_LBN
)
else if (bb
->bi_lbn
== LFS_UNUSED_LBN
)
else if (ba
->bi_lbn
< 0 && bb
->bi_lbn
>= 0)
else if (bb
->bi_lbn
< 0 && ba
->bi_lbn
>= 0)
if (diff
= (int)(ba
->bi_segcreate
- bb
->bi_segcreate
))
diff
= (int)(ba
->bi_daddr
- bb
->bi_daddr
);
const BLOCK_INFO
*ba
, *bb
;
return(ba
->bi_inode
== bb
->bi_inode
&& ba
->bi_lbn
== bb
->bi_lbn
);
toss(p
, nump
, size
, dotoss
, client
)
int (*dotoss
) __P((const void *, const void *, const void *));
for (i
= *nump
; --i
> 0;) {
if (dotoss(client
, p
, p1
)) {
memmove(p
, p1
, i
* size
);