summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostServices/SharedFolders/testcase
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostServices/SharedFolders/testcase')
-rw-r--r--src/VBox/HostServices/SharedFolders/testcase/Makefile.kmk104
-rw-r--r--src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.cpp1368
-rw-r--r--src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.h140
-rw-r--r--src/VBox/HostServices/SharedFolders/testcase/tstShflCase.cpp452
-rw-r--r--src/VBox/HostServices/SharedFolders/testcase/tstShflSizes.cpp144
5 files changed, 2208 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedFolders/testcase/Makefile.kmk b/src/VBox/HostServices/SharedFolders/testcase/Makefile.kmk
new file mode 100644
index 00000000..c451d7a1
--- /dev/null
+++ b/src/VBox/HostServices/SharedFolders/testcase/Makefile.kmk
@@ -0,0 +1,104 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for the Shared Folders Host Service testcases.
+#
+
+#
+# Copyright (C) 2006-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+SUB_DEPTH = ../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+#
+# Structure size testcase.
+#
+PROGRAMS += tstShflSizes
+TESTING += $(tstShflSizes_0_OUTDIR)/tstShflSizes.run
+ifndef VBOX_ONLY_SDK
+ ifeq ($(KBUILD_TARGET),$(KBUILD_HOST))
+ if1of ($(KBUILD_TARGET_ARCH).$(KBUILD_HOST_ARCH), x86.x86 amd64.amd64 x86.amd64)
+ OTHERS += $(tstShflSizes_0_OUTDIR)/tstShflSizes.run
+ endif
+ endif
+endif
+tstShflSizes_TEMPLATE = VBoxR3AutoTest
+tstShflSizes_DEFS = VBOX_WITH_HGCM
+tstShflSizes_SOURCES = tstShflSizes.cpp
+tstShflSizes_CLEAN = $(tstShflSizes_0_OUTDIR)/tstShflSizes.run
+
+$$(tstShflSizes_0_OUTDIR)/tstShflSizes.run: $$(tstShflSizes_1_STAGE_TARGET)
+ $(tstShflSizes_1_STAGE_TARGET) quiet
+ $(QUIET)$(APPEND) -t "$@" "done"
+
+
+ifdef VBOX_WITH_TESTCASES
+ #
+ # Case conversion testcase.
+ #
+ PROGRAMS += tstShflCase
+ tstShflCase_TEMPLATE = VBoxR3TstExe
+ tstShflCase_DEFS = VBOX_WITH_HGCM
+ tstShflCase_SOURCES = tstShflCase.cpp
+ tstShflCase_LIBS = $(LIB_RUNTIME)
+
+ #
+ # HGCM service testcase.
+ #
+
+ PROGRAMS += tstSharedFolderService
+ tstSharedFolderService_TEMPLATE = VBoxR3TstExe
+ tstSharedFolderService_DEFS = VBOX_WITH_HGCM UNITTEST
+ tstSharedFolderService_INCS = ..
+ tstSharedFolderService_SOURCES = \
+ tstSharedFolderService.cpp \
+ ../mappings.cpp \
+ ../VBoxSharedFoldersSvc.cpp \
+ ../shflhandle.cpp \
+ ../vbsfpathabs.cpp \
+ ../vbsfpath.cpp \
+ ../vbsf.cpp
+ tstSharedFolderService_LDFLAGS.darwin = \
+ -framework Carbon
+ tstSharedFolderService_LIBS = $(LIB_RUNTIME)
+
+ if 0 # Cannot define two RT_OS_XXX macros!
+ # As there are differences between the Windows build of the service and others,
+ # we do an additional build with RT_OS_WINDOWS defined on non-Windows targets.
+ PROGRAMS += \
+ tstSharedFolderService \
+ $(if $(eq $(KBUILD_TARGET),win),,tstSharedFolderService-win)
+ tstSharedFolderService-win_TEMPLATE = $(tstSharedFolderService_TEMPLATE)
+ tstSharedFolderService-win_DEFS = \
+ $(tstSharedFolderService_DEFS) \
+ RT_OS_WINDOWS
+ tstSharedFolderService-win_INCS = $(tstSharedFolderService_INCS)
+ tstSharedFolderService-win_SOURCES = $(tstSharedFolderService_SOURCES)
+ tstSharedFolderService-win_LDFLAGS.darwin = \
+ $(tstSharedFolderService_LDFLAGS.darwin)
+ tstSharedFolderService-win_LIBS = $(tstSharedFolderService_LIBS)
+ endif
+
+endif # VBOX_WITH_TESTCASES
+
+
+include $(FILE_KBUILD_SUB_FOOTER)
+
diff --git a/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.cpp b/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.cpp
new file mode 100644
index 00000000..3f105284
--- /dev/null
+++ b/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.cpp
@@ -0,0 +1,1368 @@
+/* $Id: tstSharedFolderService.cpp $ */
+/** @file
+ * Testcase for the shared folder service vbsf API.
+ *
+ * Note that this is still very threadbare (there is an awful lot which should
+ * really be tested, but it already took too long to produce this much). The
+ * idea is that anyone who makes changes to the shared folders service and who
+ * cares about unit testing them should add tests to the skeleton framework to
+ * exercise the bits they change before and after changing them.
+ */
+
+/*
+ * Copyright (C) 2011-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+
+#include "tstSharedFolderService.h"
+#include "vbsf.h"
+
+#include <iprt/fs.h>
+#include <iprt/dir.h>
+#include <iprt/file.h>
+#include <iprt/path.h>
+#include <iprt/symlink.h>
+#include <iprt/stream.h>
+#include <iprt/test.h>
+#include <iprt/string.h>
+#include <iprt/utf16.h>
+
+#include "teststubs.h"
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static RTTEST g_hTest = NIL_RTTEST;
+
+
+/*********************************************************************************************************************************
+* Declarations *
+*********************************************************************************************************************************/
+extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable);
+
+
+/*********************************************************************************************************************************
+* Helpers *
+*********************************************************************************************************************************/
+
+/** Simple call handle structure for the guest call completion callback */
+struct VBOXHGCMCALLHANDLE_TYPEDEF
+{
+ /** Where to store the result code */
+ int32_t rc;
+};
+
+/** Call completion callback for guest calls. */
+static DECLCALLBACK(int) callComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
+{
+ callHandle->rc = rc;
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) stamRegisterV(void *pvInstance, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
+ STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va)
+{
+ RT_NOREF(pvInstance, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va);
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) stamDeregisterV(void *pvInstance, const char *pszPatFmt, va_list va)
+{
+ RT_NOREF(pvInstance, pszPatFmt, va);
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) infoRegister(void *pvInstance, const char *pszName, const char *pszDesc,
+ PFNDBGFHANDLEREXT pfnHandler, void *pvUser)
+{
+ RT_NOREF(pvInstance, pszName, pszDesc, pfnHandler, pvUser);
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) infoDeregister(void *pvInstance, const char *pszName)
+{
+ RT_NOREF(pvInstance, pszName);
+ return VINF_SUCCESS;
+}
+
+/**
+ * Initialise the HGCM service table as much as we need to start the
+ * service
+ * @param pTable the table to initialise
+ */
+void initTable(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMSVCHELPERS *pHelpers)
+{
+ pTable->cbSize = sizeof (VBOXHGCMSVCFNTABLE);
+ pTable->u32Version = VBOX_HGCM_SVC_VERSION;
+ pHelpers->pfnCallComplete = callComplete;
+ pHelpers->pfnStamRegisterV = stamRegisterV;
+ pHelpers->pfnStamDeregisterV = stamDeregisterV;
+ pHelpers->pfnInfoRegister = infoRegister;
+ pHelpers->pfnInfoDeregister = infoDeregister;
+ pTable->pHelpers = pHelpers;
+}
+
+#define LLUIFY(a) ((unsigned long long)(a))
+
+static void bufferFromPath(char *pszDst, size_t cbDst, const char *pcszSrc)
+{
+ RTStrCopy(pszDst, cbDst, pcszSrc);
+ uintptr_t const uDstEnd = (uintptr_t)&pszDst[cbDst];
+ for (char *psz = pszDst; psz && (uintptr_t)psz < uDstEnd; ++psz)
+ if (*psz == '\\')
+ *psz = '/';
+}
+
+#define ARRAY_FROM_PATH(a, b) \
+ do { \
+ char *p = (a); NOREF(p); \
+ Assert((a) == p); /* Constant parameter */ \
+ Assert(sizeof((a)) > 0); \
+ bufferFromPath(a, sizeof(a), b); \
+ } while (0)
+
+
+/*********************************************************************************************************************************
+* Stub functions and data *
+*********************************************************************************************************************************/
+static bool g_fFailIfNotLowercase = false;
+
+static RTDIR g_testRTDirClose_hDir = NIL_RTDIR;
+
+extern int testRTDirClose(RTDIR hDir)
+{
+ /* RTPrintf("%s: hDir=%p\n", __PRETTY_FUNCTION__, hDir); */
+ g_testRTDirClose_hDir = hDir;
+ return VINF_SUCCESS;
+}
+
+static char g_testRTDirCreate_szPath[256];
+//static RTFMODE testRTDirCreateMode; - unused
+
+extern int testRTDirCreate(const char *pszPath, RTFMODE fMode, uint32_t fCreate)
+{
+ RT_NOREF2(fMode, fCreate);
+ /* RTPrintf("%s: pszPath=%s, fMode=0x%llx\n", __PRETTY_FUNCTION__, pszPath,
+ LLUIFY(fMode)); */
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszPath, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ ARRAY_FROM_PATH(g_testRTDirCreate_szPath, pszPath);
+ return 0;
+}
+
+static char g_testRTDirOpen_szName[256];
+static struct TESTDIRHANDLE
+{
+ int iEntry;
+ int iDir;
+} g_aTestDirHandles[4];
+static int g_iNextDirHandle = 0;
+static RTDIR g_testRTDirOpen_hDir;
+
+extern int testRTDirOpen(RTDIR *phDir, const char *pszPath)
+{
+ /* RTPrintf("%s: pszPath=%s\n", __PRETTY_FUNCTION__, pszPath); */
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszPath, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ ARRAY_FROM_PATH(g_testRTDirOpen_szName, pszPath);
+ *phDir = g_testRTDirOpen_hDir;
+ g_testRTDirOpen_hDir = NIL_RTDIR;
+ if (!*phDir && g_fFailIfNotLowercase)
+ *phDir = (RTDIR)&g_aTestDirHandles[g_iNextDirHandle++ % RT_ELEMENTS(g_aTestDirHandles)];
+ if (*phDir)
+ {
+ struct TESTDIRHANDLE *pRealDir = (struct TESTDIRHANDLE *)*phDir;
+ pRealDir->iEntry = 0;
+ pRealDir->iDir = 0;
+ const char *pszSlash = pszPath - 1;
+ while ((pszSlash = strpbrk(pszSlash + 1, "\\/")) != NULL)
+ pRealDir->iDir += 1;
+ /*RTPrintf("opendir %s = %d \n", pszPath, pRealDir->iDir);*/
+ }
+ return VINF_SUCCESS;
+}
+
+/** @todo Do something useful with the last two arguments. */
+extern int testRTDirOpenFiltered(RTDIR *phDir, const char *pszPath, RTDIRFILTER, uint32_t)
+{
+ /* RTPrintf("%s: pszPath=%s\n", __PRETTY_FUNCTION__, pszPath); */
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszPath, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ ARRAY_FROM_PATH(g_testRTDirOpen_szName, pszPath);
+ *phDir = g_testRTDirOpen_hDir;
+ g_testRTDirOpen_hDir = NIL_RTDIR;
+ if (!*phDir && g_fFailIfNotLowercase)
+ *phDir = (RTDIR)&g_aTestDirHandles[g_iNextDirHandle++ % RT_ELEMENTS(g_aTestDirHandles)];
+ if (*phDir)
+ {
+ struct TESTDIRHANDLE *pRealDir = (struct TESTDIRHANDLE *)*phDir;
+ pRealDir->iEntry = 0;
+ pRealDir->iDir = 0;
+ const char *pszSlash = pszPath - 1;
+ while ((pszSlash = strpbrk(pszSlash + 1, "\\/")) != NULL)
+ pRealDir->iDir += 1;
+ pRealDir->iDir -= 1;
+ /*RTPrintf("openfiltered %s = %d\n", pszPath, pRealDir->iDir);*/
+ }
+ return VINF_SUCCESS;
+}
+
+static RTDIR g_testRTDirQueryInfo_hDir;
+static RTTIMESPEC g_testRTDirQueryInfo_ATime;
+
+extern int testRTDirQueryInfo(RTDIR hDir, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
+{
+ RT_NOREF1(enmAdditionalAttribs);
+ /* RTPrintf("%s: hDir=%p, enmAdditionalAttribs=0x%llx\n", __PRETTY_FUNCTION__,
+ hDir, LLUIFY(enmAdditionalAttribs)); */
+ g_testRTDirQueryInfo_hDir = hDir;
+ RT_ZERO(*pObjInfo);
+ pObjInfo->AccessTime = g_testRTDirQueryInfo_ATime;
+ RT_ZERO(g_testRTDirQueryInfo_ATime);
+ return VINF_SUCCESS;
+}
+
+extern int testRTDirRemove(const char *pszPath)
+{
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszPath, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ RTPrintf("%s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+
+static RTDIR g_testRTDirReadEx_hDir;
+
+extern int testRTDirReadEx(RTDIR hDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
+ RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
+{
+ RT_NOREF4(pDirEntry, pcbDirEntry, enmAdditionalAttribs, fFlags);
+ /* RTPrintf("%s: hDir=%p, pcbDirEntry=%d, enmAdditionalAttribs=%llu, fFlags=0x%llx\n",
+ __PRETTY_FUNCTION__, hDir, pcbDirEntry ? (int) *pcbDirEntry : -1,
+ LLUIFY(enmAdditionalAttribs), LLUIFY(fFlags)); */
+ g_testRTDirReadEx_hDir = hDir;
+ if (g_fFailIfNotLowercase && hDir != NIL_RTDIR)
+ {
+ struct TESTDIRHANDLE *pRealDir = (struct TESTDIRHANDLE *)hDir;
+ if (pRealDir->iDir == 2) /* /test/mapping/ */
+ {
+ if (pRealDir->iEntry == 0)
+ {
+ pRealDir->iEntry++;
+ RT_ZERO(*pDirEntry);
+ pDirEntry->Info.Attr.fMode = RTFS_TYPE_DIRECTORY | RTFS_DOS_DIRECTORY | RTFS_UNIX_IROTH | RTFS_UNIX_IXOTH;
+ pDirEntry->cbName = 4;
+ pDirEntry->cwcShortName = 4;
+ strcpy(pDirEntry->szName, "test");
+ RTUtf16CopyAscii(pDirEntry->wszShortName, RT_ELEMENTS(pDirEntry->wszShortName), "test");
+ /*RTPrintf("readdir: 'test'\n");*/
+ return VINF_SUCCESS;
+ }
+ }
+ else if (pRealDir->iDir == 3) /* /test/mapping/test/ */
+ {
+ if (pRealDir->iEntry == 0)
+ {
+ pRealDir->iEntry++;
+ RT_ZERO(*pDirEntry);
+ pDirEntry->Info.Attr.fMode = RTFS_TYPE_FILE | RTFS_DOS_NT_NORMAL | RTFS_UNIX_IROTH | RTFS_UNIX_IXOTH;
+ pDirEntry->cbName = 4;
+ pDirEntry->cwcShortName = 4;
+ strcpy(pDirEntry->szName, "file");
+ RTUtf16CopyAscii(pDirEntry->wszShortName, RT_ELEMENTS(pDirEntry->wszShortName), "file");
+ /*RTPrintf("readdir: 'file'\n");*/
+ return VINF_SUCCESS;
+ }
+ }
+ /*else RTPrintf("%s: iDir=%d\n", pRealDir->iDir);*/
+ }
+ return VERR_NO_MORE_FILES;
+}
+
+static uint64_t g_testRTDirSetMode_fMode;
+
+extern int testRTDirSetMode(RTDIR hDir, RTFMODE fMode)
+{
+ RT_NOREF1(hDir);
+ /* RTPrintf("%s: fMode=%llu\n", __PRETTY_FUNCTION__, LLUIFY(fMode)); */
+ g_testRTDirSetMode_fMode = fMode;
+ return VINF_SUCCESS;
+}
+
+static RTTIMESPEC g_testRTDirSetTimes_ATime;
+
+extern int testRTDirSetTimes(RTDIR hDir, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
+ PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
+{
+ RT_NOREF4(hDir, pModificationTime, pChangeTime, pBirthTime);
+ /* RTPrintf("%s: hDir=%p, *pAccessTime=%lli, *pModificationTime=%lli, *pChangeTime=%lli, *pBirthTime=%lli\n",
+ __PRETTY_FUNCTION__, hDir,
+ pAccessTime ? (long long)RTTimeSpecGetNano(pAccessTime) : -1,
+ pModificationTime
+ ? (long long)RTTimeSpecGetNano(pModificationTime) : -1,
+ pChangeTime ? (long long)RTTimeSpecGetNano(pChangeTime) : -1,
+ pBirthTime ? (long long)RTTimeSpecGetNano(pBirthTime) : -1); */
+ if (pAccessTime)
+ g_testRTDirSetTimes_ATime = *pAccessTime;
+ else
+ RT_ZERO(g_testRTDirSetTimes_ATime);
+ return VINF_SUCCESS;
+}
+
+static RTFILE g_testRTFileClose_hFile;
+
+extern int testRTFileClose(RTFILE File)
+{
+ /* RTPrintf("%s: File=%p\n", __PRETTY_FUNCTION__, File); */
+ g_testRTFileClose_hFile = File;
+ return 0;
+}
+
+extern int testRTFileDelete(const char *pszFilename)
+{
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszFilename, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ RTPrintf("%s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+
+static RTFILE g_testRTFileFlush_hFile;
+
+extern int testRTFileFlush(RTFILE File)
+{
+ /* RTPrintf("%s: File=%p\n", __PRETTY_FUNCTION__, File); */
+ g_testRTFileFlush_hFile = File;
+ return VINF_SUCCESS;
+}
+
+static RTFILE g_testRTFileLock_hFile;
+static unsigned g_testRTFileLock_fLock;
+static int64_t g_testRTFileLock_offLock;
+static uint64_t g_testRTFileLock_cbLock;
+
+extern int testRTFileLock(RTFILE hFile, unsigned fLock, int64_t offLock, uint64_t cbLock)
+{
+ /* RTPrintf("%s: hFile=%p, fLock=%u, offLock=%lli, cbLock=%llu\n",
+ __PRETTY_FUNCTION__, hFile, fLock, (long long) offLock,
+ LLUIFY(cbLock)); */
+ g_testRTFileLock_hFile = hFile;
+ g_testRTFileLock_fLock = fLock;
+ g_testRTFileLock_offLock = offLock;
+ g_testRTFileLock_cbLock = cbLock;
+ return VINF_SUCCESS;
+}
+
+static char g_testRTFileOpen_szName[256];
+static uint64_t g_testRTFileOpen_fOpen;
+static RTFILE g_testRTFileOpen_hFile;
+
+extern int testRTFileOpenEx(const char *pszFilename, uint64_t fOpen, PRTFILE phFile, PRTFILEACTION penmActionTaken)
+{
+ /* RTPrintf("%s, pszFilename=%s, fOpen=0x%llx\n", __PRETTY_FUNCTION__,
+ pszFilename, LLUIFY(fOpen)); */
+ ARRAY_FROM_PATH(g_testRTFileOpen_szName, pszFilename);
+ g_testRTFileOpen_fOpen = fOpen;
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszFilename, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ *phFile = g_testRTFileOpen_hFile;
+ *penmActionTaken = RTFILEACTION_CREATED;
+ g_testRTFileOpen_hFile = 0;
+ return VINF_SUCCESS;
+}
+
+static RTFILE g_testRTFileQueryInfo_hFile;
+static RTTIMESPEC g_testRTFileQueryInfo_ATime;
+static uint32_t g_testRTFileQueryInfo_fMode;
+
+extern int testRTFileQueryInfo(RTFILE hFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
+{
+ RT_NOREF1(enmAdditionalAttribs);
+ /* RTPrintf("%s, hFile=%p, enmAdditionalAttribs=0x%llx\n",
+ __PRETTY_FUNCTION__, hFile, LLUIFY(enmAdditionalAttribs)); */
+ g_testRTFileQueryInfo_hFile = hFile;
+ RT_ZERO(*pObjInfo);
+ pObjInfo->AccessTime = g_testRTFileQueryInfo_ATime;
+ RT_ZERO(g_testRTDirQueryInfo_ATime);
+ pObjInfo->Attr.fMode = g_testRTFileQueryInfo_fMode;
+ g_testRTFileQueryInfo_fMode = 0;
+ return VINF_SUCCESS;
+}
+
+static const char *g_testRTFileRead_pszData;
+
+extern int testRTFileRead(RTFILE File, void *pvBuf, size_t cbToRead, size_t *pcbRead)
+{
+ RT_NOREF1(File);
+ /* RTPrintf("%s : File=%p, cbToRead=%llu\n", __PRETTY_FUNCTION__, File,
+ LLUIFY(cbToRead)); */
+ bufferFromPath((char *)pvBuf, cbToRead, g_testRTFileRead_pszData);
+ if (pcbRead)
+ *pcbRead = RT_MIN(cbToRead, strlen(g_testRTFileRead_pszData) + 1);
+ g_testRTFileRead_pszData = 0;
+ return VINF_SUCCESS;
+}
+
+extern int testRTFileReadAt(RTFILE hFile, uint64_t offFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
+{
+ RT_NOREF1(hFile);
+ RT_NOREF(offFile);
+ /* RTPrintf("%s : File=%p, cbToRead=%llu\n", __PRETTY_FUNCTION__, File,
+ LLUIFY(cbToRead)); */
+ bufferFromPath((char *)pvBuf, cbToRead, g_testRTFileRead_pszData);
+ if (pcbRead)
+ *pcbRead = RT_MIN(cbToRead, strlen(g_testRTFileRead_pszData) + 1);
+ g_testRTFileRead_pszData = 0;
+ return VINF_SUCCESS;
+}
+
+extern int testRTFileSeek(RTFILE hFile, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)
+{
+ RT_NOREF3(hFile, offSeek, uMethod);
+ /* RTPrintf("%s : hFile=%p, offSeek=%llu, uMethod=%u\n", __PRETTY_FUNCTION__,
+ hFile, LLUIFY(offSeek), uMethod); */
+ if (poffActual)
+ *poffActual = 0;
+ return VINF_SUCCESS;
+}
+
+static uint64_t g_testRTFileSet_fMode;
+
+extern int testRTFileSetMode(RTFILE File, RTFMODE fMode)
+{
+ RT_NOREF1(File);
+ /* RTPrintf("%s: fMode=%llu\n", __PRETTY_FUNCTION__, LLUIFY(fMode)); */
+ g_testRTFileSet_fMode = fMode;
+ return VINF_SUCCESS;
+}
+
+static RTFILE g_testRTFileSetSize_hFile;
+static RTFOFF g_testRTFileSetSize_cbSize;
+
+extern int testRTFileSetSize(RTFILE File, uint64_t cbSize)
+{
+ /* RTPrintf("%s: File=%llu, cbSize=%llu\n", __PRETTY_FUNCTION__, LLUIFY(File),
+ LLUIFY(cbSize)); */
+ g_testRTFileSetSize_hFile = File;
+ g_testRTFileSetSize_cbSize = (RTFOFF) cbSize; /* Why was this signed before? */
+ return VINF_SUCCESS;
+}
+
+static RTTIMESPEC g_testRTFileSetTimes_ATime;
+
+extern int testRTFileSetTimes(RTFILE File, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
+ PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
+{
+ RT_NOREF4(File, pModificationTime, pChangeTime, pBirthTime);
+ /* RTPrintf("%s: pFile=%p, *pAccessTime=%lli, *pModificationTime=%lli, *pChangeTime=%lli, *pBirthTime=%lli\n",
+ __PRETTY_FUNCTION__,
+ pAccessTime ? (long long)RTTimeSpecGetNano(pAccessTime) : -1,
+ pModificationTime
+ ? (long long)RTTimeSpecGetNano(pModificationTime) : -1,
+ pChangeTime ? (long long)RTTimeSpecGetNano(pChangeTime) : -1,
+ pBirthTime ? (long long)RTTimeSpecGetNano(pBirthTime) : -1); */
+ if (pAccessTime)
+ g_testRTFileSetTimes_ATime = *pAccessTime;
+ else
+ RT_ZERO(g_testRTFileSetTimes_ATime);
+ return VINF_SUCCESS;
+}
+
+static RTFILE g_testRTFileUnlock_hFile;
+static int64_t g_testRTFileUnlock_offLock;
+static uint64_t g_testRTFileUnlock_cbLock;
+
+extern int testRTFileUnlock(RTFILE File, int64_t offLock, uint64_t cbLock)
+{
+ /* RTPrintf("%s: hFile=%p, ofLock=%lli, cbLock=%llu\n", __PRETTY_FUNCTION__,
+ File, (long long) offLock, LLUIFY(cbLock)); */
+ g_testRTFileUnlock_hFile = File;
+ g_testRTFileUnlock_offLock = offLock;
+ g_testRTFileUnlock_cbLock = cbLock;
+ return VINF_SUCCESS;
+}
+
+static char g_testRTFileWrite_szData[256];
+
+extern int testRTFileWrite(RTFILE File, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
+{
+ RT_NOREF2(File, cbToWrite);
+ /* RTPrintf("%s: File=%p, pvBuf=%.*s, cbToWrite=%llu\n", __PRETTY_FUNCTION__,
+ File, cbToWrite, (const char *)pvBuf, LLUIFY(cbToWrite)); */
+ ARRAY_FROM_PATH(g_testRTFileWrite_szData, (const char *)pvBuf);
+ if (pcbWritten)
+ *pcbWritten = strlen(g_testRTFileWrite_szData) + 1;
+ return VINF_SUCCESS;
+}
+
+extern int testRTFileWriteAt(RTFILE File, uint64_t offFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
+{
+ RT_NOREF3(File, cbToWrite, offFile);
+ /* RTPrintf("%s: File=%p, pvBuf=%.*s, cbToWrite=%llu\n", __PRETTY_FUNCTION__,
+ File, cbToWrite, (const char *)pvBuf, LLUIFY(cbToWrite)); */
+ ARRAY_FROM_PATH(g_testRTFileWrite_szData, (const char *)pvBuf);
+ if (pcbWritten)
+ *pcbWritten = strlen(g_testRTFileWrite_szData) + 1;
+ return VINF_SUCCESS;
+}
+
+extern int testRTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties)
+{
+ RT_NOREF1(pszFsPath);
+ /* RTPrintf("%s, pszFsPath=%s\n", __PRETTY_FUNCTION__, pszFsPath);
+ RT_ZERO(*pProperties); */
+ pProperties->cbMaxComponent = 256;
+ pProperties->fCaseSensitive = true;
+ return VINF_SUCCESS;
+}
+
+extern int testRTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial)
+{
+ RT_NOREF2(pszFsPath, pu32Serial);
+ RTPrintf("%s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+extern int testRTFsQuerySizes(const char *pszFsPath, PRTFOFF pcbTotal, RTFOFF *pcbFree, uint32_t *pcbBlock, uint32_t *pcbSector)
+{
+ RT_NOREF5(pszFsPath, pcbTotal, pcbFree, pcbBlock, pcbSector);
+ RTPrintf("%s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+
+extern int testRTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
+{
+ RT_NOREF2(enmAdditionalAttribs, fFlags);
+ /* RTPrintf("%s: pszPath=%s, enmAdditionalAttribs=0x%x, fFlags=0x%x\n",
+ __PRETTY_FUNCTION__, pszPath, (unsigned) enmAdditionalAttribs,
+ (unsigned) fFlags); */
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszPath, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ RT_ZERO(*pObjInfo);
+ return VINF_SUCCESS;
+}
+
+extern int testRTSymlinkDelete(const char *pszSymlink, uint32_t fDelete)
+{
+ RT_NOREF2(pszSymlink, fDelete);
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszSymlink, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ RTPrintf("%s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+
+extern int testRTSymlinkRead(const char *pszSymlink, char *pszTarget, size_t cbTarget, uint32_t fRead)
+{
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszSymlink, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ RT_NOREF4(pszSymlink, pszTarget, cbTarget, fRead);
+ RTPrintf("%s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+
+
+/*********************************************************************************************************************************
+* Tests *
+*********************************************************************************************************************************/
+
+/* Sub-tests for testMappingsQuery(). */
+void testMappingsQuerySimple(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMappingsQueryTooFewBuffers(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMappingsQueryAutoMount(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMappingsQueryArrayWrongSize(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testMappingsQueryName(). */
+void testMappingsQueryNameValid(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMappingsQueryNameInvalid(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMappingsQueryNameBadBuffer(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testMapFolder(). */
+void testMapFolderValid(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMapFolderInvalid(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMapFolderTwice(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMapFolderDelimiter(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMapFolderCaseSensitive(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMapFolderCaseInsensitive(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMapFolderBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testUnmapFolder(). */
+void testUnmapFolderValid(RTTEST hTest) { RT_NOREF1(hTest); }
+void testUnmapFolderInvalid(RTTEST hTest) { RT_NOREF1(hTest); }
+void testUnmapFolderBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testCreate(). */
+void testCreateBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testClose(). */
+void testCloseBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testRead(). */
+void testReadBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testWrite(). */
+void testWriteBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testLock(). */
+void testLockBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testFlush(). */
+void testFlushBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testDirList(). */
+void testDirListBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testReadLink(). */
+void testReadLinkBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testFSInfo(). */
+void testFSInfoBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testRemove(). */
+void testRemoveBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testRename(). */
+void testRenameBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testSymlink(). */
+void testSymlinkBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testMappingsAdd(). */
+void testMappingsAddBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testMappingsRemove(). */
+void testMappingsRemoveBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+union TESTSHFLSTRING
+{
+ SHFLSTRING string;
+ char acData[256];
+};
+
+static void fillTestShflString(union TESTSHFLSTRING *pDest,
+ const char *pcszSource)
+{
+ const size_t cchSource = strlen(pcszSource);
+ AssertRelease( cchSource * 2 + 2
+ < sizeof(*pDest) - RT_UOFFSETOF(SHFLSTRING, String));
+ pDest->string.u16Length = (uint16_t)(cchSource * sizeof(RTUTF16));
+ pDest->string.u16Size = pDest->string.u16Length + sizeof(RTUTF16);
+ /* Copy pcszSource ASCIIZ, including the trailing 0, to the UTF16 pDest->string.String.ucs2. */
+ for (unsigned i = 0; i <= cchSource; ++i)
+ pDest->string.String.ucs2[i] = (uint16_t)pcszSource[i];
+}
+
+static SHFLROOT initWithWritableMapping(RTTEST hTest,
+ VBOXHGCMSVCFNTABLE *psvcTable,
+ VBOXHGCMSVCHELPERS *psvcHelpers,
+ const char *pcszFolderName,
+ const char *pcszMapping,
+ bool fCaseSensitive = true)
+{
+ VBOXHGCMSVCPARM aParms[RT_MAX(SHFL_CPARMS_ADD_MAPPING,
+ SHFL_CPARMS_MAP_FOLDER)];
+ union TESTSHFLSTRING FolderName;
+ union TESTSHFLSTRING Mapping;
+ union TESTSHFLSTRING AutoMountPoint;
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+ int rc;
+
+ initTable(psvcTable, psvcHelpers);
+ AssertReleaseRC(VBoxHGCMSvcLoad(psvcTable));
+ AssertRelease( psvcTable->pvService
+ = RTTestGuardedAllocTail(hTest, psvcTable->cbClient));
+ RT_BZERO(psvcTable->pvService, psvcTable->cbClient);
+ fillTestShflString(&FolderName, pcszFolderName);
+ fillTestShflString(&Mapping, pcszMapping);
+ fillTestShflString(&AutoMountPoint, "");
+ HGCMSvcSetPv(&aParms[0], &FolderName, RT_UOFFSETOF(SHFLSTRING, String)
+ + FolderName.string.u16Size);
+ HGCMSvcSetPv(&aParms[1], &Mapping, RT_UOFFSETOF(SHFLSTRING, String)
+ + Mapping.string.u16Size);
+ HGCMSvcSetU32(&aParms[2], 1);
+ HGCMSvcSetPv(&aParms[3], &AutoMountPoint, SHFLSTRING_HEADER_SIZE + AutoMountPoint.string.u16Size);
+ rc = psvcTable->pfnHostCall(psvcTable->pvService, SHFL_FN_ADD_MAPPING,
+ SHFL_CPARMS_ADD_MAPPING, aParms);
+ AssertReleaseRC(rc);
+ HGCMSvcSetPv(&aParms[0], &Mapping, RT_UOFFSETOF(SHFLSTRING, String)
+ + Mapping.string.u16Size);
+ HGCMSvcSetU32(&aParms[1], 0); /* root */
+ HGCMSvcSetU32(&aParms[2], '/'); /* delimiter */
+ HGCMSvcSetU32(&aParms[3], fCaseSensitive);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_MAP_FOLDER,
+ SHFL_CPARMS_MAP_FOLDER, aParms, 0);
+ AssertReleaseRC(callHandle.rc);
+ return aParms[1].u.uint32;
+}
+
+/** @todo Mappings should be automatically removed by unloading the service,
+ * but unloading is currently a no-op! */
+static void unmapAndRemoveMapping(RTTEST hTest, VBOXHGCMSVCFNTABLE *psvcTable,
+ SHFLROOT root, const char *pcszFolderName)
+{
+ RT_NOREF1(hTest);
+ VBOXHGCMSVCPARM aParms[RT_MAX(SHFL_CPARMS_UNMAP_FOLDER,
+ SHFL_CPARMS_REMOVE_MAPPING)];
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+ union TESTSHFLSTRING FolderName;
+ int rc;
+
+ HGCMSvcSetU32(&aParms[0], root);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_UNMAP_FOLDER,
+ SHFL_CPARMS_UNMAP_FOLDER, aParms, 0);
+ AssertReleaseRC(callHandle.rc);
+ fillTestShflString(&FolderName, pcszFolderName);
+ HGCMSvcSetPv(&aParms[0], &FolderName, RT_UOFFSETOF(SHFLSTRING, String)
+ + FolderName.string.u16Size);
+ rc = psvcTable->pfnHostCall(psvcTable->pvService, SHFL_FN_REMOVE_MAPPING,
+ SHFL_CPARMS_REMOVE_MAPPING, aParms);
+ AssertReleaseRC(rc);
+}
+
+static int createFile(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT Root,
+ const char *pcszFilename, uint32_t fCreateFlags,
+ SHFLHANDLE *pHandle, SHFLCREATERESULT *pResult)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_CREATE];
+ union TESTSHFLSTRING Path;
+ SHFLCREATEPARMS CreateParms;
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ fillTestShflString(&Path, pcszFilename);
+ RT_ZERO(CreateParms);
+ CreateParms.CreateFlags = fCreateFlags;
+ HGCMSvcSetU32(&aParms[0], Root);
+ HGCMSvcSetPv(&aParms[1], &Path, RT_UOFFSETOF(SHFLSTRING, String)
+ + Path.string.u16Size);
+ HGCMSvcSetPv(&aParms[2], &CreateParms, sizeof(CreateParms));
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_CREATE,
+ RT_ELEMENTS(aParms), aParms, 0);
+ if (RT_FAILURE(callHandle.rc))
+ return callHandle.rc;
+ if (pHandle)
+ *pHandle = CreateParms.Handle;
+ if (pResult)
+ *pResult = CreateParms.Result;
+ return VINF_SUCCESS;
+}
+
+static int readFile(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT Root,
+ SHFLHANDLE hFile, uint64_t offSeek, uint32_t cbRead,
+ uint32_t *pcbRead, void *pvBuf, uint32_t cbBuf)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_READ];
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ HGCMSvcSetU32(&aParms[0], Root);
+ HGCMSvcSetU64(&aParms[1], (uint64_t) hFile);
+ HGCMSvcSetU64(&aParms[2], offSeek);
+ HGCMSvcSetU32(&aParms[3], cbRead);
+ HGCMSvcSetPv(&aParms[4], pvBuf, cbBuf);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_READ,
+ RT_ELEMENTS(aParms), aParms, 0);
+ if (pcbRead)
+ *pcbRead = aParms[3].u.uint32;
+ return callHandle.rc;
+}
+
+static int writeFile(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT Root,
+ SHFLHANDLE hFile, uint64_t offSeek, uint32_t cbWrite,
+ uint32_t *pcbWritten, const void *pvBuf, uint32_t cbBuf)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_WRITE];
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ HGCMSvcSetU32(&aParms[0], Root);
+ HGCMSvcSetU64(&aParms[1], (uint64_t) hFile);
+ HGCMSvcSetU64(&aParms[2], offSeek);
+ HGCMSvcSetU32(&aParms[3], cbWrite);
+ HGCMSvcSetPv(&aParms[4], (void *)pvBuf, cbBuf);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_WRITE,
+ RT_ELEMENTS(aParms), aParms, 0);
+ if (pcbWritten)
+ *pcbWritten = aParms[3].u.uint32;
+ return callHandle.rc;
+}
+
+static int flushFile(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT root,
+ SHFLHANDLE handle)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_FLUSH];
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ HGCMSvcSetU32(&aParms[0], root);
+ HGCMSvcSetU64(&aParms[1], handle);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_FLUSH,
+ SHFL_CPARMS_FLUSH, aParms, 0);
+ return callHandle.rc;
+}
+
+static int listDir(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT root,
+ SHFLHANDLE handle, uint32_t fFlags,
+ const char *pcszPath, void *pvBuf, uint32_t cbBuf,
+ uint32_t resumePoint, uint32_t *pcFiles)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_LIST];
+ union TESTSHFLSTRING Path;
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ HGCMSvcSetU32(&aParms[0], root);
+ HGCMSvcSetU64(&aParms[1], handle);
+ HGCMSvcSetU32(&aParms[2], fFlags);
+ HGCMSvcSetU32(&aParms[3], cbBuf);
+ if (pcszPath)
+ {
+ fillTestShflString(&Path, pcszPath);
+ HGCMSvcSetPv(&aParms[4], &Path, RT_UOFFSETOF(SHFLSTRING, String)
+ + Path.string.u16Size);
+ }
+ else
+ HGCMSvcSetPv(&aParms[4], NULL, 0);
+ HGCMSvcSetPv(&aParms[5], pvBuf, cbBuf);
+ HGCMSvcSetU32(&aParms[6], resumePoint);
+ HGCMSvcSetU32(&aParms[7], 0);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_LIST,
+ RT_ELEMENTS(aParms), aParms, 0);
+ if (pcFiles)
+ *pcFiles = aParms[7].u.uint32;
+ return callHandle.rc;
+}
+
+static int sfInformation(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT root,
+ SHFLHANDLE handle, uint32_t fFlags, uint32_t cb,
+ SHFLFSOBJINFO *pInfo)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_INFORMATION];
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ HGCMSvcSetU32(&aParms[0], root);
+ HGCMSvcSetU64(&aParms[1], handle);
+ HGCMSvcSetU32(&aParms[2], fFlags);
+ HGCMSvcSetU32(&aParms[3], cb);
+ HGCMSvcSetPv(&aParms[4], pInfo, cb);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_INFORMATION,
+ RT_ELEMENTS(aParms), aParms, 0);
+ return callHandle.rc;
+}
+
+static int lockFile(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT root,
+ SHFLHANDLE handle, int64_t offLock, uint64_t cbLock,
+ uint32_t fFlags)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_LOCK];
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ HGCMSvcSetU32(&aParms[0], root);
+ HGCMSvcSetU64(&aParms[1], handle);
+ HGCMSvcSetU64(&aParms[2], offLock);
+ HGCMSvcSetU64(&aParms[3], cbLock);
+ HGCMSvcSetU32(&aParms[4], fFlags);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_LOCK,
+ RT_ELEMENTS(aParms), aParms, 0);
+ return callHandle.rc;
+}
+
+void testCreateFileSimple(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hFile = (RTFILE) 0x10000;
+ SHFLCREATERESULT Result;
+ int rc;
+
+ RTTestSub(hTest, "Create file simple");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ g_testRTFileOpen_hFile = hFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ, NULL,
+ &Result);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest,
+ !strcmp(&g_testRTFileOpen_szName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0],
+ "/test/mapping/test/file"),
+ (hTest, "pszFilename=%s\n", &g_testRTFileOpen_szName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0]));
+ RTTEST_CHECK_MSG(hTest, g_testRTFileOpen_fOpen == 0x181,
+ (hTest, "fOpen=%llu\n", LLUIFY(g_testRTFileOpen_fOpen)));
+ RTTEST_CHECK_MSG(hTest, Result == SHFL_FILE_CREATED,
+ (hTest, "Result=%d\n", (int) Result));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileClose_hFile == hFile,
+ (hTest, "File=%u\n", (uintptr_t)g_testRTFileClose_hFile));
+}
+
+void testCreateFileSimpleCaseInsensitive(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hFile = (RTFILE) 0x10000;
+ SHFLCREATERESULT Result;
+ int rc;
+
+ g_fFailIfNotLowercase = true;
+
+ RTTestSub(hTest, "Create file case insensitive");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname", false /*fCaseSensitive*/);
+ g_testRTFileOpen_hFile = hFile;
+ rc = createFile(&svcTable, Root, "/TesT/FilE", SHFL_CF_ACCESS_READ, NULL,
+ &Result);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+
+ RTTEST_CHECK_MSG(hTest,
+ !strcmp(&g_testRTFileOpen_szName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0],
+ "/test/mapping/test/file"),
+ (hTest, "pszFilename=%s\n", &g_testRTFileOpen_szName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0]));
+ RTTEST_CHECK_MSG(hTest, g_testRTFileOpen_fOpen == 0x181,
+ (hTest, "fOpen=%llu\n", LLUIFY(g_testRTFileOpen_fOpen)));
+ RTTEST_CHECK_MSG(hTest, Result == SHFL_FILE_CREATED,
+ (hTest, "Result=%d\n", (int) Result));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileClose_hFile == hFile,
+ (hTest, "File=%u\n", (uintptr_t)g_testRTFileClose_hFile));
+
+ g_fFailIfNotLowercase = false;
+}
+
+void testCreateDirSimple(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ RTDIR hDir = (RTDIR)&g_aTestDirHandles[g_iNextDirHandle++ % RT_ELEMENTS(g_aTestDirHandles)];
+ SHFLCREATERESULT Result;
+ int rc;
+
+ RTTestSub(hTest, "Create directory simple");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ g_testRTDirOpen_hDir = hDir;
+ rc = createFile(&svcTable, Root, "test/dir",
+ SHFL_CF_DIRECTORY | SHFL_CF_ACCESS_READ, NULL, &Result);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest,
+ !strcmp(&g_testRTDirCreate_szPath[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0],
+ "/test/mapping/test/dir"),
+ (hTest, "pszPath=%s\n", &g_testRTDirCreate_szPath[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0]));
+ RTTEST_CHECK_MSG(hTest,
+ !strcmp(&g_testRTDirOpen_szName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0],
+ "/test/mapping/test/dir"),
+ (hTest, "pszFilename=%s\n", &g_testRTDirOpen_szName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0]));
+ RTTEST_CHECK_MSG(hTest, Result == SHFL_FILE_CREATED,
+ (hTest, "Result=%d\n", (int) Result));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTDirClose_hDir == hDir, (hTest, "hDir=%p\n", g_testRTDirClose_hDir));
+}
+
+void testReadFileSimple(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hFile = (RTFILE) 0x10000;
+ SHFLHANDLE Handle;
+ const char *pcszReadData = "Data to read";
+ char achBuf[sizeof(pcszReadData) + 10];
+ uint32_t cbRead;
+ int rc;
+
+ RTTestSub(hTest, "Read file simple");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ g_testRTFileOpen_hFile = hFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ g_testRTFileRead_pszData = pcszReadData;
+ memset(achBuf, 'f', sizeof(achBuf));
+ rc = readFile(&svcTable, Root, Handle, 0, (uint32_t)strlen(pcszReadData) + 1,
+ &cbRead, achBuf, (uint32_t)sizeof(achBuf));
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest,
+ !strncmp(achBuf, pcszReadData, sizeof(achBuf)),
+ (hTest, "pvBuf=%.*s Handle=%#RX64\n", sizeof(achBuf), achBuf, Handle));
+ RTTEST_CHECK_MSG(hTest, cbRead == strlen(pcszReadData) + 1,
+ (hTest, "cbRead=%llu\n", LLUIFY(cbRead)));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ RTTEST_CHECK_MSG(hTest, g_testRTFileClose_hFile == hFile, (hTest, "File=%u\n", g_testRTFileClose_hFile));
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+}
+
+void testWriteFileSimple(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hFile = (RTFILE) 0x10000;
+ SHFLHANDLE Handle;
+ const char *pcszWrittenData = "Data to write";
+ uint32_t cbToWrite = (uint32_t)strlen(pcszWrittenData) + 1;
+ uint32_t cbWritten;
+ int rc;
+
+ RTTestSub(hTest, "Write file simple");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ g_testRTFileOpen_hFile = hFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ rc = writeFile(&svcTable, Root, Handle, 0, cbToWrite, &cbWritten,
+ pcszWrittenData, cbToWrite);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest,
+ !strcmp(g_testRTFileWrite_szData, pcszWrittenData),
+ (hTest, "pvBuf=%s\n", g_testRTFileWrite_szData));
+ RTTEST_CHECK_MSG(hTest, cbWritten == cbToWrite,
+ (hTest, "cbWritten=%llu\n", LLUIFY(cbWritten)));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ RTTEST_CHECK_MSG(hTest, g_testRTFileClose_hFile == hFile, (hTest, "File=%u\n", g_testRTFileClose_hFile));
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+}
+
+void testFlushFileSimple(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hFile = (RTFILE) 0x10000;
+ SHFLHANDLE Handle;
+ int rc;
+
+ RTTestSub(hTest, "Flush file simple");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ g_testRTFileOpen_hFile = hFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ rc = flushFile(&svcTable, Root, Handle);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileFlush_hFile == hFile, (hTest, "File=%u\n", g_testRTFileFlush_hFile));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileClose_hFile == hFile, (hTest, "File=%u\n", g_testRTFileClose_hFile));
+}
+
+void testDirListEmpty(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ RTDIR hDir = (RTDIR)&g_aTestDirHandles[g_iNextDirHandle++ % RT_ELEMENTS(g_aTestDirHandles)];
+ SHFLHANDLE Handle;
+ union
+ {
+ SHFLDIRINFO DirInfo;
+ uint8_t abBuffer[sizeof(SHFLDIRINFO) + 2 * sizeof(RTUTF16)];
+ } Buf;
+ uint32_t cFiles;
+ int rc;
+
+ RTTestSub(hTest, "List empty directory");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ g_testRTDirOpen_hDir = hDir;
+ rc = createFile(&svcTable, Root, "test/dir",
+ SHFL_CF_DIRECTORY | SHFL_CF_ACCESS_READ, &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ rc = listDir(&svcTable, Root, Handle, 0, NULL, &Buf.DirInfo, sizeof(Buf), 0, &cFiles);
+ RTTEST_CHECK_RC(hTest, rc, VERR_NO_MORE_FILES);
+ RTTEST_CHECK_MSG(hTest, g_testRTDirReadEx_hDir == hDir, (hTest, "Dir=%p\n", g_testRTDirReadEx_hDir));
+ RTTEST_CHECK_MSG(hTest, cFiles == 0,
+ (hTest, "cFiles=%llu\n", LLUIFY(cFiles)));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTDirClose_hDir == hDir, (hTest, "hDir=%p\n", g_testRTDirClose_hDir));
+}
+
+void testFSInfoQuerySetFMode(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hFile = (RTFILE) 0x10000;
+ const uint32_t fMode = 0660;
+ SHFLFSOBJINFO Info;
+ int rc;
+
+ RTTestSub(hTest, "Query and set file size");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ SHFLHANDLE Handle = SHFL_HANDLE_NIL;
+ g_testRTFileOpen_hFile = hFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK_RETV(hTest, rc);
+
+ RT_ZERO(Info);
+ g_testRTFileQueryInfo_fMode = fMode;
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_FILE, sizeof(Info),
+ &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileQueryInfo_hFile == hFile, (hTest, "File=%u\n", g_testRTFileQueryInfo_hFile));
+ RTTEST_CHECK_MSG(hTest, Info.Attr.fMode == fMode,
+ (hTest, "cbObject=%llu\n", LLUIFY(Info.cbObject)));
+ RT_ZERO(Info);
+ Info.Attr.fMode = fMode;
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_SET | SHFL_INFO_FILE,
+ sizeof(Info), &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileSet_fMode == fMode,
+ (hTest, "Size=%llu\n", LLUIFY(g_testRTFileSet_fMode)));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileClose_hFile == hFile, (hTest, "File=%u\n", g_testRTFileClose_hFile));
+}
+
+void testFSInfoQuerySetDirATime(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTDIR hDir = (RTDIR)&g_aTestDirHandles[g_iNextDirHandle++ % RT_ELEMENTS(g_aTestDirHandles)];
+ const int64_t ccAtimeNano = 100000;
+ SHFLFSOBJINFO Info;
+ SHFLHANDLE Handle;
+ int rc;
+
+ RTTestSub(hTest, "Query and set directory atime");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ g_testRTDirOpen_hDir = hDir;
+ rc = createFile(&svcTable, Root, "test/dir",
+ SHFL_CF_DIRECTORY | SHFL_CF_ACCESS_READ, &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RT_ZERO(Info);
+ RTTimeSpecSetNano(&g_testRTDirQueryInfo_ATime, ccAtimeNano);
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_FILE, sizeof(Info),
+ &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, g_testRTDirQueryInfo_hDir == hDir, (hTest, "Dir=%p\n", g_testRTDirQueryInfo_hDir));
+ RTTEST_CHECK_MSG(hTest, RTTimeSpecGetNano(&Info.AccessTime) == ccAtimeNano,
+ (hTest, "ATime=%llu\n",
+ LLUIFY(RTTimeSpecGetNano(&Info.AccessTime))));
+ RT_ZERO(Info);
+ RTTimeSpecSetNano(&Info.AccessTime, ccAtimeNano);
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_SET | SHFL_INFO_FILE,
+ sizeof(Info), &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, RTTimeSpecGetNano(&g_testRTDirSetTimes_ATime)
+ == ccAtimeNano,
+ (hTest, "ATime=%llu\n",
+ LLUIFY(RTTimeSpecGetNano(&g_testRTDirSetTimes_ATime))));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTDirClose_hDir == hDir, (hTest, "hDir=%p\n", g_testRTDirClose_hDir));
+}
+
+void testFSInfoQuerySetFileATime(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hFile = (RTFILE) 0x10000;
+ const int64_t ccAtimeNano = 100000;
+ SHFLFSOBJINFO Info;
+ SHFLHANDLE Handle;
+ int rc;
+
+ RTTestSub(hTest, "Query and set file atime");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ g_testRTFileOpen_hFile = hFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RT_ZERO(Info);
+ RTTimeSpecSetNano(&g_testRTFileQueryInfo_ATime, ccAtimeNano);
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_FILE, sizeof(Info),
+ &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileQueryInfo_hFile == hFile, (hTest, "File=%u\n", g_testRTFileQueryInfo_hFile));
+ RTTEST_CHECK_MSG(hTest, RTTimeSpecGetNano(&Info.AccessTime) == ccAtimeNano,
+ (hTest, "ATime=%llu\n",
+ LLUIFY(RTTimeSpecGetNano(&Info.AccessTime))));
+ RT_ZERO(Info);
+ RTTimeSpecSetNano(&Info.AccessTime, ccAtimeNano);
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_SET | SHFL_INFO_FILE,
+ sizeof(Info), &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, RTTimeSpecGetNano(&g_testRTFileSetTimes_ATime)
+ == ccAtimeNano,
+ (hTest, "ATime=%llu\n",
+ LLUIFY(RTTimeSpecGetNano(&g_testRTFileSetTimes_ATime))));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileClose_hFile == hFile, (hTest, "File=%u\n", g_testRTFileClose_hFile));
+}
+
+void testFSInfoQuerySetEndOfFile(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hFile = (RTFILE) 0x10000;
+ const RTFOFF cbNew = 50000;
+ SHFLFSOBJINFO Info;
+ SHFLHANDLE Handle;
+ int rc;
+
+ RTTestSub(hTest, "Set end of file position");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ g_testRTFileOpen_hFile = hFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RT_ZERO(Info);
+ Info.cbObject = cbNew;
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_SET | SHFL_INFO_SIZE,
+ sizeof(Info), &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileSetSize_hFile == hFile, (hTest, "File=%u\n", g_testRTFileSetSize_hFile));
+ RTTEST_CHECK_MSG(hTest, g_testRTFileSetSize_cbSize == cbNew,
+ (hTest, "Size=%llu\n", LLUIFY(g_testRTFileSetSize_cbSize)));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileClose_hFile == hFile, (hTest, "File=%u\n", g_testRTFileClose_hFile));
+}
+
+void testLockFileSimple(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hFile = (RTFILE) 0x10000;
+ const int64_t offLock = 50000;
+ const uint64_t cbLock = 4000;
+ SHFLHANDLE Handle;
+ int rc;
+
+ RTTestSub(hTest, "Simple file lock and unlock");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ g_testRTFileOpen_hFile = hFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ rc = lockFile(&svcTable, Root, Handle, offLock, cbLock, SHFL_LOCK_SHARED);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+#ifdef RT_OS_WINDOWS /* Locking is a no-op elsewhere. */
+ RTTEST_CHECK_MSG(hTest, g_testRTFileLock_hFile == hFile, (hTest, "File=%u\n", g_testRTFileLock_hFile));
+ RTTEST_CHECK_MSG(hTest, g_testRTFileLock_fLock == 0,
+ (hTest, "fLock=%u\n", g_testRTFileLock_fLock));
+ RTTEST_CHECK_MSG(hTest, g_testRTFileLock_offLock == offLock,
+ (hTest, "Offs=%llu\n", (long long) g_testRTFileLock_offLock));
+ RTTEST_CHECK_MSG(hTest, g_testRTFileLock_cbLock == cbLock,
+ (hTest, "Size=%llu\n", LLUIFY(g_testRTFileLock_cbLock)));
+#endif
+ rc = lockFile(&svcTable, Root, Handle, offLock, cbLock, SHFL_LOCK_CANCEL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+#ifdef RT_OS_WINDOWS
+ RTTEST_CHECK_MSG(hTest, g_testRTFileUnlock_hFile == hFile, (hTest, "File=%u\n", g_testRTFileUnlock_hFile));
+ RTTEST_CHECK_MSG(hTest, g_testRTFileUnlock_offLock == offLock,
+ (hTest, "Offs=%llu\n",
+ (long long) g_testRTFileUnlock_offLock));
+ RTTEST_CHECK_MSG(hTest, g_testRTFileUnlock_cbLock == cbLock,
+ (hTest, "Size=%llu\n", LLUIFY(g_testRTFileUnlock_cbLock)));
+#endif
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileClose_hFile == hFile, (hTest, "File=%u\n", g_testRTFileClose_hFile));
+}
+
+
+/*********************************************************************************************************************************
+* Main code *
+*********************************************************************************************************************************/
+
+static void testAPI(RTTEST hTest)
+{
+ testMappingsQuery(hTest);
+ testMappingsQueryName(hTest);
+ testMapFolder(hTest);
+ testUnmapFolder(hTest);
+ testCreate(hTest);
+ testClose(hTest);
+ testRead(hTest);
+ testWrite(hTest);
+ testLock(hTest);
+ testFlush(hTest);
+ testDirList(hTest);
+ testReadLink(hTest);
+ testFSInfo(hTest);
+ testRemove(hTest);
+ testRename(hTest);
+ testSymlink(hTest);
+ testMappingsAdd(hTest);
+ testMappingsRemove(hTest);
+ /* testSetStatusLed(hTest); */
+}
+
+int main(int argc, char **argv)
+{
+ RT_NOREF1(argc);
+ RTEXITCODE rcExit = RTTestInitAndCreate(RTPathFilename(argv[0]), &g_hTest);
+ if (rcExit != RTEXITCODE_SUCCESS)
+ return rcExit;
+ RTTestBanner(g_hTest);
+ testAPI(g_hTest);
+ return RTTestSummaryAndDestroy(g_hTest);
+}
diff --git a/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.h b/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.h
new file mode 100644
index 00000000..3be50c23
--- /dev/null
+++ b/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.h
@@ -0,0 +1,140 @@
+/** @file
+ * VBox Shared Folders testcase stub redefinitions.
+ */
+
+/*
+ * Copyright (C) 2011-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#ifndef VBOX_INCLUDED_SRC_SharedFolders_testcase_tstSharedFolderService_h
+#define VBOX_INCLUDED_SRC_SharedFolders_testcase_tstSharedFolderService_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+/* Grumble... if the coding style let us use the anonymous "struct RTTESTINT *"
+ * instead of "PRTTEST" here we wouldn't need to unnecessarily include this. */
+#include <iprt/test.h>
+
+void testMappingsQuery(RTTEST hTest);
+/* Sub-tests for testMappingsQuery(). */
+void testMappingsQuerySimple(RTTEST hTest);
+void testMappingsQueryTooFewBuffers(RTTEST hTest);
+void testMappingsQueryAutoMount(RTTEST hTest);
+void testMappingsQueryArrayWrongSize(RTTEST hTest);
+
+void testMappingsQueryName(RTTEST hTest);
+/* Sub-tests for testMappingsQueryName(). */
+void testMappingsQueryNameValid(RTTEST hTest);
+void testMappingsQueryNameInvalid(RTTEST hTest);
+void testMappingsQueryNameBadBuffer(RTTEST hTest);
+
+void testMapFolder(RTTEST hTest);
+/* Sub-tests for testMapFolder(). */
+void testMapFolderValid(RTTEST hTest);
+void testMapFolderInvalid(RTTEST hTest);
+void testMapFolderTwice(RTTEST hTest);
+void testMapFolderDelimiter(RTTEST hTest);
+void testMapFolderCaseSensitive(RTTEST hTest);
+void testMapFolderCaseInsensitive(RTTEST hTest);
+void testMapFolderBadParameters(RTTEST hTest);
+
+void testUnmapFolder(RTTEST hTest);
+/* Sub-tests for testUnmapFolder(). */
+void testUnmapFolderValid(RTTEST hTest);
+void testUnmapFolderInvalid(RTTEST hTest);
+void testUnmapFolderBadParameters(RTTEST hTest);
+
+void testCreate(RTTEST hTest);
+/* Sub-tests for testCreate(). */
+void testCreateFileSimple(RTTEST hTest);
+void testCreateFileSimpleCaseInsensitive(RTTEST hTest);
+void testCreateDirSimple(RTTEST hTest);
+void testCreateBadParameters(RTTEST hTest);
+
+void testClose(RTTEST hTest);
+/* Sub-tests for testClose(). */
+void testCloseBadParameters(RTTEST hTest);
+
+void testRead(RTTEST hTest);
+/* Sub-tests for testRead(). */
+void testReadBadParameters(RTTEST hTest);
+void testReadFileSimple(RTTEST hTest);
+
+void testWrite(RTTEST hTest);
+/* Sub-tests for testWrite(). */
+void testWriteBadParameters(RTTEST hTest);
+void testWriteFileSimple(RTTEST hTest);
+
+void testLock(RTTEST hTest);
+/* Sub-tests for testLock(). */
+void testLockBadParameters(RTTEST hTest);
+void testLockFileSimple(RTTEST hTest);
+
+void testFlush(RTTEST hTest);
+/* Sub-tests for testFlush(). */
+void testFlushBadParameters(RTTEST hTest);
+void testFlushFileSimple(RTTEST hTest);
+
+void testDirList(RTTEST hTest);
+/* Sub-tests for testDirList(). */
+void testDirListBadParameters(RTTEST hTest);
+void testDirListEmpty(RTTEST hTest);
+
+void testReadLink(RTTEST hTest);
+/* Sub-tests for testReadLink(). */
+void testReadLinkBadParameters(RTTEST hTest);
+
+void testFSInfo(RTTEST hTest);
+/* Sub-tests for testFSInfo(). */
+void testFSInfoBadParameters(RTTEST hTest);
+void testFSInfoQuerySetFMode(RTTEST hTest);
+void testFSInfoQuerySetDirATime(RTTEST hTest);
+void testFSInfoQuerySetFileATime(RTTEST hTest);
+void testFSInfoQuerySetEndOfFile(RTTEST hTest);
+
+void testRemove(RTTEST hTest);
+/* Sub-tests for testRemove(). */
+void testRemoveBadParameters(RTTEST hTest);
+
+void testRename(RTTEST hTest);
+/* Sub-tests for testRename(). */
+void testRenameBadParameters(RTTEST hTest);
+
+void testSymlink(RTTEST hTest);
+/* Sub-tests for testSymlink(). */
+void testSymlinkBadParameters(RTTEST hTest);
+
+void testMappingsAdd(RTTEST hTest);
+/* Sub-tests for testMappingsAdd(). */
+void testMappingsAddBadParameters(RTTEST hTest);
+
+void testMappingsRemove(RTTEST hTest);
+/* Sub-tests for testMappingsRemove(). */
+void testMappingsRemoveBadParameters(RTTEST hTest);
+
+#if 0 /* Where should this go? */
+void testSetStatusLed(RTTEST hTest);
+/* Sub-tests for testStatusLed(). */
+void testSetStatusLedBadParameters(RTTEST hTest);
+#endif
+
+#endif /* !VBOX_INCLUDED_SRC_SharedFolders_testcase_tstSharedFolderService_h */
diff --git a/src/VBox/HostServices/SharedFolders/testcase/tstShflCase.cpp b/src/VBox/HostServices/SharedFolders/testcase/tstShflCase.cpp
new file mode 100644
index 00000000..052b80d7
--- /dev/null
+++ b/src/VBox/HostServices/SharedFolders/testcase/tstShflCase.cpp
@@ -0,0 +1,452 @@
+/** @file
+ * Testcase for shared folder case conversion code.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_MISC
+#define LOG_ENABLED
+#include <VBox/shflsvc.h>
+#include <VBox/log.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/fs.h>
+#include <iprt/dir.h>
+#include <iprt/initterm.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/uni.h>
+#include <stdio.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/* Override slash for non-windows hosts. */
+#undef RTPATH_DELIMITER
+#define RTPATH_DELIMITER '\\'
+
+/* Use our own RTPath and RTDir methods. */
+#define RTPathQueryInfo rtPathQueryInfo
+#define RTDirOpenFiltered rtDirOpenFiltered
+#define RTDirClose rtDirClose
+#define RTDirReadEx rtDirReadEx
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static int iDirList = 0;
+static int iDirFile = 0;
+
+static const char *g_apszDirs[] =
+{
+ "c:",
+ "c:\\test dir",
+ "c:\\test dir\\SUBDIR",
+};
+
+static const char *g_apszDirsC[] =
+{
+ ".",
+ "..",
+ "test dir"
+};
+
+static const char *g_apszTestdirEntries[] =
+{
+ ".",
+ "..",
+ "SUBDIR",
+ "a.bat",
+ "aTestJe.bat",
+ "aTestje.bat",
+ "b.bat",
+ "c.bat",
+ "d.bat",
+ "e.bat",
+ "f.bat",
+ "g.bat",
+ "h.bat",
+ "x.bat",
+ "z.bat",
+};
+
+static const char *g_apszSUBDIREntries[] =
+{
+ ".",
+ "..",
+ "a.bat",
+ "aTestJe.bat",
+ "aTestje.bat",
+ "b.bat",
+ "c.bat",
+ "d.bat",
+ "e.bat",
+ "f.bat",
+ "g.bat",
+ "h.bat",
+ "x.bat",
+ "z.bat",
+};
+
+int rtDirOpenFiltered(RTDIR *phDir, const char *pszPath, RTDIRFILTER enmFilter, uint32_t fFlags)
+{
+ RT_NOREF2(enmFilter, fFlags);
+ if (!strcmp(pszPath, "c:\\*"))
+ iDirList = 1;
+ else if (!strcmp(pszPath, "c:\\test dir\\*"))
+ iDirList = 2;
+ else if (!strcmp(pszPath, "c:\\test dir\\SUBDIR\\*"))
+ iDirList = 3;
+ else
+ AssertFailed();
+
+ *phDir = (RTDIR)1;
+ return VINF_SUCCESS;
+}
+
+int rtDirClose(RTDIR hDir)
+{
+ RT_NOREF1(hDir);
+ iDirFile = 0;
+ return VINF_SUCCESS;
+}
+
+int rtDirReadEx(RTDIR hDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
+{
+ RT_NOREF4(hDir, pcbDirEntry, enmAdditionalAttribs, fFlags);
+ switch (iDirList)
+ {
+ case 1:
+ if (iDirFile == RT_ELEMENTS(g_apszDirsC))
+ return VERR_NO_MORE_FILES;
+ pDirEntry->cbName = (uint16_t)strlen(g_apszDirsC[iDirFile]);
+ strcpy(pDirEntry->szName, g_apszDirsC[iDirFile++]);
+ break;
+ case 2:
+ if (iDirFile == RT_ELEMENTS(g_apszTestdirEntries))
+ return VERR_NO_MORE_FILES;
+ pDirEntry->cbName = (uint16_t)strlen(g_apszTestdirEntries[iDirFile]);
+ strcpy(pDirEntry->szName, g_apszTestdirEntries[iDirFile++]);
+ break;
+ case 3:
+ if (iDirFile == RT_ELEMENTS(g_apszSUBDIREntries))
+ return VERR_NO_MORE_FILES;
+ pDirEntry->cbName = (uint16_t)strlen(g_apszSUBDIREntries[iDirFile]);
+ strcpy(pDirEntry->szName, g_apszSUBDIREntries[iDirFile++]);
+ break;
+ }
+ return VINF_SUCCESS;
+}
+
+int rtPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
+{
+ RT_NOREF2(pObjInfo, enmAdditionalAttribs);
+ int cMax;
+
+ /* first try g_apszDirs */
+ for (unsigned int i=0;i<RT_ELEMENTS(g_apszDirs);i++)
+ {
+ if(!strcmp(pszPath, g_apszDirs[i]))
+ return VINF_SUCCESS;
+ }
+
+ const char **papszDirList;
+ switch (iDirList)
+ {
+ case 1:
+ cMax = RT_ELEMENTS(g_apszDirsC);
+ papszDirList = g_apszDirsC;
+ break;
+ case 2:
+ cMax = RT_ELEMENTS(g_apszTestdirEntries);
+ papszDirList = g_apszTestdirEntries;
+ break;
+ case 3:
+ cMax = RT_ELEMENTS(g_apszSUBDIREntries);
+ papszDirList = g_apszSUBDIREntries;
+ break;
+ default:
+ return VERR_FILE_NOT_FOUND;
+ }
+ for (int i = 0; i < cMax; i++)
+ {
+ if (!strcmp(pszPath, papszDirList[i]))
+ return VINF_SUCCESS;
+ }
+ return VERR_FILE_NOT_FOUND;
+}
+
+static int vbsfCorrectCasing(char *pszFullPath, char *pszStartComponent)
+{
+ PRTDIRENTRYEX pDirEntry = NULL;
+ uint32_t cbDirEntry;
+ size_t cbComponent;
+ int rc = VERR_FILE_NOT_FOUND;
+ RTDIR hSearch = NIL_RTDIR;
+ char szWildCard[4];
+
+ Log2(("vbsfCorrectCasing: %s %s\n", pszFullPath, pszStartComponent));
+
+ cbComponent = strlen(pszStartComponent);
+
+ cbDirEntry = 4096;
+ pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
+ if (pDirEntry == 0)
+ {
+ AssertFailed();
+ return VERR_NO_MEMORY;
+ }
+
+ /** @todo this is quite inefficient, especially for directories with many files */
+ Assert(pszFullPath < pszStartComponent-1);
+ Assert(*(pszStartComponent-1) == RTPATH_DELIMITER);
+ *(pszStartComponent-1) = 0;
+ strcpy(pDirEntry->szName, pszFullPath);
+ szWildCard[0] = RTPATH_DELIMITER;
+ szWildCard[1] = '*';
+ szWildCard[2] = 0;
+ strcat(pDirEntry->szName, szWildCard);
+
+ rc = RTDirOpenFiltered(&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT, 0 /*fFlags*/);
+ *(pszStartComponent-1) = RTPATH_DELIMITER;
+ if (RT_FAILURE(rc))
+ goto end;
+
+ for(;;)
+ {
+ size_t cbDirEntrySize = cbDirEntry;
+
+ rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
+ if (rc == VERR_NO_MORE_FILES)
+ break;
+
+ if (VINF_SUCCESS != rc && rc != VWRN_NO_DIRENT_INFO)
+ {
+ AssertFailed();
+ if (rc != VERR_NO_TRANSLATION)
+ break;
+ else
+ continue;
+ }
+
+ Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0]));
+ if ( pDirEntry->cbName == cbComponent
+ && !RTStrICmp(pszStartComponent, &pDirEntry->szName[0]))
+ {
+ Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent));
+ strcpy(pszStartComponent, &pDirEntry->szName[0]);
+ rc = VINF_SUCCESS;
+ break;
+ }
+ }
+ if (RT_FAILURE(rc))
+ Log(("vbsfCorrectCasing %s failed with %d\n", pszStartComponent, rc));
+
+end:
+ if (pDirEntry)
+ RTMemFree(pDirEntry);
+
+ if (hSearch)
+ RTDirClose(hSearch);
+ return rc;
+}
+
+
+
+int testCase(char *pszFullPath, bool fWildCard = false)
+{
+ int rc;
+ RTFSOBJINFO info;
+ char *pszWildCardComponent = NULL;
+
+ if (fWildCard)
+ {
+ /* strip off the last path component, that contains the wildcard(s) */
+ size_t len = strlen(pszFullPath);
+ char *src = pszFullPath + len - 1;
+
+ while(src > pszFullPath)
+ {
+ if (*src == RTPATH_DELIMITER)
+ break;
+ src--;
+ }
+ if (*src == RTPATH_DELIMITER)
+ {
+ bool fHaveWildcards = false;
+ char *temp = src;
+
+ while(*temp)
+ {
+ char uc = *temp;
+ /** @todo should depend on the guest OS */
+ if (uc == '*' || uc == '?' || uc == '>' || uc == '<' || uc == '"')
+ {
+ fHaveWildcards = true;
+ break;
+ }
+ temp++;
+ }
+
+ if (fHaveWildcards)
+ {
+ pszWildCardComponent = src;
+ *pszWildCardComponent = 0;
+ }
+ }
+ }
+
+ rc = RTPathQueryInfo(pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
+ if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
+ {
+ size_t len = strlen(pszFullPath);
+ char *src = pszFullPath + len - 1;
+
+ Log(("Handle case insensitive guest fs on top of host case sensitive fs for %s\n", pszFullPath));
+
+ /* Find partial path that's valid */
+ while(src > pszFullPath)
+ {
+ if (*src == RTPATH_DELIMITER)
+ {
+ *src = 0;
+ rc = RTPathQueryInfo (pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
+ *src = RTPATH_DELIMITER;
+ if (rc == VINF_SUCCESS)
+ {
+#ifdef DEBUG
+ *src = 0;
+ Log(("Found valid partial path %s\n", pszFullPath));
+ *src = RTPATH_DELIMITER;
+#endif
+ break;
+ }
+ }
+
+ src--;
+ }
+ Assert(*src == RTPATH_DELIMITER && RT_SUCCESS(rc));
+ if ( *src == RTPATH_DELIMITER
+ && RT_SUCCESS(rc))
+ {
+ src++;
+ for(;;)
+ {
+ char *end = src;
+ bool fEndOfString = true;
+
+ while(*end)
+ {
+ if (*end == RTPATH_DELIMITER)
+ break;
+ end++;
+ }
+
+ if (*end == RTPATH_DELIMITER)
+ {
+ fEndOfString = false;
+ *end = 0;
+ rc = RTPathQueryInfo(src, &info, RTFSOBJATTRADD_NOTHING);
+ Assert(rc == VINF_SUCCESS || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND);
+ }
+ else
+ if (end == src)
+ rc = VINF_SUCCESS; /* trailing delimiter */
+ else
+ rc = VERR_FILE_NOT_FOUND;
+
+ if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
+ {
+ /* path component is invalid; try to correct the casing */
+ rc = vbsfCorrectCasing(pszFullPath, src);
+ if (RT_FAILURE(rc))
+ {
+ if (!fEndOfString)
+ *end = RTPATH_DELIMITER;
+ break;
+ }
+ }
+
+ if (fEndOfString)
+ break;
+
+ *end = RTPATH_DELIMITER;
+ src = end + 1;
+ }
+ if (RT_FAILURE(rc))
+ Log(("Unable to find suitable component rc=%d\n", rc));
+ }
+ else
+ rc = VERR_FILE_NOT_FOUND;
+
+ }
+ if (pszWildCardComponent)
+ *pszWildCardComponent = RTPATH_DELIMITER;
+
+ if (RT_SUCCESS(rc))
+ Log(("New valid path %s\n", pszFullPath));
+ else
+ Log(("Old invalid path %s\n", pszFullPath));
+ return rc;
+}
+
+
+int main()
+{
+ char szTest[128];
+
+ RTR3InitExeNoArguments(0);
+ RTLogFlush(NULL);
+ RTLogDestinations(NULL, "stdout");
+ RTLogGroupSettings(NULL, "misc=~0");
+ RTLogFlags(NULL, "unbuffered");
+
+ strcpy(szTest, "c:\\test Dir\\z.bAt");
+ testCase(szTest);
+ strcpy(szTest, "c:\\test dir\\z.bAt");
+ testCase(szTest);
+ strcpy(szTest, "c:\\test dir\\SUBDIR\\z.bAt");
+ testCase(szTest);
+ strcpy(szTest, "c:\\test dir\\SUBDiR\\atestje.bat");
+ testCase(szTest);
+ strcpy(szTest, "c:\\TEST dir\\subDiR\\aTestje.baT");
+ testCase(szTest);
+ strcpy(szTest, "c:\\TEST dir\\subDiR\\*");
+ testCase(szTest, true);
+ strcpy(szTest, "c:\\TEST dir\\subDiR\\");
+ testCase(szTest ,true);
+ strcpy(szTest, "c:\\test dir\\SUBDIR\\");
+ testCase(szTest);
+ strcpy(szTest, "c:\\test dir\\invalid\\SUBDIR\\test.bat");
+ testCase(szTest);
+ return 0;
+}
+
diff --git a/src/VBox/HostServices/SharedFolders/testcase/tstShflSizes.cpp b/src/VBox/HostServices/SharedFolders/testcase/tstShflSizes.cpp
new file mode 100644
index 00000000..c9832493
--- /dev/null
+++ b/src/VBox/HostServices/SharedFolders/testcase/tstShflSizes.cpp
@@ -0,0 +1,144 @@
+/** @file
+ * tstShflSize - Testcase for shared folder structure sizes.
+ * Run this on Linux and Windows, then compare.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <VBox/shflsvc.h>
+#include <iprt/string.h>
+#include <iprt/stream.h>
+
+#define STRUCT(t, size) \
+ do { \
+ if (fPrintChecks) \
+ RTPrintf(" STRUCT(" #t ", %d);\n", (int)sizeof(t)); \
+ else if ((size) != sizeof(t)) \
+ { \
+ RTPrintf("%30s: %d expected %d!\n", #t, (int)sizeof(t), (size)); \
+ cErrors++; \
+ } \
+ else if (!fQuiet)\
+ RTPrintf("%30s: %d\n", #t, (int)sizeof(t)); \
+ } while (0)
+
+
+int main(int argc, char **argv)
+{
+ unsigned cErrors = 0;
+
+ /*
+ * Prints the code below if any argument was giving.
+ */
+ bool fQuiet = argc == 2 && !strcmp(argv[1], "quiet");
+ bool fPrintChecks = !fQuiet && argc != 1;
+
+ RTPrintf("tstShflSizes: TESTING\n");
+
+ /*
+ * The checks.
+ */
+ STRUCT(SHFLROOT, 4);
+ STRUCT(SHFLHANDLE, 8);
+ STRUCT(SHFLSTRING, 6);
+ STRUCT(SHFLCREATERESULT, 4);
+ STRUCT(SHFLCREATEPARMS, 108);
+ STRUCT(SHFLMAPPING, 8);
+ STRUCT(SHFLDIRINFO, 128);
+ STRUCT(SHFLVOLINFO, 40);
+ STRUCT(SHFLFSOBJATTR, 44);
+ STRUCT(SHFLFSOBJINFO, 92);
+#ifdef VBOX_WITH_64_BITS_GUESTS
+/* The size of the guest structures depends on the current architecture bit count (ARCH_BITS)
+ * because the HGCMFunctionParameter structure differs in 32 and 64 bit guests.
+ * The host VMMDev device takes care about this.
+ *
+ * Therefore this testcase verifies whether structure sizes are correct for the current ARCH_BITS.
+ */
+# if ARCH_BITS == 64
+ STRUCT(VBoxSFQueryMappings, 88);
+ STRUCT(VBoxSFQueryMapName, 72);
+ STRUCT(VBoxSFMapFolder_Old, 88);
+ STRUCT(VBoxSFMapFolder, 104);
+ STRUCT(VBoxSFUnmapFolder, 56);
+ STRUCT(VBoxSFCreate, 88);
+ STRUCT(VBoxSFClose, 72);
+ STRUCT(VBoxSFRead, 120);
+ STRUCT(VBoxSFWrite, 120);
+ STRUCT(VBoxSFLock, 120);
+ STRUCT(VBoxSFFlush, 72);
+ STRUCT(VBoxSFList, 168);
+ STRUCT(VBoxSFInformation, 120);
+ STRUCT(VBoxSFRemove, 88);
+ STRUCT(VBoxSFRename, 104);
+# elif ARCH_BITS == 32
+ STRUCT(VBoxSFQueryMappings, 24+52);
+ STRUCT(VBoxSFQueryMapName, 24+40); /* this was changed from 52 in 21976 after VBox-1.4. */
+ STRUCT(VBoxSFMapFolder_Old, 24+52);
+ STRUCT(VBoxSFMapFolder, 24+64);
+ STRUCT(VBoxSFUnmapFolder, 24+28);
+ STRUCT(VBoxSFCreate, 24+52);
+ STRUCT(VBoxSFClose, 24+40);
+ STRUCT(VBoxSFRead, 24+76);
+ STRUCT(VBoxSFWrite, 24+76);
+ STRUCT(VBoxSFLock, 24+76);
+ STRUCT(VBoxSFFlush, 24+40);
+ STRUCT(VBoxSFList, 24+112);
+ STRUCT(VBoxSFInformation, 24+76);
+ STRUCT(VBoxSFRemove, 24+52);
+ STRUCT(VBoxSFRename, 24+64);
+# else
+# error "Unsupported ARCH_BITS"
+# endif /* ARCH_BITS */
+#else
+ STRUCT(VBoxSFQueryMappings, 24+52);
+ STRUCT(VBoxSFQueryMapName, 24+40); /* this was changed from 52 in 21976 after VBox-1.4. */
+ STRUCT(VBoxSFMapFolder_Old, 24+52);
+ STRUCT(VBoxSFMapFolder, 24+64);
+ STRUCT(VBoxSFUnmapFolder, 24+28);
+ STRUCT(VBoxSFCreate, 24+52);
+ STRUCT(VBoxSFClose, 24+40);
+ STRUCT(VBoxSFRead, 24+76);
+ STRUCT(VBoxSFWrite, 24+76);
+ STRUCT(VBoxSFLock, 24+76);
+ STRUCT(VBoxSFFlush, 24+40);
+ STRUCT(VBoxSFList, 24+112);
+ STRUCT(VBoxSFInformation, 24+76);
+ STRUCT(VBoxSFRemove, 24+52);
+ STRUCT(VBoxSFRename, 24+64);
+#endif /* VBOX_WITH_64_BITS_GUESTS */
+
+ /*
+ * The summary.
+ */
+ if (!cErrors)
+ RTPrintf("tstShflSizes: SUCCESS\n");
+ else
+ RTPrintf("tstShflSizes: FAILURE - %d errors\n", cErrors);
+ return !!cErrors;
+}
+