コード例 #1
0
ファイル: tmpfs_subr.c プロジェクト: kusumi/DragonFlyBSD
/*
 * 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;
}
コード例 #2
0
ファイル: tmpfs_subr.c プロジェクト: kusumi/DragonFlyBSD
/*
 * 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_getdotdent(struct tmpfs_node *node, struct uio *uio)
{
	int error;

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

	if (vop_write_dirent(&error, uio, node->tn_id, DT_DIR, 1, "."))
		return -1;
	if (error == 0)
		uio->uio_offset = TMPFS_DIRCOOKIE_DOTDOT;
	return error;
}
コード例 #3
0
static int
procfs_readdir_proc(struct vop_readdir_args *ap)
{
	struct pfsnode *pfs;
	int error, i, retval;
	struct proc *p;
	struct lwp *lp;
	struct proc_target *pt;
	struct uio *uio = ap->a_uio;

	pfs = VTOPFS(ap->a_vp);
	p = pfs_pfind(pfs->pfs_pid);
	if (p == NULL)
		return(0);
	if (!PRISON_CHECK(ap->a_cred, p->p_ucred)) {
		error = 0;
		goto done;
	}
	/* XXX lwp, not MPSAFE */
	lp = FIRST_LWP_IN_PROC(p);

	error = 0;
	i = (int)uio->uio_offset;
	if (i < 0) {
		error = EINVAL;
		goto done;
	}

	for (pt = &proc_targets[i];
	     !error && uio->uio_resid > 0 && i < nproc_targets; pt++, i++) {
		if (pt->pt_valid && (*pt->pt_valid)(lp) == 0)
			continue;

		retval = vop_write_dirent(&error, uio,
		    PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype), pt->pt_type,
		    pt->pt_namlen, pt->pt_name);
		if (retval)
			break;
	}

	uio->uio_offset = (off_t)i;
	error = 0;
done:
	PRELE(p);
	return error;
}
コード例 #4
0
ファイル: hpfs_vnops.c プロジェクト: juanfra684/DragonFlyBSD
static int
hpfs_de_uiomove(int *error, struct hpfsmount *hpmp, struct hpfsdirent *dep,
		struct uio *uio)
{
	char convname[HPFS_MAXFILENAME + 1];
	int i, success;

	dprintf(("[no: 0x%x, size: %d, name: %2d:%.*s, flag: 0x%x] ",
		dep->de_fnode, dep->de_size, dep->de_namelen,
		dep->de_namelen, dep->de_name, dep->de_flag));

	/*strncpy(cde.d_name, dep->de_name, dep->de_namelen);*/
	for (i=0; i<dep->de_namelen; i++) 
		convname[i] = hpfs_d2u(hpmp, dep->de_name[i]);
	convname[dep->de_namelen] = '\0';

	success = vop_write_dirent(error, uio, dep->de_fnode,
			(dep->de_flag & DE_DIR) ? DT_DIR : DT_REG,
			dep->de_namelen, convname);

	dprintf(("[0x%lx] ", uio->uio_resid));
	return (success);
}
コード例 #5
0
ファイル: nwfs_io.c プロジェクト: mihaicarabas/dragonfly
static int
nwfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
{
	struct nwmount *nmp = VTONWFS(vp);
	int error, i;
	struct nwnode *np;
	struct nw_entry_info fattr;
	struct vnode *newvp;
	ncpfid fid;
	ino_t d_ino;
	size_t d_namlen;
	const char *d_name;
	uint8_t d_type;

	np = VTONW(vp);
	NCPVNDEBUG("dirname='%s'\n",np->n_name);
	if (uio->uio_offset < 0 || uio->uio_offset > INT_MAX)
		return (EINVAL);
	error = 0;
	i = (int)uio->uio_offset; /* offset in directory */
	if (i == 0) {
		error = ncp_initsearch(vp, uio->uio_td, cred);
		if (error) {
			NCPVNDEBUG("cannot initialize search, error=%d",error);
			return( error );
		}
	}

	for (; !error && uio->uio_resid > 0; i++) {
		switch (i) {
		    case 0:		/* `.' */
			d_ino = np->n_fid.f_id;
			if (d_ino == 0)
				d_ino = NWFS_ROOT_INO;
			d_namlen = 1;
			d_name = ".";
			d_type = DT_DIR;
			break;
		    case 1:		/* `..' */
			d_ino = np->n_parent.f_id;
			if (d_ino == 0)
				d_ino = NWFS_ROOT_INO;
			d_namlen = 2;
			d_name = "..";
			d_type = DT_DIR;
			break;
		    default:
			error = ncp_search_for_file_or_subdir(nmp, &np->n_seq, &fattr, uio->uio_td, cred);
			if (error && error < 0x80)
				goto done;
			d_ino = fattr.dirEntNum;
			d_type = (fattr.attributes & aDIR) ? DT_DIR : DT_REG;
			d_namlen = fattr.nameLen;
			d_name = fattr.entryName;
#if 0
			if (error && eofflag) {
			/*	*eofflag = 1;*/
			        break;
			}
#endif
			break;
		}
		if (nwfs_fastlookup && !error && i > 1) {
			fid.f_id = fattr.dirEntNum;
			fid.f_parent = np->n_fid.f_id;
			error = nwfs_nget(vp->v_mount, fid, &fattr, vp, &newvp);
			if (!error) {
				VTONW(newvp)->n_ctime = VTONW(newvp)->n_vattr.va_ctime.tv_sec;
				vput(newvp);
			} else
				error = 0;
		}
		if (error >= 0x80) {
		    error = 0;
		    break;
		}
		if (vop_write_dirent(&error, uio, d_ino, d_type, d_namlen, d_name))
			break;
	}
done:
	uio->uio_offset = i;
	return (error);
}
コード例 #6
0
ファイル: ext2_lookup.c プロジェクト: AhmadTux/DragonFlyBSD
/*
 * this is exactly what we do here - the problem is that the conversion
 * will blow up some entries by four bytes, so it can't be done in place.
 * This is too bad. Right now the conversion is done entry by entry, the
 * converted entry is sent via uiomove.
 *
 * XXX allocate a buffer, convert as many entries as possible, then send
 * the whole buffer to uiomove
 *
 * ext2_readdir(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred)
 */
int
ext2_readdir(struct vop_readdir_args *ap)
{
        struct uio *uio = ap->a_uio;
        int count, error;
	struct ext2_dir_entry_2 *edp, *dp;
	int ncookies;
	struct uio auio;
	struct iovec aiov;
	caddr_t dirbuf;
	int DIRBLKSIZ = VTOI(ap->a_vp)->i_e2fs->s_blocksize;
	int readcnt, retval;
	off_t startoffset = uio->uio_offset;

	if ((error = vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY)) != 0)
		return(error);

	count = uio->uio_resid;
	/*
	 * Avoid complications for partial directory entries by adjusting
	 * the i/o to end at a block boundary.  Don't give up (like ufs
	 * does) if the initial adjustment gives a negative count, since
	 * many callers don't supply a large enough buffer.  The correct
	 * size is a little larger than DIRBLKSIZ to allow for expansion
	 * of directory entries, but some callers just use 512.
	 */
	count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
	if (count <= 0)
		count += DIRBLKSIZ;
	if (count > MAXBSIZE)		/* limit to a reasonable size */
		count = MAXBSIZE;

#ifdef EXT2FS_DEBUG
	kprintf("ext2_readdir: uio_offset = %lld, uio_resid = %d, count = %d\n",
	    uio->uio_offset, uio->uio_resid, count);
#endif

	auio = *uio;
	auio.uio_iov = &aiov;
	auio.uio_iovcnt = 1;
	auio.uio_resid = count;
	auio.uio_segflg = UIO_SYSSPACE;
	aiov.iov_len = count;
	dirbuf = kmalloc(count, M_TEMP, M_WAITOK);
	aiov.iov_base = dirbuf;
	error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
	if (error == 0) {
		readcnt = count - auio.uio_resid;
		edp = (struct ext2_dir_entry_2 *)&dirbuf[readcnt];
		ncookies = 0;
		for (dp = (struct ext2_dir_entry_2 *)dirbuf;
		    !error && uio->uio_resid > 0 && dp < edp; ) {
			/*-
			 * "New" ext2fs directory entries differ in 3 ways
			 * from ufs on-disk ones:
			 * - the name is not necessarily NUL-terminated.
			 * - the file type field always exists and always
			 * follows the name length field.
			 * - the file type is encoded in a different way.
			 *
			 * "Old" ext2fs directory entries need no special
			 * conversions, since they binary compatible with
			 * "new" entries having a file type of 0 (i.e.,
			 * EXT2_FT_UNKNOWN).  Splitting the old name length
			 * field didn't make a mess like it did in ufs,
			 * because ext2fs uses a machine-dependent disk
			 * layout.
			 */
			if (dp->rec_len <= 0) {
				error = EIO;
				break;
			}
			retval = vop_write_dirent(&error, uio, dp->inode,
			    FTTODT(dp->file_type), dp->name_len, dp->name);

			if (retval)
				break;
			/* advance dp */
			dp = (struct ext2_dir_entry_2 *)((char *)dp + dp->rec_len);
			if (!error)
				ncookies++;
		}
		/* we need to correct uio_offset */
		uio->uio_offset = startoffset + (caddr_t)dp - dirbuf;

		if (!error && ap->a_ncookies != NULL) {
			off_t *cookiep, *cookies, *ecookies;
			off_t off;

			if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
				panic("ext2fs_readdir: unexpected uio from NFS server");
			if (ncookies) {
				cookies = kmalloc(ncookies * sizeof(off_t),
                                                  M_TEMP, M_WAITOK);
			} else {
				cookies = kmalloc(sizeof(off_t), M_TEMP,
                                                  M_WAITOK);
			}
			off = startoffset;
			for (dp = (struct ext2_dir_entry_2 *)dirbuf,
			     cookiep = cookies, ecookies = cookies + ncookies;
			     cookiep < ecookies;
			     dp = (struct ext2_dir_entry_2 *)((caddr_t) dp + dp->rec_len)) {
				off += dp->rec_len;
				*cookiep++ = off;
			}
			*ap->a_ncookies = ncookies;
			*ap->a_cookies = cookies;
		}
	}
	kfree(dirbuf, M_TEMP);
	if (ap->a_eofflag)
		*ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset;
	vn_unlock(ap->a_vp);
        return (error);
}
コード例 #7
0
static int
smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
{
	struct smb_cred scred;
	struct smbfs_fctx *ctx;
	struct vnode *newvp;
	struct smbnode *np;
	int error, offset, retval;

	np = VTOSMB(vp);
	SMBVDEBUG("dirname='%s'\n", np->n_name);
	smb_makescred(&scred, uio->uio_td, cred);

	if (uio->uio_offset < 0 || uio->uio_offset > INT_MAX)
		return(EINVAL);

	error = 0;
	offset = uio->uio_offset;

	if (uio->uio_resid > 0 && offset < 1) {
		if (vop_write_dirent(&error, uio, np->n_ino, DT_DIR, 1, "."))
			goto done;
		if (error)
			goto done;
		++offset;
	}

	if (uio->uio_resid > 0 && offset < 2) {
		if (vop_write_dirent(&error, uio,
		    np->n_parent ? VTOSMB(np->n_parent)->n_ino : 2,
		    DT_DIR, 2, ".."))
			goto done;
		if (error)
			goto done;
		++offset;
	}

	if (uio->uio_resid == 0)
		goto done;

	if (offset != np->n_dirofs || np->n_dirseq == NULL) {
		SMBVDEBUG("Reopening search %ld:%ld\n", offset, np->n_dirofs);
		if (np->n_dirseq) {
			smbfs_findclose(np->n_dirseq, &scred);
			np->n_dirseq = NULL;
		}
		np->n_dirofs = 2;
		error = smbfs_findopen(np, "*", 1,
		    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
		    &scred, &ctx);
		if (error) {
			SMBVDEBUG("can not open search, error = %d", error);
			return error;
		}
		np->n_dirseq = ctx;
	} else {
		ctx = np->n_dirseq;
	}
	while (np->n_dirofs < offset) {
		error = smbfs_findnext(ctx, offset - np->n_dirofs, &scred);
		++np->n_dirofs;
		if (error) {
			smbfs_findclose(np->n_dirseq, &scred);
			np->n_dirseq = NULL;
			return error == ENOENT ? 0 : error;
		}
	}
	error = 0;
	while (uio->uio_resid > 0 && !error) {
		/*
		 * Overestimate the size of a record a bit, doesn't really
		 * hurt to be wrong here.
		 */
		error = smbfs_findnext(ctx, uio->uio_resid / _DIRENT_RECLEN(255) + 1, &scred);
		if (error)
			break;
		np->n_dirofs++;
		++offset;

		retval = vop_write_dirent(&error, uio, ctx->f_attr.fa_ino,
		    (ctx->f_attr.fa_attr & SMB_FA_DIR) ? DT_DIR : DT_REG,
		    ctx->f_nmlen, ctx->f_name);
		if (retval)
			break;
		if (smbfs_fastlookup && !error) {
			error = smbfs_nget(vp->v_mount, vp, ctx->f_name,
			    ctx->f_nmlen, &ctx->f_attr, &newvp);
			if (!error)
				vput(newvp);
		}
	}
	if (error == ENOENT)
		error = 0;
done:
	uio->uio_offset = offset;
	return error;
}
コード例 #8
0
static int
procfs_readdir_root_callback(struct proc *p, void *data)
{
	struct procfs_readdir_root_info *info = data;
	struct uio *uio;
	int retval;
	ino_t d_ino;
	const char *d_name;
	char d_name_pid[20];
	size_t d_namlen;
	uint8_t d_type;

	uio = info->uio;

	if (uio->uio_resid <= 0 || info->error)
		return(-1);

	switch (info->pcnt) {
	case 0:		/* `.' */
		d_ino = PROCFS_FILENO(0, Proot);
		d_name = ".";
		d_namlen = 1;
		d_type = DT_DIR;
		break;
	case 1:		/* `..' */
		d_ino = PROCFS_FILENO(0, Proot);
		d_name = "..";
		d_namlen = 2;
		d_type = DT_DIR;
		break;

	case 2:
		d_ino = PROCFS_FILENO(0, Pcurproc);
		d_namlen = 7;
		d_name = "curproc";
		d_type = DT_LNK;
		break;


	default:
		if (!PRISON_CHECK(info->cred, p->p_ucred))
			return(0);
		if (ps_showallprocs == 0 && 
		    info->cred->cr_uid != 0 &&
		    info->cred->cr_uid != p->p_ucred->cr_uid) {
			return(0);
		}

		/*
		 * Skip entries we have already returned (optimization)
		 */
		if (info->pcnt < info->i) {
			++info->pcnt;
			return(0);
		}

		d_ino = PROCFS_FILENO(p->p_pid, Pproc);
		d_namlen = ksnprintf(d_name_pid, sizeof(d_name_pid),
		    "%ld", (long)p->p_pid);
		d_name = d_name_pid;
		d_type = DT_DIR;
		break;
	}

	/*
	 * Skip entries we have already returned (optimization)
	 */
	if (info->pcnt < info->i) {
		++info->pcnt;
		return(0);
	}

	retval = vop_write_dirent(&info->error, uio,
				  d_ino, d_type, d_namlen, d_name);
	if (retval)
		return(-1);
	++info->pcnt;
	++info->i;
	return(0);
}
コード例 #9
0
ファイル: hpfs_vnops.c プロジェクト: juanfra684/DragonFlyBSD
/*
 * hpfs_readdir(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred,
 *		int *a_ncookies, off_t **cookies)
 */
int
hpfs_readdir(struct vop_readdir_args *ap)
{
	struct vnode *vp = ap->a_vp;
	struct hpfsnode *hp = VTOHP(vp);
	struct hpfsmount *hpmp = hp->h_hpmp;
	struct uio *uio = ap->a_uio;
	int ncookies = 0, i, num, cnum;
	int error = 0;
	struct buf *bp;
	struct dirblk *dp;
	struct hpfsdirent *dep;
	lsn_t olsn;
	lsn_t lsn;
	int level;

	dprintf(("hpfs_readdir(0x%x, 0x%x, 0x%lx): ",
		hp->h_no, (u_int32_t)uio->uio_offset, uio->uio_resid));

	/*
	 * As we need to fake up . and .., and the remaining directory structure
	 * can't be expressed in one off_t as well, we just increment uio_offset
	 * by 1 for each entry.
	 *
	 * num is the entry we need to start reporting
	 * cnum is the current entry
	 */
	if (uio->uio_offset < 0 || uio->uio_offset > INT_MAX)
		return(EINVAL);
	if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY)) != 0)
		return (error);

	num = uio->uio_offset;
	cnum = 0;

	if( num <= cnum ) {
		dprintf((". faked, "));
		if (vop_write_dirent(&error, uio, hp->h_no, DT_DIR, 1, "."))
			goto done;
		if (error)
			goto done;
		ncookies ++;
	}
	cnum++;

	if( num <= cnum ) {
		dprintf((".. faked, "));
		if (vop_write_dirent(&error, uio, hp->h_fn.fn_parent, DT_DIR, 2, ".."))
			goto readdone;
		if (error)
			goto done;
		ncookies ++;
	}
	cnum++;

	lsn = ((alleaf_t *)hp->h_fn.fn_abd)->al_lsn;

	olsn = 0;
	level = 1;

dive:
	dprintf(("[dive 0x%x] ", lsn));
	error = bread(hp->h_devvp, dbtodoff(lsn), D_BSIZE, &bp);
	if (error) {
		brelse(bp);
		goto done;
	}

	dp = (struct dirblk *) bp->b_data;
	if (dp->d_magic != D_MAGIC) {
		kprintf("hpfs_readdir: MAGIC DOESN'T MATCH\n");
		brelse(bp);
		error = EINVAL;
		goto done;
	}

	dep = D_DIRENT(dp);

	if (olsn) {
		dprintf(("[restore 0x%x] ", olsn));

		while(!(dep->de_flag & DE_END) ) {
			if((dep->de_flag & DE_DOWN) &&
			   (olsn == DE_DOWNLSN(dep)))
					 break;
			dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
		}

		if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) {
			if (dep->de_flag & DE_END)
				goto blockdone;

			if (!(dep->de_flag & DE_SPECIAL)) {
				if (num <= cnum) {
					if (hpfs_de_uiomove(&error, hpmp, dep, uio)) {
						brelse(bp);
						dprintf(("[resid] "));
						goto readdone;
					}
					if (error) {
						brelse (bp);
						goto done;
					}
					ncookies++;
				}
				cnum++;
			}

			dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
		} else {
			kprintf("hpfs_readdir: ERROR! oLSN not found\n");
			brelse(bp);
			error = EINVAL;
			goto done;
		}
	}

	olsn = 0;

	while(!(dep->de_flag & DE_END)) {
		if(dep->de_flag & DE_DOWN) {
			lsn = DE_DOWNLSN(dep);
			brelse(bp);
			level++;
			goto dive;
		}

		if (!(dep->de_flag & DE_SPECIAL)) {
			if (num <= cnum) {
				if (hpfs_de_uiomove(&error, hpmp, dep, uio)) {
					brelse(bp);
					dprintf(("[resid] "));
					goto readdone;
				}
				if (error) {
					brelse (bp);
					goto done;
				}
				ncookies++;
			}
			cnum++;
		}

		dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
	}

	if(dep->de_flag & DE_DOWN) {
		dprintf(("[enddive] "));
		lsn = DE_DOWNLSN(dep);
		brelse(bp);
		level++;
		goto dive;
	}

blockdone:
	dprintf(("[EOB] "));
	olsn = lsn;
	lsn = dp->d_parent;
	brelse(bp);
	level--;

	dprintf(("[level %d] ", level));

	if (level > 0)
		goto dive;	/* undive really */

	if (ap->a_eofflag) {
	    dprintf(("[EOF] "));
	    *ap->a_eofflag = 1;
	}

readdone:
	uio->uio_offset = cnum;
	dprintf(("[readdone]\n"));
	if (!error && ap->a_ncookies != NULL) {
		off_t *cookies;
		off_t *cookiep;

		dprintf(("%d cookies, ",ncookies));
		if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
			panic("hpfs_readdir: unexpected uio from NFS server");
		cookies = kmalloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
		for (cookiep = cookies, i=0; i < ncookies; i++)
			*cookiep++ = ++num;

		*ap->a_ncookies = ncookies;
		*ap->a_cookies = cookies;
	}

done:
	vn_unlock(ap->a_vp);
	return (error);
}
コード例 #10
0
ファイル: devfs_vnops.c プロジェクト: mihaicarabas/dragonfly
static int
devfs_vop_readdir(struct vop_readdir_args *ap)
{
	struct devfs_node *dnode = DEVFS_NODE(ap->a_vp);
	struct devfs_node *node;
	int cookie_index;
	int ncookies;
	int error2;
	int error;
	int r;
	off_t *cookies;
	off_t saveoff;

	devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_readdir() called!\n");

	if (ap->a_uio->uio_offset < 0 || ap->a_uio->uio_offset > INT_MAX)
		return (EINVAL);
	error = vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY | LK_FAILRECLAIM);
	if (error)
		return (error);

	if (!devfs_node_is_accessible(dnode)) {
		vn_unlock(ap->a_vp);
		return ENOENT;
	}

	lockmgr(&devfs_lock, LK_EXCLUSIVE);

	saveoff = ap->a_uio->uio_offset;

	if (ap->a_ncookies) {
		ncookies = ap->a_uio->uio_resid / 16 + 1; /* Why / 16 ?? */
		if (ncookies > 256)
			ncookies = 256;
		cookies = kmalloc(256 * sizeof(off_t), M_TEMP, M_WAITOK);
		cookie_index = 0;
	} else {
		ncookies = -1;
		cookies = NULL;
		cookie_index = 0;
	}

	nanotime(&dnode->atime);

	if (saveoff == 0) {
		r = vop_write_dirent(&error, ap->a_uio, dnode->d_dir.d_ino,
				     DT_DIR, 1, ".");
		if (r)
			goto done;
		if (cookies)
			cookies[cookie_index] = saveoff;
		saveoff++;
		cookie_index++;
		if (cookie_index == ncookies)
			goto done;
	}

	if (saveoff == 1) {
		if (dnode->parent) {
			r = vop_write_dirent(&error, ap->a_uio,
					     dnode->parent->d_dir.d_ino,
					     DT_DIR, 2, "..");
		} else {
			r = vop_write_dirent(&error, ap->a_uio,
					     dnode->d_dir.d_ino,
					     DT_DIR, 2, "..");
		}
		if (r)
			goto done;
		if (cookies)
			cookies[cookie_index] = saveoff;
		saveoff++;
		cookie_index++;
		if (cookie_index == ncookies)
			goto done;
	}

	TAILQ_FOREACH(node, DEVFS_DENODE_HEAD(dnode), link) {
		if ((node->flags & DEVFS_HIDDEN) ||
		    (node->flags & DEVFS_INVISIBLE)) {
			continue;
		}

		/*
		 * If the node type is a valid devfs alias, then we make
		 * sure that the target isn't hidden. If it is, we don't
		 * show the link in the directory listing.
		 */
		if ((node->node_type == Nlink) && (node->link_target != NULL) &&
			(node->link_target->flags & DEVFS_HIDDEN))
			continue;

		if (node->cookie < saveoff)
			continue;

		saveoff = node->cookie;

		error2 = vop_write_dirent(&error, ap->a_uio, node->d_dir.d_ino,
					  node->d_dir.d_type,
					  node->d_dir.d_namlen,
					  node->d_dir.d_name);

		if (error2)
			break;

		saveoff++;

		if (cookies)
			cookies[cookie_index] = node->cookie;
		++cookie_index;
		if (cookie_index == ncookies)
			break;
	}

done:
	lockmgr(&devfs_lock, LK_RELEASE);
	vn_unlock(ap->a_vp);

	ap->a_uio->uio_offset = saveoff;
	if (error && cookie_index == 0) {
		if (cookies) {
			kfree(cookies, M_TEMP);
			*ap->a_ncookies = 0;
			*ap->a_cookies = NULL;
		}
	} else {
		if (cookies) {
			*ap->a_ncookies = cookie_index;
			*ap->a_cookies = cookies;
		}
	}
	return (error);
}
コード例 #11
0
ファイル: tmpfs_subr.c プロジェクト: kusumi/DragonFlyBSD
/*
 * 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;
}