int setup(const char *dev) { long cg, asked, i; long bmapsize; struct disklabel *lp; off_t sizepb; struct stat statb; struct m_ext2fs proto; int doskipclean; u_int64_t maxfilesize; havesb = 0; fswritefd = -1; doskipclean = skipclean; if (stat(dev, &statb) < 0) { printf("Can't stat %s: %s\n", dev, strerror(errno)); return 0; } if (!S_ISCHR(statb.st_mode)) { pfatal("%s is not a character device", dev); if (reply("CONTINUE") == 0) return 0; } if ((fsreadfd = open(dev, O_RDONLY)) < 0) { printf("Can't open %s: %s\n", dev, strerror(errno)); return 0; } if (preen == 0) printf("** %s", dev); if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { fswritefd = -1; if (preen) pfatal("NO WRITE ACCESS"); printf(" (NO WRITE)"); } if (preen == 0) printf("\n"); fsmodified = 0; lfdir = 0; initbarea(&sblk); initbarea(&asblk); sblk.b_un.b_buf = malloc(SBSIZE); asblk.b_un.b_buf = malloc(SBSIZE); if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) errexit("cannot allocate space for superblock"); if ((lp = getdisklabel(NULL, fsreadfd)) != NULL) dev_bsize = secsize = lp->d_secsize; else dev_bsize = secsize = DEV_BSIZE; /* * Read in the superblock, looking for alternates if necessary */ if (readsb(1) == 0) { if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) return 0; if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) return 0; for (cg = 1; cg < proto.e2fs_ncg; cg++) { bflag = EXT2_FSBTODB(&proto, cg * proto.e2fs.e2fs_bpg + proto.e2fs.e2fs_first_dblock); if (readsb(0) != 0) break; } if (cg >= proto.e2fs_ncg) { printf("%s %s\n%s %s\n%s %s\n", "SEARCH FOR ALTERNATE SUPER-BLOCK", "FAILED. YOU MUST USE THE", "-b OPTION TO FSCK_FFS TO SPECIFY THE", "LOCATION OF AN ALTERNATE", "SUPER-BLOCK TO SUPPLY NEEDED", "INFORMATION; SEE fsck_ext2fs(8)."); return 0; } doskipclean = 0; pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); } if (debug) printf("state = %d\n", sblock.e2fs.e2fs_state); if (sblock.e2fs.e2fs_state == E2FS_ISCLEAN) { if (doskipclean) { pwarn("%sile system is clean; not checking\n", preen ? "f" : "** F"); return -1; } if (!preen) pwarn("** File system is already clean\n"); } maxfsblock = sblock.e2fs.e2fs_bcount; maxino = sblock.e2fs_ncg * sblock.e2fs.e2fs_ipg; sizepb = sblock.e2fs_bsize; maxfilesize = sblock.e2fs_bsize * EXT2FS_NDADDR - 1; for (i = 0; i < EXT2FS_NIADDR; i++) { sizepb *= EXT2_NINDIR(&sblock); maxfilesize += sizepb; } /* * Check and potentially fix certain fields in the super block. */ if (/* (sblock.e2fs.e2fs_rbcount < 0) || */ (sblock.e2fs.e2fs_rbcount > sblock.e2fs.e2fs_bcount)) { pfatal("IMPOSSIBLE RESERVED BLOCK COUNT=%d IN SUPERBLOCK", sblock.e2fs.e2fs_rbcount); if (reply("SET TO DEFAULT") == 1) { sblock.e2fs.e2fs_rbcount = sblock.e2fs.e2fs_bcount * MINFREE / 100; sbdirty(); dirty(&asblk); } } if (sblock.e2fs.e2fs_bpg != sblock.e2fs.e2fs_fpg) { pfatal("WRONG FPG=%d (BPG=%d) IN SUPERBLOCK", sblock.e2fs.e2fs_fpg, sblock.e2fs.e2fs_bpg); return 0; } if (asblk.b_dirty && !bflag) { copyback_sb(&asblk); flush(fswritefd, &asblk); } /* * read in the summary info. */ sblock.e2fs_gd = malloc(sblock.e2fs_ngdb * sblock.e2fs_bsize); if (sblock.e2fs_gd == NULL) errexit("out of memory"); asked = 0; for (i = 0; i < sblock.e2fs_ngdb; i++) { if (bread(fsreadfd, (char *)&sblock.e2fs_gd[i * sblock.e2fs_bsize / sizeof(struct ext2_gd)], EXT2_FSBTODB(&sblock, ((sblock.e2fs_bsize > 1024) ? 0 : 1) + i + 1), sblock.e2fs_bsize) != 0 && !asked) { pfatal("BAD SUMMARY INFORMATION"); if (reply("CONTINUE") == 0) exit(FSCK_EXIT_CHECK_FAILED); asked++; } } /* * allocate and initialize the necessary maps */ bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); blockmap = calloc((unsigned int)bmapsize, sizeof(char)); if (blockmap == NULL) { printf("cannot alloc %u bytes for blockmap\n", (unsigned int)bmapsize); goto badsblabel; } statemap = calloc((unsigned int)(maxino + 2), sizeof(char)); if (statemap == NULL) { printf("cannot alloc %u bytes for statemap\n", (unsigned int)(maxino + 1)); goto badsblabel; } typemap = calloc((unsigned int)(maxino + 1), sizeof(char)); if (typemap == NULL) { printf("cannot alloc %u bytes for typemap\n", (unsigned int)(maxino + 1)); goto badsblabel; } lncntp = calloc((unsigned)(maxino + 1), sizeof(int16_t)); if (lncntp == NULL) { printf("cannot alloc %u bytes for lncntp\n", (unsigned int)((maxino + 1) * sizeof(int16_t))); goto badsblabel; } for (numdirs = 0, cg = 0; cg < sblock.e2fs_ncg; cg++) { numdirs += fs2h16(sblock.e2fs_gd[cg].ext2bgd_ndirs); } inplast = 0; listmax = numdirs + 10; inpsort = calloc((unsigned int)listmax, sizeof(struct inoinfo *)); inphead = calloc((unsigned int)numdirs, sizeof(struct inoinfo *)); if (inpsort == NULL || inphead == NULL) { printf("cannot alloc %u bytes for inphead\n", (unsigned int)(numdirs * sizeof(struct inoinfo *))); goto badsblabel; } bufinit(); return 1; badsblabel: ckfini(0); return 0; }
/* * Common code for mount and mountroot */ int ext2fs_mountfs(struct vnode *devvp, struct mount *mp) { struct lwp *l = curlwp; struct ufsmount *ump; struct buf *bp; struct ext2fs *fs; struct m_ext2fs *m_fs; dev_t dev; int error, i, ronly; kauth_cred_t cred; dev = devvp->v_rdev; cred = l->l_cred; /* Flush out any old buffers remaining from a previous use. */ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0); VOP_UNLOCK(devvp); if (error) return error; ronly = (mp->mnt_flag & MNT_RDONLY) != 0; bp = NULL; ump = NULL; /* Read the superblock from disk, and swap it directly. */ error = bread(devvp, SBLOCK, SBSIZE, 0, &bp); if (error) goto out; fs = (struct ext2fs *)bp->b_data; m_fs = kmem_zalloc(sizeof(struct m_ext2fs), KM_SLEEP); e2fs_sbload(fs, &m_fs->e2fs); brelse(bp, 0); bp = NULL; /* Once swapped, validate and fill in the superblock. */ error = ext2fs_sbfill(m_fs, ronly); if (error) { kmem_free(m_fs, sizeof(struct m_ext2fs)); goto out; } m_fs->e2fs_ronly = ronly; ump = kmem_zalloc(sizeof(*ump), KM_SLEEP); ump->um_fstype = UFS1; ump->um_ops = &ext2fs_ufsops; ump->um_e2fs = m_fs; if (ronly == 0) { if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN) m_fs->e2fs.e2fs_state = 0; else m_fs->e2fs.e2fs_state = E2FS_ERRORS; m_fs->e2fs_fmod = 1; } /* XXX: should be added in ext2fs_sbfill()? */ m_fs->e2fs_gd = kmem_alloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize, KM_SLEEP); for (i = 0; i < m_fs->e2fs_ngdb; i++) { error = bread(devvp, EXT2_FSBTODB(m_fs, m_fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i), m_fs->e2fs_bsize, 0, &bp); if (error) { kmem_free(m_fs->e2fs_gd, m_fs->e2fs_ngdb * m_fs->e2fs_bsize); goto out; } e2fs_cgload((struct ext2_gd *)bp->b_data, &m_fs->e2fs_gd[ i * m_fs->e2fs_bsize / sizeof(struct ext2_gd)], m_fs->e2fs_bsize); brelse(bp, 0); bp = NULL; } error = ext2fs_cg_verify_and_initialize(devvp, m_fs, ronly); if (error) { kmem_free(m_fs->e2fs_gd, m_fs->e2fs_ngdb * m_fs->e2fs_bsize); goto out; } mp->mnt_data = ump; mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev; mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_EXT2FS); mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; mp->mnt_stat.f_namemax = EXT2FS_MAXNAMLEN; mp->mnt_flag |= MNT_LOCAL; mp->mnt_dev_bshift = DEV_BSHIFT; /* XXX */ mp->mnt_fs_bshift = m_fs->e2fs_bshift; mp->mnt_iflag |= IMNT_DTYPE; ump->um_flags = 0; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; ump->um_nindir = EXT2_NINDIR(m_fs); ump->um_lognindir = ffs(EXT2_NINDIR(m_fs)) - 1; ump->um_bptrtodb = m_fs->e2fs_fsbtodb; ump->um_seqinc = 1; /* no frags */ ump->um_maxsymlinklen = EXT2_MAXSYMLINKLEN; ump->um_dirblksiz = m_fs->e2fs_bsize; ump->um_maxfilesize = ((uint64_t)0x80000000 * m_fs->e2fs_bsize - 1); spec_node_setmountedfs(devvp, mp); return 0; out: if (bp != NULL) brelse(bp, 0); if (ump) { kmem_free(ump->um_e2fs, sizeof(struct m_ext2fs)); kmem_free(ump, sizeof(*ump)); mp->mnt_data = NULL; } return error; }
/* * Open a file. */ __compactcall int ext2fs_open(const char *path, struct open_file *f) { #ifndef LIBSA_FS_SINGLECOMPONENT const char *cp, *ncp; int c; #endif ino32_t inumber; struct file *fp; struct m_ext2fs *fs; int rc; #ifndef LIBSA_NO_FS_SYMLINK ino32_t parent_inumber; int nlinks = 0; char namebuf[MAXPATHLEN+1]; char *buf; #endif /* allocate file system specific data structure */ fp = alloc(sizeof(struct file)); memset(fp, 0, sizeof(struct file)); f->f_fsdata = (void *)fp; /* allocate space and read super block */ fs = alloc(sizeof(*fs)); memset(fs, 0, sizeof(*fs)); fp->f_fs = fs; twiddle(); rc = read_sblock(f, fs); if (rc) goto out; #ifdef EXT2FS_DEBUG dump_sblock(fs); #endif /* alloc a block sized buffer used for all fs transfers */ fp->f_buf = alloc(fs->e2fs_bsize); /* read group descriptor blocks */ fs->e2fs_gd = alloc(sizeof(struct ext2_gd) * fs->e2fs_ncg); rc = read_gdblock(f, fs); if (rc) goto out; /* * Calculate indirect block levels. */ { indp_t mult; int ln2; /* * We note that the number of indirect blocks is always * a power of 2. This lets us use shifts and masks instead * of divide and remainder and avoinds pulling in the * 64bit division routine into the boot code. */ mult = EXT2_NINDIR(fs); #ifdef DEBUG if (!powerof2(mult)) { /* Hummm was't a power of 2 */ rc = EINVAL; goto out; } #endif for (ln2 = 0; mult != 1; ln2++) mult >>= 1; fp->f_nishift = ln2; } inumber = EXT2_ROOTINO; if ((rc = read_inode(inumber, f)) != 0) goto out; #ifndef LIBSA_FS_SINGLECOMPONENT cp = path; while (*cp) { /* * Remove extra separators */ while (*cp == '/') cp++; if (*cp == '\0') break; /* * Check that current node is a directory. */ if ((fp->f_di.e2di_mode & EXT2_IFMT) != EXT2_IFDIR) { rc = ENOTDIR; goto out; } /* * Get next component of path name. */ ncp = cp; while ((c = *cp) != '\0' && c != '/') cp++; /* * Look up component in current directory. * Save directory inumber in case we find a * symbolic link. */ #ifndef LIBSA_NO_FS_SYMLINK parent_inumber = inumber; #endif rc = search_directory(ncp, cp - ncp, f, &inumber); if (rc) goto out; /* * Open next component. */ if ((rc = read_inode(inumber, f)) != 0) goto out; #ifndef LIBSA_NO_FS_SYMLINK /* * Check for symbolic link. */ if ((fp->f_di.e2di_mode & EXT2_IFMT) == EXT2_IFLNK) { /* XXX should handle LARGEFILE */ int link_len = fp->f_di.e2di_size; int len; len = strlen(cp); if (link_len + len > MAXPATHLEN || ++nlinks > MAXSYMLINKS) { rc = ENOENT; goto out; } memmove(&namebuf[link_len], cp, len + 1); if (link_len < EXT2_MAXSYMLINKLEN) { memcpy(namebuf, fp->f_di.e2di_blocks, link_len); } else { /* * Read file for symbolic link */ size_t buf_size; indp_t disk_block; buf = fp->f_buf; rc = block_map(f, (indp_t)0, &disk_block); if (rc) goto out; twiddle(); rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, FSBTODB(fs, disk_block), fs->e2fs_bsize, buf, &buf_size); if (rc) goto out; memcpy(namebuf, buf, link_len); } /* * If relative pathname, restart at parent directory. * If absolute pathname, restart at root. */ cp = namebuf; if (*cp != '/') inumber = parent_inumber; else inumber = (ino32_t)EXT2_ROOTINO; if ((rc = read_inode(inumber, f)) != 0) goto out; } #endif /* !LIBSA_NO_FS_SYMLINK */ } /* * Found terminal component. */ rc = 0; #else /* !LIBSA_FS_SINGLECOMPONENT */ /* look up component in the current (root) directory */ rc = search_directory(path, strlen(path), f, &inumber); if (rc) goto out; /* open it */ rc = read_inode(inumber, f); #endif /* !LIBSA_FS_SINGLECOMPONENT */ fp->f_seekp = 0; /* reset seek pointer */ out: if (rc) ext2fs_close(f); else fsmod = "ext2fs"; return rc; }
/* * Common code for mount and mountroot */ int ext2fs_mountfs(struct vnode *devvp, struct mount *mp) { struct lwp *l = curlwp; struct ufsmount *ump; struct buf *bp; struct ext2fs *fs; struct m_ext2fs *m_fs; dev_t dev; int error, i, ronly; kauth_cred_t cred; dev = devvp->v_rdev; cred = l ? l->l_cred : NOCRED; /* Flush out any old buffers remaining from a previous use. */ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0); VOP_UNLOCK(devvp); if (error) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; bp = NULL; ump = NULL; #ifdef DEBUG_EXT2 printf("ext2 sb size: %zu\n", sizeof(struct ext2fs)); #endif error = bread(devvp, SBLOCK, SBSIZE, cred, 0, &bp); if (error) goto out; fs = (struct ext2fs *)bp->b_data; error = ext2fs_checksb(fs, ronly); if (error) goto out; ump = kmem_zalloc(sizeof(*ump), KM_SLEEP); ump->um_fstype = UFS1; ump->um_ops = &ext2fs_ufsops; ump->um_e2fs = kmem_zalloc(sizeof(struct m_ext2fs), KM_SLEEP); e2fs_sbload((struct ext2fs *)bp->b_data, &ump->um_e2fs->e2fs); brelse(bp, 0); bp = NULL; m_fs = ump->um_e2fs; m_fs->e2fs_ronly = ronly; #ifdef DEBUG_EXT2 printf("ext2 ino size %zu\n", EXT2_DINODE_SIZE(m_fs)); #endif if (ronly == 0) { if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN) m_fs->e2fs.e2fs_state = 0; else m_fs->e2fs.e2fs_state = E2FS_ERRORS; m_fs->e2fs_fmod = 1; } /* compute dynamic sb infos */ m_fs->e2fs_ncg = howmany(m_fs->e2fs.e2fs_bcount - m_fs->e2fs.e2fs_first_dblock, m_fs->e2fs.e2fs_bpg); m_fs->e2fs_fsbtodb = m_fs->e2fs.e2fs_log_bsize + LOG_MINBSIZE - DEV_BSHIFT; m_fs->e2fs_bsize = MINBSIZE << m_fs->e2fs.e2fs_log_bsize; m_fs->e2fs_bshift = LOG_MINBSIZE + m_fs->e2fs.e2fs_log_bsize; m_fs->e2fs_qbmask = m_fs->e2fs_bsize - 1; m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask; m_fs->e2fs_ngdb = howmany(m_fs->e2fs_ncg, m_fs->e2fs_bsize / sizeof(struct ext2_gd)); m_fs->e2fs_ipb = m_fs->e2fs_bsize / EXT2_DINODE_SIZE(m_fs); m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg / m_fs->e2fs_ipb; m_fs->e2fs_gd = kmem_alloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize, KM_SLEEP); for (i = 0; i < m_fs->e2fs_ngdb; i++) { error = bread(devvp , EXT2_FSBTODB(m_fs, m_fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i), m_fs->e2fs_bsize, NOCRED, 0, &bp); if (error) { kmem_free(m_fs->e2fs_gd, m_fs->e2fs_ngdb * m_fs->e2fs_bsize); goto out; } e2fs_cgload((struct ext2_gd *)bp->b_data, &m_fs->e2fs_gd[ i * m_fs->e2fs_bsize / sizeof(struct ext2_gd)], m_fs->e2fs_bsize); brelse(bp, 0); bp = NULL; } mp->mnt_data = ump; mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev; mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_EXT2FS); mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; mp->mnt_stat.f_namemax = EXT2FS_MAXNAMLEN; mp->mnt_flag |= MNT_LOCAL; mp->mnt_dev_bshift = DEV_BSHIFT; /* XXX */ mp->mnt_fs_bshift = m_fs->e2fs_bshift; mp->mnt_iflag |= IMNT_DTYPE; ump->um_flags = 0; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; ump->um_nindir = EXT2_NINDIR(m_fs); ump->um_lognindir = ffs(EXT2_NINDIR(m_fs)) - 1; ump->um_bptrtodb = m_fs->e2fs_fsbtodb; ump->um_seqinc = 1; /* no frags */ ump->um_maxsymlinklen = EXT2_MAXSYMLINKLEN; ump->um_dirblksiz = m_fs->e2fs_bsize; ump->um_maxfilesize = ((uint64_t)0x80000000 * m_fs->e2fs_bsize - 1); spec_node_setmountedfs(devvp, mp); return (0); out: if (bp != NULL) brelse(bp, 0); if (ump) { kmem_free(ump->um_e2fs, sizeof(struct m_ext2fs)); kmem_free(ump, sizeof(*ump)); mp->mnt_data = NULL; } return (error); }