diff options
Diffstat (limited to 'src/VBox/HostServices/SharedFolders/testcase')
5 files changed, 2132 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..7096d4e8 --- /dev/null +++ b/src/VBox/HostServices/SharedFolders/testcase/Makefile.kmk @@ -0,0 +1,94 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for the Shared Folders Host Service testcases. +# + +# +# Copyright (C) 2006-2019 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +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 = VBOXR3AUTOTST +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..9706ded0 --- /dev/null +++ b/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.cpp @@ -0,0 +1,1332 @@ +/* $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-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + + +/********************************************************************************************************************************* +* 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 bufferFromString(void *pvDest, size_t cb, const char *pcszSrc) +{ + char *pchDest = (char *)pvDest; + + Assert((cb) > 0); + strncpy((pchDest), (pcszSrc), (cb) - 1); + (pchDest)[(cb) - 1] = 0; +} + +static void bufferFromPath(void *pvDest, size_t cb, const char *pcszSrc) +{ + char *psz; + + bufferFromString(pvDest, cb, pcszSrc); + for (psz = (char *)pvDest; psz && psz < (char *)pvDest + cb; ++psz) + if (*psz == '\\') + *psz = '/'; +} + +#define ARRAY_FROM_PATH(a, b) \ + do { \ + void *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 testRTDirCreatePath[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(testRTDirCreatePath, pszPath); + return 0; +} + +static char testRTDirOpenName[256]; +static struct TESTDIRHANDLE +{ + int iEntry; + int iDir; +} g_aTestDirHandles[4]; +static int g_iNextDirHandle = 0; +static RTDIR 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(testRTDirOpenName, pszPath); + *phDir = testRTDirOpen_hDir; + 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(testRTDirOpenName, pszPath); + *phDir = testRTDirOpen_hDir; + 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 testRTDirQueryInfoATime; + +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 = testRTDirQueryInfoATime; + RT_ZERO(testRTDirQueryInfoATime); + 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 RTTIMESPEC testRTDirSetTimesATime; + +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) + testRTDirSetTimesATime = *pAccessTime; + else + RT_ZERO(testRTDirSetTimesATime); + return VINF_SUCCESS; +} + +static RTFILE g_testRTFileCloseFile; + +extern int testRTFileClose(RTFILE File) +{ + /* RTPrintf("%s: File=%p\n", __PRETTY_FUNCTION__, File); */ + g_testRTFileCloseFile = 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_testRTFileFlushFile; + +extern int testRTFileFlush(RTFILE File) +{ + /* RTPrintf("%s: File=%p\n", __PRETTY_FUNCTION__, File); */ + g_testRTFileFlushFile = File; + return VINF_SUCCESS; +} + +static RTFILE g_testRTFileLockFile; +static unsigned testRTFileLockfLock; +static int64_t testRTFileLockOffset; +static uint64_t testRTFileLockSize; + +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_testRTFileLockFile = hFile; + testRTFileLockfLock = fLock; + testRTFileLockOffset = offLock; + testRTFileLockSize = cbLock; + return VINF_SUCCESS; +} + +static char testRTFileOpenName[256]; +static uint64_t testRTFileOpenFlags; +static RTFILE testRTFileOpenpFile; + +extern int testRTFileOpen(PRTFILE pFile, const char *pszFilename, uint64_t fOpen) +{ + /* RTPrintf("%s, pszFilename=%s, fOpen=0x%llx\n", __PRETTY_FUNCTION__, + pszFilename, LLUIFY(fOpen)); */ + ARRAY_FROM_PATH(testRTFileOpenName, pszFilename); + testRTFileOpenFlags = fOpen; + if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszFilename, "/\\"))) + return VERR_FILE_NOT_FOUND; + *pFile = testRTFileOpenpFile; + testRTFileOpenpFile = 0; + return VINF_SUCCESS; +} + +static RTFILE g_testRTFileQueryInfoFile; +static RTTIMESPEC testRTFileQueryInfoATime; +static uint32_t testRTFileQueryInfoFMode; + +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_testRTFileQueryInfoFile = hFile; + RT_ZERO(*pObjInfo); + pObjInfo->AccessTime = testRTFileQueryInfoATime; + RT_ZERO(testRTDirQueryInfoATime); + pObjInfo->Attr.fMode = testRTFileQueryInfoFMode; + testRTFileQueryInfoFMode = 0; + return VINF_SUCCESS; +} + +static const char *testRTFileReadData; + +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(pvBuf, cbToRead, testRTFileReadData); + if (pcbRead) + *pcbRead = RT_MIN(cbToRead, strlen(testRTFileReadData) + 1); + testRTFileReadData = 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 testRTFileSetFMode; + +extern int testRTFileSetMode(RTFILE File, RTFMODE fMode) +{ + RT_NOREF1(File); + /* RTPrintf("%s: fMode=%llu\n", __PRETTY_FUNCTION__, LLUIFY(fMode)); */ + testRTFileSetFMode = fMode; + return VINF_SUCCESS; +} + +static RTFILE g_testRTFileSetSizeFile; +static RTFOFF testRTFileSetSizeSize; + +extern int testRTFileSetSize(RTFILE File, uint64_t cbSize) +{ + /* RTPrintf("%s: File=%llu, cbSize=%llu\n", __PRETTY_FUNCTION__, LLUIFY(File), + LLUIFY(cbSize)); */ + g_testRTFileSetSizeFile = File; + testRTFileSetSizeSize = (RTFOFF) cbSize; /* Why was this signed before? */ + return VINF_SUCCESS; +} + +static RTTIMESPEC testRTFileSetTimesATime; + +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) + testRTFileSetTimesATime = *pAccessTime; + else + RT_ZERO(testRTFileSetTimesATime); + return VINF_SUCCESS; +} + +static RTFILE g_testRTFileUnlockFile; +static int64_t testRTFileUnlockOffset; +static uint64_t testRTFileUnlockSize; + +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_testRTFileUnlockFile = File; + testRTFileUnlockOffset = offLock; + testRTFileUnlockSize = cbLock; + return VINF_SUCCESS; +} + +static char testRTFileWriteData[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(testRTFileWriteData, (const char *)pvBuf); + if (pcbWritten) + *pcbWritten = strlen(testRTFileWriteData) + 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 hcFile = (RTFILE) 0x10000; + SHFLCREATERESULT Result; + int rc; + + RTTestSub(hTest, "Create file simple"); + Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers, + "/test/mapping", "testname"); + testRTFileOpenpFile = hcFile; + rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ, NULL, + &Result); + RTTEST_CHECK_RC_OK(hTest, rc); + RTTEST_CHECK_MSG(hTest, + !strcmp(&testRTFileOpenName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0], + "/test/mapping/test/file"), + (hTest, "pszFilename=%s\n", &testRTFileOpenName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0])); + RTTEST_CHECK_MSG(hTest, testRTFileOpenFlags == 0x181, + (hTest, "fOpen=%llu\n", LLUIFY(testRTFileOpenFlags))); + 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_testRTFileCloseFile == hcFile, + (hTest, "File=%u\n", (uintptr_t)g_testRTFileCloseFile)); +} + +void testCreateFileSimpleCaseInsensitive(RTTEST hTest) +{ + VBOXHGCMSVCFNTABLE svcTable; + VBOXHGCMSVCHELPERS svcHelpers; + SHFLROOT Root; + const RTFILE hcFile = (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*/); + testRTFileOpenpFile = hcFile; + rc = createFile(&svcTable, Root, "/TesT/FilE", SHFL_CF_ACCESS_READ, NULL, + &Result); + RTTEST_CHECK_RC_OK(hTest, rc); + + RTTEST_CHECK_MSG(hTest, + !strcmp(&testRTFileOpenName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0], + "/test/mapping/test/file"), + (hTest, "pszFilename=%s\n", &testRTFileOpenName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0])); + RTTEST_CHECK_MSG(hTest, testRTFileOpenFlags == 0x181, + (hTest, "fOpen=%llu\n", LLUIFY(testRTFileOpenFlags))); + 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_testRTFileCloseFile == hcFile, + (hTest, "File=%u\n", (uintptr_t)g_testRTFileCloseFile)); + + 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"); + 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(&testRTDirCreatePath[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0], + "/test/mapping/test/dir"), + (hTest, "pszPath=%s\n", &testRTDirCreatePath[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0])); + RTTEST_CHECK_MSG(hTest, + !strcmp(&testRTDirOpenName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0], + "/test/mapping/test/dir"), + (hTest, "pszFilename=%s\n", &testRTDirOpenName[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 hcFile = (RTFILE) 0x10000; + SHFLHANDLE Handle; + const char *pcszReadData = "Data to read"; + char acBuf[sizeof(pcszReadData) + 10]; + uint32_t cbRead; + int rc; + + RTTestSub(hTest, "Read file simple"); + Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers, + "/test/mapping", "testname"); + testRTFileOpenpFile = hcFile; + rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ, + &Handle, NULL); + RTTEST_CHECK_RC_OK(hTest, rc); + testRTFileReadData = pcszReadData; + rc = readFile(&svcTable, Root, Handle, 0, (uint32_t)strlen(pcszReadData) + 1, + &cbRead, acBuf, (uint32_t)sizeof(acBuf)); + RTTEST_CHECK_RC_OK(hTest, rc); + RTTEST_CHECK_MSG(hTest, + !strncmp(acBuf, pcszReadData, sizeof(acBuf)), + (hTest, "pvBuf=%.*s\n", sizeof(acBuf), acBuf)); + RTTEST_CHECK_MSG(hTest, cbRead == strlen(pcszReadData) + 1, + (hTest, "cbRead=%llu\n", LLUIFY(cbRead))); + unmapAndRemoveMapping(hTest, &svcTable, Root, "testname"); + RTTEST_CHECK_MSG(hTest, g_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile)); + 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 hcFile = (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"); + testRTFileOpenpFile = hcFile; + 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(testRTFileWriteData, pcszWrittenData), + (hTest, "pvBuf=%s\n", testRTFileWriteData)); + RTTEST_CHECK_MSG(hTest, cbWritten == cbToWrite, + (hTest, "cbWritten=%llu\n", LLUIFY(cbWritten))); + unmapAndRemoveMapping(hTest, &svcTable, Root, "testname"); + RTTEST_CHECK_MSG(hTest, g_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile)); + 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 hcFile = (RTFILE) 0x10000; + SHFLHANDLE Handle; + int rc; + + RTTestSub(hTest, "Flush file simple"); + Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers, + "/test/mapping", "testname"); + testRTFileOpenpFile = hcFile; + 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_testRTFileFlushFile == hcFile, (hTest, "File=%u\n", g_testRTFileFlushFile)); + 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_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile)); +} + +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"); + 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 hcFile = (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; + testRTFileOpenpFile = hcFile; + rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ, + &Handle, NULL); + RTTEST_CHECK_RC_OK_RETV(hTest, rc); + + RT_ZERO(Info); + testRTFileQueryInfoFMode = fMode; + rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_FILE, sizeof(Info), + &Info); + RTTEST_CHECK_RC_OK(hTest, rc); + RTTEST_CHECK_MSG(hTest, g_testRTFileQueryInfoFile == hcFile, (hTest, "File=%u\n", g_testRTFileQueryInfoFile)); + 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, testRTFileSetFMode == fMode, + (hTest, "Size=%llu\n", LLUIFY(testRTFileSetFMode))); + 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_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile)); +} + +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"); + 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(&testRTDirQueryInfoATime, 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(&testRTDirSetTimesATime) + == ccAtimeNano, + (hTest, "ATime=%llu\n", + LLUIFY(RTTimeSpecGetNano(&testRTDirSetTimesATime)))); + 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 hcFile = (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"); + testRTFileOpenpFile = hcFile; + rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ, + &Handle, NULL); + RTTEST_CHECK_RC_OK(hTest, rc); + RT_ZERO(Info); + RTTimeSpecSetNano(&testRTFileQueryInfoATime, ccAtimeNano); + rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_FILE, sizeof(Info), + &Info); + RTTEST_CHECK_RC_OK(hTest, rc); + RTTEST_CHECK_MSG(hTest, g_testRTFileQueryInfoFile == hcFile, (hTest, "File=%u\n", g_testRTFileQueryInfoFile)); + 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(&testRTFileSetTimesATime) + == ccAtimeNano, + (hTest, "ATime=%llu\n", + LLUIFY(RTTimeSpecGetNano(&testRTFileSetTimesATime)))); + 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_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile)); +} + +void testFSInfoQuerySetEndOfFile(RTTEST hTest) +{ + VBOXHGCMSVCFNTABLE svcTable; + VBOXHGCMSVCHELPERS svcHelpers; + SHFLROOT Root; + const RTFILE hcFile = (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"); + testRTFileOpenpFile = hcFile; + 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_testRTFileSetSizeFile == hcFile, (hTest, "File=%u\n", g_testRTFileSetSizeFile)); + RTTEST_CHECK_MSG(hTest, testRTFileSetSizeSize == cbNew, + (hTest, "Size=%llu\n", LLUIFY(testRTFileSetSizeSize))); + 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_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile)); +} + +void testLockFileSimple(RTTEST hTest) +{ + VBOXHGCMSVCFNTABLE svcTable; + VBOXHGCMSVCHELPERS svcHelpers; + SHFLROOT Root; + const RTFILE hcFile = (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"); + testRTFileOpenpFile = hcFile; + 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_testRTFileLockFile == hcFile, (hTest, "File=%u\n", g_testRTFileLockFile)); + RTTEST_CHECK_MSG(hTest, testRTFileLockfLock == 0, + (hTest, "fLock=%u\n", testRTFileLockfLock)); + RTTEST_CHECK_MSG(hTest, testRTFileLockOffset == offLock, + (hTest, "Offs=%llu\n", (long long) testRTFileLockOffset)); + RTTEST_CHECK_MSG(hTest, testRTFileLockSize == cbLock, + (hTest, "Size=%llu\n", LLUIFY(testRTFileLockSize))); +#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_testRTFileUnlockFile == hcFile, (hTest, "File=%u\n", g_testRTFileUnlockFile)); + RTTEST_CHECK_MSG(hTest, testRTFileUnlockOffset == offLock, + (hTest, "Offs=%llu\n", + (long long) testRTFileUnlockOffset)); + RTTEST_CHECK_MSG(hTest, testRTFileUnlockSize == cbLock, + (hTest, "Size=%llu\n", LLUIFY(testRTFileUnlockSize))); +#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_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile)); +} + + +/********************************************************************************************************************************* +* 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..93a9995a --- /dev/null +++ b/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.h @@ -0,0 +1,130 @@ +/** @file + * VBox Shared Folders testcase stub redefinitions. + */ + +/* + * Copyright (C) 2011-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#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..6920f8dd --- /dev/null +++ b/src/VBox/HostServices/SharedFolders/testcase/tstShflCase.cpp @@ -0,0 +1,442 @@ +/** @file + * Testcase for shared folder case conversion code. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + + +/********************************************************************************************************************************* +* 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..ab4e6a91 --- /dev/null +++ b/src/VBox/HostServices/SharedFolders/testcase/tstShflSizes.cpp @@ -0,0 +1,134 @@ +/** @file + * tstShflSize - Testcase for shared folder structure sizes. + * Run this on Linux and Windows, then compare. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/shflsvc.h> +#include <iprt/string.h> +#include <stdio.h> + +#define STRUCT(t, size) \ + do { \ + if (fPrintChecks) \ + printf(" STRUCT(" #t ", %d);\n", (int)sizeof(t)); \ + else if ((size) != sizeof(t)) \ + { \ + printf("%30s: %d expected %d!\n", #t, (int)sizeof(t), (size)); \ + cErrors++; \ + } \ + else if (!fQuiet)\ + printf("%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; + + printf("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) + printf("tstShflSizes: SUCCESS\n"); + else + printf("tstShflSizes: FAILURE - %d errors\n", cErrors); + return !!cErrors; +} + |