Exemplo n.º 1
0
Arquivo: gfs.c Projeto: RJVB/zfs
/*
 * gfs_dir_readdir: does a readdir() on the given directory
 *
 *    dvp	- directory vnode
 *    uiop	- uio structure
 *    eofp	- eof pointer
 *    data	- arbitrary data passed to readdir callback
 *
 * This routine does all the readdir() dirty work.  Even so, the caller must
 * supply two callbacks in order to get full compatibility.
 *
 * If the directory contains static entries, an inode callback must be
 * specified.  This avoids having to create every vnode and call VOP_GETATTR()
 * when reading the directory.  This function has the following arguments:
 *
 *	ino_t gfs_inode_cb(struct vnode *vp, int index);
 *
 * 	vp	- vnode for the directory
 * 	index	- index in original gfs_dirent_t array
 *
 * 	Returns the inode number for the given entry.
 *
 * For directories with dynamic entries, a readdir callback must be provided.
 * This is significantly more complex, thanks to the particulars of
 * VOP_READDIR().
 *
 *	int gfs_readdir_cb(struct vnode *vp, void *dp, int *eofp,
 *	    offset_t *off, offset_t *nextoff, void *data, int flags)
 *
 *	vp	- directory vnode
 *	dp	- directory entry, sized according to maxlen given to
 *		  gfs_dir_create().  callback must fill in d_name and
 *		  d_ino (if a dirent64_t), or ed_name, ed_ino, and ed_eflags
 *		  (if an edirent_t). edirent_t is used if V_RDDIR_ENTFLAGS
 *		  is set in 'flags'.
 *	eofp	- callback must set to 1 when EOF has been reached
 *	off	- on entry, the last offset read from the directory.  Callback
 *		  must set to the offset of the current entry, typically left
 *		  untouched.
 *	nextoff	- callback must set to offset of next entry.  Typically
 *		  (off + 1)
 *	data	- caller-supplied data
 *	flags	- VOP_READDIR flags
 *
 *	Return 0 on success, or error on failure.
 */
int
gfs_dir_readdir(struct vnode *dvp, uio_t *uiop, int *eofp, int *ncookies,
    u_long **cookies, void *data, cred_t *cr, int flags)
{
	gfs_readdir_state_t gstate;
	int error, eof = 0;
	ino64_t ino, pino;
	offset_t off, next;
	gfs_dir_t *dp = vnode_fsnode(dvp);

	error = gfs_get_parent_ino(dvp, cr, NULL, &pino, &ino);
	if (error)
		return (error);

	if ((error = gfs_readdir_init(&gstate, dp->gfsd_maxlen, 1, uiop,
	    pino, ino, flags)) != 0)
		return (error);

	while ((error = gfs_readdir_pred(&gstate, uiop, &off, ncookies,
	    cookies)) == 0 && !eof) {

		if (off >= 0 && off < dp->gfsd_nstatic) {
			ino = dp->gfsd_inode(dvp, off);

			if ((error = gfs_readdir_emit(&gstate, uiop,
			    off, ino, dp->gfsd_static[off].gfse_name, 0,
			    ncookies, cookies)) != 0)
				break;

		} else if (dp->gfsd_readdir) {
			off -= dp->gfsd_nstatic;

			if ((error = dp->gfsd_readdir(dvp,
			    gstate.grd_dirent, &eof, &off, &next,
			    data, flags)) != 0 || eof)
				break;

			off += dp->gfsd_nstatic + 2;
			next += dp->gfsd_nstatic + 2;

			if ((error = gfs_readdir_emit_int(&gstate, uiop,
			    next, ncookies, cookies)) != 0)
				break;
		} else {
			/*
			 * Offset is beyond the end of the static entries, and
			 * we have no dynamic entries.  Set EOF.
			 */
			eof = 1;
		}
	}

	return (gfs_readdir_fini(&gstate, error, eofp, eof));
}
Exemplo n.º 2
0
static int
xattr_dir_readdir(vnode_t *dvp, uio_t *uiop, cred_t *cr, int *eofp,
    caller_context_t *ct, int flags)
{
	vnode_t *pvp;
	int error;
	int local_eof;
	int reset_off = 0;
	int has_xattrs = 0;

	if (eofp == NULL) {
		eofp = &local_eof;
	}
	*eofp = 0;

	/*
	 * See if there is a real extended attribute directory.
	 */
	error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct);
	if (error == 0) {
		has_xattrs = 1;
	}

	/*
	 * Start by reading up the static entries.
	 */
	if (uiop->uio_loffset == 0) {
		ino64_t pino, ino;
		offset_t off;
		gfs_dir_t *dp = dvp->v_data;
		gfs_readdir_state_t gstate;

		if (has_xattrs) {
			/*
			 * If there is a real xattr dir, skip . and ..
			 * in the GFS dir.  We'll pick them up below
			 * when we call into the underlying fs.
			 */
			uiop->uio_loffset = GFS_STATIC_ENTRY_OFFSET;
		}
		error = gfs_get_parent_ino(dvp, cr, ct, &pino, &ino);
		if (error == 0) {
			error = gfs_readdir_init(&gstate, dp->gfsd_maxlen, 1,
			    uiop, pino, ino, flags);
		}
		if (error) {
			return (error);
		}

		while ((error = gfs_readdir_pred(&gstate, uiop, &off)) == 0 &&
		    !*eofp) {
			if (off >= 0 && off < dp->gfsd_nstatic) {
				int eflags;

				/*
				 * Check to see if this sysattr set name has a
				 * case-insensitive conflict with a real xattr
				 * name.
				 */
				eflags = 0;
				if ((flags & V_RDDIR_ENTFLAGS) && has_xattrs) {
					error = readdir_xattr_casecmp(pvp,
					    dp->gfsd_static[off].gfse_name,
					    cr, ct, &eflags);
					if (error)
						break;
				}
				ino = dp->gfsd_inode(dvp, off);

				error = gfs_readdir_emit(&gstate, uiop, off,
				    ino, dp->gfsd_static[off].gfse_name,
				    eflags);
				if (error)
					break;
			} else {
				*eofp = 1;
			}
		}

		error = gfs_readdir_fini(&gstate, error, eofp, *eofp);
		if (error) {
			return (error);
		}

		/*
		 * We must read all of the static entries in the first
		 * call.  Otherwise we won't know if uio_loffset in a
		 * subsequent call refers to the static entries or to those
		 * in an underlying fs.
		 */
		if (*eofp == 0)
			return (EINVAL);
		reset_off = 1;
	}

	if (!has_xattrs) {
		*eofp = 1;
		return (0);
	}

	*eofp = 0;
	if (reset_off) {
		uiop->uio_loffset = 0;
	}
	(void) VOP_RWLOCK(pvp, V_WRITELOCK_FALSE, NULL);
	error = VOP_READDIR(pvp, uiop, cr, eofp, ct, flags);
	VOP_RWUNLOCK(pvp, V_WRITELOCK_FALSE, NULL);

	return (error);
}