Ejemplo n.º 1
0
Archivo: gfs.c Proyecto: RJVB/zfs
/*
 * gfs_readdir_pred: readdir loop predicate
 *   voffp - a pointer in which the next virtual offset should be stored
 *
 * Returns a 0 on success, a non-zero errno on failure, or -1 if the
 * readdir loop should terminate.  A non-zero result (either errno or
 * -1) from this function is typically passed directly to
 * gfs_readdir_fini().
 */
int
gfs_readdir_pred(gfs_readdir_state_t *st, uio_t *uiop, offset_t *voffp,
    int *ncookies, u_long **cookies)
{
	offset_t off, voff;
	int error;

top:
	if (uio_resid(uiop) <= 0)
		return (-1);

	off = uio_offset(uiop) / st->grd_ureclen;
	voff = off - 2;
	if (off == 0) {
		if ((error = gfs_readdir_emit(st, uiop, voff, st->grd_self,
		    ".", 0, ncookies, cookies)) == 0)
			goto top;
	} else if (off == 1) {
        dprintf("Sending out .. with id %d\n", st->grd_parent);
		if ((error = gfs_readdir_emit(st, uiop, voff, st->grd_parent,
		    "..", 0, ncookies, cookies)) == 0)
			goto top;
	} else {
		*voffp = voff;
		return (0);
	}

	return (error);
}
Ejemplo n.º 2
0
/*
 * gfs_readdir_pred: readdir loop predicate
 *   voffp - a pointer in which the next virtual offset should be stored
 *
 * Returns a 0 on success, a non-zero errno on failure, or -1 if the
 * readdir loop should terminate.  A non-zero result (either errno or
 * -1) from this function is typically passed directly to
 * gfs_readdir_fini().
 */
int
gfs_readdir_pred(gfs_readdir_state_t *st, uio_t *uiop, offset_t *voffp)
{
	offset_t off, voff;
	int error;

top:
	if (uiop->uio_resid <= 0)
		return (-1);

	off = uiop->uio_loffset / st->grd_ureclen;
	voff = off - 2;
	if (off == 0) {
		if ((error = gfs_readdir_emit(st, uiop, voff, st->grd_self,
		    ".", 0)) == 0)
			goto top;
	} else if (off == 1) {
		if ((error = gfs_readdir_emit(st, uiop, voff, st->grd_parent,
		    "..", 0)) == 0)
			goto top;
	} else {
		*voffp = voff;
		return (0);
	}

	return (error);
}
Ejemplo n.º 3
0
Archivo: gfs.c Proyecto: RJVB/zfs
/*
 * gfs_readdir_emitn: like gfs_readdir_emit(), but takes an integer
 * instead of a string for the entry's name.
 */
int
gfs_readdir_emitn(gfs_readdir_state_t *st, uio_t *uiop, offset_t voff,
    ino64_t ino, unsigned long num)
{
	char buf[40];

	numtos(num, buf);
	return (gfs_readdir_emit(st, uiop, voff, ino, buf, 0));
}
Ejemplo n.º 4
0
Archivo: gfs.c Proyecto: 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));
}
Ejemplo n.º 5
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);
}