Ejemplo n.º 1
0
/*
 * Helper function for tmpfs_readdir.  Creates a '..' entry for the given
 * directory and returns it in the uio space.  The function returns 0
 * on success, -1 if there was not enough space in the uio structure to
 * hold the directory entry or an appropriate error code if another
 * error happens.
 */
int
tmpfs_dir_getdotdotdent(struct tmpfs_mount *tmp, struct tmpfs_node *node,
			struct uio *uio)
{
	int error;
	ino_t d_ino;

	TMPFS_VALIDATE_DIR(node);
	KKASSERT(uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT);

	if (node->tn_dir.tn_parent) {
		TMPFS_NODE_LOCK(node);
		if (node->tn_dir.tn_parent)
			d_ino = node->tn_dir.tn_parent->tn_id;
		else
			d_ino = tmp->tm_root->tn_id;
		TMPFS_NODE_UNLOCK(node);
	} else {
		d_ino = tmp->tm_root->tn_id;
	}

	if (vop_write_dirent(&error, uio, d_ino, DT_DIR, 2, ".."))
		return -1;
	if (error == 0) {
		struct tmpfs_dirent *de;
		de = RB_MIN(tmpfs_dirtree_cookie, &node->tn_dir.tn_cookietree);
		if (de == NULL)
			uio->uio_offset = TMPFS_DIRCOOKIE_EOF;
		else
			uio->uio_offset = tmpfs_dircookie(de);
	}
	return error;
}
Ejemplo n.º 2
0
static int
lubycookie_callback(struct tmpfs_dirent *de, void *arg)
{
	struct lubycookie_info *info = arg;

	if (tmpfs_dircookie(de) == info->cookie) {
		info->de = de;
		return(-1);
	}
	return(0);
}
Ejemplo n.º 3
0
static int
lubycookie_cmp(struct tmpfs_dirent *de, void *arg)
{
	struct lubycookie_info *info = arg;
	off_t cookie = tmpfs_dircookie(de);

	if (cookie < info->cookie)
		return(-1);
	if (cookie > info->cookie)
		return(1);
	return(0);
}
Ejemplo n.º 4
0
static int
tmpfs_readdir(struct vop_readdir_args *v)
{
	struct vnode *vp = v->a_vp;
	struct uio *uio = v->a_uio;
	int *eofflag = v->a_eofflag;
	off_t **cookies = v->a_cookies;
	int *ncookies = v->a_ncookies;
	struct tmpfs_mount *tmp;
	int error;
	off_t startoff;
	off_t cnt = 0;
	struct tmpfs_node *node;

	/* This operation only makes sense on directory nodes. */
	if (vp->v_type != VDIR) {
		return ENOTDIR;
	}

	tmp = VFS_TO_TMPFS(vp->v_mount);
	node = VP_TO_TMPFS_DIR(vp);
	startoff = uio->uio_offset;

	if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) {
		error = tmpfs_dir_getdotdent(node, uio);
		if (error != 0) {
			TMPFS_NODE_LOCK_SH(node);
			goto outok;
		}
		cnt++;
	}

	if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) {
		/* may lock parent, cannot hold node lock */
		error = tmpfs_dir_getdotdotdent(tmp, node, uio);
		if (error != 0) {
			TMPFS_NODE_LOCK_SH(node);
			goto outok;
		}
		cnt++;
	}

	TMPFS_NODE_LOCK_SH(node);
	error = tmpfs_dir_getdents(node, uio, &cnt);

outok:
	KKASSERT(error >= -1);

	if (error == -1)
		error = 0;

	if (eofflag != NULL)
		*eofflag =
		    (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);

	/* Update NFS-related variables. */
	if (error == 0 && cookies != NULL && ncookies != NULL) {
		off_t i;
		off_t off = startoff;
		struct tmpfs_dirent *de = NULL;

		*ncookies = cnt;
		*cookies = kmalloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK);

		for (i = 0; i < cnt; i++) {
			KKASSERT(off != TMPFS_DIRCOOKIE_EOF);
			if (off == TMPFS_DIRCOOKIE_DOT) {
				off = TMPFS_DIRCOOKIE_DOTDOT;
			} else {
				if (off == TMPFS_DIRCOOKIE_DOTDOT) {
					de = RB_MIN(tmpfs_dirtree_cookie,
						&node->tn_dir.tn_cookietree);
				} else if (de != NULL) {
					de = RB_NEXT(tmpfs_dirtree_cookie,
					       &node->tn_dir.tn_cookietree, de);
				} else {
					de = tmpfs_dir_lookupbycookie(node,
								      off);
					KKASSERT(de != NULL);
					de = RB_NEXT(tmpfs_dirtree_cookie,
					       &node->tn_dir.tn_cookietree, de);
				}
				if (de == NULL)
					off = TMPFS_DIRCOOKIE_EOF;
				else
					off = tmpfs_dircookie(de);
			}
			(*cookies)[i] = off;
		}
		KKASSERT(uio->uio_offset == off);
	}
	TMPFS_NODE_UNLOCK(node);

	if ((node->tn_status & TMPFS_NODE_ACCESSED) == 0) {
		TMPFS_NODE_LOCK(node);
		node->tn_status |= TMPFS_NODE_ACCESSED;
		TMPFS_NODE_UNLOCK(node);
	}
	return error;
}
Ejemplo n.º 5
0
static int
tmpfs_readdir(struct vop_readdir_args *v)
{
	struct vnode *vp = v->a_vp;
	struct uio *uio = v->a_uio;
	int *eofflag = v->a_eofflag;
	u_long **cookies = v->a_cookies;
	int *ncookies = v->a_ncookies;

	int error;
	off_t startoff;
	off_t cnt = 0;
	struct tmpfs_node *node;

	/* This operation only makes sense on directory nodes. */
	if (vp->v_type != VDIR)
		return ENOTDIR;

	node = VP_TO_TMPFS_DIR(vp);

	startoff = uio->uio_offset;

	if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) {
		error = tmpfs_dir_getdotdent(node, uio);
		if (error != 0)
			goto outok;
		cnt++;
	}

	if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) {
		error = tmpfs_dir_getdotdotdent(node, uio);
		if (error != 0)
			goto outok;
		cnt++;
	}

	error = tmpfs_dir_getdents(node, uio, &cnt);

outok:
	MPASS(error >= -1);

	if (error == -1)
		error = (cnt != 0) ? 0 : EINVAL;

	if (eofflag != NULL)
		*eofflag =
		    (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);

	/* Update NFS-related variables. */
	if (error == 0 && cookies != NULL && ncookies != NULL) {
		off_t i;
		off_t off = startoff;
		struct tmpfs_dirent *de = NULL;

		*ncookies = cnt;
		*cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK);

		for (i = 0; i < cnt; i++) {
			MPASS(off != TMPFS_DIRCOOKIE_EOF);
			if (off == TMPFS_DIRCOOKIE_DOT) {
				off = TMPFS_DIRCOOKIE_DOTDOT;
			} else {
				if (off == TMPFS_DIRCOOKIE_DOTDOT) {
					de = TAILQ_FIRST(&node->tn_dir.tn_dirhead);
				} else if (de != NULL) {
					de = TAILQ_NEXT(de, td_entries);
				} else {
					de = tmpfs_dir_lookupbycookie(node,
					    off);
					MPASS(de != NULL);
					de = TAILQ_NEXT(de, td_entries);
				}
				if (de == NULL)
					off = TMPFS_DIRCOOKIE_EOF;
				else
					off = tmpfs_dircookie(de);
			}

			(*cookies)[i] = off;
		}
		MPASS(uio->uio_offset == off);
	}

	return error;
}
Ejemplo n.º 6
0
/*
 * Helper function for tmpfs_readdir.  Returns as much directory entries
 * as can fit in the uio space.  The read starts at uio->uio_offset.
 * The function returns 0 on success, -1 if there was not enough space
 * in the uio structure to hold the directory entry or an appropriate
 * error code if another error happens.
 *
 * Caller must hold the node locked (shared ok)
 */
int
tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, off_t *cntp)
{
	int error;
	off_t startcookie;
	struct tmpfs_dirent *de;

	TMPFS_VALIDATE_DIR(node);

	/*
	 * Locate the first directory entry we have to return.  We have cached
	 * the last readdir in the node, so use those values if appropriate.
	 * Otherwise do a linear scan to find the requested entry.
	 */
	startcookie = uio->uio_offset;
	KKASSERT(startcookie != TMPFS_DIRCOOKIE_DOT);
	KKASSERT(startcookie != TMPFS_DIRCOOKIE_DOTDOT);

	if (startcookie == TMPFS_DIRCOOKIE_EOF)
		return 0;

	de = tmpfs_dir_lookupbycookie(node, startcookie);
	if (de == NULL)
		return EINVAL;

	/*
	 * Read as much entries as possible; i.e., until we reach the end of
	 * the directory or we exhaust uio space.
	 */
	do {
		ino_t d_ino;
		uint8_t d_type;

		/* Create a dirent structure representing the current
		 * tmpfs_node and fill it. */
		d_ino = de->td_node->tn_id;
		switch (de->td_node->tn_type) {
		case VBLK:
			d_type = DT_BLK;
			break;

		case VCHR:
			d_type = DT_CHR;
			break;

		case VDIR:
			d_type = DT_DIR;
			break;

		case VFIFO:
			d_type = DT_FIFO;
			break;

		case VLNK:
			d_type = DT_LNK;
			break;

		case VREG:
			d_type = DT_REG;
			break;

		case VSOCK:
			d_type = DT_SOCK;
			break;

		default:
			panic("tmpfs_dir_getdents: type %p %d",
			    de->td_node, (int)de->td_node->tn_type);
		}
		KKASSERT(de->td_namelen < 256); /* 255 + 1 */

		if (vop_write_dirent(&error, uio, d_ino, d_type,
		    de->td_namelen, de->td_name)) {
			error = -1;
			break;
		}

		(*cntp)++;
		de = RB_NEXT(tmpfs_dirtree_cookie,
			     node->tn_dir.tn_cookietree, de);
	} while (error == 0 && uio->uio_resid > 0 && de != NULL);

	/* Update the offset and cache. */
	if (de == NULL) {
		uio->uio_offset = TMPFS_DIRCOOKIE_EOF;
	} else {
		uio->uio_offset = tmpfs_dircookie(de);
	}

	return error;
}