Beispiel #1
0
static int
mkentry(struct inodesc *idesc)
{
	LFS_DIRHEADER *dirp = idesc->id_dirp;
	unsigned namlen;
	unsigned newreclen, oldreclen;

	/* figure the length needed for id_name */
	namlen = strlen(idesc->id_name);
	newreclen = LFS_DIRECTSIZ(fs, namlen);

	/* find the minimum record length for the existing name */
	if (lfs_dir_getino(fs, dirp) != 0)
		oldreclen = LFS_DIRSIZ(fs, dirp);
	else
		oldreclen = 0;

	/* Can we insert here? */
	if (lfs_dir_getreclen(fs, dirp) - oldreclen < newreclen)
		return (KEEPON);

	/* Divide the record; all but oldreclen goes to the new record */
	newreclen = lfs_dir_getreclen(fs, dirp) - oldreclen;
	lfs_dir_setreclen(fs, dirp, oldreclen);

	/* advance the pointer to the new record */
	dirp = LFS_NEXTDIR(fs, dirp);

	/* write record; ino to be entered is in id_parent */
	lfs_dir_setino(fs, dirp, idesc->id_parent);
	lfs_dir_setreclen(fs, dirp, newreclen);
	lfs_dir_settype(fs, dirp, typemap[idesc->id_parent]);
	lfs_dir_setnamlen(fs, dirp, namlen);
	lfs_copydirname(fs, lfs_dir_nameptr(fs, dirp), idesc->id_name,
			namlen, newreclen);

	return (ALTERED | STOP);
}
Beispiel #2
0
/*
 * allocate a new directory
 */
int
allocdir(ino_t parent, ino_t request, int mode)
{
	ino_t ino;
	char *cp;
	union lfs_dinode *dp;
	struct ubuf *bp;
	LFS_DIRHEADER *dirp;
	struct uvnode *vp;

	ino = allocino(request, LFS_IFDIR | mode);
	vp = vget(fs, ino);
	dp = VTOD(vp);
	bread(vp, lfs_dino_getdb(fs, dp, 0), lfs_sb_getfsize(fs), 0, &bp);
	if (bp->b_flags & B_ERROR) {
		brelse(bp, 0);
		freeino(ino);
		return (0);
	}
	dirp = (LFS_DIRHEADER *)bp->b_data;
	/* . */
	lfs_dir_setino(fs, dirp, ino);
	lfs_dir_setreclen(fs, dirp, LFS_DIRECTSIZ(fs, 1));
	lfs_dir_settype(fs, dirp, LFS_DT_DIR);
	lfs_dir_setnamlen(fs, dirp, 1);
	lfs_copydirname(fs, lfs_dir_nameptr(fs, dirp), ".", 1,
			LFS_DIRECTSIZ(fs, 1));
	/* .. */
	dirp = LFS_NEXTDIR(fs, dirp);
	lfs_dir_setino(fs, dirp, parent);
	lfs_dir_setreclen(fs, dirp, LFS_DIRBLKSIZ - LFS_DIRECTSIZ(fs, 1));
	lfs_dir_settype(fs, dirp, LFS_DT_DIR);
	lfs_dir_setnamlen(fs, dirp, 2);
	lfs_copydirname(fs, lfs_dir_nameptr(fs, dirp), "..", 2,
			LFS_DIRBLKSIZ - LFS_DIRECTSIZ(fs, 1));
	for (cp = &bp->b_data[LFS_DIRBLKSIZ];
	    cp < &bp->b_data[lfs_sb_getfsize(fs)];
	    cp += LFS_DIRBLKSIZ) {
		zerodirblk(cp);
	}
	VOP_BWRITE(bp);
	lfs_dino_setnlink(fs, dp, 2);
	inodirty(VTOI(vp));
	if (ino == ULFS_ROOTINO) {
		lncntp[ino] = lfs_dino_getnlink(fs, dp);
		cacheino(dp, ino);
		return (ino);
	}
	if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
		freeino(ino);
		return (0);
	}
	cacheino(dp, ino);
	statemap[ino] = statemap[parent];
	if (statemap[ino] == DSTATE) {
		lncntp[ino] = lfs_dino_getnlink(fs, dp);
		lncntp[parent]++;
	}
	vp = vget(fs, parent);
	dp = VTOD(vp);
	lfs_dino_setnlink(fs, dp, lfs_dino_getnlink(fs, dp) + 1);
	inodirty(VTOI(vp));
	return (ino);
}
/*
 * Vnode op for reading directories.
 *
 * This routine handles converting from the on-disk directory format
 * "struct lfs_direct" to the in-memory format "struct dirent" as well as
 * byte swapping the entries if necessary.
 */
int
ulfs_readdir(void *v)
{
	struct vop_readdir_args /* {
		struct vnode	*a_vp;
		struct uio	*a_uio;
		kauth_cred_t	a_cred;
		int		*a_eofflag;
		off_t		**a_cookies;
		int		*ncookies;
	} */ *ap = v;
	struct vnode	*vp = ap->a_vp;
	LFS_DIRHEADER	*cdp, *ecdp;
	struct dirent	*ndp;
	char		*cdbuf, *ndbuf, *endp;
	struct uio	auio, *uio;
	struct iovec	aiov;
	int		error;
	size_t		count, ccount, rcount, cdbufsz, ndbufsz;
	off_t		off, *ccp;
	off_t		startoff;
	size_t		skipbytes;
	struct ulfsmount *ump = VFSTOULFS(vp->v_mount);
	struct lfs *fs = ump->um_lfs;
	uio = ap->a_uio;
	count = uio->uio_resid;
	rcount = count - ((uio->uio_offset + count) & (fs->um_dirblksiz - 1));

	if (rcount < LFS_DIRECTSIZ(fs, 0) || count < _DIRENT_MINSIZE(ndp))
		return EINVAL;

	startoff = uio->uio_offset & ~(fs->um_dirblksiz - 1);
	skipbytes = uio->uio_offset - startoff;
	rcount += skipbytes;

	auio.uio_iov = &aiov;
	auio.uio_iovcnt = 1;
	auio.uio_offset = startoff;
	auio.uio_resid = rcount;
	UIO_SETUP_SYSSPACE(&auio);
	auio.uio_rw = UIO_READ;
	cdbufsz = rcount;
	cdbuf = kmem_alloc(cdbufsz, KM_SLEEP);
	aiov.iov_base = cdbuf;
	aiov.iov_len = rcount;
	error = VOP_READ(vp, &auio, 0, ap->a_cred);
	if (error != 0) {
		kmem_free(cdbuf, cdbufsz);
		return error;
	}

	rcount -= auio.uio_resid;

	cdp = (LFS_DIRHEADER *)(void *)cdbuf;
	ecdp = (LFS_DIRHEADER *)(void *)&cdbuf[rcount];

	ndbufsz = count;
	ndbuf = kmem_alloc(ndbufsz, KM_SLEEP);
	ndp = (struct dirent *)(void *)ndbuf;
	endp = &ndbuf[count];

	off = uio->uio_offset;
	if (ap->a_cookies) {
		ccount = rcount / _DIRENT_RECLEN(ndp, 1);
		ccp = *(ap->a_cookies) = malloc(ccount * sizeof(*ccp),
		    M_TEMP, M_WAITOK);
	} else {
		/* XXX: GCC */
		ccount = 0;
		ccp = NULL;
	}

	while (cdp < ecdp) {
		if (skipbytes > 0) {
			if (lfs_dir_getreclen(fs, cdp) <= skipbytes) {
				skipbytes -= lfs_dir_getreclen(fs, cdp);
				cdp = LFS_NEXTDIR(fs, cdp);
				continue;
			}
			/*
			 * invalid cookie.
			 */
			error = EINVAL;
			goto out;
		}
		if (lfs_dir_getreclen(fs, cdp) == 0) {
			struct dirent *ondp = ndp;
			ndp->d_reclen = _DIRENT_MINSIZE(ndp);
			ndp = _DIRENT_NEXT(ndp);
			ondp->d_reclen = 0;
			cdp = ecdp;
			break;
		}
		ndp->d_type = lfs_dir_gettype(fs, cdp);
		ndp->d_namlen = lfs_dir_getnamlen(fs, cdp);
		ndp->d_reclen = _DIRENT_RECLEN(ndp, ndp->d_namlen);
		if ((char *)(void *)ndp + ndp->d_reclen +
		    _DIRENT_MINSIZE(ndp) > endp)
			break;
		ndp->d_fileno = lfs_dir_getino(fs, cdp);
		(void)memcpy(ndp->d_name, lfs_dir_nameptr(fs, cdp),
			     ndp->d_namlen);
		memset(&ndp->d_name[ndp->d_namlen], 0,
		    ndp->d_reclen - _DIRENT_NAMEOFF(ndp) - ndp->d_namlen);
		off += lfs_dir_getreclen(fs, cdp);
		if (ap->a_cookies) {
			KASSERT(ccp - *(ap->a_cookies) < ccount);
			*(ccp++) = off;
		}
		ndp = _DIRENT_NEXT(ndp);
		cdp = LFS_NEXTDIR(fs, cdp);
	}

	count = ((char *)(void *)ndp - ndbuf);
	error = uiomove(ndbuf, count, uio);
out:
	if (ap->a_cookies) {
		if (error) {
			free(*(ap->a_cookies), M_TEMP);
			*(ap->a_cookies) = NULL;
			*(ap->a_ncookies) = 0;
		} else {
			*ap->a_ncookies = ccp - *(ap->a_cookies);
		}
	}
	uio->uio_offset = off;
	kmem_free(ndbuf, ndbufsz);
	kmem_free(cdbuf, cdbufsz);
	*ap->a_eofflag = VTOI(vp)->i_size <= uio->uio_offset;
	return error;
}