static int vboxvfs_vnode_readdir(struct vnop_readdir_args *args) { vboxvfs_mount_t *pMount; vboxvfs_vnode_t *pVnodeData; SHFLDIRINFO *Info; uint32_t cbInfo; mount_t mp; vnode_t vnode; struct uio *uio; int rc = 0, rc2; PDEBUG("Reading directory..."); AssertReturn(args, EINVAL); AssertReturn(args->a_eofflag, EINVAL); AssertReturn(args->a_numdirent, EINVAL); uio = args->a_uio; AssertReturn(uio, EINVAL); vnode = args->a_vp; AssertReturn(vnode, EINVAL); AssertReturn(vnode_isdir(vnode), EINVAL); pVnodeData = (vboxvfs_vnode_t *)vnode_fsnode(vnode); AssertReturn(pVnodeData, EINVAL); mp = vnode_mount(vnode); AssertReturn(mp, EINVAL); pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL); lck_rw_lock_shared(pVnodeData->pLock); cbInfo = sizeof(Info) + MAXPATHLEN; Info = (SHFLDIRINFO *)RTMemAllocZ(cbInfo); if (!Info) { PDEBUG("No memory to allocate internal data"); lck_rw_unlock_shared(pVnodeData->pLock); return ENOMEM; } uint32_t index = (uint32_t)uio_offset(uio) / (uint32_t)sizeof(struct dirent); uint32_t cFiles = 0; PDEBUG("Exploring VBoxVFS directory (%s), handle (0x%.8X), offset (0x%X), count (%d)", (char *)pVnodeData->pPath->String.utf8, (int)pVnodeData->pHandle, index, uio_iovcnt(uio)); /* Currently, there is a problem when vboxCallDirInfo() is not able to * continue retrieve directory content if the same VBoxVFS handle is used. * This macro forces to use a new handle in readdir() callback. If enabled, * the original handle (obtained in open() callback is ignored). */ SHFLHANDLE Handle; rc = vboxvfs_open_internal(pMount, pVnodeData->pPath, SHFL_CF_DIRECTORY | SHFL_CF_ACCESS_READ | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW, &Handle); if (rc != 0) { PDEBUG("Unable to open dir: %d", rc); RTMemFree(Info); lck_rw_unlock_shared(pVnodeData->pLock); return rc; } #if 0 rc = vboxCallDirInfo(&g_vboxSFClient, &pMount->pMap, Handle, 0, 0, index, &cbInfo, (PSHFLDIRINFO)Info, &cFiles); #else SHFLSTRING *pMask = vboxvfs_construct_shflstring("*", strlen("*")); if (pMask) { for (uint32_t cSkip = 0; (cSkip < index + 1) && (rc == VINF_SUCCESS); cSkip++) { //rc = vboxCallDirInfo(&g_vboxSFClient, &pMount->pMap, Handle, 0 /* pMask */, 0 /* SHFL_LIST_RETURN_ONE */, 0, &cbInfo, (PSHFLDIRINFO)Info, &cFiles); uint32_t cbReturned = cbInfo; //rc = vboxCallDirInfo(&g_vboxSFClient, &pMount->pMap, Handle, pMask, SHFL_LIST_RETURN_ONE, 0, &cbReturned, (PSHFLDIRINFO)Info, &cFiles); rc = vboxCallDirInfo(&g_vboxSFClient, &pMount->pMap, Handle, 0, SHFL_LIST_RETURN_ONE, 0, &cbReturned, (PSHFLDIRINFO)Info, &cFiles); } PDEBUG("read %d files", cFiles); RTMemFree(pMask); } else { PDEBUG("Can't alloc mask"); rc = ENOMEM; } #endif rc2 = vboxvfs_close_internal(pMount, Handle); if (rc2 != 0) { PDEBUG("Unable to close directory: %s: %d", pVnodeData->pPath->String.utf8, rc2); } switch (rc) { case VINF_SUCCESS: { rc = vboxvfs_vnode_readdir_copy_data((ino_t)(index + 1), Info, uio, args->a_numdirent); break; } case VERR_NO_MORE_FILES: { PDEBUG("No more entries in directory"); *(args->a_eofflag) = 1; break; } default: { PDEBUG("vboxCallDirInfo() for item #%d has failed: %d", (int)index, (int)rc); rc = EINVAL; break; } } RTMemFree(Info); lck_rw_unlock_shared(pVnodeData->pLock); return rc; }
int sf_dir_read_all(struct sf_glob_info *sf_g, struct sf_inode_info *sf_i, struct sf_dir_info *sf_d, SHFLHANDLE handle) { int err; SHFLSTRING *mask; struct sf_dir_buf *b; TRACE(); err = sf_make_path(__func__, sf_i, "*", 1, &mask); if (err) goto fail0; for (;;) { int rc; void *buf; uint32_t cbSize; uint32_t cEntries; b = sf_get_empty_dir_buf(sf_d); if (!b) { b = sf_dir_buf_alloc(); if (!b) { err = -ENOMEM; LogRelFunc(("could not alloc directory buffer\n")); goto fail1; } list_add(&b->head, &sf_d->info_list); } buf = b->buf; cbSize = b->cbFree; rc = vboxCallDirInfo(&client_handle, &sf_g->map, handle, mask, 0, 0, &cbSize, buf, &cEntries); switch (rc) { case VINF_SUCCESS: /* fallthrough */ case VERR_NO_MORE_FILES: break; case VERR_NO_TRANSLATION: LogFunc(("host could not translate entry\n")); /* XXX */ break; default: err = -RTErrConvertToErrno(rc); LogFunc(("vboxCallDirInfo failed rc=%Rrc\n", rc)); goto fail1; } b->cEntries += cEntries; b->cbFree -= cbSize; b->cbUsed += cbSize; if (RT_FAILURE(rc)) break; } err = 0; fail1: kfree(mask); fail0: return err; }