Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
/*
 * 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;
}
Ejemplo n.º 4
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->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);
}