예제 #1
0
파일: dir.c 프로젝트: ajinkya93/netbsd-src
/*
 * Initialize a completely empty directory block.
 * (block size is LFS_DIRBLKSIZ)
 */
static void
zerodirblk(void *buf)
{
	LFS_DIRHEADER *dirp;

	dirp = buf;
	lfs_dir_setino(fs, dirp, 0);
	lfs_dir_setreclen(fs, dirp, LFS_DIRBLKSIZ);
	lfs_dir_settype(fs, dirp, LFS_DT_UNKNOWN);
	lfs_dir_setnamlen(fs, dirp, 0);
	lfs_copydirname(fs, lfs_dir_nameptr(fs, dirp), "", 0,
			LFS_DIRBLKSIZ);
}
예제 #2
0
파일: dir.c 프로젝트: ajinkya93/netbsd-src
static int
chgino(struct inodesc *idesc)
{
	LFS_DIRHEADER *dirp = idesc->id_dirp;
	int namlen;

	namlen = lfs_dir_getnamlen(fs, dirp);
	if (memcmp(lfs_dir_nameptr(fs, dirp), idesc->id_name, namlen + 1))
		return (KEEPON);
	lfs_dir_setino(fs, dirp, idesc->id_parent);
	lfs_dir_settype(fs, dirp, typemap[idesc->id_parent]);
	return (ALTERED | STOP);
}
예제 #3
0
파일: dir.c 프로젝트: ajinkya93/netbsd-src
/*
 * Verify that a directory entry is valid.
 * This is a superset of the checks made in the kernel.
 */
int
dircheck(struct inodesc *idesc, LFS_DIRHEADER *dp)
{
	int size;
	const char *cp;
	u_char namlen, type;
	int spaceleft;

	spaceleft = LFS_DIRBLKSIZ - (idesc->id_loc % LFS_DIRBLKSIZ);
	if (lfs_dir_getino(fs, dp) >= maxino ||
	    lfs_dir_getreclen(fs, dp) == 0 ||
	    lfs_dir_getreclen(fs, dp) > spaceleft ||
	    (lfs_dir_getreclen(fs, dp) & 0x3) != 0) {
		pwarn("ino too large, reclen=0, reclen>space, or reclen&3!=0\n");
		pwarn("dp->d_ino = 0x%jx\tdp->d_reclen = 0x%x\n",
		    (uintmax_t)lfs_dir_getino(fs, dp),
		    lfs_dir_getreclen(fs, dp));
		pwarn("maxino = %ju\tspaceleft = 0x%x\n",
		    (uintmax_t)maxino, spaceleft);
		return (0);
	}
	if (lfs_dir_getino(fs, dp) == 0)
		return (1);
	size = LFS_DIRSIZ(fs, dp);
	namlen = lfs_dir_getnamlen(fs, dp);
	type = lfs_dir_gettype(fs, dp);
	if (lfs_dir_getreclen(fs, dp) < size ||
	    idesc->id_filesize < size ||
	/* namlen > MAXNAMLEN || */
	    type > 15) {
		printf("reclen<size, filesize<size, namlen too large, or type>15\n");
		return (0);
	}
	cp = lfs_dir_nameptr(fs, dp);
	for (size = 0; size < namlen; size++)
		if (*cp == '\0' || (*cp++ == '/')) {
			printf("name contains NUL or /\n");
			return (0);
		}
	if (*cp != '\0') {
		printf("name size misstated\n");
		return (0);
	}
	return (1);
}
예제 #4
0
파일: dir.c 프로젝트: ajinkya93/netbsd-src
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);
}
예제 #5
0
파일: dir.c 프로젝트: ajinkya93/netbsd-src
/*
 * 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);
}
예제 #6
0
파일: dir.c 프로젝트: ajinkya93/netbsd-src
/*
 * get next entry in a directory.
 */
static LFS_DIRHEADER *
fsck_readdir(struct uvnode *vp, struct inodesc *idesc)
{
	LFS_DIRHEADER *dp, *ndp;
	struct ubuf *bp;
	long size, blksiz, fix, dploc;

	blksiz = idesc->id_numfrags * lfs_sb_getfsize(fs);
	bread(vp, idesc->id_lblkno, blksiz, 0, &bp);
	if (idesc->id_loc % LFS_DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
	    idesc->id_loc < blksiz) {
		dp = (LFS_DIRHEADER *) (bp->b_data + idesc->id_loc);
		if (dircheck(idesc, dp))
			goto dpok;
		brelse(bp, 0);
		if (idesc->id_fix == IGNORE)
			return (0);
		fix = dofix(idesc, "DIRECTORY CORRUPTED");
		bread(vp, idesc->id_lblkno, blksiz, 0, &bp);
		dp = (LFS_DIRHEADER *) (bp->b_data + idesc->id_loc);
		lfs_dir_setino(fs, dp, 0);
		lfs_dir_settype(fs, dp, LFS_DT_UNKNOWN);
		lfs_dir_setnamlen(fs, dp, 0);
		lfs_dir_setreclen(fs, dp, LFS_DIRBLKSIZ);
		/* for now at least, don't zero the old contents */
		/*lfs_copydirname(fs, lfs_dir_nameptr(fs, dp), "", 0, LFS_DIRBLKSIZ);*/
		lfs_dir_nameptr(fs, dp)[0] = '\0';
		if (fix)
			VOP_BWRITE(bp);
		else
			brelse(bp, 0);
		idesc->id_loc += LFS_DIRBLKSIZ;
		idesc->id_filesize -= LFS_DIRBLKSIZ;
		return (dp);
	}
dpok:
	if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) {
		brelse(bp, 0);
		return NULL;
	}
	dploc = idesc->id_loc;
	dp = (LFS_DIRHEADER *) (bp->b_data + dploc);
	idesc->id_loc += lfs_dir_getreclen(fs, dp);
	idesc->id_filesize -= lfs_dir_getreclen(fs, dp);
	if ((idesc->id_loc % LFS_DIRBLKSIZ) == 0) {
		brelse(bp, 0);
		return dp;
	}
	ndp = (LFS_DIRHEADER *) (bp->b_data + idesc->id_loc);
	if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
	    dircheck(idesc, ndp) == 0) {
		brelse(bp, 0);
		size = LFS_DIRBLKSIZ - (idesc->id_loc % LFS_DIRBLKSIZ);
		idesc->id_loc += size;
		idesc->id_filesize -= size;
		if (idesc->id_fix == IGNORE)
			return 0;
		fix = dofix(idesc, "DIRECTORY CORRUPTED");
		bread(vp, idesc->id_lblkno, blksiz, 0, &bp);
		dp = (LFS_DIRHEADER *) (bp->b_data + dploc);
		lfs_dir_setreclen(fs, dp, lfs_dir_getreclen(fs, dp) + size);
		if (fix)
			VOP_BWRITE(bp);
		else
			brelse(bp, 0);
	} else
		brelse(bp, 0);

	return (dp);
}
/*
 * 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;
}