Beispiel #1
0
static void serve_readdir(fuse_req_t req, fuse_ino_t fuse_ino, size_t size,
                          off_t foff, struct fuse_file_info * fi)
{
	fdesc_t * fdesc = fi_get_fdesc(fi);
	uint32_t off = foff;
	uint32_t total_size = 0;
	char * buf = NULL;
	int r;
	Dprintf("%s(ino = %lu, size = %u, off = %lld)\n", __FUNCTION__, fuse_ino, size, foff);

	while (1)
	{
		dirent_t dirent;
		int nbytes;
		struct stat stbuf;
		inode_t entry_cfs_ino;
		size_t oldsize = total_size;

		nbytes = CALL(reqcfs(req), get_dirent, fdesc, &dirent, sizeof(dirent), &off);
		if (nbytes == -1)
			break;
		else if (nbytes < 0)
		{
			fprintf(stderr, "%s:%s(): CALL(cfs, get_dirent, fdesc = %p, off = %d) = %d (%s)\n", __FILE__, __FUNCTION__, fdesc, off, nbytes, strerror(nbytes));
			assert(nbytes >= 0);
		}

		if (total_size + fuse_dirent_size(dirent.d_namelen) > size)
			break;
		Dprintf("%s: \"%s\"\n", __FUNCTION__, dirent.d_name);

		total_size += fuse_dirent_size(dirent.d_namelen);
		buf = (char *) realloc(buf, total_size);
		if (!buf)
			kpanic("realloc() failed");

		memset(&stbuf, 0, sizeof(stbuf));
		// Generate "." and ".." here rather than in the base file system
		// because they are not able to find ".."'s inode from just
		// "."'s inode
		if (!strcmp(dirent.d_name, "."))
			entry_cfs_ino = fusecfsino(req, fuse_ino);
		else if (!strcmp(dirent.d_name, ".."))
			entry_cfs_ino = fdesc->common->parent;
		else
		{
			r = CALL(reqcfs(req), lookup, fusecfsino(req, fuse_ino), dirent.d_name, &entry_cfs_ino);
			assert(r >= 0);
		}
		stbuf.st_ino = cfsfuseino(req, entry_cfs_ino);
		fuse_add_dirent(buf + oldsize, dirent.d_name, &stbuf, off);
	}

	r = fuse_reply_buf(req, buf, total_size);
	fuse_reply_assert(!r);
	free(buf);
}
Beispiel #2
0
static void dirbuf_add(struct dirbuf *b, const char *name, fuse_ino_t ino)
{
    struct stat stbuf;
    size_t oldsize = b->size;
    b->size += fuse_dirent_size(strlen(name));
    b->p = (char *) realloc(b->p, b->size);
    memset(&stbuf, 0, sizeof(stbuf));
    stbuf.st_ino = ino;
    fuse_add_dirent(b->p + oldsize, name, &stbuf, b->size);
}
Beispiel #3
0
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
                         const char *name, const struct stat *stbuf, off_t off)
{
    size_t entsize;

    (void) req;
    entsize = fuse_dirent_size(strlen(name));
    if (entsize <= bufsize && buf)
        fuse_add_dirent(buf, name, stbuf, off);
    return entsize;
}
Beispiel #4
0
static size_t sqfs_ll_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
		const char *name, const struct stat *st, off_t off) {
	#if HAVE_DECL_FUSE_ADD_DIRENTRY
		return fuse_add_direntry(req, buf, bufsize, name, st, off);
	#else
		size_t esize = fuse_dirent_size(strlen(name));
		if (bufsize >= esize)
			fuse_add_dirent(buf, name, st, off);
		return esize;
	#endif
}
static int zfsfuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
{
	vnode_t *vp = ((file_info_t *)(uintptr_t) fi->fh)->vp;
	ASSERT(vp != NULL);
	ASSERT(VTOZ(vp) != NULL);
	ASSERT(VTOZ(vp)->z_id == ino);

	if(vp->v_type != VDIR)
		return ENOTDIR;

	vfs_t *vfs = (vfs_t *) fuse_req_userdata(req);
	zfsvfs_t *zfsvfs = vfs->vfs_data;

	char *outbuf = kmem_alloc(size, KM_NOSLEEP);
	if(outbuf == NULL)
		return ENOMEM;

	ZFS_ENTER(zfsvfs);

	cred_t cred;
	zfsfuse_getcred(req, &cred);

	union {
		char buf[DIRENT64_RECLEN(MAXNAMELEN)];
		struct dirent64 dirent;
	} entry;

	struct stat fstat = { 0 };

	iovec_t iovec;
	uio_t uio;
	uio.uio_iov = &iovec;
	uio.uio_iovcnt = 1;
	uio.uio_segflg = UIO_SYSSPACE;
	uio.uio_fmode = 0;
	uio.uio_llimit = RLIM64_INFINITY;

	int eofp = 0;

	int outbuf_off = 0;
	int outbuf_resid = size;

	off_t next = off;

	int error;

	for(;;) {
		iovec.iov_base = entry.buf;
		iovec.iov_len = sizeof(entry.buf);
		uio.uio_resid = iovec.iov_len;
		uio.uio_loffset = next;

		error = VOP_READDIR(vp, &uio, &cred, &eofp, NULL, 0);
		if(error)
			goto out;

		/* No more directory entries */
		if(iovec.iov_base == entry.buf)
			break;

		fstat.st_ino = entry.dirent.d_ino;
		fstat.st_mode = 0;

		int dsize = fuse_dirent_size(strlen(entry.dirent.d_name));
		if(dsize > outbuf_resid)
			break;

		fuse_add_dirent(outbuf + outbuf_off, entry.dirent.d_name, &fstat, entry.dirent.d_off);

		outbuf_off += dsize;
		outbuf_resid -= dsize;
		next = entry.dirent.d_off;
	}

out:
	ZFS_EXIT(zfsvfs);

	if(!error)
		fuse_reply_buf(req, outbuf, outbuf_off);

	kmem_free(outbuf, size);

	return error;
}