static void raw_read_queue(void *buf, daddr_t blkpos, size_t bytelen) /* bytelen: must be DEV_BSIZE aligned */ { static daddr_t rq_start; static char *rq_buf; if (rq_len) { if (bytelen && blkpos == rq_start + (ssize_t) btodb(rq_len) && buf == rq_buf + rq_len) { rq_len += bytelen; return; } else { #ifdef DEBUG_WITH_STDIO printf("raw_read_queue: read: buf %p, blk %d, len %d\n", rq_buf, (int) rq_start, rq_len); #endif RAW_READ(rq_buf, rq_start, rq_len); } } rq_buf = buf; rq_start = blkpos; rq_len = bytelen; }
/* * Read and check superblock. * If it is an LFS, save information from the superblock. */ int try_lfs(void) { struct ufs_info *ufsinfo = &ufs_info; struct dlfs sblk, sblk2; struct dlfs *s = &sblk; daddr_t sbpos; int fsbshift; #ifdef DEBUG_WITH_STDIO printf("trying LFS\n"); #endif sbpos = btodb(LFS_LABELPAD); /* read primary superblock */ for (;;) { #ifdef DEBUG_WITH_STDIO printf("LFS: reading primary sblk at: 0x%x\n", (unsigned)sbpos); #endif RAW_READ(&sblk, sbpos, sizeof sblk); #ifdef DEBUG_WITH_STDIO printf("LFS: sblk: magic: 0x%x, version: %d\n", sblk.dlfs_magic, sblk.dlfs_version); #endif if (sblk.dlfs_magic != LFS_MAGIC) return 1; #ifdef DEBUG_WITH_STDIO printf("LFS: bsize %d, fsize %d, bshift %d, blktodb %d, fsbtodb %d, inopf %d, inopb %d\n", sblk.dlfs_bsize, sblk.dlfs_fsize, sblk.dlfs_bshift, sblk.dlfs_blktodb, sblk.dlfs_fsbtodb, sblk.dlfs_inopf, sblk.dlfs_inopb); #endif if ((fsi_lfs.version = sblk.dlfs_version) == 1) { fsbshift = 0; break; } else { daddr_t sbpos1; #if 0 fsbshift = sblk.dlfs_bshift - sblk.dlfs_blktodb + sblk.dlfs_fsbtodb - DEV_BSHIFT; #endif fsbshift = sblk.dlfs_fsbtodb; sbpos1 = sblk.dlfs_sboffs[0] << fsbshift; if (sbpos == sbpos1) break; #ifdef DEBUG_WITH_STDIO printf("LFS: correcting primary sblk location\n"); #endif sbpos = sbpos1; } } #ifdef DEBUG_WITH_STDIO printf("fsbshift: %d\n", fsbshift); printf("sboff[1]: %d\n", sblk.dlfs_sboffs[1]); #endif if (sblk.dlfs_sboffs[1] > 0) { #ifdef DEBUG_WITH_STDIO printf("LFS: reading secondary sblk at: 0x%x\n", sblk.dlfs_sboffs[1] << fsbshift); #endif /* read secondary superblock */ RAW_READ(&sblk2, (daddr_t) sblk.dlfs_sboffs[1] << fsbshift, sizeof sblk2); #ifdef DEBUG_WITH_STDIO printf("LFS: sblk2: magic: 0x%x, version: %d\n", sblk2.dlfs_magic, sblk2.dlfs_version); #endif if (sblk2.dlfs_magic == LFS_MAGIC) { if (fsi_lfs.version == 1) { if (sblk.dlfs_otstamp > sblk2.dlfs_otstamp) s = &sblk2; } else { if (sblk.dlfs_serial > sblk2.dlfs_serial) s = &sblk2; } } } /* This partition looks like an LFS. */ #if 0 fsi.get_inode = get_lfs_inode; #endif /* * version 1: disk addr is in disk sector --- no shifting * version 2: disk addr is in fragment */ fsi.fsbtodb = fsbshift; /* Get information from the superblock. */ fsi.bsize = s->dlfs_bsize; fsi.nindir = s->dlfs_nindir; fsi_lfs.idaddr = s->dlfs_idaddr; fsi_lfs.ibsize = (fsi_lfs.version == 1) ? s->dlfs_bsize : s->dlfs_fsize; /* * version 1: number of inode per block * version 2: number of inode per fragment (but in dlfs_inopb) */ fsi_lfs.inopb = s->dlfs_inopb; fsi_lfs.ifpb = s->dlfs_ifpb; fsi_lfs.ioffset = s->dlfs_cleansz + s->dlfs_segtabsz; /* ifile is always used to look-up other inodes, so keep its inode. */ if (get_lfs_inode(LFS_IFILE_INUM, (union ufs_dinode *)&ifile_dinode)) return 1; /* OOPS, failed to find inode of ifile! */ fsi.fstype = UFSTYPE_LFS; return 0; }
/* * Get inode from disk. */ int get_lfs_inode(ino32_t ino, union ufs_dinode *dibuf) { struct ufs_info *ufsinfo = &ufs_info; daddr_t daddr; char *buf = alloca(fsi.bsize); struct ulfs1_dinode *di, *diend; int i; /* Get fs block which contains the specified inode. */ if (ino == LFS_IFILE_INUM) daddr = fsi_lfs.idaddr; else { #ifdef DEBUG_WITH_STDIO printf("LFS: ino: %d\nifpb: %d, bsize: %d\n", ino, fsi_lfs.ifpb, fsi.bsize); #endif ufs_read((union ufs_dinode *) &ifile_dinode, buf, ino / fsi_lfs.ifpb + fsi_lfs.ioffset, fsi.bsize); i = ino % fsi_lfs.ifpb; daddr = (fsi_lfs.version == 1) ? ((IFILE_V1 *) buf + i)->if_daddr : ((IFILE *) buf + i)->if_daddr; } #ifdef DEBUG_WITH_STDIO printf("LFS(%d): daddr: %d\n", ino, (int) daddr); #endif if (daddr == LFS_UNUSED_DADDR) return 1; /* Read the inode block. */ RAW_READ(buf, daddr << fsi.fsbtodb, fsi_lfs.ibsize); /* Search for the inode. */ di = (struct ulfs1_dinode *) buf; diend = di + fsi_lfs.inopb; for ( ; di < diend; di++) if (di->di_inumber == ino) goto found; /* not found */ return 1; found: #ifdef DEBUG_WITH_STDIO printf("LFS: dinode(%d): mode 0%o, nlink %d, inumber %d, size %d, uid %d, db[0] %d\n", ino, di->di_mode, di->di_nlink, di->di_inumber, (int) di->di_size, di->di_uid, di->di_db[0]); #endif #if 0 /* currently UFS1 only */ #if defined(USE_UFS1) && defined(USE_UFS2) /* XXX for DI_SIZE() macro */ if (ufsinfo->ufstype != UFSTYPE_UFS1) di->di1.di_size = di->si2.di_size; #endif #endif dibuf->dil1 = *di; return 0; }
static int ufs_read_indirect(daddr_t blk, int level, void **buf, unsigned *poff, size_t count) /* poff: position in block */ { struct ufs_info *ufsinfo = &fs; size_t bsize = ufsinfo->bsize; void *idbuf = alloca(bsize); #ifdef USE_UFS1 int32_t *idbuf1 = idbuf; #endif #ifdef USE_UFS2 int64_t *idbuf2 = idbuf; #endif daddr_t pos; unsigned off = *poff; unsigned b; #ifdef DEBUG_WITH_STDIO printf("ufs_read_indirect: off: %d, count %u\n", off, count); #endif if (off) { unsigned subindirsize = 1, indirsize; int i; for (i = level; i > 0; i--) subindirsize *= ufsinfo->nindir; indirsize = subindirsize * ufsinfo->nindir; if (off >= indirsize) { /* no need to read any data */ *poff = off - indirsize; return 0; } b = off / subindirsize; off -= b * subindirsize; *poff = 0; } else b = 0; /* read the indirect block */ RAW_READ(idbuf, blk << ufsinfo->fsbtodb, bsize); for ( ; b < ufsinfo->nindir && count > 0; b++) { #if defined(USE_UFS1) && defined(USE_UFS2) if (ufsinfo->ufstype == UFSTYPE_UFS1) #endif #ifdef USE_UFS1 pos = idbuf1[b]; #endif #if defined(USE_UFS1) && defined(USE_UFS2) else #endif #ifdef USE_UFS2 pos = idbuf2[b]; #endif if (level) count = ufs_read_indirect(pos, level - 1, buf, &off, count); else { #if 0 printf("ufs_read: read: blk: %d\n", (int) pos << ufsinfo->fsbtodb); #endif raw_read_queue(*buf, pos << ufsinfo->fsbtodb, bsize); *buf += bsize; count -= bsize; } } return count; }