diff options
author | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2010-08-13 11:17:20 +0000 |
---|---|---|
committer | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2010-08-13 11:17:20 +0000 |
commit | db20805d61e95087717e46334b9d7c13748b8c22 (patch) | |
tree | bc42c4e05e9a39df7c7ba48788ae04190c322a32 /src/VBox/Additions/WINNT | |
parent | 861da90197c13f11483eb93c4f9ba1ad4af73de5 (diff) | |
download | VirtualBox-svn-db20805d61e95087717e46334b9d7c13748b8c22.tar.gz |
Windows Additions: export shared folders and installer to OSE
git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@31634 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src/VBox/Additions/WINNT')
73 files changed, 19474 insertions, 0 deletions
diff --git a/src/VBox/Additions/WINNT/Installer/ISO/AUTORUN.INF b/src/VBox/Additions/WINNT/Installer/ISO/AUTORUN.INF new file mode 100644 index 00000000000..b1c22a22d8e --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/ISO/AUTORUN.INF @@ -0,0 +1,11 @@ +;
+; Copyright (C) 2006-2010 Oracle Corporation
+;
+; Oracle Corporation confidential
+; All rights reserved
+;
+
+[autorun]
+open=VBoxWindowsAdditions.exe
+icon=VBoxWindowsAdditions.exe
+label=VirtualBox Guest Additions
diff --git a/src/VBox/Additions/WINNT/Installer/ISO/ReadmeDrivers.txt b/src/VBox/Additions/WINNT/Installer/ISO/ReadmeDrivers.txt new file mode 100644 index 00000000000..d362d2a78d5 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/ISO/ReadmeDrivers.txt @@ -0,0 +1,19 @@ +Oracle VM VirtualBox Guest Additions
+
+Where have the Windows drivers gone?
+- The Windows Guest Additions drivers were removed from this directory to
+ save space on your hard drive. To get the files you have to extract them
+ from the Windows Guest Additions installers:
+
+ To extract the 32-bit drivers to "C:\Drivers", do the following:
+ VBoxWindowsAdditions-x86 /extract /D=C:\Drivers
+
+ For the 64-bit drivers:
+ VBoxWindowsAdditions-amd64 /extract /D=C:\Drivers
+
+ Note: The extraction routine will create an additional sub directory
+ with the selected architecture (x86 or amd64) to prevent mixing up
+ the drivers.
+
+ To get further help with the command line parameteres of the installer,
+ type: VBoxWindowsAdditions-<arch> /?
diff --git a/src/VBox/Additions/WINNT/Installer/Loader/Makefile.kmk b/src/VBox/Additions/WINNT/Installer/Loader/Makefile.kmk new file mode 100644 index 00000000000..f37c069d72e --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/Loader/Makefile.kmk @@ -0,0 +1,53 @@ +# $Id$ +## @file +# Sub-Makefile for the Guest Additions loader. +# + +# +# Copyright (C) 2008 Oracle Corporation +# +# Oracle Corporation confidential +# All rights reserved +# + +SUB_DEPTH = ../../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# This has to be 32-bit, so don't include it in the 64-bit build. +if "$(KBUILD_TARGET_ARCH)" == "x86" + PROGRAMS.x86 += VBoxWindowsAdditions + VBoxWindowsAdditions_TEMPLATE= VBOXGUESTR3EXE + VBoxWindowsAdditions_DEFS = _WIN32_WINNT=0x0400 _UNICODE UNICODE + VBoxWindowsAdditions_SOURCES = \ + VBoxWindowsAdditions.cpp \ + VBoxWindowsAdditions.rc + + VBoxWindowsAdditions_LDFLAGS = \ + /DISALLOWLIB:msvcrt.lib \ + /DISALLOWLIB:msvcprt.lib \ + /DISALLOWLIB:libcmt.lib + + VBoxWindowsAdditions_LIBS = \ + $(PATH_TOOL_$(TEMPLATE_VBOXR3EXE_TOOL)_LIB)/oldnames.lib \ + $(PATH_TOOL_$(TEMPLATE_VBOXR3EXE_TOOL)_LIB)/libcmt.lib \ + $(PATH_TOOL_$(TEMPLATE_VBOXR3EXE_TOOL)_LIB)/libcpmt.lib + + # Version stuff. + VBoxWindowsAdditions.cpp_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV) + VBoxWindowsAdditions.cpp_DEPS = $(VBOX_SVN_REV_KMK) + + # The icon location is configurable. + VBoxWindowsAdditions.rc_INCS += $(PATH_VBoxWindowsAdditions) + VBoxWindowsAdditions.rc_DEPS += $(PATH_VBoxWindowsAdditions)/VBoxWindowsAdditions-icon.rc + VBoxWindowsAdditions.rc_CLEAN = $(PATH_VBoxWindowsAdditions)/VBoxWindowsAdditions-icon.rc + + + # Icon include file. +$$(PATH_VBoxWindowsAdditions)/VBoxWindowsAdditions-icon.rc: $(VBOX_WINDOWS_ADDITIONS_ICON_FILE) Makefile.kmk | $$(dir $$@) + $(RM) -f $@ + $(APPEND) $@ 'IDI_VIRTUALBOX ICON DISCARDABLE "$(subst /,\\,$(VBOX_WINDOWS_ADDITIONS_ICON_FILE))"' + +endif # x86 only + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.cpp b/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.cpp new file mode 100644 index 00000000000..5568c02504f --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.cpp @@ -0,0 +1,141 @@ +/* $Id$ */ +/** @file + * VBoxWindowsAdditions - The Windows Guest Additions Loader + */ + +/* + * Copyright (C) 2006-2007 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +#ifndef UNICODE +#define UNICODE +#endif + +#include <windows.h> +#include <stdio.h> +#include <tchar.h> + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + +LPFN_ISWOW64PROCESS fnIsWow64Process; + +BOOL IsWow64 () +{ + BOOL bIsWow64 = FALSE; + fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); + + if (NULL != fnIsWow64Process) + { + if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) + { + _tprintf(_T("ERROR: Could not determine process type!\n")); + + /* Error in retrieving process type - assume that we're running on 32bit. */ + return FALSE; + } + } + return bIsWow64; +} + +int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + int iRet = 0; + + LPWSTR *pszArgList = NULL; + int nArgs = 0; + + TCHAR szCurDir[_MAX_PATH + 1] = { 0 }; + GetCurrentDirectory(_MAX_PATH, szCurDir); + + SHELLEXECUTEINFOW TempInfo = { 0 }; + TempInfo.cbSize = sizeof(SHELLEXECUTEINFOW); + + TCHAR szModule[_MAX_PATH + 1] = { 0 }; + TCHAR szApp[_MAX_PATH + 1] = { 0 }; + TCHAR szProg[_MAX_PATH + 1] = { 0 }; + + pszArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs); + if (0 == GetModuleFileName(NULL, szModule, _MAX_PATH)) + { + /* Module not found, use a default name. */ + _stprintf(szModule, _T("%ws"), (pszArgList != NULL) ? pszArgList[0] : _T("VBoxWindowsAdditions.exe")); + } + + TCHAR* pcExt = wcsrchr(szModule, _T('.')); + if (NULL != pcExt) + wcsncpy(szApp, szModule, (pcExt - szModule)); + + if (IsWow64()) /* 64bit Windows. */ + { + _stprintf(szProg, _T("%ws-amd64.exe"), szApp); + } + else /* 32bit Windows. */ + { + _stprintf(szProg, _T("%ws-x86.exe"), szApp); + } + + /* Construct parameter list. */ + TCHAR *pszParams = (TCHAR*)LocalAlloc(LPTR, _MAX_PATH*sizeof(TCHAR)); + TCHAR szDelim = _T(' '); + + if (pszParams) + { + wcsncat(pszParams, szProg, + __min(wcslen(szProg),_MAX_PATH-wcslen(pszParams))); + wcsncat(pszParams, &szDelim, + __min(1,_MAX_PATH-wcslen(pszParams))); + + if (nArgs > 1) + { + for (int i=0; i<nArgs-1; i++) + { + if (i > 0) + { + wcsncat(pszParams, &szDelim, + __min(1,_MAX_PATH-wcslen(pszParams))); + } + wcsncat(pszParams, pszArgList[i+1], + __min(wcslen(pszArgList[i+1]),_MAX_PATH-wcslen(pszParams))); + } + } + } + + /* Struct for ShellExecute. */ + TempInfo.fMask = 0; + TempInfo.hwnd = NULL; + TempInfo.lpVerb =L"runas" ; + TempInfo.lpFile = szProg; + TempInfo.lpParameters = pszParams; + TempInfo.lpDirectory = szCurDir; + TempInfo.nShow = SW_NORMAL; + + STARTUPINFOW si; + PROCESS_INFORMATION pi; + DWORD dwRes = 0; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + + dwRes = CreateProcessW(szProg, pszParams, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + if (!dwRes && GetLastError() == 740) /* 740 = ERROR_ELEVATION_REQUIRED -> Only for Windows Vista. */ + { + if (FALSE == ::ShellExecuteExW(&TempInfo)) + { + _tprintf (_T("ERROR: Could not launch program! Code: %ld\n"), GetLastError()); + iRet = 1; + } + } + + if (pszParams) + LocalFree(pszParams); + + if (pszArgList) + LocalFree(pszArgList); + + return iRet; +} + diff --git a/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.rc b/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.rc new file mode 100644 index 00000000000..48a3ce1fc05 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.rc @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +#include <windows.h> +#include <VBox/version.h> +#include "resource.h" + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + PRODUCTVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + FILEFLAGSMASK 0x3fL + FILEFLAGS 0x0L + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", VBOX_RC_COMPANY_NAME + VALUE "FileDescription", "VirtualBox Guest Additions Loader\0" + VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + VALUE "InternalName", "VBoxWindowsAdditions\0" + VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "VBoxWindowsAdditions.exe\0" + VALUE "ProductName", "VirtualBox Guest Additions Loader\0" + VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#include "VBoxWindowsAdditions-icon.rc" diff --git a/src/VBox/Additions/WINNT/Installer/Loader/resource.h b/src/VBox/Additions/WINNT/Installer/Loader/resource.h new file mode 100644 index 00000000000..d46682ee14a --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/Loader/resource.h @@ -0,0 +1,13 @@ +/* $Id$ */ +/** @file + * AutoStartMenu - resource header file. + */ + +/* + * Copyright (C) 2008 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +#define IDI_VIRTUALBOX 101 diff --git a/src/VBox/Additions/WINNT/Installer/Makefile.kmk b/src/VBox/Additions/WINNT/Installer/Makefile.kmk new file mode 100644 index 00000000000..a5bb601c737 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/Makefile.kmk @@ -0,0 +1,207 @@ +# $Id$ +## @file +# Sub-Makefile for the Windows Guest Additions Installer. +# + +# +# Copyright (C) 2006-2007 Oracle Corporation +# +# Oracle Corporation confidential +# All rights reserved +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# Include Sub-Makefiles. +include $(PATH_SUB_CURRENT)/Loader/Makefile.kmk + +# Globals +VBOX_PATH_WIN_ADD_INS_SRC := $(PATH_SUB_CURRENT) +VBOX_PATH_ADDITIONS.win.x86 := $(PATH_OUT_BASE)/win.x86/$(KBUILD_TYPE)/bin/additions + +## @todo VBOX_WIN_ADD_INS_OUT_DIR := $(PATH_TARGET)/Additions/Installer/win + +DLLS += VBCoInst +VBCoInst_TEMPLATE = VBOXGUESTR3DLL +ifdef VBOX_SIGN_ADDITIONS # (See the parent makefile.) + VBCoInst_NOINST = true +endif +VBCoInst_DEFS = _WIN32_WINNT=0x0400 WIN32_LEAN_AND_MEAN=1 UNICODE +VBCoInst_LDFLAGS = /subsystem:console,4.10 +VBCoInst_SOURCES = \ + VBCoInst.cpp \ + VBCoInst.def \ + VBCoInst.rc + +PROGRAMS += VBoxDrvInst +VBoxDrvInst_TEMPLATE= VBOXGUESTR3EXE +VBoxDrvInst_DEFS = _WIN32_WINNT=0x0400 _UNICODE UNICODE +VBoxDrvInst_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV) +VBoxDrvInst_DEPS = $(VBOX_SVN_REV_KMK) +VBoxDrvInst_SDKS = WINPSDK W2K3DDK +VBoxDrvInst_LIBS = \ + $(PATH_SDK_W2K3DDK_LIB)/setupapi.lib \ + $(PATH_SDK_W2K3DDK_LIB)/newdev.lib +VBoxDrvInst_SOURCES = \ + VBoxDrvInst.cpp \ + VBoxDrvInst.rc + +PROGRAMS += VBoxGuestDrvInst +VBoxGuestDrvInst_TEMPLATE= VBOXGUESTR3EXE +VBoxGuestDrvInst_DEFS = _WIN32_WINNT=0x0400 UNICODE +VBoxGuestDrvInst_SOURCES = \ + VBoxGuestDrvInst.cpp \ + VBoxGuestDrvInst.rc + +PROGRAMS += RegCleanup +RegCleanup_TEMPLATE = VBOXGUESTR3EXE +RegCleanup_DEFS = _WIN32_WINNT=0x0400 UNICODE +RegCleanup_SOURCES = \ + RegCleanup.cpp \ + RegCleanup.rc + + +# +# The installer. +# +PACKING += $(PATH_BIN)/additions/VBoxWindowsAdditions-$(KBUILD_TARGET_ARCH).exe +OTHER_CLEAN += \ + $(PATH_BIN)/additions/VBoxWindowsAdditions-$(KBUILD_TARGET_ARCH).exe \ + $(PATH_BIN)/additions/VBoxWHQLFake.exe + +DRIVER_FILES := \ + $(PATH_BIN)/additions/VBoxGuestDrvInst.exe \ + $(PATH_BIN)/additions/RegCleanup.exe \ + $(PATH_BIN)/additions/VBoxMouse.sys \ + $(PATH_BIN)/additions/VBoxGuest.sys \ + $(PATH_BIN)/additions/VBoxVideo.sys \ + $(PATH_BIN)/additions/VBoxDisp.dll \ + $(PATH_BIN)/additions/VBoxSF.sys \ + $(PATH_BIN)/additions/VBoxMRXNP.dll \ + $(PATH_BIN)/additions/VBoxTray.exe \ + $(PATH_BIN)/additions/VBoxControl.exe \ + $(PATH_BIN)/additions/VBoxWHQLFake.exe \ + $(PATH_BIN)/additions/VBoxService.exe +ifeq ($(KBUILD_TARGET_ARCH),x86) +DRIVER_FILES += \ + $(PATH_BIN)/additions/VBoxMouseNT.sys \ + $(PATH_BIN)/additions/VBoxGuestNT.sys +endif +DRIVER_FILES += \ + $(PATH_BIN)/additions/VBoxVideo.inf \ + $(PATH_BIN)/additions/VBoxGuest.inf +ifdef VBOX_SIGN_ADDITIONS +DRIVER_FILES += \ + $(PATH_BIN)/additions/VBoxVideo.cat \ + $(PATH_BIN)/additions/VBoxGuest.cat +endif +ifdef VBOX_WITH_CROGL +DRIVER_FILES += \ + $(PATH_BIN)/additions/VBoxOGLarrayspu.dll \ + $(PATH_BIN)/additions/VBoxOGLcrutil.dll \ + $(PATH_BIN)/additions/VBoxOGLerrorspu.dll \ + $(PATH_BIN)/additions/VBoxOGLpackspu.dll \ + $(PATH_BIN)/additions/VBoxOGLpassthroughspu.dll \ + $(PATH_BIN)/additions/VBoxOGLfeedbackspu.dll \ + $$(PATH_BIN)/additions/VBoxOGL.dll + ifeq ($(KBUILD_TARGET_ARCH),amd64) + # Also include 32-bit DLLs on 64-bit guests to enable + # running 32-bit OpenGL apps on that. + DRIVER_FILES += \ + $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGLarrayspu.dll \ + $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGLcrutil.dll \ + $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGLerrorspu.dll \ + $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGLpackspu.dll \ + $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGLpassthroughspu.dll \ + $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGLfeedbackspu.dll \ + $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGL.dll + endif +endif + +VB_WIN_ADD_NSIS_ENV := \ + -E 'PATH_OUT=$(subst /,\,$(PATH_OUT))' \ + -E 'PATH_TARGET=$(subst /,\,$(PATH_TARGET))' \ + -E 'VBOX_PATH_ADDITIONS_WIN_X86=$(subst /,\,$(VBOX_PATH_ADDITIONS.win.x86))' \ + -E 'VBOX_VENDOR=$(VBOX_VENDOR)' \ + -E 'VBOX_VENDOR_SHORT=$(VBOX_VENDOR_SHORT)' \ + -E 'VBOX_PRODUCT=$(VBOX_PRODUCT)' \ + -E 'VBOX_C_YEAR=$(VBOX_C_YEAR)' \ + -E 'VBOX_VERSION_STRING=$(VBOX_VERSION_STRING)' \ + -E 'VBOX_VERSION_MAJOR=$(VBOX_VERSION_MAJOR)' \ + -E 'VBOX_VERSION_MINOR=$(VBOX_VERSION_MINOR)' \ + -E 'VBOX_VERSION_BUILD=$(VBOX_VERSION_BUILD)' \ + -E 'VBOX_SVN_REV=$(VBOX_SVN_REV)' \ + -E 'VBOX_WINDOWS_ADDITIONS_ICON_FILE=$(subst /,\,$(VBOX_WINDOWS_ADDITIONS_ICON_FILE))' \ + -E 'VBOX_NSIS_ICON_FILE=$(subst /,\,$(VBOX_NSIS_ICON_FILE))' \ + -E 'VBOX_WITH_CROGL=$(if $(VBOX_WITH_CROGL),1,0)' \ + -E 'VBOX_BRAND_WIN_ADD_INST_DLGBMP=$(subst /,\,$(VBOX_BRAND_WIN_ADD_INST_DLGBMP))' \ + -E 'VBOX_BRAND_LICENSE_RTF=$(subst /,\,$(VBOX_BRAND_LICENSE_RTF))' \ + $(foreach lang,$(VBOX_INSTALLER_ADD_LANGUAGES),-E 'VBOX_BRAND_$(lang)_LICENSE_RTF=$(VBOX_BRAND_$(lang)_LICENSE_RTF)') \ + -E 'BUILD_TYPE=$(KBUILD_TYPE)' \ + -E 'BUILD_TARGET_ARCH=$(KBUILD_TARGET_ARCH)' + +ifdef VBOX_SIGNING_MODE +# +# This is a hack to sign the uninstaller. +# See http://nsis.sourceforge.net/Signing_an_Uninstaller for more details. +# +OTHER_CLEAN += $(PATH_TARGET)/VBoxWindowsAdditions-$(KBUILD_TARGET_ARCH)-uninst.exe + +$(PATH_TARGET)/VBoxWindowsAdditions-$(KBUILD_TARGET_ARCH)-uninst.exe: \ + $(PATH_SUB_CURRENT)/VBoxGuestAdditions.nsi \ + $(DRIVER_FILES) \ + $(VBOX_WINDOWS_ADDITIONS_ICON_FILE) \ + $(VBOX_NSIS_ICON_FILE) \ + $(VBOX_VERSION_STAMP)\ + | $$(dir $$@) + $(call MSG_L1,Creating $@, from $<) + $(QUIET)$(REDIRECT) -C $(VBOX_PATH_WIN_ADD_INS_SRC) \ + $(VB_WIN_ADD_NSIS_ENV) \ + -- $(EXEC_X86_WIN32) $(VBOX_PATH_NSIS)/makensis.exe /NOCD /V2 \ + $(if $(VBOX_SIGN_ADDITIONS),'/DVBOX_SIGN_ADDITIONS=1') \ + $(if $(VBOX_INSTALLER_ADD_LANGUAGES),'/DVBOX_INSTALLER_ADD_LANGUAGES=1') \ + $(foreach lang,$(VBOX_INSTALLER_ADD_LANGUAGES),'/DVBOX_BRAND_$(lang)_LICENSE_RTF=1') \ + '/DUNINSTALLER_ONLY=1' \ + '$(subst /,\,$<)' + +OTHER_CLEAN += $(PATH_TARGET)/uninst.exe +$(PATH_TARGET)/uninst.exe: $(PATH_TARGET)/VBoxWindowsAdditions-$(KBUILD_TARGET_ARCH)-uninst.exe | $$(dir $$@) + $(call MSG_L1,Creating $@, from $<) + $(QUIET)$(RM) -f $@ + - $< + $(TEST) -f $@ + $(call VBOX_SIGN_FILE_FN,$@) +endif + +WHQLFAKE := $(PATH_SUB_CURRENT)/VBoxWHQLFake.au3 + +$(PATH_BIN)/additions/VBoxWHQLFake.exe: + $(call MSG_L1,Creating $@, from $<) + $(QUIET)$(EXEC_X86_WIN32) $(VBOX_PATH_AUTOIT3)/Aut2Exe/Aut2exe.exe \ + /in $(WHQLFAKE) \ + /out $(PATH_BIN)/additions/VBoxWHQLFake.exe \ + /icon $(VBOX_WINDOWS_ADDITIONS_ICON_FILE) \ + /comp 4 \ + /unicode + +$(PATH_BIN)/additions/VBoxWindowsAdditions-$(KBUILD_TARGET_ARCH).exe: \ + $(PATH_SUB_CURRENT)/VBoxGuestAdditions.nsi \ + $(DRIVER_FILES) \ + $(VBOX_WINDOWS_ADDITIONS_ICON_FILE) \ + $(VBOX_NSIS_ICON_FILE) \ + $(if $(VBOX_SIGNING_MODE),$(PATH_TARGET)/uninst.exe) \ + $(VBOX_VERSION_STAMP) + $(call MSG_L1,Creating $@, from $<) + $(QUIET)$(REDIRECT) -C $(VBOX_PATH_WIN_ADD_INS_SRC) \ + $(VB_WIN_ADD_NSIS_ENV) \ + -- $(EXEC_X86_WIN32) $(VBOX_PATH_NSIS)/makensis.exe /NOCD /V2 \ + $(if $(VBOX_SIGN_ADDITIONS),'/DVBOX_SIGN_ADDITIONS=1') \ + $(if $(VBOX_SIGNING_MODE),'/DEXTERNAL_UNINSTALLER=1') \ + $(if $(VBOX_INSTALLER_ADD_LANGUAGES),'/DVBOX_INSTALLER_ADD_LANGUAGES=1') \ + $(foreach lang,$(VBOX_INSTALLER_ADD_LANGUAGES),'/DVBOX_BRAND_$(lang)_LICENSE_RTF=1') \ + '$(subst /,\,$<)' + $(call VBOX_SIGN_FILE_FN,$@) + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/WINNT/Installer/RegCleanup.cpp b/src/VBox/Additions/WINNT/Installer/RegCleanup.cpp new file mode 100644 index 00000000000..c2393c9d85d --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/RegCleanup.cpp @@ -0,0 +1,83 @@ +/** @file + * + * delinvalid - remove "InvalidDisplay" key on NT4 + * + * Copyright (C) 2006-2007 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +/* + Purpose: + + Delete the "InvalidDisplay" key which causes the display + applet to be started on every boot. For some reason this key + isn't removed after setting the proper resolution and even not when + doing a driver reinstall. Removing it doesn't seem to do any harm. + The key is inserted by windows on first reboot after installing + the VBox video driver using the VirtualBox utility. + It's not inserted when using the Display applet for installation. + There seems to be a subtle problem with the VirtualBox util. + */ + +//#define _UNICODE + +#include <windows.h> +#include <setupapi.h> +#include <regstr.h> +#include <DEVGUID.h> +#include <stdio.h> + +#include "tchar.h" +#include "string.h" + +/******************************************************************************* + * Defined Constants And Macros * + *******************************************************************************/ + +///////////////////////////////////////////////////////////////////////////// + + +BOOL isNT4 (void) +{ + OSVERSIONINFO OSversion; + + OSversion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + ::GetVersionEx(&OSversion); + + switch (OSversion.dwPlatformId) + { + case VER_PLATFORM_WIN32s: + case VER_PLATFORM_WIN32_WINDOWS: + return FALSE; + case VER_PLATFORM_WIN32_NT: + if (OSversion.dwMajorVersion == 4) + return TRUE; + else return FALSE; + default: + break; + } + return FALSE; +} + +int main (int argc, char **argv) +{ + int rc = 0; + + /* This program is only for installing drivers on NT4 */ + if (!isNT4()) + { + printf("This program only runs on NT4\n"); + return -1; + } + + /* Delete the "InvalidDisplay" key which causes the display + applet to be started on every boot. For some reason this key + isn't removed after setting the proper resolution and even not when + doing a driverreinstall. */ + RegDeleteKey(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers\\InvalidDisplay")); + RegDeleteKey(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers\\NewDisplay")); + + return rc; +} diff --git a/src/VBox/Additions/WINNT/Installer/RegCleanup.rc b/src/VBox/Additions/WINNT/Installer/RegCleanup.rc new file mode 100644 index 00000000000..50b8339783c --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/RegCleanup.rc @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2006-2007 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +#include <windows.h> +#include <VBox/version.h> + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + PRODUCTVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + FILEFLAGSMASK 0x3fL + FILEFLAGS 0x0L + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", VBOX_RC_COMPANY_NAME + VALUE "FileDescription", "VirtualBox RegCleanup\0" + VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + VALUE "InternalName", "VBoxRegCleanup\0" + VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "VBoxRegCleanup.exe\0" + VALUE "ProductName", "VirtualBox Guest Additions\0" + VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/VBox/Additions/WINNT/Installer/ReplaceDLL.nsh b/src/VBox/Additions/WINNT/Installer/ReplaceDLL.nsh new file mode 100644 index 00000000000..480221d5e43 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/ReplaceDLL.nsh @@ -0,0 +1,149 @@ + + +; Macro - Upgrade DLL File +; Written by Joost Verburg +; ------------------------ +; +; Parameters: +; LOCALFILE - Location of the new DLL file (on the compiler system) +; DESTFILE - Location of the DLL file that should be upgraded +; (on the user's system) +; TEMPBASEDIR - Directory on the user's system to store a temporary file +; when the system has to be rebooted. +; For Win9x support, this should be on the same volume as the +; DESTFILE! +; The Windows temp directory could be located on any volume, +; so you cannot use this directory. +; +; Define REPLACEDLL_NOREGISTER if you want to upgrade a DLL that does not +; have to be registered. +; +; Note: If you want to support Win9x, you can only use +; short filenames (8.3). +; +; Example of usage: +; !insertmacro ReplaceDLL "dllname.dll" "$SYSDIR\dllname.dll" "$SYSDIR" +; + +!macro ReplaceDLL LOCALFILE DESTFILE TEMPBASEDIR + + Push $R0 + Push $R1 + Push $R2 + Push $R3 + Push $R4 + Push $R5 + + ;------------------------ + ;Unique number for labels + + !define REPLACEDLL_UNIQUE ${__LINE__} + + ;------------------------ + ;Copy the parameters used on run-time to a variable + ;This allows the usage of variables as paramter + + StrCpy $R4 "${DESTFILE}" + StrCpy $R5 "${TEMPBASEDIR}" + + ;------------------------ + ;Check file and version + ; + IfFileExists $R4 0 replacedll.copy_${REPLACEDLL_UNIQUE} + + ;ClearErrors + ; GetDLLVersionLocal "${LOCALFILE}" $R0 $R1 + ; GetDLLVersion $R4 $R2 $R3 + ;IfErrors replacedll.upgrade_${REPLACEDLL_UNIQUE} + ; + ;IntCmpU $R0 $R2 0 replacedll.done_${REPLACEDLL_UNIQUE} + ; replacedll.upgrade_${REPLACEDLL_UNIQUE} + ;IntCmpU $R1 $R3 replacedll.done_${REPLACEDLL_UNIQUE} + ; replacedll.done_${REPLACEDLL_UNIQUE} + ; replacedll.upgrade_${REPLACEDLL_UNIQUE} + + ;------------------------ + ;Let's replace the DLL! + + SetOverwrite try + + ;replacedll.upgrade_${REPLACEDLL_UNIQUE}: + !ifndef REPLACEDLL_NOREGISTER + ;Unregister the DLL + UnRegDLL $R4 + !endif + + ;------------------------ + ;Try to copy the DLL directly + + ClearErrors + StrCpy $R0 $R4 + Call :replacedll.file_${REPLACEDLL_UNIQUE} + IfErrors 0 replacedll.noreboot_${REPLACEDLL_UNIQUE} + + ;------------------------ + ;DLL is in use. Copy it to a temp file and Rename it on reboot. + + GetTempFileName $R0 $R5 + Call :replacedll.file_${REPLACEDLL_UNIQUE} + Rename /REBOOTOK $R0 $R4 + + ;------------------------ + ;Register the DLL on reboot + + !ifndef REPLACEDLL_NOREGISTER + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" \ + "Register $R4" 'rundll32.exe "$R4",DllRegisterServer' + !endif + + Goto replacedll.done_${REPLACEDLL_UNIQUE} + + ;------------------------ + ;DLL does not exist - just extract + + replacedll.copy_${REPLACEDLL_UNIQUE}: + StrCpy $R0 $R4 + Call :replacedll.file_${REPLACEDLL_UNIQUE} + + ;------------------------ + ;Register the DLL + + replacedll.noreboot_${REPLACEDLL_UNIQUE}: + !ifndef REPLACEDLL_NOREGISTER + RegDLL $R4 + !endif + + ;------------------------ + ;Done + + replacedll.done_${REPLACEDLL_UNIQUE}: + + Pop $R5 + Pop $R4 + Pop $R3 + Pop $R2 + Pop $R1 + Pop $R0 + + ;------------------------ + ;End + + Goto replacedll.end_${REPLACEDLL_UNIQUE} + + ;------------------------ + ;Called to extract the DLL + + replacedll.file_${REPLACEDLL_UNIQUE}: + File /oname=$R0 "${LOCALFILE}" + Return + + replacedll.end_${REPLACEDLL_UNIQUE}: + + ;------------------------ + ;Restore settings + + SetOverwrite lastused + + !undef REPLACEDLL_UNIQUE + +!macroend diff --git a/src/VBox/Additions/WINNT/Installer/VBCoInst.cpp b/src/VBox/Additions/WINNT/Installer/VBCoInst.cpp new file mode 100644 index 00000000000..4dda8a1e99b --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBCoInst.cpp @@ -0,0 +1,331 @@ +// 45678901234567890123456789012345678901234567890123456789012345678901234567890 +//+--------------------------------------------------------------------------- +// +// Microsoft Windows +// Copyright (C) Microsoft Corporation, 1999. +// +// File: COINST.C +// +// Contents: co-installer hook. +// +// Notes: For a complete description of CoInstallers, please see the +// Microsoft Windows 2000 DDK Documentation +// +// Author: keithga 4 June 1999 +// +// Revision History: +// Added FriendlyName interface (Eliyas Yakub Aug 2, 1999) +// +//---------------------------------------------------------------------------- + +#undef UNICODE +#if !defined(_UNICODE) && defined(UNICODE) +#define _UNICODE +#endif + +#include <windows.h> +#include <setupapi.h> +#include <stdio.h> +#include <tchar.h> + +// #define LOG_ENABLED + +#ifdef LOG_ENABLED +#include <stdio.h> + +static VOID _dprintf(LPSTR String, ...) +{ + va_list va; + + va_start(va, String); + + CHAR Buffer[1024]; + if (strlen(String) < 1000) + { + _vsntprintf (Buffer, sizeof(Buffer), String, va); + + FILE *f = fopen ("\\coinst.log", "ab"); + if (f) + { + fprintf (f, "%s", Buffer); + fclose (f); + } + } + + va_end (va); +} +#define dprintf(a) _dprintf a +#else +#define dprintf(a) do {} while (0) +#endif /* LOG_ENABLED */ + +//+--------------------------------------------------------------------------- +// +// WARNING! +// +// A Coinstaller must not generate any popup to the user. +// it should provide appropriate defaults. +// +// OutputDebugString should be fine... +// +#if DBG +#define DbgOut(Text) OutputDebugString(TEXT("CoInstaller: " Text "\n")) +#else +#define DbgOut(Text) +#endif + +/** strip the filename and leave the slash. */ +void StripFilename (TCHAR *psz) +{ + TCHAR *pchSep = NULL; + TCHAR *pch = psz; + + /* strip of the filename. */ + for (; *pch; pch++) + { + if (*pch == '\\' || *pch == '/' || *pch == ':') + pchSep = pch + 1; + } + if (pchSep) + *pchSep = '\0'; + else + { + psz[0] = '.'; + psz[1] = '\0'; + } +} + +/** + Check the installation type. + This function checks if the currently used + INF file not OEMxx.inf. If yes, the user installs the guest additions by hand, + if no this is an automated installation. + */ +BOOL CheckForNormalInstall (TCHAR *psz) +{ + TCHAR *pchSep = NULL; + TCHAR *pch = psz; + + /* strip of the filename. */ + for (; *pch; pch++) + { + if (*pch == '\\' || *pch == '/' || *pch == ':') + pchSep = pch + 1; + } + if (pchSep) + { + if (*pchSep == 'o' || *pchSep == 'O') + return FALSE; + return TRUE; + } + return TRUE; /* We shouldn't end here... */ +} + +ULONG startMouseInstallation (TCHAR *pszVBoxGuestInfName) +{ + TCHAR szAppCmd[MAX_PATH]; + STARTUPINFO sInfo = { 0 }; + PROCESS_INFORMATION pInfo = { 0 }; + BOOL fNotAutomated; + + dprintf(("startMouseInstallation: filename = %s\n", pszVBoxGuestInfName)); + + /* Check if we do an automated install */ + fNotAutomated = CheckForNormalInstall(pszVBoxGuestInfName); + + StripFilename(pszVBoxGuestInfName); + + dprintf(("startMouseInstallation: fNotAutomated = %d, filename = %s\n", fNotAutomated, pszVBoxGuestInfName)); + + if (fNotAutomated) + { + /* This is a normal guest installation done by inserting the ISO */ + _sntprintf(szAppCmd, sizeof(szAppCmd), TEXT("rundll32.exe SETUPAPI.DLL,InstallHinfSection VBoxMouse 132 %sVBoxMouse.inf"), pszVBoxGuestInfName); + + sInfo.cb = sizeof(STARTUPINFO); + + if (CreateProcess(NULL, szAppCmd, NULL, //lpProcessAttributes + NULL, //lpThreadAttributes + FALSE, //bInheritHandles + 0, //dwCreationFlags + NULL, //lpEnvironment + NULL, //lpCurrentDirectory, + &sInfo, //lpStartupInfo, + &pInfo)) //lpProcessInformation + { + DWORD dwExitCode = 0; + + /* Wait for rundll32 to finish and then check the exit code; only then do we know if it succeeded or not! */ + WaitForSingleObject(pInfo.hProcess, INFINITE); + if (GetExitCodeProcess(pInfo.hProcess, &dwExitCode) != 0 && dwExitCode == 0) + { + // + // hook the filter into the mouse class + // + + dprintf(("startMouseInstallation: hooking\n")); + + // first determine the GUID of the Mouse class + GUID guid; + DWORD numGuids; + if (SetupDiClassGuidsFromNameEx("Mouse", &guid, 1, &numGuids, NULL, NULL) || (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + // get the corresponding class registry key + HKEY hkey = SetupDiOpenClassRegKeyEx(&guid, KEY_READ | KEY_WRITE, DIOCR_INSTALLER, NULL, NULL); + if (hkey) + { + // hardcoded value, ours + the standard filter + RegSetValueEx(hkey, "UpperFilters", 0, REG_MULTI_SZ, (const BYTE*)"VBoxMouse\0mouclass\0\0", 20); + RegCloseKey(hkey); + } + } + CloseHandle(pInfo.hProcess); + CloseHandle(pInfo.hThread); + dprintf(("startMouseInstallation: return ok\n")); + return 0; + } + CloseHandle(pInfo.hProcess); + CloseHandle(pInfo.hThread); + } /* CreateProcess() */ + } /* fNotAutomated */ + else + { + /* This is an automated installation */ + + // + // hook the filter into the mouse class + // + + dprintf(("startMouseInstallation: automated\n")); + + // first determine the GUID of the Mouse class + GUID guid; + DWORD numGuids; + if (SetupDiClassGuidsFromNameEx("Mouse", &guid, 1, &numGuids, NULL, NULL) || (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + // get the corresponding class registry key + HKEY hkey = SetupDiOpenClassRegKeyEx(&guid, KEY_READ | KEY_WRITE, DIOCR_INSTALLER, NULL, NULL); + if (hkey) + { + // hardcoded value, ours + the standard filter + RegSetValueEx(hkey, "UpperFilters", 0, REG_MULTI_SZ, (const BYTE*)"VBoxMouse\0mouclass\0\0", 20); + RegCloseKey(hkey); + } + } + return 0; + } + + /* bitch to debug output */ + return -1; +} + +//+--------------------------------------------------------------------------- +// +// Function: VBoxCoInstaller +// +// Purpose: Responds to co-installer messages +// +// Arguments: +// InstallFunction [in] +// DeviceInfoSet [in] +// DeviceInfoData [in] +// Context [inout] +// +// Returns: NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or an error code. +// +// This co-installer is used to install the mouse filter after installation of +// the VBoxGuest driver +extern "C" +HRESULT WINAPI +VBoxCoInstaller ( + IN DI_FUNCTION InstallFunction, + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL + IN OUT PCOINSTALLER_CONTEXT_DATA Context +) +{ + dprintf((__DATE__ __TIME__ "VBoxCoInstaller InstallFunction 0x%02X\n", InstallFunction)); + + switch (InstallFunction) + { + case DIF_INSTALLDEVICE: + { + SP_DEVINSTALL_PARAMS DeviceInstallParams; + DeviceInstallParams.cbSize = sizeof (DeviceInstallParams); + + if (!SetupDiGetDeviceInstallParams (DeviceInfoSet, + DeviceInfoData, + &DeviceInstallParams)) + { + dprintf(("Failed to get DeviceInstallParams\n")); + return NO_ERROR; + } + + /* Reboot the system and do not dynamically load the driver. */ + DeviceInstallParams.Flags |= DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG; + + if (!SetupDiSetDeviceInstallParams (DeviceInfoSet, + DeviceInfoData, + &DeviceInstallParams)) + { + dprintf(("Failed to set DeviceInstallParams\n")); + return NO_ERROR; + } + + return NO_ERROR; + } + + // case DIF_REMOVE: + // { + // return NO_ERROR; + // } break; +#if 0 + /* This request is only sent when the installation of the VBoxGuest + succeeded. Because VBoxMouse needs VBoxGuest to work this is + a nice installation prerequisite check, too. */ + case DIF_NEWDEVICEWIZARD_FINISHINSTALL: + { + SP_DRVINFO_DATA DriverInfoData; + SP_DRVINFO_DETAIL_DATA DriverInfoDetailData; + HRESULT Status; + + /* Get the path to the VBoxGuest INF. The VBoxMouse INF is in the same + directory. */ + DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA); + if (!SetupDiGetSelectedDriver(DeviceInfoSet, + DeviceInfoData, + &DriverInfoData)) + { + return NO_ERROR; /* Should return an error here? */ + } + + DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); + if (!SetupDiGetDriverInfoDetail(DeviceInfoSet, + DeviceInfoData, + &DriverInfoData, + &DriverInfoDetailData, + sizeof(SP_DRVINFO_DETAIL_DATA), + NULL)) + { + if ((Status = GetLastError()) == ERROR_INSUFFICIENT_BUFFER) + { + // We don't need the extended information. Ignore. + } + else + { + return NO_ERROR; /* Should return an error here? */ + } + } + + startMouseInstallation(DriverInfoDetailData.InfFileName); + break; + } +#endif + + default: + break; + } + + return NO_ERROR; +} + diff --git a/src/VBox/Additions/WINNT/Installer/VBCoInst.def b/src/VBox/Additions/WINNT/Installer/VBCoInst.def new file mode 100644 index 00000000000..a607398dff6 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBCoInst.def @@ -0,0 +1,15 @@ +; +; VBCoInst -- Guest Additions Driver Co Installation Module +; Copyright (C) 2006-2007 Oracle Corporation +; +; Oracle Corporation confidential +; All rights reserved +; + +LIBRARY VBCOINST + +EXPORTS + VBoxCoInstaller + + + diff --git a/src/VBox/Additions/WINNT/Installer/VBCoInst.rc b/src/VBox/Additions/WINNT/Installer/VBCoInst.rc new file mode 100644 index 00000000000..6577985bded --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBCoInst.rc @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2006-2007 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +#include <windows.h> +#include <VBox/version.h> + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + PRODUCTVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + FILEFLAGSMASK 0x3fL + FILEFLAGS 0x0L + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", VBOX_RC_COMPANY_NAME + VALUE "FileDescription", "VirtualBox CoInst\0" + VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + VALUE "InternalName", "VBoxCoInst\0" + VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "VBoxCoInst.exe\0" + VALUE "ProductName", "VirtualBox Guest Additions\0" + VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.cpp b/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.cpp new file mode 100644 index 00000000000..21f5a2ae200 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.cpp @@ -0,0 +1,2200 @@ +/*++ + + Copyright (c) Microsoft Corporation. All rights reserved. + + Module Name: + + VBoxDrvInst.cpp + + Abstract: + + Command-line interface for installing / uninstalling device drivers + with a given Hardware-ID (and .INF-file). + + --*/ + +#ifndef UNICODE +#define UNICODE +#endif + +#include <VBox/version.h> + +#include <windows.h> +#include <setupapi.h> +#include <newdev.h> +#include <regstr.h> +#include <cfgmgr32.h> +#include <devguid.h> +#include <stdio.h> +#include <tchar.h> +#include <string.h> + +/*#define _DEBUG*/ + +typedef int (*fnCallback) (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context); + +struct IdEntry +{ + LPCTSTR szString; /* string looking for */ + LPCTSTR szWild; /* first wild character if any */ + BOOL bInstanceId; +}; + +#define INSTANCEID_PREFIX_CHAR TEXT('@') /* character used to prefix instance ID's */ +#define CLASS_PREFIX_CHAR TEXT('=') /* character used to prefix class name */ +#define WILD_CHAR TEXT('*') /* wild character */ +#define QUOTE_PREFIX_CHAR TEXT('\'') /* prefix character to ignore wild characters */ +#define SPLIT_COMMAND_SEP TEXT(":=") /* whole word, indicates end of id's */ + +/* @todo Split this program into several modules: + + - Main + - Utility functions + - Dynamic API loading + - Installation / uninstallation routines + - ... + */ + +/* Exit codes */ +#define EXIT_OK (0) +#define EXIT_REBOOT (1) +#define EXIT_FAIL (2) +#define EXIT_USAGE (3) + +/* Dynamic loaded libs */ +HMODULE g_hSetupAPI = NULL; +HMODULE g_hNewDev = NULL; +HMODULE g_hCfgMgr = NULL; + +/* Function pointers for dynamic loading of some API calls NT4 hasn't ... */ +typedef BOOL (WINAPI *fnSetupDiCreateDeviceInfo) (HDEVINFO DeviceInfoSet, PCTSTR DeviceName, LPGUID ClassGuid, PCTSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags, + PSP_DEVINFO_DATA DeviceInfoData); +fnSetupDiCreateDeviceInfo g_pfnSetupDiCreateDeviceInfo = NULL; + +typedef BOOL (WINAPI *fnSetupDiOpenDeviceInfo) (HDEVINFO DeviceInfoSet, PCTSTR DeviceInstanceId, HWND hwndParent, DWORD OpenFlags, PSP_DEVINFO_DATA DeviceInfoData); +fnSetupDiOpenDeviceInfo g_pfnSetupDiOpenDeviceInfo = NULL; + +typedef BOOL (WINAPI *fnSetupDiEnumDeviceInfo) (HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData); +fnSetupDiEnumDeviceInfo g_pfnSetupDiEnumDeviceInfo = NULL; + +/***/ + +typedef HDEVINFO (WINAPI *fnSetupDiCreateDeviceInfoList) (LPGUID ClassGuid, HWND hwndParent); +fnSetupDiCreateDeviceInfoList g_pfnSetupDiCreateDeviceInfoList = NULL; + +typedef HDEVINFO (WINAPI *fnSetupDiCreateDeviceInfoListEx) (LPGUID ClassGuid, HWND hwndParent, PCTSTR MachineName, PVOID Reserved); +fnSetupDiCreateDeviceInfoListEx g_pfnSetupDiCreateDeviceInfoListEx = NULL; + +typedef BOOL (WINAPI *fnSetupDiDestroyDriverInfoList) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType); +fnSetupDiDestroyDriverInfoList g_pfnSetupDiDestroyDriverInfoList = NULL; + +typedef BOOL (WINAPI *fnSetupDiDestroyDeviceInfoList) (HDEVINFO DeviceInfoSet); +fnSetupDiDestroyDeviceInfoList g_pfnSetupDiDestroyDeviceInfoList = NULL; + +typedef BOOL (WINAPI *fnSetupDiGetDeviceInfoListDetail) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_LIST_DETAIL_DATA DeviceInfoSetDetailData); +fnSetupDiGetDeviceInfoListDetail g_pfnSetupDiGetDeviceInfoListDetail = NULL; + +/***/ + +typedef BOOL (WINAPI *fnSetupDiSetDeviceRegistryProperty) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, CONST BYTE *PropertyBuffer, DWORD PropertyBufferSize); +fnSetupDiSetDeviceRegistryProperty g_pfnSetupDiSetDeviceRegistryProperty = NULL; + +typedef BOOL (WINAPI *fnSetupDiGetDeviceRegistryProperty) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer, + DWORD PropertyBufferSize, PDWORD RequiredSize); +fnSetupDiGetDeviceRegistryProperty g_pfnSetupDiGetDeviceRegistryProperty = NULL; + +/***/ + +typedef BOOL (WINAPI *fnSetupDiCallClassInstaller) (DI_FUNCTION InstallFunction, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData); +fnSetupDiCallClassInstaller g_pfnSetupDiCallClassInstaller = NULL; + +typedef BOOL (WINAPI *fnSetupDiClassGuidsFromNameEx) (PCTSTR ClassName, LPGUID ClassGuidList, DWORD ClassGuidListSize, PDWORD RequiredSize, PCTSTR MachineName, PVOID Reserved); +fnSetupDiClassGuidsFromNameEx g_pfnSetupDiClassGuidsFromNameEx = NULL; + +typedef HDEVINFO (WINAPI *fnSetupDiGetClassDevsEx) (LPGUID ClassGuid, PCTSTR Enumerator, HWND hwndParent, DWORD Flags, HDEVINFO DeviceInfoSet, PCTSTR MachineName, PVOID Reserved); +fnSetupDiGetClassDevsEx g_pfnSetupDiGetClassDevsEx = NULL; + +typedef BOOL (WINAPI *fnSetupDiSetClassInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_CLASSINSTALL_HEADER ClassInstallParams, DWORD ClassInstallParamsSize); +fnSetupDiSetClassInstallParams g_pfnSetupDiSetClassInstallParams = NULL; + +typedef BOOL (WINAPI *fnSetupDiGetDeviceInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DEVINSTALL_PARAMS DeviceInstallParams); +fnSetupDiGetDeviceInstallParams g_pfnSetupDiGetDeviceInstallParams = NULL; + +typedef HKEY (WINAPI *fnSetupDiOpenDevRegKey) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired); +fnSetupDiOpenDevRegKey g_pfnSetupDiOpenDevRegKey = NULL; + +typedef BOOL (WINAPI *fnSetupDiBuildDriverInfoList) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType); +fnSetupDiBuildDriverInfoList g_pfnSetupDiBuildDriverInfoList = NULL; + +typedef BOOL (WINAPI *fnSetupDiEnumDriverInfo) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType, DWORD MemberIndex, PSP_DRVINFO_DATA DriverInfoData); +fnSetupDiEnumDriverInfo g_pfnSetupDiEnumDriverInfo = NULL; + +typedef BOOL (WINAPI *fnSetupDiGetDriverInfoDetail) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DRVINFO_DATA DriverInfoData, PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData, + DWORD DriverInfoDetailDataSize, PDWORD RequiredSize); +fnSetupDiGetDriverInfoDetail g_pfnSetupDiGetDriverInfoDetail = NULL; + +typedef BOOL (WINAPI *fnSetupDiSetSelectedDriver) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DRVINFO_DATA DriverInfoData); +fnSetupDiSetSelectedDriver g_pfnSetupDiSetSelectedDriver = NULL; + +typedef BOOL (WINAPI *fnSetupDiSetDeviceInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DEVINSTALL_PARAMS DeviceInstallParams); +fnSetupDiSetDeviceInstallParams g_pfnSetupDiSetDeviceInstallParams = NULL; + +typedef CONFIGRET (WINAPI *fnCM_Get_Device_ID_Ex) (DEVINST dnDevInst, PTCHAR Buffer, ULONG BufferLen, ULONG ulFlags, HMACHINE hMachine); +fnCM_Get_Device_ID_Ex g_pfnCM_Get_Device_ID_Ex = NULL; + +typedef BOOL (WINAPI* fnSetupCopyOEMInf) (PCTSTR SourceInfFileName, PCTSTR OEMSourceMediaLocation, DWORD OEMSourceMediaType, DWORD CopyStyle, PTSTR DestinationInfFileName, + DWORD DestinationInfFileNameSize, PDWORD RequiredSize, PTSTR DestinationInfFileNameComponent); +fnSetupCopyOEMInf g_pfnSetupCopyOEMInf = NULL; + +typedef BOOL (WINAPI* fnUpdateDriverForPlugAndPlayDevices) (HWND hwndParent, LPCTSTR HardwareId, LPCTSTR FullInfPath, DWORD InstallFlags, PBOOL bRebootRequired); +fnUpdateDriverForPlugAndPlayDevices g_pfnUpdateDriverForPlugAndPlayDevices = NULL; + +#define VBOX_LOAD_API( a_hModule, a_Func ) \ +{ \ + g_pfn##a_Func = (fn##a_Func)GetProcAddress(a_hModule, "##a_Func"); \ + _tprintf (_T("API call ##a_Func loaded: %p\n"), g_pfn##a_Func); \ +} + +int LoadAPICalls () +{ + int rc = ERROR_SUCCESS; + OSVERSIONINFO OSinfo; + OSinfo.dwOSVersionInfoSize = sizeof(OSinfo); + GetVersionEx(&OSinfo); + +#ifdef _DEBUG + _tprintf (_T("Loading API calls ...\n")); +#endif + + /* Use unicode calls where available. */ + if (OSinfo.dwMajorVersion >= 5) /* APIs available only on W2K and up! */ + { + g_hSetupAPI = LoadLibrary(_T("SetupAPI")); + if (NULL == g_hSetupAPI) + { + _tprintf(_T("ERROR: SetupAPI.dll not found! Return code: %d\n"), GetLastError()); + rc = ERROR_NOT_INSTALLED; + } + else + { + g_pfnSetupDiCreateDeviceInfoList = (fnSetupDiCreateDeviceInfoList)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoList"); + g_pfnSetupDiCreateDeviceInfo = (fnSetupDiCreateDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoW"); + g_pfnSetupDiSetDeviceRegistryProperty = (fnSetupDiSetDeviceRegistryProperty)GetProcAddress(g_hSetupAPI, "SetupDiSetDeviceRegistryPropertyW"); + g_pfnSetupDiCallClassInstaller = (fnSetupDiCallClassInstaller)GetProcAddress(g_hSetupAPI, "SetupDiCallClassInstaller"); + g_pfnSetupDiDestroyDeviceInfoList = (fnSetupDiDestroyDeviceInfoList)GetProcAddress(g_hSetupAPI, "SetupDiDestroyDeviceInfoList"); + g_pfnSetupDiClassGuidsFromNameEx = (fnSetupDiClassGuidsFromNameEx)GetProcAddress(g_hSetupAPI, "SetupDiClassGuidsFromNameExW"); + g_pfnSetupDiGetDeviceRegistryProperty = (fnSetupDiGetDeviceRegistryProperty)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceRegistryPropertyW"); + g_pfnSetupDiGetClassDevsEx = (fnSetupDiGetClassDevsEx)GetProcAddress(g_hSetupAPI, "SetupDiGetClassDevsExW"); + g_pfnSetupDiCreateDeviceInfoListEx = (fnSetupDiCreateDeviceInfoListEx)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoListExW"); + g_pfnSetupDiOpenDeviceInfo = (fnSetupDiOpenDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiOpenDeviceInfoW"); + g_pfnSetupDiGetDeviceInfoListDetail = (fnSetupDiGetDeviceInfoListDetail)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceInfoListDetailW"); + g_pfnSetupDiEnumDeviceInfo = (fnSetupDiEnumDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiEnumDeviceInfo"); + g_pfnSetupDiSetClassInstallParams = (fnSetupDiSetClassInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiSetClassInstallParamsW"); + g_pfnSetupDiGetDeviceInstallParams = (fnSetupDiGetDeviceInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceInstallParamsW"); + g_pfnSetupDiOpenDevRegKey = (fnSetupDiOpenDevRegKey)GetProcAddress(g_hSetupAPI, "SetupDiOpenDevRegKey"); + g_pfnSetupDiBuildDriverInfoList = (fnSetupDiBuildDriverInfoList)GetProcAddress(g_hSetupAPI, "SetupDiBuildDriverInfoList"); + g_pfnSetupDiEnumDriverInfo = (fnSetupDiEnumDriverInfo)GetProcAddress(g_hSetupAPI, "SetupDiEnumDriverInfoW"); + g_pfnSetupDiGetDriverInfoDetail = (fnSetupDiGetDriverInfoDetail)GetProcAddress(g_hSetupAPI, "SetupDiGetDriverInfoDetailW"); + g_pfnSetupDiDestroyDriverInfoList = (fnSetupDiDestroyDriverInfoList)GetProcAddress(g_hSetupAPI, "SetupDiDestroyDriverInfoList"); + g_pfnSetupDiSetSelectedDriver = (fnSetupDiSetSelectedDriver)GetProcAddress(g_hSetupAPI, "SetupDiSetSelectedDriverW"); + g_pfnSetupDiSetDeviceInstallParams = (fnSetupDiSetDeviceInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiSetDeviceInstallParamsW"); + g_pfnSetupCopyOEMInf = (fnSetupCopyOEMInf)GetProcAddress(g_hSetupAPI, "SetupCopyOEMInfW"); + } + + if (rc == ERROR_SUCCESS) + { + g_hNewDev = LoadLibrary(_T("NewDev")); + if (NULL != g_hNewDev) + { + g_pfnUpdateDriverForPlugAndPlayDevices = (fnUpdateDriverForPlugAndPlayDevices)GetProcAddress(g_hNewDev, "UpdateDriverForPlugAndPlayDevicesW"); + } + else + { + _tprintf(_T("ERROR: NewDev.dll not found! Return code: %d\n"), GetLastError()); + rc = ERROR_FILE_NOT_FOUND; + } + } + + if (rc == ERROR_SUCCESS) + { + g_hCfgMgr = LoadLibrary(_T("CfgMgr32")); + if (NULL != g_hCfgMgr) + { + g_pfnCM_Get_Device_ID_Ex = (fnCM_Get_Device_ID_Ex)GetProcAddress(g_hCfgMgr, "CM_Get_Device_ID_ExW"); + } + else + { + _tprintf(_T("ERROR: NewDev.dll not found! Return code: %d\n"), GetLastError()); + rc = ERROR_FILE_NOT_FOUND; + } + } + } + else if (OSinfo.dwMajorVersion <= 4) /* Windows NT 4.0. */ + { + /* Nothing to do here yet. */ + } + else /* Other platforms */ + { + _tprintf(_T("ERROR: Platform not supported yet!\n")); + rc = ERROR_NOT_SUPPORTED; + } + + return rc; +} + +void FreeAPICalls () +{ +#ifdef _DEBUG + _tprintf (_T("Freeing API calls ...\n")); +#endif + + if (NULL != g_hSetupAPI) + FreeLibrary(g_hSetupAPI); + + if (NULL != g_hNewDev) + FreeLibrary(g_hNewDev); + + if (NULL != g_hCfgMgr) + FreeLibrary(g_hCfgMgr); +} + +bool GetErrorMsg (DWORD a_dwLastError, _TCHAR* a_pszMsg, DWORD a_dwBufSize) +{ + if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, a_dwLastError, 0, a_pszMsg, a_dwBufSize, NULL) == 0) + { + _stprintf(a_pszMsg, _T("Unknown error!\n"), a_dwLastError); + return false; + } + else + { + _TCHAR* p = _tcschr(a_pszMsg, _T('\r')); + + if (p != NULL) + *p = _T('\0'); + } + + return true; +} + +/* @todo Add exception handling instead of crappy goto's! */ + +int CreateDevice (_TCHAR* a_pszHwID, GUID a_devClass) +{ + int iRet = EXIT_OK; + HDEVINFO devInfoSet; + SP_DEVINFO_DATA devInfoData; + DWORD dwErr = 0; + _TCHAR szErrMsg[_MAX_PATH + 1] = { 0 }; + + _tprintf(_T("Creating device ...\n")); + + devInfoSet = g_pfnSetupDiCreateDeviceInfoList(&a_devClass, NULL); + if (devInfoSet == INVALID_HANDLE_VALUE) + { + _tprintf(_T("Could not build device info list!\n")); + return EXIT_FAIL; + } + + devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + if (FALSE == g_pfnSetupDiCreateDeviceInfo(devInfoSet, a_pszHwID, &a_devClass, NULL, NULL, DICD_GENERATE_ID, &devInfoData)) + { + dwErr = GetLastError(); + + switch (dwErr) + { + + case ERROR_DEVINST_ALREADY_EXISTS: + + _tprintf(_T("Device already exists.\n")); + break; + + case ERROR_CLASS_MISMATCH: + + _tprintf(_T("ERROR: Device does not match to class ID!\n")); + break; + + case ERROR_INVALID_USER_BUFFER: + + _tprintf(_T("ERROR: Invalid user buffer!\n")); + break; + + case ERROR_INVALID_DEVINST_NAME: + + _tprintf(_T("ERROR: Invalid device instance name!\n")); + break; + + default: + + GetErrorMsg(dwErr, szErrMsg, sizeof(szErrMsg)); + _tprintf(_T("ERROR (%08x): %ws\n"), dwErr, szErrMsg); + break; + } + + iRet = EXIT_FAIL; + goto InstallCleanup; + } + + if (FALSE == g_pfnSetupDiSetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_HARDWAREID, (LPBYTE)a_pszHwID, (DWORD)((_tcsclen(a_pszHwID) + 2) * sizeof(_TCHAR)))) + { + dwErr = GetLastError(); + _tprintf(_T("Could not set device registry info!\n")); + iRet = EXIT_FAIL; + goto InstallCleanup; + } + + if (FALSE == g_pfnSetupDiCallClassInstaller(DIF_REGISTERDEVICE, devInfoSet, &devInfoData)) + { + dwErr = GetLastError(); + _tprintf(_T("Could not register device!\n")); + iRet = EXIT_FAIL; + goto InstallCleanup; + } + + InstallCleanup: g_pfnSetupDiDestroyDeviceInfoList(devInfoSet); + + return iRet; +} + +int InstallDriver (_TCHAR* a_pszInfFile, _TCHAR* a_pszHwID, _TCHAR* a_pszDevClass) +{ + DWORD dwErr = 0; + BOOL bReboot = FALSE; + + _TCHAR szInf[_MAX_PATH] = { 0 }; /* Full path + .INF file */ + _TCHAR szInfPath[_MAX_PATH] = { 0 }; /* Full path to .INF file */ + GUID devClassArr[32]; /* The device class GUID array */ + DWORD dwReqSize = 0; /* Number of GUIDs in array after lookup */ + + _tprintf(_T("Installing driver ...\n")); + _tprintf(_T("HardwareID: %ws\n"), a_pszHwID); + _tprintf(_T("Device class name: %ws\n"), a_pszDevClass); + + /* Retrieve GUID of device class */ + /* Not used here: g_pfnSetupDiClassNameFromGuidEx( ... ) */ + if (FALSE == g_pfnSetupDiClassGuidsFromNameEx(a_pszDevClass, devClassArr, 32, &dwReqSize, NULL, NULL)) + { + _tprintf(_T("Could not retrieve device class GUID! Error: %ld\n"), GetLastError()); + return EXIT_FAIL; + } + else + { + /* Do not fail if dwReqSize is 0. For whatever reason Windows Server 2008 Core does not have the "Media" + device class installed. Maybe they stripped down too much? :-/ */ + if (dwReqSize <= 0) + { + _tprintf(_T("WARNING: No device class with this name found! ReqSize: %ld, Error: %ld\n"), dwReqSize, GetLastError()); + } + else + { + _tprintf(_T("Number of GUIDs found: %ld\n"), dwReqSize); + } + + /* Not needed for now! + if (EXIT_FAIL == CreateDevice (a_pszHwID, devClassArr[0])) + return EXIT_FAIL;*/ + } + + _TCHAR* pcFile = NULL; + if (0 == GetFullPathName(a_pszInfFile, _MAX_PATH, szInf, &pcFile)) + { + dwErr = GetLastError(); + + _tprintf(_T("ERROR: INF-Path too long / could not be retrieved!\n")); + return EXIT_FAIL; + } + + /* Extract path from path+INF */ + if (pcFile != NULL) + _tcsnccpy(szInfPath, szInf, pcFile - szInf); + + _tprintf(_T("INF-File: %ws\n"), szInf); + _tprintf(_T("INF-Path: %ws\n"), szInfPath); + + _tprintf(_T("Updating driver for plug'n play devices ...\n")); + if (!g_pfnUpdateDriverForPlugAndPlayDevices(NULL, a_pszHwID, szInf, INSTALLFLAG_FORCE, &bReboot)) + { + DWORD dwErr = GetLastError(); + _TCHAR szErrMsg[_MAX_PATH + 1] = { 0 }; + + if (dwErr == ERROR_NO_SUCH_DEVINST) + { + _TCHAR szDestInf[_MAX_PATH] = { 0 }; + _tprintf(_T("The device is not plugged in (yet), pre-installing drivers ...\n")); + + if (FALSE == g_pfnSetupCopyOEMInf(szInf, szInfPath, SPOST_PATH, 0, szDestInf, sizeof(szDestInf), NULL, NULL)) + { + dwErr = GetLastError(); + GetErrorMsg(dwErr, szErrMsg, sizeof(szErrMsg)); + _tprintf(_T("ERROR (%08x): %ws\n"), dwErr, szErrMsg); + return EXIT_FAIL; + } + + _tprintf(_T("OK. Installed to: %ws\n"), szDestInf); + return EXIT_OK; + } + + switch (dwErr) + { + + case ERROR_INVALID_FLAGS: + + _tprintf(_T("ERROR: The value specified for InstallFlags is invalid!\n")); + break; + + case ERROR_NO_MORE_ITEMS: + + _tprintf( + _T( + "ERROR: The function found a match for the HardwareId value, but the specified driver was not a better match than the current driver and the caller did not specify the INSTALLFLAG_FORCE flag!\n")); + break; + + case ERROR_FILE_NOT_FOUND: + + _tprintf(_T("ERROR: File not found!\n")); + break; + + case ERROR_IN_WOW64: + + _tprintf(_T("ERROR: The calling application is a 32-bit application attempting to execute in a 64-bit environment, which is not allowed!")); + break; + + case ERROR_NO_DRIVER_SELECTED: + + _tprintf(_T("ERROR: No driver in .INF-file selected!\n")); + break; + + case ERROR_SECTION_NOT_FOUND: + + _tprintf(_T("ERROR: Section in .INF-file was not found!\n")); + break; + + default: + + /* Try error lookup with GetErrorMsg() */ + GetErrorMsg(dwErr, szErrMsg, sizeof(szErrMsg)); + _tprintf(_T("ERROR (%08x): %ws\n"), dwErr, szErrMsg); + break; + } + + return EXIT_FAIL; + } + + _tprintf(_T("Installation successful.\n")); + + return EXIT_OK; +} + +/*++ + + Routine Description: + + Determine if this is instance id or hardware id and if there's any wildcards + instance ID is prefixed by '@' + wildcards are '*' + + + Arguments: + + Id - ptr to string to check + + Return Value: + + IdEntry + + --*/ +IdEntry GetIdType (LPCTSTR Id) +{ + IdEntry Entry; + + Entry.bInstanceId = FALSE; + Entry.szWild = NULL; + Entry.szString = Id; + + if (Entry.szString[0] == INSTANCEID_PREFIX_CHAR) + { + Entry.bInstanceId = TRUE; + Entry.szString = CharNext(Entry.szString); + } + if (Entry.szString[0] == QUOTE_PREFIX_CHAR) + { + /* prefix to treat rest of string literally */ + Entry.szString = CharNext(Entry.szString); + } + else + { + /* see if any wild characters exist */ + Entry.szWild = _tcschr(Entry.szString, WILD_CHAR); + } + return Entry; +} + +/*++ + + Routine Description: + + Get an index array pointing to the MultiSz passed in + + Arguments: + + MultiSz - well formed multi-sz string + + Return Value: + + array of strings. last entry+1 of array contains NULL + returns NULL on failure + + --*/ +LPTSTR * GetMultiSzIndexArray (LPTSTR MultiSz) +{ + LPTSTR scan; + LPTSTR * array; + int elements; + + for (scan = MultiSz, elements = 0; scan[0]; elements++) + { + scan += lstrlen(scan) + 1; + } + array = new LPTSTR[elements + 2]; + if (!array) + { + return NULL; + } + array[0] = MultiSz; + array++; + if (elements) + { + for (scan = MultiSz, elements = 0; scan[0]; elements++) + { + array[elements] = scan; + scan += lstrlen(scan) + 1; + } + } + array[elements] = NULL; + return array; +} + +/*++ + + Routine Description: + + Deletes the string array allocated by GetDevMultiSz/GetRegMultiSz/GetMultiSzIndexArray + + Arguments: + + Array - pointer returned by GetMultiSzIndexArray + + Return Value: + + None + + --*/ +void DelMultiSz (LPTSTR * Array) +{ + if (Array) + { + Array--; + if (Array[0]) + { + delete[] Array[0]; + } + delete[] Array; + } +} + +/*++ + + Routine Description: + + Get a multi-sz device property + and return as an array of strings + + Arguments: + + Devs - HDEVINFO containing DevInfo + DevInfo - Specific device + Prop - SPDRP_HARDWAREID or SPDRP_COMPATIBLEIDS + + Return Value: + + array of strings. last entry+1 of array contains NULL + returns NULL on failure + + --*/ +LPTSTR * GetDevMultiSz (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Prop) +{ + LPTSTR buffer; + DWORD size; + DWORD reqSize; + DWORD dataType; + LPTSTR * array; + DWORD szChars; + + size = 8192; /* initial guess, nothing magic about this */ + buffer = new TCHAR[(size / sizeof(TCHAR)) + 2]; + if (!buffer) + { + return NULL; + } + while (!g_pfnSetupDiGetDeviceRegistryProperty(Devs, DevInfo, Prop, &dataType, (LPBYTE)buffer, size, &reqSize)) + { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + goto failed; + } + if (dataType != REG_MULTI_SZ) + { + goto failed; + } + size = reqSize; + delete[] buffer; + buffer = new TCHAR[(size / sizeof(TCHAR)) + 2]; + if (!buffer) + { + goto failed; + } + } + szChars = reqSize / sizeof(TCHAR); + buffer[szChars] = TEXT('\0'); + buffer[szChars + 1] = TEXT('\0'); + array = GetMultiSzIndexArray(buffer); + if (array) + { + return array; + } + + failed: if (buffer) + { + delete[] buffer; + } + return NULL; +} + +/*++ + + Routine Description: + + Compare a single item against wildcard + I'm sure there's better ways of implementing this + Other than a command-line management tools + it's a bad idea to use wildcards as it implies + assumptions about the hardware/instance ID + eg, it might be tempting to enumerate root\* to + find all root devices, however there is a CfgMgr + API to query status and determine if a device is + root enumerated, which doesn't rely on implementation + details. + + Arguments: + + Item - item to find match for eg a\abcd\c + MatchEntry - eg *\*bc*\* + + Return Value: + + TRUE if any match, otherwise FALSE + + --*/ +BOOL WildCardMatch (LPCTSTR Item, const IdEntry & MatchEntry) +{ + LPCTSTR scanItem; + LPCTSTR wildMark; + LPCTSTR nextWild; + size_t matchlen; + + /* Before attempting anything else, + try and compare everything up to first wild */ + // + if (!MatchEntry.szWild) + { + return _tcsicmp(Item, MatchEntry.szString) ? FALSE : TRUE; + } + if (_tcsnicmp(Item, MatchEntry.szString, MatchEntry.szWild - MatchEntry.szString) != 0) + { + return FALSE; + } + wildMark = MatchEntry.szWild; + scanItem = Item + (MatchEntry.szWild - MatchEntry.szString); + + for (; wildMark[0];) + { + /* If we get here, we're either at or past a wildcard */ + if (wildMark[0] == WILD_CHAR) + { + /* So skip wild chars */ + wildMark = CharNext(wildMark); + continue; + } + + /* Find next wild-card */ + nextWild = _tcschr(wildMark, WILD_CHAR); + + if (nextWild) + { + /* Substring */ + matchlen = nextWild - wildMark; + } + else + { + /* Last portion of match */ + size_t scanlen = lstrlen(scanItem); + matchlen = lstrlen(wildMark); + + if (scanlen < matchlen) + { + return FALSE; + } + + return _tcsicmp(scanItem + scanlen - matchlen, wildMark) ? FALSE : TRUE; + } + + if (_istalpha(wildMark[0])) + { + /* Scan for either lower or uppercase version of first character */ + TCHAR u = _totupper(wildMark[0]); + TCHAR l = _totlower(wildMark[0]); + while (scanItem[0] && scanItem[0] != u && scanItem[0] != l) + { + scanItem = CharNext(scanItem); + } + + if (!scanItem[0]) + { + /* Ran out of string */ + return FALSE; + } + } + else + { + /* Scan for first character (no case) */ + scanItem = _tcschr(scanItem, wildMark[0]); + if (!scanItem) + { + /* Ran out of string */ + return FALSE; + } + } + + /* Try and match the sub-string at wildMark against scanItem */ + if (_tcsnicmp(scanItem, wildMark, matchlen) != 0) + { + /* Nope, try again */ + scanItem = CharNext(scanItem); + continue; + } + + /* Substring matched */ + scanItem += matchlen; + wildMark += matchlen; + } + return (wildMark[0] ? FALSE : TRUE); +} + +/*++ + + Routine Description: + + Compares all strings in Array against Id + Use WildCardMatch to do real compare + + Arguments: + + Array - pointer returned by GetDevMultiSz + MatchEntry - string to compare against + + Return Value: + + TRUE if any match, otherwise FALSE + + --*/ +BOOL WildCompareHwIds (LPTSTR * Array, const IdEntry & MatchEntry) +{ + if (Array) + { + while (Array[0]) + { + if (WildCardMatch(Array[0], MatchEntry)) + { + return TRUE; + } + Array++; + } + } + return FALSE; +} + +/*++ + + Routine Description: + + Generic enumerator for devices that will be passed the following arguments: + <id> [<id>...] + =<class> [<id>...] + where <id> can either be @instance-id, or hardware-id and may contain wildcards + <class> is a class name + + Arguments: + + BaseName - name of executable + Machine - name of machine to enumerate + Flags - extra enumeration flags (eg DIGCF_PRESENT) + argc/argv - remaining arguments on command line + Callback - function to call for each hit + Context - data to pass function for each hit + + Return Value: + + EXIT_xxxx + + --*/ +int EnumerateDevices (LPCTSTR BaseName, LPCTSTR Machine, DWORD Flags, int argc, LPTSTR argv[], fnCallback Callback, LPVOID Context) +{ + HDEVINFO devs = INVALID_HANDLE_VALUE; + IdEntry * templ = NULL; + int failcode = EXIT_FAIL; + int retcode; + int argIndex; + DWORD devIndex; + SP_DEVINFO_DATA devInfo; + SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail; + BOOL doSearch = FALSE; + BOOL match; + BOOL all = FALSE; + GUID cls; + DWORD numClass = 0; + int skip = 0; + + if (!argc) + { + return EXIT_USAGE; + } + + templ = new IdEntry[argc]; + if (!templ) + { + goto final; + } + + /* Determine if a class is specified */ + if (argc > skip && argv[skip][0] == CLASS_PREFIX_CHAR && argv[skip][1]) + { + if (!g_pfnSetupDiClassGuidsFromNameEx(argv[skip] + 1, &cls, 1, &numClass, Machine, NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + goto final; + } + if (!numClass) + { + failcode = EXIT_OK; + goto final; + } + skip++; + } + + if (argc > skip && argv[skip][0] == WILD_CHAR && !argv[skip][1]) + { + /* Catch convinient case of specifying a single argument '*' */ + all = TRUE; + skip++; + } + else if (argc <= skip) + { + /* At least one parameter, but no <id>'s */ + all = TRUE; + } + + /* Determine if any instance id's were specified */ + + /* Note, if =<class> was specified with no id's + we'll mark it as not doSearch + but will go ahead and add them all */ + for (argIndex = skip; argIndex < argc; argIndex++) + { + templ[argIndex] = GetIdType(argv[argIndex]); + if (templ[argIndex].szWild || !templ[argIndex].bInstanceId) + { + /* Anything other than simple bInstanceId's require a search */ + doSearch = TRUE; + } + } + if (doSearch || all) + { + /* Add all id's to list + If there's a class, filter on specified class */ + devs = g_pfnSetupDiGetClassDevsEx(numClass ? &cls : NULL, NULL, NULL, (numClass ? 0 : DIGCF_ALLCLASSES) | Flags, NULL, Machine, NULL); + + } + else + { + /* Blank list, we'll add instance id's by hand */ + devs = g_pfnSetupDiCreateDeviceInfoListEx(numClass ? &cls : NULL, NULL, Machine, NULL); + } + if (devs == INVALID_HANDLE_VALUE) + { + goto final; + } + for (argIndex = skip; argIndex < argc; argIndex++) + { + /* Add explicit instances to list (even if enumerated all, + this gets around DIGCF_PRESENT) + do this even if wildcards appear to be detected since they + might actually be part of the instance ID of a non-present device */ + if (templ[argIndex].bInstanceId) + { + g_pfnSetupDiOpenDeviceInfo(devs, templ[argIndex].szString, NULL, 0, NULL); + } + } + + devInfoListDetail.cbSize = sizeof(devInfoListDetail); + if (!g_pfnSetupDiGetDeviceInfoListDetail(devs, &devInfoListDetail)) + { + goto final; + } + + /* Now enumerate them */ + if (all) + { + doSearch = FALSE; + } + + devInfo.cbSize = sizeof(devInfo); + for (devIndex = 0; g_pfnSetupDiEnumDeviceInfo(devs, devIndex, &devInfo); devIndex++) + { + + if (doSearch) + { + for (argIndex = skip, match = FALSE; (argIndex < argc) && !match; argIndex++) + { + TCHAR devID[MAX_DEVICE_ID_LEN]; + LPTSTR *hwIds = NULL; + LPTSTR *compatIds = NULL; + + /* Determine instance ID */ + if (g_pfnCM_Get_Device_ID_Ex(devInfo.DevInst, devID, MAX_DEVICE_ID_LEN, 0, devInfoListDetail.RemoteMachineHandle) != CR_SUCCESS) + { + devID[0] = TEXT('\0'); + } + + if (templ[argIndex].bInstanceId) + { + /* Match on the instance ID */ + if (WildCardMatch(devID, templ[argIndex])) + match = TRUE; + + } + else + { + /* Determine hardware ID's and search for matches */ + hwIds = GetDevMultiSz(devs, &devInfo, SPDRP_HARDWAREID); + compatIds = GetDevMultiSz(devs, &devInfo, SPDRP_COMPATIBLEIDS); + + if (WildCompareHwIds(hwIds, templ[argIndex]) || WildCompareHwIds(compatIds, templ[argIndex])) + { + match = TRUE; + } + } + DelMultiSz(hwIds); + DelMultiSz(compatIds); + } + } + else + { + match = TRUE; + } + if (match) + { + retcode = Callback(devs, &devInfo, devIndex, Context); + if (retcode) + { + failcode = retcode; + goto final; + } + } + } + + failcode = EXIT_OK; + + final: if (templ) + { + delete[] templ; + } + if (devs != INVALID_HANDLE_VALUE) + { + g_pfnSetupDiDestroyDeviceInfoList(devs); + } + return failcode; + +} + +/*++ + + Routine Description: + + Callback for use by Remove + Invokes DIF_REMOVE + uses g_pfnSetupDiCallClassInstaller so cannot be done for remote devices + Don't use CM_xxx API's, they bypass class/co-installers and this is bad. + + Arguments: + + Devs )_ uniquely identify the device + DevInfo ) + Index - index of device + Context - GenericContext + + Return Value: + + EXIT_xxxx + + --*/ +int UninstallCallback (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context) +{ + SP_REMOVEDEVICE_PARAMS rmdParams; + SP_DEVINSTALL_PARAMS devParams; + LPCTSTR action = NULL; + + /* Need hardware ID before trying to remove, as we wont have it after */ + TCHAR devID[MAX_DEVICE_ID_LEN]; + SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail; + + devInfoListDetail.cbSize = sizeof(devInfoListDetail); + + if ((!g_pfnSetupDiGetDeviceInfoListDetail(Devs, &devInfoListDetail)) || (g_pfnCM_Get_Device_ID_Ex(DevInfo->DevInst, devID, MAX_DEVICE_ID_LEN, 0, devInfoListDetail.RemoteMachineHandle) + != CR_SUCCESS)) + { + /* Skip this */ + return EXIT_OK; + } + + rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE; + rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL; + rmdParams.HwProfile = 0; + + if (!g_pfnSetupDiSetClassInstallParams(Devs, DevInfo, &rmdParams.ClassInstallHeader, sizeof(rmdParams)) || !g_pfnSetupDiCallClassInstaller(DIF_REMOVE, Devs, DevInfo)) + { + /* Failed to invoke DIF_REMOVE, TODO! */ + _tprintf(_T("Failed to invoke interface!\n")); + return EXIT_FAIL; + } + + /* See if device needs reboot */ + devParams.cbSize = sizeof(devParams); + if (g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &devParams) && (devParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))) + { + /* Reboot required */ + _tprintf(_T("To fully uninstall, a reboot is required!\n")); + } + else + { + /* Appears to have succeeded */ + _tprintf(_T("Uninstall succeeded!\n")); + } + + return EXIT_OK; +} + +/*++ + + Routine Description: + + Find the driver that is associated with the current device + We can do this either the quick way (available in WinXP) + or the long way that works in Win2k. + + Arguments: + + Devs )_ uniquely identify device + DevInfo ) + + Return Value: + + TRUE if we managed to determine and select current driver + + --*/ +BOOL FindCurrentDriver (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, PSP_DRVINFO_DATA DriverInfoData) +{ + SP_DEVINSTALL_PARAMS deviceInstallParams; + WCHAR SectionName[LINE_LEN]; + WCHAR DrvDescription[LINE_LEN]; + WCHAR MfgName[LINE_LEN]; + WCHAR ProviderName[LINE_LEN]; + HKEY hKey = NULL; + DWORD RegDataLength; + DWORD RegDataType; + DWORD c; + BOOL match = FALSE; + long regerr; + + ZeroMemory(&deviceInstallParams, sizeof(deviceInstallParams)); + deviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); + + if (!g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams)) + { + printf("Could not retrieve install params!"); + return FALSE; + } + +#ifdef DI_FLAGSEX_INSTALLEDDRIVER + + /* Set the flags that tell g_pfnSetupDiBuildDriverInfoList to just put the + currently installed driver node in the list, and that it should allow + excluded drivers. This flag introduced in WinXP. */ + deviceInstallParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS); + + if (g_pfnSetupDiSetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams)) + { + /* We were able to specify this flag, so proceed the easy way + We should get a list of no more than 1 driver */ + if (!g_pfnSetupDiBuildDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER)) + { + return FALSE; + } + if (!g_pfnSetupDiEnumDriverInfo(Devs, DevInfo, SPDIT_CLASSDRIVER, 0, DriverInfoData)) + { + return FALSE; + } + + /* We've selected the current driver */ + return TRUE; + } + + deviceInstallParams.FlagsEx &= ~(DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS); + +#endif + + /* The following method works in Win2k, but it's slow and painful. + First, get driver key - if it doesn't exist, no driver */ + hKey = g_pfnSetupDiOpenDevRegKey(Devs, DevInfo, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ + ); + + if (hKey == INVALID_HANDLE_VALUE) + { + + _tprintf(_T("No associated driver found in registry!")); + + /* No such value exists, so there can't be an associated driver */ + RegCloseKey(hKey); + return FALSE; + } + + /* Obtain path of INF - we'll do a search on this specific INF */ + RegDataLength = sizeof(deviceInstallParams.DriverPath); /* Bytes!!! */ + regerr = RegQueryValueEx(hKey, REGSTR_VAL_INFPATH, NULL, &RegDataType, (PBYTE)deviceInstallParams.DriverPath, &RegDataLength); + + if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ)) + { + + _tprintf(_T("No associated .inf path found in registry!")); + + /* No such value exists, so no associated driver */ + RegCloseKey(hKey); + return FALSE; + } + + /* Obtain name of Provider to fill into DriverInfoData */ + RegDataLength = sizeof(ProviderName); /* Bytes!!! */ + regerr = RegQueryValueEx(hKey, REGSTR_VAL_PROVIDER_NAME, NULL, &RegDataType, (PBYTE)ProviderName, &RegDataLength); + + if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ)) + { + /* No such value exists, so we don't have a valid associated driver */ + RegCloseKey(hKey); + return FALSE; + } + + /* Obtain name of section - for final verification */ + RegDataLength = sizeof(SectionName); /* Bytes!!! */ + regerr = RegQueryValueEx(hKey, REGSTR_VAL_INFSECTION, NULL, &RegDataType, (PBYTE)SectionName, &RegDataLength); + + if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ)) + { + /* No such value exists, so we don't have a valid associated driver */ + RegCloseKey(hKey); + return FALSE; + } + + /* Driver description (need not be same as device description) - for final verification */ + RegDataLength = sizeof(DrvDescription); /* Bytes!!! */ + regerr = RegQueryValueEx(hKey, REGSTR_VAL_DRVDESC, NULL, &RegDataType, (PBYTE)DrvDescription, &RegDataLength); + + RegCloseKey(hKey); + + if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ)) + { + /* No such value exists, so we don't have a valid associated driver */ + return FALSE; + } + + /* Manufacturer (via SPDRP_MFG, don't access registry directly!) */ + if (!g_pfnSetupDiGetDeviceRegistryProperty(Devs, DevInfo, SPDRP_MFG, NULL, /* Datatype is guaranteed to always be REG_SZ */ + (PBYTE)MfgName, sizeof(MfgName), /* Bytes!!! */ + NULL)) + { + /* No such value exists, so we don't have a valid associated driver */ + return FALSE; + } + + /* Now search for drivers listed in the INF */ + deviceInstallParams.Flags |= DI_ENUMSINGLEINF; + deviceInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS; + + if (!g_pfnSetupDiSetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams)) + { + return FALSE; + } + if (!g_pfnSetupDiBuildDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER)) + { + return FALSE; + } + + /* Find the entry in the INF that was used to install the driver for this device */ + for (c = 0; g_pfnSetupDiEnumDriverInfo(Devs, DevInfo, SPDIT_CLASSDRIVER, c, DriverInfoData); c++) + { + if ((_tcscmp(DriverInfoData->MfgName, MfgName) == 0) && (_tcscmp(DriverInfoData->ProviderName, ProviderName) == 0)) + { + /* These two fields match, try more detailed info to ensure we have the exact driver entry used */ + SP_DRVINFO_DETAIL_DATA detail; + detail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); + if (!g_pfnSetupDiGetDriverInfoDetail(Devs, DevInfo, DriverInfoData, &detail, sizeof(detail), NULL) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) + { + continue; + } + if ((_tcscmp(detail.SectionName, SectionName) == 0) && (_tcscmp(detail.DrvDescription, DrvDescription) == 0)) + { + match = TRUE; + break; + } + } + } + if (!match) + { + g_pfnSetupDiDestroyDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER); + } + return match; +} + +/*++ + + Routine Description: + + if Context provided, Simply count + otherwise dump files indented 2 + + Arguments: + + Context - DWORD Count + Notification - SPFILENOTIFY_QUEUESCAN + Param1 - scan + + Return Value: + + none + + --*/ +UINT DumpDeviceDriversCallback (IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2) +{ + LPDWORD count = (LPDWORD)Context; + LPTSTR file = (LPTSTR)Param1; + if (count) + { + count[0]++; + } + else + { + _tprintf(TEXT("%s\n"), file); + } + + return NO_ERROR; +} + +/*++ + + Routine Description: + + Dump information about what files were installed for driver package + <tab>Installed using OEM123.INF section [abc.NT] + <tab><tab>file... + + Arguments: + + Devs )_ uniquely identify device + DevInfo ) + + Return Value: + + none + + --*/ +int DeleteOEMInfCallback (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context) +{ + /* Do this by 'searching' for the current driver + mimmicing a copy-only install to our own file queue + and then parsing that file queue */ + SP_DEVINSTALL_PARAMS deviceInstallParams; + SP_DRVINFO_DATA driverInfoData; + SP_DRVINFO_DETAIL_DATA driverInfoDetail; + HSPFILEQ queueHandle = INVALID_HANDLE_VALUE; + DWORD count; + DWORD scanResult; + int success = EXIT_FAIL; + + ZeroMemory(&driverInfoData,sizeof(driverInfoData)); + driverInfoData.cbSize = sizeof(driverInfoData); + + if (!FindCurrentDriver(Devs, DevInfo, &driverInfoData)) + return EXIT_FAIL; + + _tprintf(_T("Driver files found!\n")); + + /* Get useful driver information */ + driverInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); + if (!g_pfnSetupDiGetDriverInfoDetail(Devs, DevInfo, &driverInfoData, &driverInfoDetail, sizeof(SP_DRVINFO_DETAIL_DATA), NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + /* No information about driver or section */ + _tprintf(_T("No information about driver or section!\n")); + goto final; + } + + if (!driverInfoDetail.InfFileName[0] || !driverInfoDetail.SectionName[0]) + { + _tprintf(_T("Driver or section name is empty!\n")); + goto final; + } + + _tprintf(_T("Desc: %s\n"), driverInfoDetail.DrvDescription); + _tprintf(_T("SecName: %s\n"), driverInfoDetail.SectionName); + _tprintf(_T("INF-File: %s\n"), driverInfoDetail.InfFileName); + + /* Pretend to do the file-copy part of a driver install + to determine what files are used + the specified driver must be selected as the active driver */ + if (!g_pfnSetupDiSetSelectedDriver(Devs, DevInfo, &driverInfoData)) + goto final; + + /* Create a file queue so we can look at this queue later */ + queueHandle = SetupOpenFileQueue(); + + if (queueHandle == (HSPFILEQ)INVALID_HANDLE_VALUE) + { + goto final; + } + + /* Modify flags to indicate we're providing our own queue */ + ZeroMemory(&deviceInstallParams, sizeof(deviceInstallParams)); + deviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); + if (!g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams)) + goto final; + + /* We want to add the files to the file queue, not install them! */ + deviceInstallParams.FileQueue = queueHandle; + deviceInstallParams.Flags |= DI_NOVCP; + + if (!g_pfnSetupDiSetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams)) + goto final; + + /* Now fill queue with files that are to be installed this involves all class/co-installers */ + if (!g_pfnSetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES, Devs, DevInfo)) + goto final; + + /* We now have a list of delete/rename/copy files + iterate the copy queue twice - 1st time to get # of files + 2nd time to get files (WinXP has API to get # of files, but we want this to work + on Win2k too */ + count = 0; + scanResult = 0; + + /* Call once to count (NOT YET IMPLEMENTED!) */ + //SetupScanFileQueue(queueHandle,SPQ_SCAN_USE_CALLBACK,NULL,DumpDeviceDriversCallback,&count,&scanResult); + //FormatToStream(stdout, count ? MSG_DUMP_DRIVER_FILES : MSG_DUMP_NO_DRIVER_FILES, count, driverInfoDetail.InfFileName, driverInfoDetail.SectionName); + + /* Call again to dump the files (NOT YET IMPLEMENTED!) */ + //SetupScanFileQueue(queueHandle,SPQ_SCAN_USE_CALLBACK,NULL,DumpDeviceDriversCallback,NULL,&scanResult); + + if (!DeleteFile(driverInfoDetail.InfFileName)) + scanResult = GetLastError(); + else + { + DWORD index = 0; + + index = lstrlen(driverInfoDetail.InfFileName); + if (index > 3) + { + lstrcpy(driverInfoDetail.InfFileName + index - 3, TEXT( "pnf" ) ); + + if (!DeleteFile(driverInfoDetail.InfFileName)) + scanResult = GetLastError(); + } + } + + success = EXIT_OK; + + final: + + g_pfnSetupDiDestroyDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER); + + if (queueHandle != (HSPFILEQ)INVALID_HANDLE_VALUE) + { + SetupCloseFileQueue(queueHandle); + } + + if (EXIT_OK != success) + { + _tprintf(_T("Something went wrong while delete the OEM INF-files!\n\n")); + } + + return success; + +} + +int UninstallDriver (_TCHAR* a_pszHwID) +{ + _tprintf(_T("Uninstalling device: %ws\n"), a_pszHwID); + + _tprintf(_T("Removing driver files ...\n\n")); + int iRet = EnumerateDevices(NULL, NULL, DIGCF_PRESENT, 1, &a_pszHwID, DeleteOEMInfCallback, NULL); + + if (EXIT_OK != iRet) + return iRet; + + _tprintf(_T("Uninstalling driver ...\n\n")); + iRet = EnumerateDevices(NULL, NULL, DIGCF_PRESENT, 1, &a_pszHwID, UninstallCallback, NULL); + + return iRet; +} + +int ExecuteInfFile (_TCHAR* a_pszSection, int a_iMode, _TCHAR* a_pszInf) +{ + _tprintf(_T("Executing INF-File: %ws (%ws) ...\n"), a_pszInf, a_pszSection); + + /* Executed by the installer that already has proper privileges. */ + _TCHAR szCommandLine[_MAX_PATH + 1] = { 0 }; + swprintf(szCommandLine, sizeof(szCommandLine), TEXT( "%ws %d %ws" ), a_pszSection, a_iMode, a_pszInf); + +#ifdef _DEBUG + _tprintf (_T( "Commandline: %ws\n"), szCommandLine); +#endif + + InstallHinfSection(NULL, NULL, szCommandLine, SW_SHOW); + + return EXIT_OK; +} + +int AddNetworkProvider (TCHAR* a_pszProvider, int a_iOrder) +{ + TCHAR szKeyValue[512] = { 0 }; + TCHAR szNewKeyValue[512] = { 0 }; + HKEY hKey = NULL; + DWORD disp, dwType; + int rc; + + _tprintf(_T("Adding network provider: %ws (Order = %d)\n"), a_pszProvider, a_iOrder); + + /* Note: HWOrder is not accessible in Windows 2000; it is updated automatically anyway. */ + TCHAR *pszKey = _T("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"); + + rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp); + if (rc != ERROR_SUCCESS) + { + _tprintf(_T("RegCreateKeyEx %ts failed with %d!\n"), pszKey, rc); + return EXIT_FAIL; + } + DWORD cbKeyValue = sizeof(szKeyValue); + + rc = RegQueryValueEx(hKey, _T("ProviderOrder"), NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue); + if (rc != ERROR_SUCCESS || dwType != REG_SZ) + { + _tprintf(_T("RegQueryValueEx failed with %d dwType = 0x%x!\n"), rc, dwType); + return EXIT_FAIL; + } + +#ifdef _DEBUG + _tprintf(_T("Key value: %ws\n"), szKeyValue); +#endif + + /* Create entire new list. */ + int iPos = 0; + + TCHAR* pszToken = wcstok(szKeyValue, _T(",")); + TCHAR* pszNewToken = NULL; + while (pszToken != NULL) + { + pszNewToken = wcstok(NULL, _T(",")); + + /* Append new provider name (at beginning if a_iOrder=0). */ + if (iPos == a_iOrder) + { + wcscat(szNewKeyValue, a_pszProvider); + wcscat(szNewKeyValue, _T(",")); + iPos++; + } + + if (0 != wcsicmp(pszToken, a_pszProvider)) + { + wcscat(szNewKeyValue, pszToken); + wcscat(szNewKeyValue, _T(",")); + iPos++; + } + +#ifdef _DEBUG + _tprintf (_T("Temp new key value: %ws\n"), szNewKeyValue); +#endif + + pszToken = pszNewToken; + } + + /* Append as last item if needed. */ + if (a_iOrder >= iPos) + wcscat(szNewKeyValue, a_pszProvider); + + /* Last char a delimiter? Cut off ... */ + if (szNewKeyValue[wcslen(szNewKeyValue) - 1] == ',') + szNewKeyValue[wcslen(szNewKeyValue) - 1] = '\0'; + + size_t iNewLen = (wcslen(szNewKeyValue) * sizeof(WCHAR)) + sizeof(WCHAR); + + _tprintf(_T("New provider list (%u bytes): %ws\n"), iNewLen, szNewKeyValue); + + rc = RegSetValueExW(hKey, _T("ProviderOrder"), 0, REG_SZ, (LPBYTE)szNewKeyValue, (DWORD)iNewLen); + + if (rc != ERROR_SUCCESS) + { + _tprintf(_T("RegSetValueEx failed with %d!\n"), rc); + return EXIT_FAIL; + } + + rc = RegCloseKey(hKey); + + if (rc == ERROR_SUCCESS) + { + _tprintf(_T("Network provider successfully installed!\n"), rc); + rc = EXIT_OK; + } + + return rc; +} + +int AddStringToMultiSZ (TCHAR* a_pszSubKey, TCHAR* a_pszKeyValue, TCHAR* a_pszValueToAdd, int a_iOrder) +{ + TCHAR szKeyValue[512] = { 0 }; + TCHAR szNewKeyValue[512] = { 0 }; + HKEY hKey = NULL; + DWORD disp, dwType; + int rc = 0; + + _tprintf(_T("Adding MULTI_SZ string: %ws to %ws\\%ws (Order = %d)\n"), a_pszValueToAdd, a_pszSubKey, a_pszKeyValue, a_iOrder); + + rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, a_pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp); + if (rc != ERROR_SUCCESS) + { + _tprintf(_T("RegCreateKeyEx %ts failed with %d!\n"), a_pszSubKey, rc); + return EXIT_FAIL; + } + DWORD cbKeyValue = sizeof(szKeyValue); + + rc = RegQueryValueEx(hKey, a_pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue); + if (rc != ERROR_SUCCESS || dwType != REG_MULTI_SZ) + { + _tprintf(_T("RegQueryValueEx failed with %d, dwType = 0x%x!\n"), rc, dwType); + return EXIT_FAIL; + } + + /* Look if the network provider is already in the list. */ + int iPos = 0; + size_t cb = 0; + + /* Replace delimiting "\0"'s with "," to make tokenizing work. */ + for (int i=0; i<cbKeyValue/sizeof(TCHAR);i++) + if (szKeyValue[i] == '\0') szKeyValue[i] = ','; + + TCHAR* pszToken = wcstok(szKeyValue, _T(",")); + TCHAR* pszNewToken = NULL; + TCHAR* pNewKeyValuePos = szNewKeyValue; + while (pszToken != NULL) + { + pszNewToken = wcstok(NULL, _T(",")); + + /* Append new value (at beginning if a_iOrder=0). */ + if (iPos == a_iOrder) + { + memcpy(pNewKeyValuePos, a_pszValueToAdd, wcslen(a_pszValueToAdd)*sizeof(TCHAR)); + + cb += (wcslen(a_pszValueToAdd) + 1) * sizeof(TCHAR); /* Add trailing zero as well. */ + pNewKeyValuePos += wcslen(a_pszValueToAdd) + 1; + iPos++; + } + + if (0 != wcsicmp(pszToken, a_pszValueToAdd)) + { + memcpy(pNewKeyValuePos, pszToken, wcslen(pszToken)*sizeof(TCHAR)); + cb += (wcslen(pszToken) + 1) * sizeof(TCHAR); /* Add trailing zero as well. */ + pNewKeyValuePos += wcslen(pszToken) + 1; + iPos++; + } + + pszToken = pszNewToken; + } + + /* Append as last item if needed. */ + if (a_iOrder >= iPos) + { + memcpy(pNewKeyValuePos, a_pszValueToAdd, wcslen(a_pszValueToAdd)*sizeof(TCHAR)); + cb += wcslen(a_pszValueToAdd) * sizeof(TCHAR); /* Add trailing zero as well. */ + } + + rc = RegSetValueExW(hKey, a_pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szNewKeyValue, (DWORD)cb); + + if (rc != ERROR_SUCCESS) + { + _tprintf(_T("RegSetValueEx failed with %d!\n"), rc); + return EXIT_FAIL; + } + + rc = RegCloseKey(hKey); + + if (rc == ERROR_SUCCESS) + { + _tprintf(_T("Value successfully written (%u bytes)!\n"), cb); + rc = EXIT_OK; + } + + return rc; +} + +int RemoveStringFromMultiSZ (TCHAR* a_pszSubKey, TCHAR* a_pszKeyValue, TCHAR* a_pszValueToRemove) +{ + // @todo Make string sizes dynamically allocated! + + TCHAR szKeyValue[1024]; + HKEY hkey; + DWORD disp, dwType; + int rc; + + TCHAR *pszKey = a_pszSubKey; + + _tprintf(_T("Removing MULTI_SZ string: %ws from %ws\\%ws ...\n"), a_pszValueToRemove, a_pszSubKey, a_pszKeyValue); + + rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkey, &disp); + if (rc != ERROR_SUCCESS) + { + _tprintf(_T("RegCreateKeyEx %ts failed with %d!\n"), pszKey, rc); + return EXIT_FAIL; + } + DWORD cbKeyValue = sizeof(szKeyValue); + + rc = RegQueryValueEx(hkey, a_pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue); + if (rc != ERROR_SUCCESS || dwType != REG_MULTI_SZ) + { + _tprintf(_T("RegQueryValueEx failed with %d dwType = 0x%x!\n"), rc, dwType); + return EXIT_FAIL; + } + +#ifdef _DEBUG + _tprintf(_T("Current key len: %d\n"), cbKeyValue); +#endif + + TCHAR szCurString[1024] = { 0 }; + TCHAR szFinalString[1024] = { 0 }; + int iIndex = 0; + int iNewIndex = 0; + for (int i = 0; i < cbKeyValue / sizeof(TCHAR); i++) + { + if (szKeyValue[i] != _T('\0')) + szCurString[iIndex++] = szKeyValue[i]; + + if ((!szKeyValue[i] == _T('\0')) && szKeyValue[i + 1] == _T('\0')) + { + if (NULL == wcsstr(szCurString, a_pszValueToRemove)) + { + wcscat(&szFinalString[iNewIndex], szCurString); + + if (iNewIndex == 0) + iNewIndex = iIndex; + else iNewIndex += iIndex; + + szFinalString[++iNewIndex] = _T('\0'); + } + + iIndex = 0; + ZeroMemory( szCurString, sizeof(szCurString)); + } + } + + szFinalString[++iNewIndex] = _T('\0'); + +#ifdef _DEBUG + _tprintf(_T("New key len: %d\n"), iNewIndex * sizeof(TCHAR)); + _tprintf(_T("New key value: %ws\n"), szFinalString); +#endif + + rc = RegSetValueExW(hkey, a_pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szFinalString, iNewIndex * sizeof(TCHAR)); + + if (rc != ERROR_SUCCESS) + { + _tprintf(_T("RegSetValueEx failed with %d!\n"), rc); + return EXIT_FAIL; + } + + rc = RegCloseKey(hkey); + + if (rc == ERROR_SUCCESS) + { + _tprintf(_T("Value successfully removed!\n"), rc); + rc = EXIT_OK; + } + + return rc; +} + +int CreateService (TCHAR* a_pszStartStopName, + TCHAR* a_pszDisplayName, + int a_iServiceType, + int a_iStartType, + TCHAR* a_pszBinPath, + TCHAR* a_pszLoadOrderGroup, + TCHAR* a_pszDependencies, + TCHAR* a_pszLogonUser, + TCHAR* a_pszLogonPw) +{ + int rc = ERROR_SUCCESS; + + _tprintf(_T("Installing service %ws (%ws) ...\n"), a_pszDisplayName, a_pszStartStopName); + + SC_HANDLE hSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (hSCManager == NULL) + { + _tprintf(_T("Could not get handle to SCM! Error: %ld\n"), GetLastError()); + return EXIT_FAIL; + } + + /* Fixup end of multistring */ + TCHAR szDepend[ _MAX_PATH ] = { 0 }; /* @todo Use dynamically allocated string here! */ + if (a_pszDependencies != NULL) + { + _tcsnccpy (szDepend, a_pszDependencies, wcslen(a_pszDependencies)); + DWORD len = (DWORD)wcslen (szDepend); + szDepend [len + 1] = 0; + + /* Replace comma separator on null separator */ + for (DWORD i = 0; i < len; i++) + { + if (',' == szDepend [i]) + szDepend [i] = 0; + } + } + + DWORD dwTag = 0xDEADBEAF; + SC_HANDLE hService = CreateService (hSCManager, // SCManager database + a_pszStartStopName, // name of service + a_pszDisplayName, // name to display + SERVICE_ALL_ACCESS, // desired access + a_iServiceType, // service type + a_iStartType, // start type + SERVICE_ERROR_NORMAL, // error control type + a_pszBinPath, // service's binary + a_pszLoadOrderGroup, // ordering group + (a_pszLoadOrderGroup != NULL) ? &dwTag : NULL, // tag identifier + (a_pszDependencies != NULL) ? szDepend : NULL, // dependencies + (a_pszLogonUser != NULL) ? a_pszLogonUser: NULL, // account + (a_pszLogonPw != NULL) ? a_pszLogonPw : NULL); // password + if (NULL == hService) + { + DWORD dwErr = GetLastError(); + switch (dwErr) + { + + case ERROR_SERVICE_EXISTS: + { + _tprintf(_T("Service already exists. No installation required. Updating the service config.\n")); + + hService = OpenService (hSCManager, // SCManager database + a_pszStartStopName, // name of service + SERVICE_ALL_ACCESS); // desired access + if (NULL == hService) + { + dwErr = GetLastError(); + _tprintf(_T("Could not open service! Error: %ld\n"), dwErr); + } + else + { + BOOL Result = ChangeServiceConfig (hService, // service handle + a_iServiceType, // service type + a_iStartType, // start type + SERVICE_ERROR_NORMAL, // error control type + a_pszBinPath, // service's binary + a_pszLoadOrderGroup, // ordering group + (a_pszLoadOrderGroup != NULL) ? &dwTag : NULL, // tag identifier + (a_pszDependencies != NULL) ? szDepend : NULL, // dependencies + (a_pszLogonUser != NULL) ? a_pszLogonUser: NULL, // account + (a_pszLogonPw != NULL) ? a_pszLogonPw : NULL, // password + a_pszDisplayName); // name to display + if (Result) + { + _tprintf(_T("The service config has been successfully updated.\n")); + } + else + { + dwErr = GetLastError(); + _tprintf(_T("Could not change service config! Error: %ld\n"), dwErr); + } + + CloseServiceHandle (hService); + } + + /* This entire branch do not return an error to avoid installations failures, + * if updating service parameters. Better to have a running system with old + * parameters and the failure information in the installation log. + */ + break; + } + + case ERROR_INVALID_PARAMETER: + + _tprintf(_T("Invalid parameter specified!\n")); + rc = EXIT_FAIL; + break; + + default: + + _tprintf(_T("Could not create service! Error: %ld\n"), dwErr); + rc = EXIT_FAIL; + break; + } + + if (rc == EXIT_FAIL) + goto cleanup; + } + else + { + CloseServiceHandle (hService); + _tprintf(_T("Installation of service successful!\n")); + } + +cleanup: + + if (hSCManager != NULL) + CloseServiceHandle (hSCManager); + + return rc; +} + +int DelService (TCHAR* a_pszStartStopName) +{ + int rc = ERROR_SUCCESS; + + _tprintf(_T("Deleting service '%ws' ...\n"), a_pszStartStopName); + + SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + SC_HANDLE hService = NULL; + if (hSCManager == NULL) + { + _tprintf(_T("Could not get handle to SCM! Error: %ld\n"), GetLastError()); + rc = EXIT_FAIL; + } + else + { + hService = OpenService(hSCManager, a_pszStartStopName, SERVICE_ALL_ACCESS); + if (NULL == hService) + { + _tprintf(_T("Could not open service '%ws'! Error: %ld\n"), a_pszStartStopName, GetLastError()); + rc = EXIT_FAIL; + } + } + + if (hService != NULL) + { + if (LockServiceDatabase(hSCManager)) + { + if (FALSE == DeleteService(hService)) + { + DWORD dwErr = GetLastError(); + switch (dwErr) + { + + case ERROR_SERVICE_MARKED_FOR_DELETE: + + _tprintf(_T("Service '%ws' already marked for deletion.\n"), a_pszStartStopName); + break; + + default: + + _tprintf(_T("Could not delete service '%ws'! Error: %ld\n"), a_pszStartStopName, GetLastError()); + rc = EXIT_FAIL; + break; + } + } + else + { + _tprintf(_T("Service '%ws' successfully removed!\n"), a_pszStartStopName); + } + UnlockServiceDatabase(hSCManager); + } + else + { + _tprintf(_T("Unable to lock service database! Error: %ld\n"), GetLastError()); + rc = EXIT_FAIL; + } + CloseServiceHandle(hService); + } + + if (hSCManager != NULL) + CloseServiceHandle(hSCManager); + + return rc; +} + +DWORD RegistryWrite(HKEY hRootKey, + const _TCHAR *pszSubKey, + const _TCHAR *pszValueName, + DWORD dwType, + const BYTE *pbData, + DWORD cbData) +{ + DWORD lRet; + HKEY hKey; + lRet = RegCreateKeyEx (hRootKey, + pszSubKey, + 0, /* Reserved */ + NULL, /* lpClass [in, optional] */ + 0, /* dwOptions [in] */ + KEY_WRITE, + NULL, /* lpSecurityAttributes [in, optional] */ + &hKey, + NULL); /* lpdwDisposition [out, optional] */ + if (lRet != ERROR_SUCCESS) + { + _tprintf(_T("Could not open registry key! Error: %ld\n"), GetLastError()); + } + else + { + lRet = RegSetValueEx(hKey, pszValueName, 0, dwType, (BYTE*)pbData, cbData); + if (lRet != ERROR_SUCCESS) + _tprintf(_T("Could not write to registry! Error: %ld\n"), GetLastError()); + RegCloseKey(hKey); + + } + return lRet; +} + +void PrintHelp (void) +{ + _tprintf(_T("Installs / Uninstalls VirtualBox drivers for Windows XP/2K/Vista\n")); + _tprintf(_T("Version: %d.%d.%d.%d\n\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV); + _tprintf(_T("Syntax:\n")); + _tprintf(_T("\tTo install: VBoxDrvInst /i <HardwareID> <INF-File> <Device Class>\n")); + _tprintf(_T("\tTo uninstall: VBoxDrvInst /u <HardwareID>\n")); + _tprintf(_T("\tTo execute an INF-File: VBoxDrvInst /inf <INF-File>\n")); + _tprintf(_T("\tTo add a network provider: VBoxDrvInst /addnetprovider <Name> [Order]\n\n")); + _tprintf(_T("\tTo write registry values: VBoxDrvInst /registry write <root> <sub key> <key name> <key type> <value> [type] [size]\n\n")); + _tprintf(_T("Examples:\n")); + _tprintf(_T("\tVBoxDrvInst /i \"PCI\\VEN_80EE&DEV_BEEF&SUBSYS_00000000&REV_00\" VBoxVideo.inf Display\n")); + _tprintf(_T("\tVBoxDrvInst /addnetprovider VboxSF 1\n\n")); +} + +int __cdecl _tmain (int argc, _TCHAR* argv[]) +{ + int rc; + OSVERSIONINFO OSinfo; + + _TCHAR szHwID[_MAX_PATH] = { 0 }; /* Hardware ID. */ + _TCHAR szINF[_MAX_PATH] = { 0 }; /* Complete path to INF file.*/ + _TCHAR szDevClass[_MAX_PATH] = { 0 }; /* Device class. */ + _TCHAR szProvider[_MAX_PATH] = { 0 }; /* The network provider name for the registry. */ + + rc = LoadAPICalls(); + if ( rc == ERROR_SUCCESS + && argc >= 2) + { + OSinfo.dwOSVersionInfoSize = sizeof(OSinfo); + GetVersionEx(&OSinfo); + + if (0 == _tcsicmp(argv[1], _T("/i"))) + { + if (argc < 5) + { + rc = EXIT_USAGE; + } + else + { + if (OSinfo.dwMajorVersion < 5) + { + _tprintf(_T("ERROR: Platform not supported yet!\n")); + rc = ERROR_NOT_SUPPORTED; + } + + if (rc == ERROR_SUCCESS) + { + _stprintf(szHwID, _T("%ws"), argv[2]); + _stprintf(szINF, _T("%ws"), argv[3]); + _stprintf(szDevClass, _T("%ws"), argv[4]); + + rc = InstallDriver(szINF, szHwID, szDevClass); + } + } + } + else if (0 == _tcsicmp(argv[1], _T("/u"))) + { + if (argc < 3) + { + rc = EXIT_USAGE; + } + else + { + if (OSinfo.dwMajorVersion < 5) + { + _tprintf(_T("ERROR: Platform not supported yet!\n")); + rc = ERROR_NOT_SUPPORTED; + } + + if (rc == ERROR_SUCCESS) + { + _stprintf(szHwID, _T("%ws"), argv[2]); + rc = UninstallDriver(szHwID); + } + } + } + else if (0 == _tcsicmp(argv[1], _T("/inf"))) + { + if (argc < 3) + { + rc = EXIT_USAGE; + } + else + { + if (OSinfo.dwMajorVersion < 5) + { + _tprintf(_T("ERROR: Platform not supported yet!\n")); + rc = ERROR_NOT_SUPPORTED; + } + + if (rc == ERROR_SUCCESS) + { + _stprintf(szINF, _T("%ws"), argv[2]); + rc = ExecuteInfFile(_T("DefaultInstall"), 132, szINF); + } + } + } + else if (0 == _tcsicmp(argv[1], _T("/addnetprovider"))) + { + if (argc < 3) + { + rc = EXIT_USAGE; + } + else + { + + int iOrder = 0; + if (argc > 3) + iOrder = _ttoi(argv[3]); + _stprintf(szProvider, _T("%ws"), argv[2]); + rc = AddNetworkProvider(szProvider, iOrder); + } + } + else if (0 == _tcsicmp(argv[1], _T("/reg_addmultisz"))) + { + if (argc < 6) + { + rc = EXIT_USAGE; + } + else + { + rc = AddStringToMultiSZ(argv[2], argv[3], argv[4], _ttoi(argv[5])); + } + } + else if (0 == _tcsicmp(argv[1], _T("/reg_delmultisz"))) + { + if (argc < 5) + { + rc = EXIT_USAGE; + } + else + { + rc = RemoveStringFromMultiSZ(argv[2], argv[3], argv[4]); + } + } + else if (0 == _tcsicmp(argv[1], _T("/createsvc"))) + { + if (argc < 7) + { + rc = EXIT_USAGE; + } + else + { + rc = CreateService( + argv[2], + argv[3], + _ttoi(argv[4]), + _ttoi(argv[5]), + argv[6], + (argc > 7) ? argv[7] : NULL, + (argc > 8) ? argv[8] : NULL, + (argc > 9) ? argv[9] : NULL, + (argc > 10) ? argv[10] : NULL); + } + } + else if (0 == _tcsicmp(argv[1], _T("/delsvc"))) + { + if (argc < 3) + { + rc = EXIT_USAGE; + } + else + { + rc = DelService(argv[2]); + } + } + else if (0 == _tcsicmp(argv[1], _T("/registry"))) + { + if (argc < 8) + { + rc = EXIT_USAGE; + } + else + { + /** @todo add a handleRegistry(argc, argv) method to keep things cleaner */ + if (0 == _tcsicmp(argv[2], _T("write"))) + { + HKEY hRootKey = HKEY_LOCAL_MACHINE; /** @todo needs to be expanded (argv[3]) */ + DWORD dwValSize; + BYTE *pbVal = NULL; + DWORD dwVal; + + if (argc > 8) + { + if (0 == _tcsicmp(argv[8], _T("dword"))) + { + dwVal = _ttol(argv[7]); + pbVal = (BYTE*)&dwVal; + dwValSize = sizeof(DWORD); + } + } + if (pbVal == NULL) /* By default interpret value as string */ + { + pbVal = (BYTE*)argv[7]; + dwValSize = _tcslen(argv[7]); + } + if (argc > 9) + dwValSize = _ttol(argv[9]); /* Get the size in bytes of the value we want to write */ + rc = RegistryWrite(hRootKey, + argv[4], /* Sub key */ + argv[5], /* Value name */ + REG_BINARY, /** @todo needs to be expanded (argv[6]) */ + pbVal, /* The value itself */ + dwValSize); /* Size of the value */ + } + /*else if (0 == _tcsicmp(argv[2], _T("read"))) + { + } + else if (0 == _tcsicmp(argv[2], _T("del"))) + { + }*/ + else + rc = EXIT_USAGE; + } + } + } + + if (rc == EXIT_USAGE) + PrintHelp(); + + FreeAPICalls(); + return rc; +} diff --git a/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.rc b/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.rc new file mode 100644 index 00000000000..d750d3db90f --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.rc @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2006-2007 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +#include <windows.h> +#include <VBox/version.h> + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + PRODUCTVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + FILEFLAGSMASK 0x3fL + FILEFLAGS 0x0L + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", VBOX_RC_COMPANY_NAME + VALUE "FileDescription", "VirtualBox Driver Installer\0" + VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + VALUE "InternalName", "VBoxDrvInst\0" + VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "VBoxDrvInst.exe\0" + VALUE "ProductName", "VirtualBox Guest Additions\0" + VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditions.nsi b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditions.nsi new file mode 100644 index 00000000000..a5e4252bda7 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditions.nsi @@ -0,0 +1,1126 @@ + +!if $%BUILD_TYPE% == "debug" + !define _DEBUG ; Turn this on to get extra output +!endif + +; Defines for special functions +!define WHQL_FAKE ; Turns on the faking of non WHQL signed / approved drivers. + ; Needs the VBoxWHQLFake.exe in the additions output directory! + +!define VENDOR_ROOT_KEY "SOFTWARE\$%VBOX_VENDOR_SHORT%" + +!define PRODUCT_NAME "$%VBOX_PRODUCT% Guest Additions" +!define PRODUCT_DESC "$%VBOX_PRODUCT% Guest Additions" +!define PRODUCT_VERSION "$%VBOX_VERSION_MAJOR%.$%VBOX_VERSION_MINOR%.$%VBOX_VERSION_BUILD%.0" +!define PRODUCT_PUBLISHER " $%VBOX_VENDOR%" +!define PRODUCT_COPYRIGHT "(C) $%VBOX_C_YEAR% $%VBOX_VENDOR%" +!define PRODUCT_OUTPUT "VBoxWindowsAdditions-$%BUILD_TARGET_ARCH%.exe" +!define PRODUCT_WEB_SITE "http://www.virtualbox.org" +!define PRODUCT_INSTALL_KEY "${VENDOR_ROOT_KEY}\VirtualBox Guest Additions" +!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" +!define PRODUCT_UNINST_ROOT_KEY "HKLM" + +VIProductVersion "${PRODUCT_VERSION}" +VIAddVersionKey "FileVersion" "$%VBOX_VERSION_STRING%" +VIAddVersionKey "ProductName" "${PRODUCT_NAME}" +VIAddVersionKey "ProductVersion" "${PRODUCT_VERSION}" +VIAddVersionKey "CompanyName" "${PRODUCT_PUBLISHER}" +VIAddVersionKey "FileDescription" "${PRODUCT_DESC}" +VIAddVersionKey "LegalCopyright" "${PRODUCT_COPYRIGHT}" +VIAddVersionKey "InternalName" "${PRODUCT_OUTPUT}" + +; This registry key will hold the mouse driver path before install (NT4 only) +!define ORG_MOUSE_PATH "MousePath" + +!include "LogicLib.nsh" +!include "FileFunc.nsh" + !insertmacro GetParameters + !insertmacro GetOptions +!include "WordFunc.nsh" + !insertmacro WordFind + !insertmacro StrFilter + +!include "nsProcess.nsh" +!include "Library.nsh" +!include "strstr.nsh" ; Function "strstr" +!include "servicepack.nsh" ; Function "GetServicePack" +!include "winver.nsh" ; Function for determining Windows version +!define REPLACEDLL_NOREGISTER ; Replace in use DLL function +!include "ReplaceDLL.nsh" +!include "dumplog.nsh" ; Dump log to file function + +!if $%BUILD_TARGET_ARCH% == "amd64" + !include "x64.nsh" +!endif + +; Use modern UI (MUI) +!include "MUI.nsh" + +; MUI Settings +!define MUI_WELCOMEFINISHPAGE_BITMAP "$%VBOX_BRAND_WIN_ADD_INST_DLGBMP%" +!define MUI_ABORTWARNING +!define MUI_WELCOMEPAGE_TITLE_3LINES "Welcome to the ${PRODUCT_NAME} Additions Setup" + +; API defines +!define SM_CLEANBOOT 67 + +; Icons +!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit + !define MUI_ICON "$%VBOX_NSIS_ICON_FILE%" + !define MUI_UNICON "$%VBOX_NSIS_ICON_FILE%" +!else ; 64-bit + !define MUI_ICON "$%VBOX_WINDOWS_ADDITIONS_ICON_FILE%" + !define MUI_UNICON "$%VBOX_WINDOWS_ADDITIONS_ICON_FILE%" +!endif + +; Welcome page +!insertmacro MUI_PAGE_WELCOME +; License page +!insertmacro MUI_PAGE_LICENSE "$(VBOX_LICENSE)" +!define MUI_LICENSEPAGE_RADIOBUTTONS +; Directory page +!insertmacro MUI_PAGE_DIRECTORY +; Components Page +!insertmacro MUI_PAGE_COMPONENTS +; Instfiles page +!insertmacro MUI_PAGE_INSTFILES + +!ifndef _DEBUG + !define MUI_FINISHPAGE_TITLE_3LINES ; Have a bit more vertical space for text + !insertmacro MUI_PAGE_FINISH ; Only show in release mode - useful information for debugging! +!endif + +; Uninstaller pages +!insertmacro MUI_UNPAGE_INSTFILES + +; Define languages we will use +!insertmacro MUI_LANGUAGE "English" +!insertmacro MUI_LANGUAGE "French" +!insertmacro MUI_LANGUAGE "German" + +; Set branding text which appears on the horizontal line at the bottom +BrandingText "VirtualBox Windows Additions" + +; Set license language +LicenseLangString VBOX_LICENSE ${LANG_ENGLISH} "$%VBOX_BRAND_LICENSE_RTF%" + +; If license files not available (OSE / PUEL) build, then use the English one as default. +!ifdef VBOX_BRAND_fr_FR_LICENSE_RTF + LicenseLangString VBOX_LICENSE ${LANG_FRENCH} "$%VBOX_BRAND_fr_FR_LICENSE_RTF%" +!else + LicenseLangString VBOX_LICENSE ${LANG_FRENCH} "$%VBOX_BRAND_LICENSE_RTF%" +!endif +!ifdef VBOX_BRAND_de_DE_LICENSE_RTF + LicenseLangString VBOX_LICENSE ${LANG_GERMAN} "$%VBOX_BRAND_de_DE_LICENSE_RTF%" +!else + LicenseLangString VBOX_LICENSE ${LANG_GERMAN} "$%VBOX_BRAND_LICENSE_RTF%" +!endif + +!insertmacro MUI_RESERVEFILE_LANGDLL +; MUI end ------ + +; Language files +!include "Languages\English.nsh" +!include "Languages\French.nsh" +!include "Languages\German.nsh" + +; Variables and output files +Name "${PRODUCT_NAME} $%VBOX_VERSION_STRING%" +!ifdef UNINSTALLER_ONLY +!echo "Uninstaller only!" +OutFile "$%PATH_TARGET%\VBoxWindowsAdditions-$%BUILD_TARGET_ARCH%-uninst.exe" +!else +OutFile "VBoxWindowsAdditions-$%BUILD_TARGET_ARCH%.exe" +!endif + +!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit + InstallDir "$PROGRAMFILES32\$%VBOX_VENDOR_SHORT%\VirtualBox Guest Additions" +!else ; 64-bit + InstallDir "$PROGRAMFILES64\$%VBOX_VENDOR_SHORT%\VirtualBox Guest Additions" +!endif + +InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" "" +ShowInstDetails show +ShowUnInstDetails show +RequestExecutionLevel highest + +Var g_iSystemMode ; Current system mode (0 = Normal boot, 1 = Fail-safe boot, 2 = Fail-safe with network boot) +Var g_strSystemDir ; Windows system directory +Var g_strCurUser ; Current user using the system +Var g_strAddVerMaj ; Installed Guest Additions: Major version +Var g_strAddVerMin ; Installed Guest Additions: Minor version +Var g_strAddVerBuild ; Installed Guest Additions: Build number +Var g_strAddVerRev ; Installed Guest Additions: SVN revision +Var g_strWinVersion ; Current Windows version we're running on +Var g_bLogEnable ; Do logging when installing? "true" or "false" +Var g_bFakeWHQL ; Cmd line: Fake Windows to install non WHQL certificated drivers (only for W2K and XP currently!!) ("/unsig_drv") +Var g_bUninstall ; Cmd line: Just uninstall any previous Guest Additions and exit +Var g_bRebootOnExit ; Cmd line: Auto-Reboot on successful installation. Good for unattended installations ("/reboot") +Var g_iScreenBpp ; Cmd line: Screen depth ("/depth=X") +Var g_iScreenX ; Cmd line: Screen resolution X ("/resx=X") +Var g_iScreenY ; Cmd line: Screen resolution Y ("/resy=Y") +Var g_iSfOrder ; Cmd line: Order of Shared Folders network provider (0=first, 1=second, ...) +Var g_bNoVideoDrv ; Cmd line: Do not install the VBoxVideo driver +Var g_bNoGuestDrv ; Cmd line: Do not install the VBoxGuest driver +Var g_bNoMouseDrv ; Cmd line: Do not install the VBoxMouse driver +Var g_bWithAutoLogon ; Cmd line: Install VBoxGINA / VBoxCredProv for auto logon support +Var g_bWithD3D ; Cmd line: Install Direct3D support +Var g_bOnlyExtract ; Cmd line: Only extract all files, do *not* install them. Only valid with param "/D" (target directory) + +; Platform parts of this installer +!include "VBoxGuestAdditionsCommon.nsh" +!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit only +!include "VBoxGuestAdditionsNT4.nsh" +!endif +!include "VBoxGuestAdditionsW2KXP.nsh" +!include "VBoxGuestAdditionsVista.nsh" +!include "VBoxGuestAdditionsUninstall.nsh" ; Product uninstallation +!include "VBoxGuestAdditionsUninstallOld.nsh" ; Uninstallation of deprecated versions which must be removed first + +Function HandleCommandLine + + Push $0 ; Command line (without process name) + Push $1 ; Number of parameters + Push $2 ; Current parameter index + Push $3 ; Current parameter pair (name=value) + Push $4 ; Current parameter name + Push $5 ; Current parameter value (if present) + + StrCpy $1 "0" ; Init param counter + StrCpy $2 "1" ; Init current param counter + + ${GetParameters} $0 ; Extract command line + ${If} $0 == "" ; If no parameters at all exit + Goto exit + ${EndIf} + + ; Enable for debugging + ;MessageBox MB_OK "CmdLine: $0" + + ${WordFind} $0 " " "#" $1 ; Get number of parameters in cmd line + ${If} $0 == $1 ; If result matches the input then + StrCpy $1 "1" ; no delimeter was found. Correct to 1 word total. + ${EndIf} + + ${While} $2 <= $1 ; Loop through all params + + ${WordFind} $0 " " "+$2" $3 ; Get current name=value pair + ${WordFind} $3 "=" "+1" $4 ; Get current param name + ${WordFind} $3 "=" "+2" $5 ; Get current param value + + ${StrFilter} $4 "-" "" "" $4 ; Transfor param name to lowercase + + ; Enable for debugging + ;MessageBox MB_OK "#$2 of #$1, param='$3', name=$4, val=$5" + + ${Switch} $4 + + ${Case} '/d' ; NSIS: /D=<instdir> switch, skip + ${Break} + + ${Case} '/depth' + ${Case} 'depth' + StrCpy $g_iScreenBpp $5 + ${Break} + + ${Case} '/extract' + StrCpy $g_bOnlyExtract "true" + ${Break} + + ${Case} '/help' + ${Case} '/H' + ${Case} '/h' + ${Case} '/?' + Goto usage + ${Break} + + ${Case} '/l' + ${Case} '/log' + ${Case} '/logging' + StrCpy $g_bLogEnable "true" + ${Break} + + ${Case} '/ncrc' ; NSIS: /NCRC switch, skip + ${Break} + + ${Case} '/no_videodrv' + StrCpy $g_bNoVideoDrv "true" + ${Break} + + ${Case} '/no_guestdrv' + StrCpy $g_bNoGuestDrv "true" + ${Break} + + ${Case} '/no_mousedrv' + StrCpy $g_bNoMouseDrv "true" + ${Break} + + ${Case} '/reboot' + StrCpy $g_bRebootOnExit "true" + ${Break} + + ${Case} '/s' ; NSIS: /S switch, skip + ${Break} + + ${Case} '/sforder' + ${Case} 'sforder' + StrCpy $g_iSfOrder $5 + ${Break} + + !ifdef WHQL_FAKE + ${Case} '/unsig_drv' + StrCpy $g_bFakeWHQL "true" + ${Break} + !endif + + ${Case} '/uninstall' + StrCpy $g_bUninstall "true" + ${Break} + + ${Case} '/with_autologon' + StrCpy $g_bWithAutoLogon "true" + ${Break} + + !if $%VBOX_WITH_CROGL% == "1" + ${Case} '/with_d3d' + ${Case} '/with_direct3d' + StrCpy $g_bWithD3D "true" + ${Break} + !endif + + ${Case} '/xres' + ${Case} 'xres' + StrCpy $g_iScreenX $5 + ${Break} + + ${Case} '/yres' + ${Case} 'yres' + StrCpy $g_iScreenY $5 + ${Break} + + ${Default} ; Unknown parameter, print usage message + goto usage + ${Break} + + ${EndSwitch} + IntOp $2 $2 + 1 + + ${EndWhile} + Goto exit + +usage: + + MessageBox MB_OK "${PRODUCT_NAME} Installer$\r$\n$\r$\n \ + Usage: VBoxWindowsAdditions-$%BUILD_TARGET_ARCH% [OPTIONS] [/l] [/S] [/D=<PATH>]$\r$\n$\r$\n \ + Options:$\r$\n \ + /depth=BPP$\tSets the guest's display color depth (bits per pixel)$\r$\n \ + /extract$\t$\tOnly extract installation files$\r$\n \ + /uninstall$\t$\tJust uninstalls the Guest Additions and exits$\r$\n \ + /with_autologon$\tInstalls auto-logon support$\r$\n \ + /with_d3d$\tInstalls D3D support$\r$\n \ + /xres=X$\t$\tSets the guest's display resolution (width in pixels)$\r$\n \ + /yres=Y$\t$\tSets the guest's display resolution (height in pixels)$\r$\n \ + $\r$\n \ + Installer parameters:$\r$\n \ + /l$\t$\tEnables logging$\r$\n \ + /S$\t$\tSilent install$\r$\n \ + /D=<PATH>$\tSets the default install path$\r$\n \ + $\r$\n \ + Note: Order of options and installer parameters are mandatory." + + ; No stack restore needed, we're about to quit + Quit + +done: + + IfSilent 0 +2 + LogText "Installer is in silent mode!" + + LogText "Property: XRes: $g_iScreenX" + LogText "Property: YRes: $g_iScreenY" + LogText "Property: BPP: $g_iScreenBpp" + LogText "Property: Logging enabled: $g_bLogEnable" + +exit: + + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 + +FunctionEnd + +Function CheckForOldGuestAdditions + + Push $0 + Push $1 + Push $2 + +begin: + +sun_check: + + ; Check for old "Sun VirtualBox Guest Additions" + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sun VirtualBox Guest Additions" "UninstallString" + StrCmp $0 "" sun_xvm_check ; If string is empty, Sun additions are probably not installed (anymore). + + MessageBox MB_YESNO $(VBOX_SUN_FOUND) /SD IDYES IDYES sun_uninstall + Pop $2 + Pop $1 + Pop $0 + MessageBox MB_ICONSTOP $(VBOX_SUN_ABORTED) /SD IDOK + Quit + +sun_uninstall: + + Call Uninstall_Sun + Goto success + +sun_xvm_check: + + ; Check for old "innotek" Guest Additions" before rebranding to "Sun" + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sun xVM VirtualBox Guest Additions" "UninstallString" + StrCmp $0 "" innotek_check ; If string is empty, Sun xVM additions are probably not installed (anymore). + + MessageBox MB_YESNO $(VBOX_SUN_FOUND) /SD IDYES IDYES sun_xvm_uninstall + Pop $2 + Pop $1 + Pop $0 + MessageBox MB_ICONSTOP $(VBOX_SUN_ABORTED) /SD IDOK + Quit + +sun_xvm_uninstall: + + Call Uninstall_SunXVM + Goto success + +innotek_check: + + ; Check for old "innotek" Guest Additions" before rebranding to "Sun" + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\innotek VirtualBox Guest Additions" "UninstallString" + StrCmp $0 "" exit ; If string is empty, Guest Additions are probably not installed (anymore). + + MessageBox MB_YESNO $(VBOX_INNOTEK_FOUND) /SD IDYES IDYES innotek_uninstall + Pop $2 + Pop $1 + Pop $0 + MessageBox MB_ICONSTOP $(VBOX_INNOTEK_ABORTED) /SD IDOK + Quit + +innotek_uninstall: + + Call Uninstall_Innotek + Goto success + +success: + + ; Nothing to do here yet + +exit: + + Pop $2 + Pop $1 + Pop $0 + +FunctionEnd + +Function CheckArchitecture + + System::Call "kernel32::GetCurrentProcess() i .s" + System::Call "kernel32::IsWow64Process(i s, *i .r0)" + DetailPrint "Running on 64bit: $0" + +!if $%BUILD_TARGET_ARCH% == "amd64" ; 64-bit + IntCmp $0 0 not_32bit_platform +!else ; 32-bit + IntCmp $0 1 not_64bit_platform +!endif + + Goto exit + +not_32bit_platform: + + MessageBox MB_ICONSTOP $(VBOX_NOTICE_ARCH_AMD64) /SD IDOK + Quit + +not_64bit_platform: + + MessageBox MB_ICONSTOP $(VBOX_NOTICE_ARCH_X86) /SD IDOK + Quit + +exit: + +FunctionEnd + +Function PrepareForUpdate + + StrCmp $g_strAddVerMaj "1" v1 ; Handle major version "v1.x" + StrCmp $g_strAddVerMaj "2" v2 ; Handle major version "v2.x" + StrCmp $g_strAddVerMaj "3" v3 ; Handle major version "v3.x" + Goto exit + +v3: + + Goto exit + +v2: + + Goto exit + +v1: + + StrCmp $g_strAddVerMin "5" v1_5 ; Handle major version "v1.5.x" + StrCmp $g_strAddVerMin "6" v1_6 ; Handle major version "v1.6.x" + +v1_5: + + Goto exit + +v1_6: + + Goto exit + +exit: + +FunctionEnd + +Function Common_CopyFiles + + SetOutPath "$INSTDIR" + SetOverwrite on + + FILE "$%PATH_OUT%\bin\additions\VBoxDrvInst.exe" + + FILE "$%PATH_OUT%\bin\additions\VBoxVideo.inf" +!ifdef VBOX_SIGN_ADDITIONS + FILE "$%PATH_OUT%\bin\additions\VBoxVideo.cat" +!endif + + FILE "iexplore.ico" + +FunctionEnd + +; Main Files +Section $(VBOX_COMPONENT_MAIN) SEC01 + + SectionIn RO ; Section cannot be unselected (read-only) + + SetOutPath "$INSTDIR" + SetOverwrite on + + ; Because this NSIS installer is always built in 32-bit mode, we have to + ; do some tricks for the Windows paths +!if $%BUILD_TARGET_ARCH% == "amd64" + ; Because the next two lines will crash at the license page (??) we have to re-enable that here again + ${DisableX64FSRedirection} + SetRegView 64 +!endif + + StrCpy $g_strSystemDir "$SYSDIR" + DetailPrint "System Directory: $g_strSystemDir" + + Call EnableLog + Call PrepareForUpdate + + DetailPrint "Version: $%VBOX_VERSION_STRING%" + ${If} $g_strAddVerMaj != "" + DetailPrint "Previous version: $g_strAddVerMaj.$g_strAddVerMin.$g_strAddVerBuild (Rev $g_strAddVerRev)" + ${Else} + DetailPrint "No previous version of ${PRODUCT_NAME} detected." + ${EndIf} + DetailPrint "Handled Windows version: $g_strWinVersion" + +!ifdef _DEBUG + DetailPrint "Debug!" +!endif + + ; Which OS we are using? +!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit + StrCmp $g_strWinVersion "nt4" nt4 +!endif + StrCmp $g_strWinVersion "2k" w2k + StrCmp $g_strWinVersion "vista" vista + + Goto notsupported + +!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit +nt4: ; Windows NT4 + + Call GetServicePack + Pop $R0 ; Major version + Pop $R1 ; Minor version + + ; At least Service Pack 6 installed? + StrCmp $R0 "6" +3 + MessageBox MB_YESNO $(VBOX_NT4_NO_SP6) /SD IDYES IDYES +2 + Quit + + ; Copy some common files ... + Call Common_CopyFiles + + Call NT_Main + goto success +!endif + +vista: ; Windows Vista (fall through, needs stuff from w2k label, too) + + ; Copy some common files ... + Call Common_CopyFiles + + Call W2K_Main ; First install stuff from Windows 2000 / XP + Call Vista_Main ; ... and some specific stuff for Vista + goto success + +w2k: ; Windows 2000 and XP ... + + ; Copy some common files ... + Call Common_CopyFiles + + Call W2K_Main + goto success + +notsupported: + + MessageBox MB_ICONSTOP $(VBOX_PLATFORM_UNSUPPORTED) /SD IDOK + goto exit + +success: + + ; Write a registry key with version and installation path for later lookup + WriteRegStr HKLM "${PRODUCT_INSTALL_KEY}" "Version" "$%VBOX_VERSION_STRING%" + WriteRegStr HKLM "${PRODUCT_INSTALL_KEY}" "Revision" "$%VBOX_SVN_REV%" + WriteRegStr HKLM "${PRODUCT_INSTALL_KEY}" "InstallDir" "$INSTDIR" + +!ifndef _DEBUG + SetRebootFlag true ; This will show a reboot page at end of installation +!endif + +exit: + + Call WriteLogUI + +SectionEnd + +; Auto-logon support (section is hidden at the moment -- only can be enabled via command line switch) +Section /o -$(VBOX_COMPONENT_AUTOLOGON) SEC02 + + ; Because this NSIS installer is always built in 32-bit mode, we have to + ; do some tricks for the Windows paths. +!if $%BUILD_TARGET_ARCH% == "amd64" + ; Because the next two lines will crash at the license page (??) we have to re-enable that here again + ${DisableX64FSRedirection} + SetRegView 64 +!endif + + Call GetWindowsVersion + Pop $R0 ; Windows Version + + DetailPrint "Installing auto-logon support ..." + + ; Another GINA already is installed? Check if this is ours, otherwise let the user decide (unless it's a silent setup) + ; whether to replace it with the VirtualBox one or not. + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon" "GinaDLL" + ${If} $0 != "" + ${If} $0 != "VBoxGINA.dll" + MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON1 $(VBOX_COMPONENT_AUTOLOGON_WARN_3RDPARTY) /SD IDYES IDYES install + goto exit + ${EndIf} + ${EndIf} + +install: + + ; Do we need VBoxCredProv or VBoxGINA? + ${If} $R0 == 'Vista' + ${OrIf} $R0 == '7' + !insertmacro ReplaceDLL "$%PATH_OUT%\bin\additions\VBoxCredProv.dll" "$g_strSystemDir\VBoxCredProv.dll" "$INSTDIR" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{275D3BCC-22BB-4948-A7F6-3A3054EBA92B}" "" "VBoxCredProv" ; adding to (default) key + WriteRegStr HKCR "CLSID\{275D3BCC-22BB-4948-A7F6-3A3054EBA92B}" "" "VBoxCredProv" ; adding to (Default) key + WriteRegStr HKCR "CLSID\{275D3BCC-22BB-4948-A7F6-3A3054EBA92B}\InprocServer32" "" "VBoxCredProv.dll" ; adding to (Default) key + WriteRegStr HKCR "CLSID\{275D3BCC-22BB-4948-A7F6-3A3054EBA92B}\InprocServer32" "ThreadingModel" "Apartment" + ${Else} + !insertmacro ReplaceDLL "$%PATH_OUT%\bin\additions\VBoxGINA.dll" "$g_strSystemDir\VBoxGINA.dll" "$INSTDIR" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon" "GinaDLL" "VBoxGINA.dll" + ${EndIf} + +exit: + +SectionEnd + +; Prepares the access rights for replacing a WRP protected file +Function PrepareWRPFile + + Pop $0 + IfFileExists "$g_strSystemDir\takeown.exe" 0 +2 + nsExec::ExecToLog '"$g_strSystemDir\takeown.exe" /F "$0"' + AccessControl::SetFileOwner "$0" "(S-1-5-32-545)" + Pop $1 + DetailPrint "Setting file owner for '$0': $1" + AccessControl::GrantOnFile "$0" "(S-1-5-32-545)" "FullAccess" + Pop $1 + DetailPrint "Setting access rights for '$0': $1" + +FunctionEnd + +; Direct3D support +!if $%VBOX_WITH_CROGL% == "1" +Section /o $(VBOX_COMPONENT_D3D) SEC03 + + Push $R0 + + Call GetWindowsVersion + Pop $R0 ; Windows Version + + ; If we're not in safe mode, print a warning and do nothing here + ${If} $g_iSystemMode == '0' + DetailPrint "System is not in safe mode, D3D support will not be installed!" + Return + ${EndIf} + + ; Do not install on < XP + ${If} $R0 == 'NT 3' + ${OrIf} $R0 == 'NT 4' + ${OrIf} $R0 == '2000' + ${OrIf} $R0 == '' + DetailPrint "Direct3D guest support not available on this platform!" + Return + ${EndIf} + + !define LIBRARY_IGNORE_VERSION ; Install in every case + SetOverwrite on + + ${If} $g_strSystemDir == '' + StrCpy $g_strSystemDir "$SYSDIR" + ${EndIf} + + ; crOpenGL: Do *not* install 64-bit files - they don't work yet (use !define LIBRARY_X64 later) + ; Only 32-bit apps on 64-bit work (see next block) + !if $%BUILD_TARGET_ARCH% == "x86" + SetOutPath $g_strSystemDir + DetailPrint "Installing Direct3D support ..." + FILE "$%PATH_OUT%\bin\additions\libWine.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxD3D8.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxD3D9.dll" + FILE "$%PATH_OUT%\bin\additions\wined3d.dll" + + ; Update DLL cache + SetOutPath "$g_strSystemDir\dllcache" + IfFileExists "$g_strSystemDir\dllcache\msd3d8.dll" +1 + CopyFiles /SILENT "$g_strSystemDir\dllcache\d3d8.dll" "$g_strSystemDir\dllcache\msd3d8.dll" + IfFileExists "$g_strSystemDir\dllcache\msd3d9.dll" +1 + CopyFiles /SILENT "$g_strSystemDir\dllcache\d3d9.dll" "$g_strSystemDir\dllcache\msd3d9.dll" + + Push "$g_strSystemDir\dllcache\d3d8.dll" + Call PrepareWRPFile + + Push "$g_strSystemDir\dllcache\d3d9.dll" + Call PrepareWRPFile + + ; Exchange DLLs + !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d8.dll" "$g_strSystemDir\dllcache\d3d8.dll" "$TEMP" + !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d9.dll" "$g_strSystemDir\dllcache\d3d9.dll" "$TEMP" + + ; If exchange above failed, do it on reboot + !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d8.dll" "$g_strSystemDir\dllcache\d3d8.dll" "$TEMP" + !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d9.dll" "$g_strSystemDir\dllcache\d3d9.dll" "$TEMP" + + ; Save original DLLs ... + SetOutPath $g_strSystemDir + IfFileExists "$g_strSystemDir\msd3d8.dll" +1 + CopyFiles /SILENT "$g_strSystemDir\d3d8.dll" "$g_strSystemDir\msd3d8.dll" + IfFileExists "$g_strSystemDir\msd3d8.dll" +1 + CopyFiles /SILENT "$g_strSystemDir\d3d9.dll" "$g_strSystemDir\msd3d9.dll" + + Push "$g_strSystemDir\d3d8.dll" + Call PrepareWRPFile + + Push "$g_strSystemDir\d3d9.dll" + Call PrepareWRPFile + + ; Exchange DLLs + !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d8.dll" "$g_strSystemDir\d3d8.dll" "$TEMP" + !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d9.dll" "$g_strSystemDir\d3d9.dll" "$TEMP" + + ; If exchange above failed, do it on reboot + !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d8.dll" "$g_strSystemDir\d3d8.dll" "$TEMP" + !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d9.dll" "$g_strSystemDir\d3d9.dll" "$TEMP" + !endif + + !if $%BUILD_TARGET_ARCH% == "amd64" + ; Only 64-bit installer: Also copy 32-bit DLLs on 64-bit target arch in + ; Wow64 node (32-bit sub system) + ${EnableX64FSRedirection} + SetOutPath $SYSDIR + DetailPrint "Installing Direct3D support (Wow64) ..." + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\libWine.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxD3D8.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxD3D9.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\wined3d.dll" + + ; Update DLL cache + SetOutPath "$SYSDIR\dllcache" + IfFileExists "$SYSDIR\dllcache\msd3d8.dll" +1 + CopyFiles /SILENT "$SYSDIR\dllcache\d3d8.dll" "$SYSDIR\dllcache\msd3d8.dll" + IfFileExists "$SYSDIR\dllcache\msd3d9.dll" +1 + CopyFiles /SILENT "$SYSDIR\dllcache\d3d9.dll" "$SYSDIR\dllcache\msd3d9.dll" + + Push "$SYSDIR\dllcache\d3d8.dll" + Call PrepareWRPFile + + Push "$SYSDIR\dllcache\d3d9.dll" + Call PrepareWRPFile + + ; Exchange DLLs + !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d8.dll" "$SYSDIR\dllcache\d3d8.dll" "$TEMP" + !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d9.dll" "$SYSDIR\dllcache\d3d9.dll" "$TEMP" + + ; If exchange above failed, do it on reboot + !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d8.dll" "$SYSDIR\dllcache\d3d8.dll" "$TEMP" + !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d9.dll" "$SYSDIR\dllcache\d3d9.dll" "$TEMP" + + ; Save original DLLs ... + SetOutPath $SYSDIR + IfFileExists "$SYSDIR\dllcache\msd3d8.dll" +1 + CopyFiles /SILENT "$SYSDIR\d3d8.dll" "$SYSDIR\msd3d8.dll" + IfFileExists "$SYSDIR\dllcache\msd3d9.dll" +1 + CopyFiles /SILENT "$SYSDIR\d3d9.dll" "$SYSDIR\msd3d9.dll" + + Push "$SYSDIR\d3d8.dll" + Call PrepareWRPFile + + Push "$SYSDIR\d3d9.dll" + Call PrepareWRPFile + + ; Exchange DLLs + !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d8.dll" "$SYSDIR\d3d8.dll" "$TEMP" + !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d9.dll" "$SYSDIR\d3d9.dll" "$TEMP" + + ; If exchange above failed, do it on reboot + !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d8.dll" "$SYSDIR\d3d8.dll" "$TEMP" + !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d9.dll" "$SYSDIR\d3d9.dll" "$TEMP" + + ${DisableX64FSRedirection} + !endif ; amd64 + Goto done + +error: + ; @todo + Goto exit + +done: + MessageBox MB_ICONINFORMATION|MB_OK $(VBOX_WFP_WARN_REPLACE) /SD IDOK + Goto exit + + Pop $R0 + +exit: + +SectionEnd +!endif ; VBOX_WITH_CROGL + +;Assign language strings to sections +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${SEC01} $(VBOX_COMPONENT_MAIN_DESC) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC02} $(VBOX_COMPONENT_AUTOLOGON_DESC) +!if $%VBOX_WITH_CROGL% == "1" + !insertmacro MUI_DESCRIPTION_TEXT ${SEC03} $(VBOX_COMPONENT_D3D_DESC) +!endif +!insertmacro MUI_FUNCTION_DESCRIPTION_END + +Section -Content + + WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}" + +SectionEnd + +Section -StartMenu + + CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}" + CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url" "" "$INSTDIR\iexplore.ico" + CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\uninst.exe" + +SectionEnd + +; This section is called after all the files are in place +Section -Post + +!ifdef _DEBUG + DetailPrint "Doing post install ..." +!endif + +!ifdef EXTERNAL_UNINSTALLER + SetOutPath "$INSTDIR" + FILE "$%PATH_TARGET%\uninst.exe" +!else + WriteUninstaller "$INSTDIR\uninst.exe" +!endif + + ; Write uninstaller in "Add / Remove programs" + WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" + WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe" + WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" + WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" + WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" + + ; Tune TcpWindowSize for a better network throughput + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" "TcpWindowSize" 64240 + + DetailPrint "Installation completed." + +SectionEnd + +; This function is called when a critical error occured +Function .onInstFailed + + MessageBox MB_ICONSTOP $(VBOX_ERROR_INST_FAILED) /SD IDOK + StrCpy $g_bLogEnable "true" + Call WriteLogUI + SetErrorLevel 1 + +FunctionEnd + +; This function is called when installation was successful! +Function .onInstSuccess + + ; Nothing to do here yet ... + +FunctionEnd + +; This function is called at the very beginning of installer execution +Function .onInit + + ; Init values + StrCpy $g_iSystemMode "0" + StrCpy $g_strAddVerMaj "0" + StrCpy $g_strAddVerMin "0" + StrCpy $g_strAddVerBuild "0" + StrCpy $g_strAddVerRev "0" + + StrCpy $g_bLogEnable "false" + StrCpy $g_bFakeWHQL "false" + StrCpy $g_bUninstall "false" + StrCpy $g_bRebootOnExit "false" + StrCpy $g_iScreenX "0" + StrCpy $g_iScreenY "0" + StrCpy $g_iScreenBpp "0" + StrCpy $g_iSfOrder "0" + StrCpy $g_bNoVideoDrv "false" + StrCpy $g_bNoGuestDrv "false" + StrCpy $g_bNoMouseDrv "false" + StrCpy $g_bWithAutoLogon "false" + StrCpy $g_bWithD3D "false" + StrCpy $g_bOnlyExtract "false" + + SetErrorLevel 0 + ClearErrors + +!ifndef UNINSTALLER_ONLY + + ; Handle command line + Call HandleCommandLine + + ; Retrieve Windows version and store result in $g_strWinVersion + Call GetWindowsVer + + ; Retrieve system mode and store result in + System::Call 'user32::GetSystemMetrics(i ${SM_CLEANBOOT}) i .r0' + StrCpy $g_iSystemMode $0 + DetailPrint "System mode: $g_iSystemMode" + + ; Get user Name + AccessControl::GetCurrentUserName + Pop $g_strCurUser + DetailPrint "Current user: $g_strCurUser" + + ; Only uninstall? + StrCmp $g_bUninstall "true" uninstall + + ; Only extract files? + StrCmp $g_bOnlyExtract "true" extract_files + + ; Set section bits + ${If} $g_bWithAutoLogon == "true" ; Auto-logon support + SectionSetFlags ${SEC02} ${SF_SELECTED} + ${EndIf} +!if $%VBOX_WITH_CROGL% == "1" + ${If} $g_bWithD3D == "true" ; D3D support + SectionSetFlags ${SEC03} ${SF_SELECTED} + ${EndIf} +!endif + + ; Display language selection dialog (will be hidden in silent mode!) + !ifdef VBOX_INSTALLER_ADD_LANGUAGES + !insertmacro MUI_LANGDLL_DISPLAY + !endif + + ; Do some checks before we actually start ... + Call IsUserAdmin + + ; Check if there's already another instance of the installer is running - + ; important for preventing NT4 to spawn the installer twice + System::Call 'kernel32::CreateMutexA(i 0, i 0, t "VBoxGuestInstaller") ?e' + Pop $R0 + StrCmp $R0 0 +1 exit + + ; Check for correct architecture + Call CheckArchitecture + + ; Because this NSIS installer is always built in 32-bit mode, we have to + ; do some tricks for the Windows paths for checking for old additions + ; in block below. +!if $%BUILD_TARGET_ARCH% == "amd64" + ${DisableX64FSRedirection} + SetRegView 64 +!endif + + ; Check for old additions + Call CheckForOldGuestAdditions + Call GetAdditionsVersion + + ; Due to some bug in NSIS the license page won't be displayed if we're in + ; 64-bit registry view, so as a workaround switch back to 32-bit (Wow6432Node) + ; mode for now. +!if $%BUILD_TARGET_ARCH% == "amd64" + ${EnableX64FSRedirection} + SetRegView 32 +!endif + + Goto done + +uninstall: + + Call Uninstall_Innotek + Call Uninstall + MessageBox MB_ICONINFORMATION|MB_OK $(VBOX_UNINST_SUCCESS) /SD IDOK + Goto exit + +extract_files: + + Call ExtractFiles + MessageBox MB_OK|MB_ICONINFORMATION $(VBOX_EXTRACTION_COMPLETE) /SD IDOK + Goto exit + +!else ; UNINSTALLER_ONLY + + ; + ; If UNINSTALLER_ONLY is defined, we're only interested in uninst.exe + ; so we can sign it. + ; + ; Note that the Quit causes the exit status to be 2 instead of 0. + ; + WriteUninstaller "$%PATH_TARGET%\uninst.exe" + Goto exit + +!endif ; UNINSTALLER_ONLY + +exit: ; Abort installer for some reason + + Quit + +done: + +FunctionEnd + +; +; The uninstaller is built separately when doing code signing. +; For some reason NSIS still finds the Uninstall section even +; when EXTERNAL_UNINSTALLER is defined. This causes a silly warning. +; +!ifndef EXTERNAL_UNINSTALLER + +Function un.onUninstSuccess + + HideWindow + MessageBox MB_ICONINFORMATION|MB_OK $(VBOX_UNINST_SUCCESS) /SD IDOK + +FunctionEnd + +Function un.onInit + + Call un.IsUserAdmin + + MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 $(VBOX_UNINST_CONFIRM) /SD IDYES IDYES proceed + Quit + +proceed: + + ; Because this NSIS installer is always built in 32-bit mode, we have to + ; do some tricks for the Windows paths. +!if $%BUILD_TARGET_ARCH% == "amd64" + ${DisableX64FSRedirection} + SetRegView 64 +!endif + + ; Set system directory. + StrCpy $g_strSystemDir "$SYSDIR" + + ; Retrieve Windows version we're running on and store it in $g_strWinVersion + Call un.GetWindowsVer + +FunctionEnd + +Function .onSelChange + + Push $0 + + ; Section: D3D + SectionGetFlags ${SEC03} $0 + + ${If} $0 == ${SF_SELECTED} + ; If we're not in safe mode, print a warning and don't install D3D support + ${If} $g_iSystemMode == '0' + IntOp $0 $0 & ${SECTION_OFF} ; Unselect section again + SectionSetFlags ${SEC03} $0 + MessageBox MB_ICONINFORMATION|MB_OK $(VBOX_COMPONENT_D3D_NO_SM) /SD IDOK + Return + ${EndIf} + ${EndIf} + + Pop $0 + +FunctionEnd + +Section Uninstall + +!ifdef _DEBUG + ; Enable logging + Call un.EnableLog +!endif + + ; Because this NSIS installer is always built in 32-bit mode, we have to + ; do some tricks for the Windows paths. +!if $%BUILD_TARGET_ARCH% == "amd64" + ; Do *not* add this line in .onInit - it will crash at the license page (??) because of a weird NSIS bug. + ${DisableX64FSRedirection} + SetRegView 64 +!endif + + ; Call the uninstall main function. + Call un.Uninstall + + ; ... and remove the local install directory + Call un.UninstallInstDir + +!ifndef _DEBUG + SetAutoClose true + MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 $(VBOX_REBOOT_REQUIRED) /SD IDNO IDYES restart + StrCmp $g_bRebootOnExit "true" restart +!endif + + Goto exit + +restart: + + DetailPrint "Rebooting ..." + Reboot + +exit: + +SectionEnd + +; !EXTERNAL_UNINSTALLER +!endif + +;Direct the output to our bin dir +!cd "$%PATH_OUT%\bin\additions" diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsCommon.nsh b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsCommon.nsh new file mode 100644 index 00000000000..be1101d1e92 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsCommon.nsh @@ -0,0 +1,438 @@ + +!ifndef UNINSTALLER_ONLY +Function ExtractFiles + + ; @todo: Use a define for all the file specs to group the files per module + ; and keep the redundancy low. + + Push $0 + StrCpy "$0" "$INSTDIR\$%BUILD_TARGET_ARCH%" + + ; Video driver + SetOutPath "$0\VBoxVideo" + FILE "$%PATH_OUT%\bin\additions\VBoxVideo.sys" + FILE "$%PATH_OUT%\bin\additions\VBoxVideo.inf" +!ifdef VBOX_SIGN_ADDITIONS + FILE "$%PATH_OUT%\bin\additions\VBoxVideo.cat" +!endif + FILE "$%PATH_OUT%\bin\additions\VBoxDisp.dll" + +!if $%VBOX_WITH_CROGL% == "1" + ; crOpenGL + FILE "$%PATH_OUT%\bin\additions\VBoxOGLarrayspu.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxOGLcrutil.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxOGLerrorspu.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxOGLpackspu.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxOGLpassthroughspu.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxOGLfeedbackspu.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxOGL.dll" + + ; Do *not* install 64-bit d3d files - they don't work yet. + !if $%BUILD_TARGET_ARCH% == "x86" + SetOutPath "$0\VBoxVideo\OpenGL" + FILE "$%PATH_OUT%\bin\additions\d3d8.dll" + FILE "$%PATH_OUT%\bin\additions\d3d9.dll" + FILE "$%PATH_OUT%\bin\additions\libWine.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxD3D8.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxD3D9.dll" + FILE "$%PATH_OUT%\bin\additions\wined3d.dll" + !endif + + !if $%BUILD_TARGET_ARCH% == "amd64" + ; Only 64-bit installer: Also copy 32-bit DLLs on 64-bit target + SetOutPath "$0\VBoxVideo\OpenGL\SysWow64" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d8.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d9.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\libWine.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLarrayspu.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLcrutil.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLerrorspu.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLpackspu.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLpassthroughspu.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLfeedbackspu.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGL.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxD3D8.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxD3D9.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\wined3d.dll" + !endif +!endif + + ; Mouse driver + SetOutPath "$0\VBoxMouse" + FILE "$%PATH_OUT%\bin\additions\VBoxMouse.sys" + FILE "$%PATH_OUT%\bin\additions\VBoxMouse.inf" +!ifdef VBOX_SIGN_ADDITIONS + FILE "$%PATH_OUT%\bin\additions\VBoxMouse.cat" +!endif + +!if $%BUILD_TARGET_ARCH% == "x86" + SetOutPath "$0\VBoxMouse\NT4" + FILE "$%PATH_OUT%\bin\additions\VBoxMouseNT.sys" +!endif + + ; Guest driver + SetOutPath "$0\VBoxGuest" + FILE "$%PATH_OUT%\bin\additions\VBoxGuest.sys" + FILE "$%PATH_OUT%\bin\additions\VBoxGuest.inf" +!ifdef VBOX_SIGN_ADDITIONS + FILE "$%PATH_OUT%\bin\additions\VBoxGuest.cat" +!endif + FILE "$%PATH_OUT%\bin\additions\VBCoInst.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxTray.exe" + FILE "$%PATH_OUT%\bin\additions\VBoxHook.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxControl.exe" + +!if $%BUILD_TARGET_ARCH% == "x86" + SetOutPath "$0\VBoxGuest\NT4" + FILE "$%PATH_OUT%\bin\additions\VBoxGuestNT.sys" +!endif + + ; VBoxService + SetOutPath "$0\Bin" + FILE "$%PATH_OUT%\bin\additions\VBoxService.exe" +!if $%BUILD_TARGET_ARCH% == "x86" + FILE "$%PATH_OUT%\bin\additions\VBoxServiceNT.exe" +!endif + + ; Shared Folders + SetOutPath "$0\VBoxSF" + FILE "$%PATH_OUT%\bin\additions\VBoxSF.sys" + FILE "$%PATH_OUT%\bin\additions\VBoxMRXNP.dll" + + ; AMD PCNet driver + SetOutPath "$0\Network\AMD" + FILE "..\Network\AMD\netamd.inf" + FILE "..\Network\AMD\pcntpci5.cat" + FILE "..\Network\AMD\PCNTPCI5.sys" + + ; Auto-Logon + SetOutPath "$0\AutoLogon" + FILE "$%PATH_OUT%\bin\additions\VBoxGINA.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxCredProv.dll" + + ; Misc tools + SetOutPath "$0\Tools" + FILE "$%PATH_OUT%\bin\additions\VBoxDrvInst.exe" + +!if $%BUILD_TARGET_ARCH% == "x86" + SetOutPath "$0\Tools\NT4" + FILE "$%PATH_OUT%\bin\additions\VBoxGuestDrvInst.exe" + FILE "$%PATH_OUT%\bin\additions\RegCleanup.exe" +!endif + + Pop $0 + +FunctionEnd +!endif ; UNINSTALLER_ONLY + +!macro EnableLog un +Function ${un}EnableLog + +!ifdef _DEBUG + Goto log +!endif + + StrCmp $g_bLogEnable "true" log + Goto exit + +log: + + LogSet on + LogText "Start logging." + +exit: + +FunctionEnd +!macroend +!insertmacro EnableLog "" +!insertmacro EnableLog "un." + +!macro WriteLogUI un +Function ${un}WriteLogUI + + IfSilent exit + +!ifdef _DEBUG + Goto log +!endif + + StrCmp $g_bLogEnable "true" log + Goto exit + +log: + + ; Dump log to see what happend + StrCpy $0 "$INSTDIR\${un}install_ui.log" + Push $0 + Call ${un}DumpLog + +exit: + +FunctionEnd +!macroend +!insertmacro WriteLogUI "" +!insertmacro WriteLogUI "un." + +!macro GetWindowsVer un +Function ${un}GetWindowsVer + + ; Check if we are running on w2k or above. For other windows versions (>XP) it may be necessary to change winver.nsh + ; Get the Windows version + Call ${un}GetWindowsVersion + Pop $R3 ; Windows Version + + Push $R3 ; The windows version string + Push "NT" ; String to search for. Win 2k family returns no string containing 'NT' + Call ${un}StrStr + Pop $R0 + StrCmp $R0 '' no_nt4 ; Not NT 3.XX or 4.XX + + ; Ok we know it is NT. Must be a string like NT X.XX + Push $R3 ; The windows version string + Push "4." ; String to search for + Call ${un}StrStr + Pop $R0 + StrCmp $R0 "" no_nt4 nt4 ; If empty -> not NT 4 + +no_nt4: + + StrCmp $R3 "2000" w2k_xp + StrCmp $R3 "XP" w2k_xp + StrCmp $R3 "2003" w2k_xp + StrCmp $R3 "Vista" vista + StrCmp $R3 "7" vista + Goto unknown + +nt4: ; NT 4.0 + + StrCpy $g_strWinVersion "nt4" + goto exit + +w2k_xp: ; NT 5.0, 5.1 or 5.2 + + StrCpy $g_strWinVersion "2k" + goto exit + +vista: ; NT 6.0 or 6.1 (Vista or Windows 7) + + StrCpy $g_strWinVersion "vista" + goto exit + +unknown: + + StrCpy $g_strWinVersion "unknown" + goto exit + +exit: + +FunctionEnd +!macroend + +; Insert function as an installer and uninstaller function. +!insertmacro GetWindowsVer "" +!insertmacro GetWindowsVer "un." + +!macro GetAdditionsVersion un +Function ${un}GetAdditionsVersion + + Push $0 + Push $1 + + ; Get additions version + ReadRegStr $0 HKLM "SOFTWARE\$%VBOX_VENDOR_SHORT%\VirtualBox Guest Additions" "Version" + + ; Get revision + ReadRegStr $g_strAddVerRev HKLM "SOFTWARE\$%VBOX_VENDOR_SHORT%\VirtualBox Guest Additions" "Revision" + + ; Extract major version + Push "$0" ; String + Push "." ; SubString + Push ">" ; SearchDirection + Push "<" ; StrInclusionDirection + Push "0" ; IncludeSubString + Push "0" ; Loops + Push "0" ; CaseSensitive + Call ${un}StrStrAdv + Pop $g_strAddVerMaj + + ; Extract minor version + Push "$0" ; String + Push "." ; SubString + Push ">" ; SearchDirection + Push ">" ; StrInclusionDirection + Push "0" ; IncludeSubString + Push "0" ; Loops + Push "0" ; CaseSensitive + Call ${un}StrStrAdv + Pop $1 ; Got first part (e.g. "1.5") + + Push "$1" ; String + Push "." ; SubString + Push ">" ; SearchDirection + Push "<" ; StrInclusionDirection + Push "0" ; IncludeSubString + Push "0" ; Loops + Push "0" ; CaseSensitive + Call ${un}StrStrAdv + Pop $g_strAddVerMin ; Extracted second part (e.g. "5" from "1.5") + + ; Extract build number + Push "$0" ; String + Push "." ; SubString + Push "<" ; SearchDirection + Push ">" ; StrInclusionDirection + Push "0" ; IncludeSubString + Push "0" ; Loops + Push "0" ; CaseSensitive + Call ${un}StrStrAdv + Pop $g_strAddVerBuild + +exit: + + Pop $1 + Pop $0 + +FunctionEnd +!macroend + +; Insert function as an installer and uninstaller function. +!insertmacro GetAdditionsVersion "" +!insertmacro GetAdditionsVersion "un." + +!macro IsUserAdmin un +Function ${un}IsUserAdmin + + ; Check if current user has admin rights + UserInfo::GetAccountType + Pop $0 + StrCmp $0 "Admin" is_admin 0 + MessageBox MB_ICONSTOP $(VBOX_NOADMIN) + Abort + +is_admin: + +FunctionEnd +!macroend + +; Insert function as an installer and uninstaller function. +!insertmacro IsUserAdmin "" +!insertmacro IsUserAdmin "un." + +!macro StopVBoxService un +Function ${un}StopVBoxService + + Push $0 ; Temp results + Push $1 + Push $2 ; Image name of VBoxService + Push $3 ; Safety counter + + StrCpy $3 "0" ; Init counter + DetailPrint "Stopping VBoxService ..." + +svc_stop: + + LogText "Stopping VBoxService (as service) ..." + ${If} $g_strWinVersion == "nt4" + nsExec::Exec '"$SYSDIR\net.exe" stop VBoxService' + ${Else} + nsExec::Exec '"$SYSDIR\SC.exe" stop VBoxService' + ${EndIf} + Sleep "1000" ; Wait a bit + +exe_stop: + +!ifdef _DEBUG + DetailPrint "Stopping VBoxService (as exe) ..." +!endif + +exe_stop_loop: + + IntCmp $3 10 exit ; Only try this loop 10 times max + IntOp $3 $3 + 1 ; Increment + + LogText "Try: $3" + + ${If} $g_strWinVersion == "nt4" + StrCpy $2 "VBoxServiceNT.exe" + ${Else} + StrCpy $2 "VBoxService.exe" + ${EndIf} + + ${nsProcess::FindProcess} $2 $0 + StrCmp $0 0 0 exit + + ${nsProcess::KillProcess} $2 $0 + Sleep "1000" ; Wait a bit + Goto exe_stop_loop + +exit: + + DetailPrint "Stopping VBoxService done." + + Pop $3 + Pop $2 + Pop $1 + Pop $0 + +FunctionEnd +!macroend + +; Insert function as an installer and uninstaller function. +!insertmacro StopVBoxService "" +!insertmacro StopVBoxService "un." + +!macro StopVBoxTray un +Function ${un}StopVBoxTray + + Push $0 ; Temp results + Push $1 ; Safety counter + + StrCpy $1 "0" ; Init counter + DetailPrint "Stopping VBoxTray ..." + +exe_stop: + + IntCmp $1 10 exit ; Only try this loop 10 times max + IntOp $1 $1 + 1 ; Increment + + ${nsProcess::FindProcess} "VBoxTray.exe" $0 + StrCmp $0 0 0 exit + + ${nsProcess::KillProcess} "VBoxTray.exe" $0 + Sleep "1000" ; Wait a bit + Goto exe_stop + +exit: + + DetailPrint "Stopping VBoxTray done." + + Pop $1 + Pop $0 + +FunctionEnd +!macroend + +; Insert function as an installer and uninstaller function. +!insertmacro StopVBoxTray "" +!insertmacro StopVBoxTray "un." + +!macro WriteRegBinR ROOT KEY NAME VALUE + WriteRegBin "${ROOT}" "${KEY}" "${NAME}" "${VALUE}" +!macroend + +!macro AbortShutdown un +Function ${un}AbortShutdown + + Push $0 + + ; Try to abort the shutdown + nsExec::ExecToLog '"$g_strSystemDir\shutdown.exe" -a' $0 + + Pop $0 + +FunctionEnd +!macroend + +; Insert function as an installer and uninstaller function. +!insertmacro AbortShutdown "" +!insertmacro AbortShutdown "un." diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsNT4.nsh b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsNT4.nsh new file mode 100644 index 00000000000..313702a9f99 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsNT4.nsh @@ -0,0 +1,258 @@ + +Function NT_SetVideoResolution + + ; Check for all required parameters + StrCmp $g_iScreenX "0" missingParms + StrCmp $g_iScreenY "0" missingParms + StrCmp $g_iScreenBpp "0" missingParms + Goto haveParms + +missingParms: + + DetailPrint "Missing display parameters for NT, setting default (640x480, 8 BPP) ..." + + StrCpy $g_iScreenX '640' ; Default value + StrCpy $g_iScreenY '480' ; Default value + StrCpy $g_iScreenBpp '8' ; Default value + + ; Write setting into registry to show the desktop applet on next boot + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Control\GraphicsDrivers\NewDisplay" "" "" + +haveParms: + + DetailPrint "Setting display parameters for NT ($g_iScreenXx$g_iScreenY, $g_iScreenBpp BPP) ..." + + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.BitsPerPel" $g_iScreenBpp + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.Flags" 0x00000000 + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.VRefresh" 0x00000001 + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.XPanning" 0x00000000 + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.XResolution" $g_iScreenX + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.YPanning" 0x00000000 + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.YResolution" $g_iScreenY + +FunctionEnd + +Function NT_SaveMouseDriverInfo + + Push $0 + + ; !!! NOTE !!! + ; Due to some re-branding (see functions Uninstall_Sun, Uninstall_Innotek and + ; Uninstall_SunXVM) the installer *has* to transport the very first saved i8042prt + ; value to the current installer's "uninstall" directory in both mentioned + ; functions above, otherwise NT4 will be screwed because it then would store + ; "VBoxMouseNT.sys" as the original i8042prt driver which obviously isn't there + ; after uninstallation anymore. + ; !!! NOTE !!! + + ; Save current mouse driver info so we may restore it on uninstallation + ; But first check if we already installed the additions otherwise we will + ; overwrite it with the VBoxMouseNT.sys + ReadRegStr $0 HKLM "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH} + StrCmp $0 "" 0 exists + + DetailPrint "Saving mouse driver info ..." + ReadRegStr $0 HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" + WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH} $0 + Goto exit + +exists: + + DetailPrint "Mouse driver info already saved." + Goto exit + +exit: + +!ifdef _DEBUG + DetailPrint "Mouse driver info: $0" +!endif + + Pop $0 + +FunctionEnd + +Function NT_Prepare + + ; Stop / kill VBoxService + Call StopVBoxService + + ; Stop / kill VBoxTray + Call StopVBoxTray + + ; Delete VBoxService from registry + DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxService" + + ; Delete old VBoxService.exe from install directory (replaced by VBoxTray.exe) + Delete /REBOOTOK "$INSTDIR\VBoxService.exe" + +FunctionEnd + +Function NT_CopyFiles + + DetailPrint "Copying files..." + + SetOutPath "$INSTDIR" + FILE "$%PATH_OUT%\bin\additions\VBoxGuestDrvInst.exe" + FILE "$%PATH_OUT%\bin\additions\RegCleanup.exe" + + ; The files to install for NT 4, they go into the system directories + SetOutPath "$SYSDIR" + FILE "$%PATH_OUT%\bin\additions\VBoxDisp.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxTray.exe" + FILE "$%PATH_OUT%\bin\additions\VBoxHook.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxControl.exe" + + ; VBoxService + FILE "$%PATH_OUT%\bin\additions\VBoxServiceNT.exe" + + ; The drivers into the "drivers" directory + SetOutPath "$SYSDIR\drivers" + FILE "$%PATH_OUT%\bin\additions\VBoxVideo.sys" + FILE "$%PATH_OUT%\bin\additions\VBoxMouseNT.sys" + FILE "$%PATH_OUT%\bin\additions\VBoxGuestNT.sys" + ;FILE "$%PATH_OUT%\bin\additions\VBoxSFNT.sys" ; Shared Folders not available on NT4! + +FunctionEnd + +Function NT_InstallFiles + + DetailPrint "Installing Drivers..." + + ; Install guest driver + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /createsvc "VBoxGuest" "VBoxGuest Support Driver" 1 1 "$SYSDIR\drivers\VBoxGuestNT.sys" "Base"' + + ; Bugfix: Set "Start" to 1, otherwise, VBoxGuest won't start on boot-up! + ; Bugfix: Correct invalid "ImagePath" (\??\C:\WINNT\...) + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Services\VBoxGuest" "Start" 1 + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxGuest" "ImagePath" "System32\Drivers\VBoxGuestNT.sys" + + ; Run VBoxTray when Windows NT starts + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxTray" '"$SYSDIR\VBoxTray.exe"' + + ; Video driver + nsExec::ExecToLog '"$INSTDIR\VBoxGuestDrvInst.exe" /i' + Pop $0 ; Ret value + IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error) + + DetailPrint "Installing VirtualBox service ..." + + ; Create the VBoxService service + ; No need to stop/remove the service here! Do this only on uninstallation! + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /createsvc "VBoxService" "VirtualBox Guest Additions Service" 16 2 "system32\VBoxServiceNT.exe" "Base"' + + ; Create the Shared Folders service ... + ;nsSCM::Install /NOUNLOAD "VBoxSF" "VirtualBox Shared Folders" 1 1 "$SYSDIR\drivers\VBoxSFNT.sys" "Network" "" "" "" + ;Pop $0 ; Ret value + +!ifdef _DEBUG + ;DetailPrint "SCM::Install VBoxSFNT.sys: $0" +!endif + + ;IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error) + + ; ... and the link to the network provider + ;WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxSF\NetworkProvider" "DeviceName" "\Device\VBoxMiniRdr" + ;WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxSF\NetworkProvider" "Name" "VirtualBox Shared Folders" + ;WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxSF\NetworkProvider" "ProviderPath" "$SYSDIR\VBoxMRXNP.dll" + + ; Add the shared folders network provider + ;nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /addnetprovider VBoxSF' + ;Pop $0 ; Ret value + +!ifdef _DEBUG + ;DetailPrint "VBoxDrvInst::AddProvider VBoxSF: $0" +!endif + + ;IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error) + + Goto done + +error: + Abort "ERROR: Could not install files for Windows NT! Installation aborted." + +done: + +FunctionEnd + +Function NT_Main + + SetOutPath "$INSTDIR" + + Call NT_Prepare + Call NT_CopyFiles + + ; This removes the flag "new display driver installed on the next bootup + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" "VBoxGuestInst" '"$INSTDIR\RegCleanup.exe"' + + Call NT_SaveMouseDriverInfo + Call NT_InstallFiles + Call NT_SetVideoResolution + + ; Write mouse driver name to registry overwriting the default name + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" "System32\DRIVERS\VBoxMouseNT.sys" + +FunctionEnd + +!macro NT_UninstallInstDir un +Function ${un}NT_UninstallInstDir + + ; Delete remaining files + Delete /REBOOTOK "$INSTDIR\VBoxGuestDrvInst.exe" + Delete /REBOOTOK "$INSTDIR\RegCleanup.exe" + +FunctionEnd +!macroend +!insertmacro NT_UninstallInstDir "" +!insertmacro NT_UninstallInstDir "un." + +!macro NT_Uninstall un +Function ${un}NT_Uninstall + + Push $0 + + ; Remove the guest driver service + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxGuest' + Delete /REBOOTOK "$SYSDIR\drivers\VBoxGuestNT.sys" + + ; Delete the VBoxService service + Call ${un}StopVBoxService + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxService' + Pop $0 ; Ret value + DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxService" + Delete /REBOOTOK "$SYSDIR\VBoxServiceNT.exe" + + ; Delete the VBoxTray app + Call ${un}StopVBoxTray + DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxTray" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" "VBoxTrayDel" "$SYSDIR\cmd.exe /c del /F /Q $SYSDIR\VBoxTray.exe" + Delete /REBOOTOK "$SYSDIR\VBoxTray.exe" ; If it can't be removed cause it's running, try next boot with "RunOnce" key above! + Delete /REBOOTOK "$SYSDIR\VBoxHook.dll" + + ; Delete the VBoxControl utility + Delete /REBOOTOK "$SYSDIR\VBoxControl.exe" + + ; Delete the VBoxVideo service + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxVideo' + + ; Delete the VBox video driver files + Delete /REBOOTOK "$SYSDIR\drivers\VBoxVideo.sys" + Delete /REBOOTOK "$SYSDIR\VBoxDisp.dll" + + ; Get original mouse driver info and restore it + ReadRegStr $0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH} + ; If we still got our driver stored in $0 then this will *never* work, so + ; warn the user and set it to the default driver to not screw up NT4 here + ${If} $0 == "System32\DRIVERS\VBoxMouseNT.sys" + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" "System32\DRIVERS\i8042prt.sys" + DetailPrint "Old mouse driver is set to VBoxMouseNT.sys, defaulting to i8042prt.sys ..." + ${Else} + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" $0 + ${EndIf} + Delete /REBOOTOK "$SYSDIR\drivers\VBoxMouseNT.sys" + + Pop $0 + +FunctionEnd +!macroend +!insertmacro NT_Uninstall "" +!insertmacro NT_Uninstall "un." diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstall.nsh b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstall.nsh new file mode 100644 index 00000000000..24954530129 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstall.nsh @@ -0,0 +1,209 @@ +
+; @todo Replace this crappy stuff with a "VBoxDrvInst /delnetprovider".
+!macro RemoveFromProvider un
+Function ${un}RemoveFromProvider
+ Exch $0
+ Push $1
+ Push $2
+ Push $3
+ Push $4
+ Push $5
+ Push $6
+
+ ReadRegStr $1 HKLM "$R0" "ProviderOrder"
+ StrCpy $5 $1 1 -1 # copy last char
+ StrCmp $5 "," +2 # if last char != ,
+ StrCpy $1 "$1," # append ,
+ Push $1
+ Push "$0,"
+ Call ${un}StrStr ; Find `$0,` in $1
+ Pop $2 ; pos of our dir
+ StrCmp $2 "" unRemoveFromPath_done
+ ; else, it is in path
+ # $0 - path to add
+ # $1 - path var
+ StrLen $3 "$0,"
+ StrLen $4 $2
+ StrCpy $5 $1 -$4 # $5 is now the part before the path to remove
+ StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove
+ StrCpy $3 $5$6
+
+ StrCpy $5 $3 1 -1 # copy last char
+ StrCmp $5 "," 0 +2 # if last char == ,
+ StrCpy $3 $3 -1 # remove last char
+
+ WriteRegStr HKLM "$R0" "ProviderOrder" $3
+
+unRemoveFromPath_done:
+ Pop $6
+ Pop $5
+ Pop $4
+ Pop $3
+ Pop $2
+ Pop $1
+ Pop $0
+FunctionEnd
+!macroend
+!insertmacro RemoveFromProvider ""
+!insertmacro RemoveFromProvider "un."
+
+!macro RemoveProvider un
+Function ${un}RemoveProvider
+ Push $R0
+ StrCpy $R0 "VBoxSF"
+ Push $R0
+ StrCpy $R0 "SYSTEM\CurrentControlSet\Control\NetworkProvider\HWOrder"
+ Call ${un}RemoveFromProvider
+ StrCpy $R0 "VBoxSF"
+ Push $R0
+ StrCpy $R0 "SYSTEM\CurrentControlSet\Control\NetworkProvider\Order"
+ Call ${un}RemoveFromProvider
+ Pop $R0
+FunctionEnd
+!macroend
+!insertmacro RemoveProvider ""
+!insertmacro RemoveProvider "un."
+
+!macro UninstallCommon un
+Function ${un}UninstallCommon
+
+ Delete /REBOOTOK "$INSTDIR\install.log"
+ Delete /REBOOTOK "$INSTDIR\uninst.exe"
+ Delete /REBOOTOK "$INSTDIR\${PRODUCT_NAME}.url"
+
+ ; Remove common files
+ Delete /REBOOTOK "$INSTDIR\VBoxDrvInst.exe"
+
+ Delete /REBOOTOK "$INSTDIR\VBoxVideo.inf"
+!ifdef VBOX_SIGN_ADDITIONS
+ Delete /REBOOTOK "$INSTDIR\VBoxVideo.cat"
+!endif
+
+ Delete /REBOOTOK "$INSTDIR\VBoxGINA.dll"
+ Delete /REBOOTOK "$INSTDIR\iexplore.ico"
+
+ ; Delete registry keys
+ DeleteRegKey /ifempty HKLM "${PRODUCT_INSTALL_KEY}"
+ DeleteRegKey /ifempty HKLM "${VENDOR_ROOT_KEY}"
+
+ ; Delete desktop & start menu entries
+ Delete "$DESKTOP\${PRODUCT_NAME} Guest Additions.lnk"
+ Delete "$SMPROGRAMS\${PRODUCT_NAME} Guest Additions\Uninstall.lnk"
+ Delete "$SMPROGRAMS\${PRODUCT_NAME} Guest Additions\Website.lnk"
+ RMDIR "$SMPROGRAMS\${PRODUCT_NAME} Guest Additions"
+
+ ; Delete Guest Additions directory (only if completely empty)
+ RMDir /REBOOTOK "$INSTDIR"
+
+ ; Delete vendor installation directory (only if completely empty)
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ RMDir /REBOOTOK "$PROGRAMFILES32\$%VBOX_VENDOR_SHORT%"
+!else ; 64-bit
+ RMDir /REBOOTOK "$PROGRAMFILES64\$%VBOX_VENDOR_SHORT%"
+!endif
+
+ ; Remove registry entries
+ DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
+
+FunctionEnd
+!macroend
+!insertmacro UninstallCommon ""
+!insertmacro UninstallCommon "un."
+
+!macro Uninstall un
+Function ${un}Uninstall
+
+ DetailPrint "Uninstalling system files ..."
+ DetailPrint "Handled Windows version: $g_strWinVersion"
+ DetailPrint "System Directory: $g_strSystemDir"
+
+ ; Which OS are we using?
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ StrCmp $g_strWinVersion "nt4" nt4
+!endif
+ StrCmp $g_strWinVersion "2k" w2k
+ StrCmp $g_strWinVersion "vista" vista
+
+ Goto notsupported
+
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+nt4:
+
+ Call ${un}NT_Uninstall
+ goto common
+!endif
+
+w2k:
+
+ Call ${un}W2K_Uninstall
+ goto common
+
+vista:
+
+ Call ${un}W2K_Uninstall
+ Call ${un}Vista_Uninstall
+ goto common
+
+notsupported:
+
+ MessageBox MB_ICONSTOP $(VBOX_PLATFORM_UNSUPPORTED) /SD IDOK
+ Goto exit
+
+common:
+
+exit:
+
+FunctionEnd
+!macroend
+!insertmacro Uninstall ""
+!insertmacro Uninstall "un."
+
+!macro UninstallInstDir un
+Function ${un}UninstallInstDir
+
+ DetailPrint "Uninstalling directory ..."
+ DetailPrint "Handled Windows version: $g_strWinVersion"
+ DetailPrint "System Directory: $g_strSystemDir"
+
+ ; Which OS are we using?
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ StrCmp $g_strWinVersion "nt4" nt4
+!endif
+ StrCmp $g_strWinVersion "2k" w2k
+ StrCmp $g_strWinVersion "vista" vista
+
+ Goto notsupported
+
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+nt4:
+
+ Call ${un}NT_UninstallInstDir
+ goto common
+!endif
+
+w2k:
+
+ Call ${un}W2K_UninstallInstDir
+ goto common
+
+vista:
+
+ Call ${un}W2K_UninstallInstDir
+ Call ${un}Vista_UninstallInstDir
+ goto common
+
+notsupported:
+
+ MessageBox MB_ICONSTOP $(VBOX_PLATFORM_UNSUPPORTED) /SD IDOK
+ Goto exit
+
+common:
+
+ Call ${un}UninstallCommon
+
+exit:
+
+FunctionEnd
+!macroend
+!insertmacro UninstallInstDir ""
+!insertmacro UninstallInstDir "un."
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstallOld.nsh b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstallOld.nsh new file mode 100644 index 00000000000..e3f4d992fd0 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstallOld.nsh @@ -0,0 +1,345 @@ +
+!macro Uninstall_RunExtUnInstaller un
+Function ${un}Uninstall_RunExtUnInstaller
+
+ Pop $0
+ Push $1
+ Push $2
+
+ ; Try to run the current uninstaller
+ StrCpy $1 "$0\uninst.exe"
+ IfFileExists "$1" run 0
+ MessageBox MB_OK "VirtualBox Guest Additions uninstaller not found! Path = $1" /SD IDOK
+ StrCpy $0 1 ; Tell the caller that we were not able to start the uninstaller
+ Goto exit
+
+run:
+
+ ; Always try to run in silent mode
+ Goto run_uninst_silent
+
+run_uninst_silent:
+
+ ExecWait '"$1" /S _?=$0' $2 ; Silently run uninst.exe in it's dir and don't copy it to a temp. location
+ Goto handle_result
+
+run_uninst:
+
+ ExecWait '"$1" _?=$0' $2 ; Run uninst.exe in it's dir and don't copy it to a temp. location
+ Goto handle_result
+
+handle_result:
+
+ ; Note that here a race might going on after the user clicked on
+ ; "Reboot now" in the installer ran above and this installer cleaning
+ ; up aftwards.
+
+ ; ... so try to abort the current reboot / shutdown caused by the installer ran before
+ Call ${un}AbortShutdown
+
+;!ifdef _DEBUG
+; MessageBox MB_OK 'Debug Message: Uninstaller was called, result is: $2' /SD IDOK
+;!endif
+
+ ${Switch} $2 ; Check exit codes
+ ${Case} 1 ; Aborted by user
+ StrCpy $0 1 ; Tell the caller that we were aborted by the user
+ ${Break}
+ ${Case} 2 ; Aborted by script (that might be okay)
+ StrCpy $0 0 ; All went well
+ ${Break}
+ ${Default} ; Normal exixt
+ StrCpy $0 0 ; All went well
+ ${Break}
+ ${EndSwitch}
+ Goto exit
+
+exit:
+
+ Pop $2
+ Pop $1
+ Push $0
+
+FunctionEnd
+!macroend
+!insertmacro Uninstall_RunExtUnInstaller ""
+!insertmacro Uninstall_RunExtUnInstaller "un."
+
+!macro Uninstall_WipeInstallationDirectory un
+Function ${un}Uninstall_WipeInstallationDirectory
+
+ Pop $0
+ Push $1
+ Push $2
+
+ ; Do some basic sanity checks for not screwing up too fatal ...
+ DetailPrint "Removing old installation directory ($0) ..."
+ ${If} $0 != $PROGRAMFILES
+ ${AndIf} $0 != $PROGRAMFILES32
+ ${AndIf} $0 != $PROGRAMFILES64
+ ${AndIf} $0 != $COMMONFILES32
+ ${AndIf} $0 != $COMMONFILES64
+ ${AndIf} $0 != $WINDIR
+ ${AndIf} $0 != $SYSDIR
+ DetailPrint "Wiping ($0) ..."
+ Goto wipe
+ ${EndIf}
+ Goto wipe_abort
+
+wipe:
+
+ RMDir /r /REBOOTOK "$0"
+ StrCpy $0 0 ; All went well
+ Goto exit
+
+wipe_abort:
+
+ DetailPrint "Won't remove directory ($0)!"
+ StrCpy $0 1 ; Signal some failure
+ Goto exit
+
+exit:
+
+ Pop $2
+ Pop $1
+ Push $0
+
+FunctionEnd
+!macroend
+!insertmacro Uninstall_WipeInstallationDirectory ""
+!insertmacro Uninstall_WipeInstallationDirectory "un."
+
+; This function cleans up an old Sun installation
+!macro Uninstall_Sun un
+Function ${un}Uninstall_Sun
+
+ Push $0
+ Push $1
+ Push $2
+
+ ; Get current installation path
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sun VirtualBox Guest Additions" "UninstallString"
+ StrCmp $0 "" exit
+
+ ; Extract path
+ Push "$0" ; String
+ Push "\" ; SubString
+ Push "<" ; SearchDirection
+ Push "<" ; StrInclusionDirection
+ Push "0" ; IncludeSubString
+ Push "0" ; Loops
+ Push "0" ; CaseSensitive
+ Call ${un}StrStrAdv
+ Pop $1 ; $1 only contains the full path
+
+ StrCmp $1 "" exit
+
+ ; Save current i8042prt info to new uninstall registry path
+ ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Sun VirtualBox Guest Additions" ${ORG_MOUSE_PATH}
+ WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH} $0
+
+ ; Try to wipe current installation directory
+ Push $1 ; Push uninstaller path to stack
+ Call ${un}Uninstall_WipeInstallationDirectory
+ Pop $2 ; Get uninstaller exit code from stack
+ StrCmp $2 0 common exit ; Only process common part if exit code is 0, otherwise exit
+
+common:
+
+ ; Make sure everything is cleaned up in case the old uninstaller did forget something
+ DeleteRegKey HKLM "SOFTWARE\Sun\VirtualBox Guest Additions"
+ DeleteRegKey /ifempty HKLM "SOFTWARE\Sun"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Sun VirtualBox Guest Additions"
+ Delete /REBOOTOK "$1\netamd.inf"
+ Delete /REBOOTOK "$1\pcntpci5.cat"
+ Delete /REBOOTOK "$1\PCNTPCI5.sys"
+
+ ; Try to remove old installation directory if empty
+ RMDir /r /REBOOTOK "$SMPROGRAMS\Sun VirtualBox Guest Additions"
+ RMDir /REBOOTOK "$1"
+
+ ; Get original mouse driver info and restore it
+ ;ReadRegStr $0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH}
+ ;WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" $0
+ ;Delete "$SYSDIR\drivers\VBoxMouseNT.sys"
+
+ ; Delete vendor installation directory (only if completely empty)
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ RMDir /REBOOTOK "$PROGRAMFILES32\Sun"
+!else ; 64-bit
+ RMDir /REBOOTOK "$PROGRAMFILES64\Sun"
+!endif
+
+exit:
+
+ Pop $2
+ Pop $1
+ Pop $0
+
+FunctionEnd
+!macroend
+!insertmacro Uninstall_Sun ""
+!insertmacro Uninstall_Sun "un."
+
+; This function cleans up an old xVM Sun installation
+!macro Uninstall_SunXVM un
+Function ${un}Uninstall_SunXVM
+
+ Push $0
+ Push $1
+ Push $2
+
+ ; Get current installation path
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sun xVM VirtualBox Guest Additions" "UninstallString"
+ StrCmp $0 "" exit
+
+ ; Extract path
+ Push "$0" ; String
+ Push "\" ; SubString
+ Push "<" ; SearchDirection
+ Push "<" ; StrInclusionDirection
+ Push "0" ; IncludeSubString
+ Push "0" ; Loops
+ Push "0" ; CaseSensitive
+ Call ${un}StrStrAdv
+ Pop $1 ; $1 only contains the full path
+
+ StrCmp $1 "" exit
+
+ ; Save current i8042prt info to new uninstall registry path
+ ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Sun xVM VirtualBox Guest Additions" ${ORG_MOUSE_PATH}
+ WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH} $0
+
+ ; Try to wipe current installation directory
+ Push $1 ; Push uninstaller path to stack
+ Call ${un}Uninstall_WipeInstallationDirectory
+ Pop $2 ; Get uninstaller exit code from stack
+ StrCmp $2 0 common exit ; Only process common part if exit code is 0, otherwise exit
+
+common:
+
+ ; Make sure everything is cleaned up in case the old uninstaller did forget something
+ DeleteRegKey HKLM "SOFTWARE\Sun\xVM VirtualBox Guest Additions"
+ DeleteRegKey /ifempty HKLM "SOFTWARE\Sun"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Sun xVM VirtualBox Guest Additions"
+ Delete /REBOOTOK "$1\netamd.inf"
+ Delete /REBOOTOK "$1\pcntpci5.cat"
+ Delete /REBOOTOK "$1\PCNTPCI5.sys"
+
+ ; Try to remove old installation directory if empty
+ RMDir /r /REBOOTOK "$SMPROGRAMS\Sun xVM VirtualBox Guest Additions"
+ RMDir /REBOOTOK "$1"
+
+ ; Delete vendor installation directory (only if completely empty)
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ RMDir /REBOOTOK "$PROGRAMFILES32\Sun"
+!else ; 64-bit
+ RMDir /REBOOTOK "$PROGRAMFILES64\Sun"
+!endif
+
+ ; Get original mouse driver info and restore it
+ ;ReadRegStr $0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH}
+ ;WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" $0
+ ;Delete "$SYSDIR\drivers\VBoxMouseNT.sys"
+
+exit:
+
+ Pop $2
+ Pop $1
+ Pop $0
+
+FunctionEnd
+!macroend
+!insertmacro Uninstall_SunXVM ""
+!insertmacro Uninstall_SunXVM "un."
+
+; This function cleans up an old innotek installation.
+!macro Uninstall_Innotek un
+Function ${un}Uninstall_Innotek
+
+ Push $0
+ Push $1
+ Push $2
+
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\innotek VirtualBox Guest Additions" "UninstallString"
+ StrCmp $0 "" exit
+
+ ; Extract path
+ Push "$0" ; String
+ Push "\" ; SubString
+ Push "<" ; SearchDirection
+ Push "<" ; StrInclusionDirection
+ Push "0" ; IncludeSubString
+ Push "0" ; Loops
+ Push "0" ; CaseSensitive
+ Call ${un}StrStrAdv
+ Pop $1 ; $1 only contains the full path
+
+ StrCmp $1 "" exit
+
+ ; Save current i8042prt info to new uninstall registry path
+ ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\innotek VirtualBox Guest Additions" ${ORG_MOUSE_PATH}
+ WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH} $0
+
+ ; Try to wipe current installation directory
+ Push $1 ; Push uninstaller path to stack
+ Call ${un}Uninstall_WipeInstallationDirectory
+ Pop $2 ; Get uninstaller exit code from stack
+ StrCmp $2 0 common exit ; Only process common part if exit code is 0, otherwise exit
+
+common:
+
+ ; Remove left over files which were not entirely catched by the formerly running
+ ; uninstaller
+ DeleteRegKey HKLM "SOFTWARE\innotek\VirtualBox Guest Additions"
+ DeleteRegKey HKLM "SOFTWARE\innotek"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\innotek VirtualBox Guest Additions"
+ Delete /REBOOTOK "$1\VBoxGuestDrvInst.exe"
+ Delete /REBOOTOK "$1\VBoxMouseInst.exe"
+ Delete /REBOOTOK "$1\VBoxSFDrvInst.exe"
+ Delete /REBOOTOK "$1\RegCleanup.exe"
+ Delete /REBOOTOK "$1\VBoxService.exe"
+ Delete /REBOOTOK "$1\VBoxMouseInst.exe"
+ Delete /REBOOTOK "$1\innotek VirtualBox Guest Additions.url"
+ Delete /REBOOTOK "$1\uninst.exe"
+ Delete /REBOOTOK "$1\iexplore.ico"
+ Delete /REBOOTOK "$1\install.log"
+ Delete /REBOOTOK "$1\VBCoInst.dll"
+ Delete /REBOOTOK "$1\VBoxControl.exe"
+ Delete /REBOOTOK "$1\VBoxDisp.dll"
+ Delete /REBOOTOK "$1\VBoxGINA.dll"
+ Delete /REBOOTOK "$1\VBoxGuest.cat"
+ Delete /REBOOTOK "$1\VBoxGuest.inf"
+ Delete /REBOOTOK "$1\VBoxGuest.sys"
+ Delete /REBOOTOK "$1\VBoxMouse.inf"
+ Delete /REBOOTOK "$1\VBoxMouse.sys"
+ Delete /REBOOTOK "$1\VBoxVideo.cat"
+ Delete /REBOOTOK "$1\VBoxVideo.inf"
+ Delete /REBOOTOK "$1\VBoxVideo.sys"
+
+ ; Try to remove old installation directory if empty
+ RMDir /r /REBOOTOK "$SMPROGRAMS\innotek VirtualBox Guest Additions"
+ RMDir /REBOOTOK "$1"
+
+ ; Delete vendor installation directory (only if completely empty)
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ RMDir /REBOOTOK "$PROGRAMFILES32\innotek"
+!else ; 64-bit
+ RMDir /REBOOTOK "$PROGRAMFILES64\innotek"
+!endif
+
+ ; Get original mouse driver info and restore it
+ ;ReadRegStr $0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH}
+ ;WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" $0
+ ;Delete "$SYSDIR\drivers\VBoxMouseNT.sys"
+
+exit:
+
+ Pop $2
+ Pop $1
+ Pop $0
+
+FunctionEnd
+!macroend
+!insertmacro Uninstall_Innotek ""
+!insertmacro Uninstall_Innotek "un."
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsVista.nsh b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsVista.nsh new file mode 100644 index 00000000000..3807c94275f --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsVista.nsh @@ -0,0 +1,89 @@ + +Function Vista_CopyFiles + + SetOutPath "$INSTDIR" + SetOverwrite on + + ; The files are for Vista only, they go into the application directory + + ; VBoxNET drivers are not tested yet - commented out until officially supported and released + ;FILE "$%PATH_OUT%\bin\additions\VBoxNET.inf" + ;FILE "$%PATH_OUT%\bin\additions\VBoxNET.sys" + +!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit + ; AMD PCNet network driver + FILE "..\Network\AMD\netamd.inf" + FILE "..\Network\AMD\pcntpci5.cat" + FILE "..\Network\AMD\PCNTPCI5.sys" +!endif + +FunctionEnd + +Function Vista_InstallFiles + + DetailPrint "Installing Drivers for Vista / Windows 7 ..." + + SetOutPath "$INSTDIR" + + ; VBoxNET drivers are not tested yet - commented out until officially supported and released + ;nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /i "PCI\VEN_1022&DEV_2000&SUBSYS_20001022&REV_40" "$INSTDIR\VBoxNET.inf" "Net"' + ;Pop $0 ; Ret value + ;IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error) + ;Goto done + +!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit + ; AMD PCnet drivers + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /i "PCI\VEN_1022&DEV_2000&SUBSYS_20001022&REV_40" "$INSTDIR\netamd.inf" "Net"' + Pop $0 ; Ret value + IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error) +!endif + + Goto done + +error: + Abort "ERROR: Could not install files for Vista / Windows 7! Installation aborted." + +done: + +FunctionEnd + +Function Vista_Main + + Call Vista_CopyFiles + Call Vista_InstallFiles + +FunctionEnd + +!macro Vista_UninstallInstDir un +Function ${un}Vista_UninstallInstDir + +!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit + Delete /REBOOTOK "$INSTDIR\netamd.inf" + Delete /REBOOTOK "$INSTDIR\pcntpci5.cat" + Delete /REBOOTOK "$INSTDIR\PCNTPCI5.sys" +!endif + +FunctionEnd +!macroend +!insertmacro Vista_UninstallInstDir "" +!insertmacro Vista_UninstallInstDir "un." + +!macro Vista_Uninstall un +Function ${un}Vista_Uninstall + + ; Remove credential provider + DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{275D3BCC-22BB-4948-A7F6-3A3054EBA92B}" + DeleteRegKey HKCR "CLSID\{275D3BCC-22BB-4948-A7F6-3A3054EBA92B}" + Delete /REBOOTOK "$g_strSystemDir\VBoxCredProv.dll" + +!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit + ; Remove network card driver + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /u "PCI\VEN_1022&DEV_2000&SUBSYS_20001022&REV_40"' + Pop $0 ; Ret value + ; @todo Add error handling here! +!endif + +FunctionEnd +!macroend +!insertmacro Vista_Uninstall "" +!insertmacro Vista_Uninstall "un." diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsW2KXP.nsh b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsW2KXP.nsh new file mode 100644 index 00000000000..ff9d13ea591 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsW2KXP.nsh @@ -0,0 +1,562 @@ + +Function W2K_SetVideoResolution + + ; NSIS only supports global vars, even in functions -- great + Var /GLOBAL i + Var /GLOBAL tmp + Var /GLOBAL tmppath + Var /GLOBAL win_ver + Var /GLOBAL dev_id + Var /GLOBAL dev_desc + + ; Check for all required parameters + StrCmp $g_iScreenX "0" exit + StrCmp $g_iScreenY "0" exit + StrCmp $g_iScreenBpp "0" exit + + Call GetWindowsVersion + Pop $win_ver ; Now contains Windows version + + DetailPrint "Setting display parameters ($g_iScreenXx$g_iScreenY, $g_iScreenBpp BPP) ..." + + ; Enumerate all video devices (up to 32 at the moment, use key "MaxObjectNumber" key later) + ${For} $i 0 32 + + ReadRegStr $tmp HKLM "HARDWARE\DEVICEMAP\VIDEO" "\Device\Video$i" + StrCmp $tmp "" dev_not_found + + ; Extract path to video settings + ; Ex: \Registry\Machine\System\CurrentControlSet\Control\Video\{28B74D2B-F0A9-48E0-8028-D76F6BB1AE65}\0000 + ; Or: \Registry\Machine\System\CurrentControlSet\Control\Video\vboxvideo\Device0 + ; Result: Machine\System\CurrentControlSet\Control\Video\{28B74D2B-F0A9-48E0-8028-D76F6BB1AE65}\0000 + Push "$tmp" ; String + Push "\" ; SubString + Push ">" ; SearchDirection + Push ">" ; StrInclusionDirection + Push "0" ; IncludeSubString + Push "2" ; Loops + Push "0" ; CaseSensitive + Call StrStrAdv + Pop $tmppath ; $1 only contains the full path + StrCmp $tmppath "" dev_not_found + + ; Get device description + ReadRegStr $dev_desc HKLM "$tmppath" "Device Description" +!ifdef _DEBUG + DetailPrint "Registry path: $tmppath" + DetailPrint "Registry path to device name: $temp" +!endif + DetailPrint "Detected video device: $dev_desc" + + ${If} $dev_desc == "VirtualBox Graphics Adapter" + DetailPrint "VirtualBox video device found!" + Goto dev_found + ${EndIf} + ${Next} + Goto dev_not_found + +dev_found: + + ; If we're on Windows 2000, skip the ID detection ... + StrCmp $win_ver "2000" change_res + Goto dev_found_detect_id + +dev_found_detect_id: + + StrCpy $i 0 ; Start at index 0 + DetailPrint "Detecting device ID ..." + +dev_found_detect_id_loop: + + ; Resolve real path to hardware instance "{GUID}" + EnumRegKey $dev_id HKLM "SYSTEM\CurrentControlSet\Control\Video" $i + StrCmp $dev_id "" dev_not_found ; No more entries? Jump out +!ifdef _DEBUG + DetailPrint "Got device ID: $dev_id" +!endif + ReadRegStr $dev_desc HKLM "SYSTEM\CurrentControlSet\Control\Video\$dev_id\0000" "Device Description" ; Try to read device name + ${If} $dev_desc == "VirtualBox Graphics Adapter" + DetailPrint "Device ID of $dev_desc: $dev_id" + Goto change_res + ${EndIf} + + IntOp $i $i + 1 ; Increment index + goto dev_found_detect_id_loop + +dev_not_found: + + DetailPrint "No VirtualBox video device (yet) detected! No custom mode set." + Goto exit + +change_res: + +!ifdef _DEBUG + DetailPrint "Device description: $dev_desc" + DetailPrint "Device ID: $dev_id" +!endif + + Var /GLOBAL reg_path_device + Var /GLOBAL reg_path_monitor + + DetailPrint "Custom mode set: Platform is '$win_ver'." + ${If} $win_ver == "2000" + ${OrIf} $win_ver == "Vista" + StrCpy $reg_path_device "SYSTEM\CurrentControlSet\SERVICES\VBoxVideo\Device0" + StrCpy $reg_path_monitor "SYSTEM\CurrentControlSet\SERVICES\VBoxVideo\Device0\Mon00000001" + ${ElseIf} $win_ver == "XP" + ${OrIf} $win_ver == "7" + StrCpy $reg_path_device "SYSTEM\CurrentControlSet\Control\Video\$dev_id\0000" + StrCpy $reg_path_monitor "SYSTEM\CurrentControlSet\Control\VIDEO\$dev_id\0000\Mon00000001" + ${Else} + DetailPrint "Custom mode set: Platform '$win_ver' not supported yet." + Goto exit + ${EndIf} + + ; Write the new value in the adapter config (VBoxVideo.sys) using hex values in binary format + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /registry write HKLM $reg_path_device CustomXRes REG_BIN $g_iScreenX DWORD' + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /registry write HKLM $reg_path_device CustomYRes REG_BIN $g_iScreenY DWORD' + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /registry write HKLM $reg_path_device CustomBPP REG_BIN $g_iScreenBpp DWORD' + + ; ... and tell Windows to use that mode on next start! + WriteRegDWORD HKCC $reg_path_device "DefaultSettings.XResolution" "$g_iScreenX" + WriteRegDWORD HKCC $reg_path_device "DefaultSettings.YResolution" "$g_iScreenY" + WriteRegDWORD HKCC $reg_path_device "DefaultSettings.BitsPerPixel" "$g_iScreenBpp" + + WriteRegDWORD HKCC $reg_path_monitor "DefaultSettings.XResolution" "$g_iScreenX" + WriteRegDWORD HKCC $reg_path_monitor "DefaultSettings.YResolution" "$g_iScreenY" + WriteRegDWORD HKCC $reg_path_monitor "DefaultSettings.BitsPerPixel" "$g_iScreenBpp" + + DetailPrint "Custom mode set to $g_iScreenXx$g_iScreenY, $g_iScreenBpp BPP on next restart." + +exit: + +FunctionEnd + +Function W2K_Prepare + + ; Stop / kill VBoxService + Call StopVBoxService + + ; Stop / kill VBoxTray + Call StopVBoxTray + + ; Delete VBoxService from registry + DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxService" + + ; Delete old VBoxService.exe from install directory (replaced by VBoxTray.exe) + Delete /REBOOTOK "$INSTDIR\VBoxService.exe" + +FunctionEnd + +Function W2K_CopyFiles + + SetOutPath "$INSTDIR" + + ; Video driver + FILE "$%PATH_OUT%\bin\additions\VBoxVideo.sys" + FILE "$%PATH_OUT%\bin\additions\VBoxDisp.dll" + + ; Mouse driver + FILE "$%PATH_OUT%\bin\additions\VBoxMouse.sys" + FILE "$%PATH_OUT%\bin\additions\VBoxMouse.inf" +!ifdef VBOX_SIGN_ADDITIONS + FILE "$%PATH_OUT%\bin\additions\VBoxMouse.cat" +!endif + + ; Guest driver + FILE "$%PATH_OUT%\bin\additions\VBoxGuest.sys" + FILE "$%PATH_OUT%\bin\additions\VBoxGuest.inf" +!ifdef VBOX_SIGN_ADDITIONS + FILE "$%PATH_OUT%\bin\additions\VBoxGuest.cat" +!endif + + ; Guest driver files + FILE "$%PATH_OUT%\bin\additions\VBCoInst.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxTray.exe" + FILE "$%PATH_OUT%\bin\additions\VBoxControl.exe" ; Not used by W2K and up, but required by the .INF file + + ; WHQL fake +!ifdef WHQL_FAKE + FILE "$%PATH_OUT%\bin\additions\VBoxWHQLFake.exe" +!endif + + SetOutPath $g_strSystemDir + + ; VBoxService + FILE "$%PATH_OUT%\bin\additions\VBoxService.exe" ; Only used by W2K and up (for Shared Folders at the moment) + +!if $%VBOX_WITH_CROGL% == "1" + ; crOpenGL + SetOutPath $g_strSystemDir + FILE "$%PATH_OUT%\bin\additions\VBoxOGLarrayspu.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxOGLcrutil.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxOGLerrorspu.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxOGLpackspu.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxOGLpassthroughspu.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxOGLfeedbackspu.dll" + FILE "$%PATH_OUT%\bin\additions\VBoxOGL.dll" + + !if $%BUILD_TARGET_ARCH% == "amd64" + ; Only 64-bit installer: Also copy 32-bit DLLs on 64-bit target arch in + ; Wow64 node (32-bit sub system). + ${EnableX64FSRedirection} + SetOutPath $SYSDIR + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLarrayspu.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLcrutil.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLerrorspu.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLpackspu.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLpassthroughspu.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLfeedbackspu.dll" + FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGL.dll" + ${DisableX64FSRedirection} + !endif + +!endif ; VBOX_WITH_CROGL + +FunctionEnd + +!ifdef WHQL_FAKE + +Function W2K_WHQLFakeOn + + StrCmp $g_bFakeWHQL "true" do + Goto exit + +do: + + DetailPrint "Turning off WHQL protection..." + nsExec::ExecToLog '"$INSTDIR\VBoxWHQLFake.exe" "ignore"' + +exit: + +FunctionEnd + +Function W2K_WHQLFakeOff + + StrCmp $g_bFakeWHQL "true" do + Goto exit + +do: + + DetailPrint "Turning back on WHQL protection..." + nsExec::ExecToLog '"$INSTDIR\VBoxWHQLFake.exe" "warn"' + +exit: + +FunctionEnd + +!endif + +Function W2K_InstallFiles + + ; The Shared Folder IFS goes to the system directory + FILE /oname=$g_strSystemDir\drivers\VBoxSF.sys "$%PATH_OUT%\bin\additions\VBoxSF.sys" + !insertmacro ReplaceDLL "$%PATH_OUT%\bin\additions\VBoxMRXNP.dll" "$g_strSystemDir\VBoxMRXNP.dll" "$INSTDIR" + AccessControl::GrantOnFile "$g_strSystemDir\VBoxMRXNP.dll" "(BU)" "GenericRead" + + ; The VBoxTray hook DLL also goes to the system directory; it might be locked + !insertmacro ReplaceDLL "$%PATH_OUT%\bin\additions\VBoxHook.dll" "$g_strSystemDir\VBoxHook.dll" "$INSTDIR" + AccessControl::GrantOnFile "$g_strSystemDir\VBoxHook.dll" "(BU)" "GenericRead" + + DetailPrint "Installing Drivers..." + +drv_video: + + StrCmp $g_bNoVideoDrv "true" drv_guest + SetOutPath "$INSTDIR" + DetailPrint "Installing video driver ..." + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /i "PCI\VEN_80EE&DEV_BEEF&SUBSYS_00000000&REV_00" "$INSTDIR\VBoxVideo.inf" "Display"' + Pop $0 ; Ret value + LogText "Video driver result: $0" + IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error) + +drv_guest: + + StrCmp $g_bNoGuestDrv "true" drv_mouse + DetailPrint "Installing guest driver ..." + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /i "PCI\VEN_80EE&DEV_CAFE&SUBSYS_00000000&REV_00" "$INSTDIR\VBoxGuest.inf" "Media"' + Pop $0 ; Ret value + LogText "Guest driver result: $0" + IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error) + +drv_mouse: + + StrCmp $g_bNoMouseDrv "true" vbox_service + DetailPrint "Installing mouse filter ..." + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /inf "$INSTDIR\VBoxMouse.inf"' + Pop $0 ; Ret value + LogText "Mouse driver returned: $0" + IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error) + +vbox_service: + + DetailPrint "Installing VirtualBox service ..." + + ; Create the VBoxService service + ; No need to stop/remove the service here! Do this only on uninstallation! + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /createsvc "VBoxService" "VirtualBox Guest Additions Service" 16 2 "system32\VBoxService.exe" "Base"' + Pop $0 ; Ret value + LogText "VBoxService returned: $0" + + ; Set service description + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxService" "Description" "Manages VM runtime information, time synchronization, remote sysprep execution and miscellaneous utilities for guest operating systems." + +sf: + + DetailPrint "Installing Shared Folders service ..." + + ; Create the Shared Folders service ... + ; No need to stop/remove the service here! Do this only on uninstallation! + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /createsvc "VBoxSF" "VirtualBox Shared Folders" 2 1 "system32\drivers\VBoxSF.sys" "NetworkProvider"' + + ; ... and the link to the network provider + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxSF\NetworkProvider" "DeviceName" "\Device\VBoxMiniRdr" + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxSF\NetworkProvider" "Name" "VirtualBox Shared Folders" + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxSF\NetworkProvider" "ProviderPath" "$SYSDIR\VBoxMRXNP.dll" + + ; Add default network providers (if not present or corrupted) + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /addnetprovider WebClient' + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /addnetprovider LanmanWorkstation' + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /addnetprovider RDPNP' + + ; Add the shared folders network provider + DetailPrint "Adding network provider (Order = $g_iSfOrder) ..." + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /addnetprovider VBoxSF $g_iSfOrder' + Pop $0 ; Ret value + IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error) + +!if $%VBOX_WITH_CROGL% == "1" +cropengl: + + DetailPrint "Installing 3D OpenGL support ..." + WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "Version" 2 + WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "DriverVersion" 1 + WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "Flags" 1 + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "Dll" "VBoxOGL.dll" + + ; Write additional keys required for Windows 7 & XP 64-bit (but for 32-bit stuff) + Push $R0 + Call GetWindowsVersion + Pop $R0 ; Windows Version + ${If} $R0 == '7' + ${OrIf} $R0 == 'XP' + WriteRegDWORD HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "Version" 2 + WriteRegDWORD HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "DriverVersion" 1 + WriteRegDWORD HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "Flags" 1 + WriteRegStr HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "Dll" "VBoxOGL.dll" + ${EndIf} + Pop $R0 +!endif + + Goto done + +error: + + Abort "ERROR: Could not install files for Windows 2000 / XP / Vista! Installation aborted." + +done: + +FunctionEnd + +Function W2K_Main + + SetOutPath "$INSTDIR" + SetOverwrite on + + Call W2K_Prepare + Call W2K_CopyFiles + +!ifdef WHQL_FAKE + Call W2K_WHQLFakeOn +!endif + + Call W2K_InstallFiles + +!ifdef WHQL_FAKE + Call W2K_WHQLFakeOff +!endif + + Call W2K_SetVideoResolution + +FunctionEnd + +!macro W2K_UninstallInstDir un +Function ${un}W2K_UninstallInstDir + + Delete /REBOOTOK "$INSTDIR\VBoxVideo.sys" + Delete /REBOOTOK "$INSTDIR\VBoxVideo.inf" + Delete /REBOOTOK "$INSTDIR\VBoxVideo.cat" + Delete /REBOOTOK "$INSTDIR\VBoxDisp.dll" + + Delete /REBOOTOK "$INSTDIR\VBoxMouse.sys" + Delete /REBOOTOK "$INSTDIR\VBoxMouse.inf" + Delete /REBOOTOK "$INSTDIR\VBoxMouse.cat" + + Delete /REBOOTOK "$INSTDIR\VBoxTray.exe" + + Delete /REBOOTOK "$INSTDIR\VBoxGuest.sys" + Delete /REBOOTOK "$INSTDIR\VBoxGuest.inf" + Delete /REBOOTOK "$INSTDIR\VBoxGuest.cat" + + Delete /REBOOTOK "$INSTDIR\VBCoInst.dll" + Delete /REBOOTOK "$INSTDIR\VBoxControl.exe" + Delete /REBOOTOK "$INSTDIR\VBoxService.exe" ; File from an older installation maybe, not present here anymore + + ; WHQL fake +!ifdef WHQL_FAKE + Delete /REBOOTOK "$INSTDIR\VBoxWHQLFake.exe" +!endif + + ; Log file + Delete /REBOOTOK "$INSTDIR\install.log" + Delete /REBOOTOK "$INSTDIR\install_ui.log" + +FunctionEnd +!macroend +!insertmacro W2K_UninstallInstDir "" +!insertmacro W2K_UninstallInstDir "un." + +!macro W2K_Uninstall un +Function ${un}W2K_Uninstall + + Push $0 + + ; Remove VirtualBox graphics adapter & PCI base drivers + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /u "PCI\VEN_80EE&DEV_BEEF&SUBSYS_00000000&REV_00"' + Pop $0 ; Ret value + ; @todo Add error handling here! + + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /u "PCI\VEN_80EE&DEV_CAFE&SUBSYS_00000000&REV_00"' + Pop $0 ; Ret value + ; @todo Add error handling here! + + ; @todo restore old drivers + + ; Remove video driver + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxVideo' + Delete /REBOOTOK "$g_strSystemDir\drivers\VBoxVideo.sys" + Delete /REBOOTOK "$g_strSystemDir\VBoxDisp.dll" + + ; Remove mouse driver + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxMouse' + Pop $0 ; Ret value + Delete /REBOOTOK "$g_strSystemDir\drivers\VBoxMouse.sys" + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /reg_delmultisz "SYSTEM\CurrentControlSet\Control\Class\{4D36E96F-E325-11CE-BFC1-08002BE10318}" "UpperFilters" "VBoxMouse"' + Pop $0 ; Ret value + ; @todo Add error handling here! + + ; Delete the VBoxService service + Call ${un}StopVBoxService + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxService' + Pop $0 ; Ret value + DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxService" + Delete /REBOOTOK "$g_strSystemDir\VBoxService.exe" + + ; GINA + Delete /REBOOTOK "$g_strSystemDir\VBoxGINA.dll" + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon" "GinaDLL" + ${If} $0 == "VBoxGINA.dll" + DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon" "GinaDLL" + ${EndIf} + + ; Delete VBoxTray + Call ${un}StopVBoxTray + DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxTray" + + ; Remove guest driver + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxGuest' + Pop $0 ; Ret value + Delete /REBOOTOK "$g_strSystemDir\drivers\VBoxGuest.sys" + Delete /REBOOTOK "$g_strSystemDir\vbcoinst.dll" + Delete /REBOOTOK "$g_strSystemDir\VBoxTray.exe" + Delete /REBOOTOK "$g_strSystemDir\VBoxHook.dll" + DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxTray" ; Remove VBoxTray autorun + Delete /REBOOTOK "$g_strSystemDir\VBoxControl.exe" + + ; Remove shared folders driver + call ${un}RemoveProvider ; Remove Shared Folders network provider from registry + ; @todo Add a /delnetprovider to VBoxDrvInst for doing this job! + nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxSF' + Delete /REBOOTOK "$g_strSystemDir\VBoxMRXNP.dll" ; The network provider DLL will be locked + Delete /REBOOTOK "$g_strSystemDir\drivers\VBoxSF.sys" + +!if $%VBOX_WITH_CROGL% == "1" + + DetailPrint "Removing 3D graphics support ..." + !if $%BUILD_TARGET_ARCH% == "x86" + Delete /REBOOTOK "$g_strSystemDir\VBoxOGLarrayspu.dll" + Delete /REBOOTOK "$g_strSystemDir\VBoxOGLcrutil.dll" + Delete /REBOOTOK "$g_strSystemDir\VBoxOGLerrorspu.dll" + Delete /REBOOTOK "$g_strSystemDir\VBoxOGLpackspu.dll" + Delete /REBOOTOK "$g_strSystemDir\VBoxOGLpassthroughspu.dll" + Delete /REBOOTOK "$g_strSystemDir\VBoxOGLfeedbackspu.dll" + Delete /REBOOTOK "$g_strSystemDir\VBoxOGL.dll" + + ; Remove D3D stuff + ; @todo add a feature flag to only remove if installed explicitly + Delete /REBOOTOK "$g_strSystemDir\libWine.dll" + Delete /REBOOTOK "$g_strSystemDir\VBoxD3D8.dll" + Delete /REBOOTOK "$g_strSystemDir\VBoxD3D9.dll" + Delete /REBOOTOK "$g_strSystemDir\wined3d.dll" + ; Update DLL cache + IfFileExists "$g_strSystemDir\dllcache\msd3d8.dll" 0 +2 + Delete /REBOOTOK "$g_strSystemDir\dllcache\d3d8.dll" + Rename /REBOOTOK "$g_strSystemDir\dllcache\msd3d8.dll" "$g_strSystemDir\dllcache\d3d8.dll" + IfFileExists g_strSystemDir\dllcache\msd3d9.dll" 0 +2 + Delete /REBOOTOK "$g_strSystemDir\dllcache\d3d9.dll" + Rename /REBOOTOK "$g_strSystemDir\dllcache\msd3d9.dll" "$g_strSystemDir\dllcache\d3d9.dll" + ; Restore original DX DLLs + IfFileExists "$g_strSystemDir\msd3d8.dll" 0 +2 + Delete /REBOOTOK "$g_strSystemDir\d3d8.dll" + Rename /REBOOTOK "$g_strSystemDir\msd3d8.dll" "$g_strSystemDir\d3d8.dll" + IfFileExists "$g_strSystemDir\msd3d9.dll" 0 +2 + Delete /REBOOTOK "$g_strSystemDir\d3d9.dll" + Rename /REBOOTOK "$g_strSystemDir\msd3d9.dll" "$g_strSystemDir\d3d9.dll" + + !else ; amd64 + + ; Only 64-bit installer: Also remove 32-bit DLLs on 64-bit target arch in Wow64 node + ${EnableX64FSRedirection} + Delete /REBOOTOK "$SYSDIR\VBoxOGLarrayspu.dll" + Delete /REBOOTOK "$SYSDIR\VBoxOGLcrutil.dll" + Delete /REBOOTOK "$SYSDIR\VBoxOGLerrorspu.dll" + Delete /REBOOTOK "$SYSDIR\VBoxOGLpackspu.dll" + Delete /REBOOTOK "$SYSDIR\VBoxOGLpassthroughspu.dll" + Delete /REBOOTOK "$SYSDIR\VBoxOGLfeedbackspu.dll" + Delete /REBOOTOK "$SYSDIR\VBoxOGL.dll" + + ; Remove D3D stuff + ; @todo add a feature flag to only remove if installed explicitly + Delete /REBOOTOK "$SYSDIR\libWine.dll" + Delete /REBOOTOK "$SYSDIR\VBoxD3D8.dll" + Delete /REBOOTOK "$SYSDIR\VBoxD3D9.dll" + Delete /REBOOTOK "$SYSDIR\wined3d.dll" + ; Update DLL cache + IfFileExists "$SYSDIR\dllcache\msd3d8.dll" 0 +2 + Delete /REBOOTOK "$SYSDIR\dllcache\d3d8.dll" + Rename /REBOOTOK "$SYSDIR\dllcache\msd3d8.dll" "$SYSDIR\dllcache\d3d8.dll" + IfFileExists "$SYSDIR\dllcache\msd3d9.dll" 0 +2 + Delete /REBOOTOK "$SYSDIR\dllcache\d3d9.dll" + Rename /REBOOTOK "$SYSDIR\dllcache\msd3d9.dll" "$SYSDIR\dllcache\d3d9.dll" + ; Restore original DX DLLs + IfFileExists "$SYSDIR\msd3d8.dll" 0 +2 + Delete /REBOOTOK "$SYSDIR\d3d8.dll" + Rename /REBOOTOK "$SYSDIR\msd3d8.dll" "$SYSDIR\d3d8.dll" + IfFileExists "$SYSDIR\msd3d9.dll" 0 +2 + Delete /REBOOTOK "$SYSDIR\d3d9.dll" + Rename /REBOOTOK "$SYSDIR\msd3d9.dll" "$SYSDIR\d3d9.dll" + DeleteRegKey HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" + ${DisableX64FSRedirection} + !endif ; amd64 + + DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" + +!endif ; VBOX_WITH_CROGL + + Pop $0 + +FunctionEnd +!macroend +!insertmacro W2K_Uninstall "" +!insertmacro W2K_Uninstall "un." + diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.cpp b/src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.cpp new file mode 100644 index 00000000000..8651d850255 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.cpp @@ -0,0 +1,472 @@ +/** @file + * + * instdrvmain - Install guest drivers on NT4 + * + * Copyright (C) 2006-2007 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +/** + * @todo + * The spacing in this file is horrible! Here are some simple rules: + * - tabs are forbidden + * - indentation is 4 spaces + */ + + +#include <windows.h> +#include <setupapi.h> +#include <regstr.h> +#include <DEVGUID.h> +#include <stdio.h> + +#include "tchar.h" +#include "string.h" + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ + +/** The video service name. */ +#define VBOXGUEST_VIDEO_NAME "VBoxVideo" + +/** The video inf file name */ +#define VBOXGUEST_VIDEO_INF_NAME "VBoxVideo.inf" + +///////////////////////////////////////////////////////////////////////////// + + + +/** + * Do some cleanup of data we used. Called by installVideoDriver() + */ +void closeAndDestroy(HDEVINFO hDevInfo, HINF hInf) +{ + SetupDiDestroyDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER); + SetupDiDestroyDeviceInfoList(hDevInfo); + SetupCloseInfFile(hInf); +} + + +/** + * Install the VBox video driver. + * + * @returns TRUE on success. + * @returns FALSE on failure. + * @param szDriverDir The base directory where we find the INF. + */ +BOOL installVideoDriver(TCHAR* szDriverDir) +{ + HDEVINFO hDevInfo; + SP_DEVINSTALL_PARAMS DeviceInstallParams={0}; + SP_DRVINFO_DATA drvInfoData={0}; + SP_DRVINFO_DETAIL_DATA DriverInfoDetailData={0}; + + DWORD cbReqSize; + + /* Vars used for reading the INF */ + HINF hInf; + TCHAR szServiceSection[LINE_LEN]; + INFCONTEXT serviceContext; + TCHAR szServiceData[LINE_LEN]; + TCHAR deviceRegStr[1000];//I'm lazy here. 1000 ought to be enough for everybody... + + SP_DEVINFO_DATA deviceInfoData; + DWORD configFlags; + + HKEY hkey; + DWORD disp; + TCHAR regKeyName[LINE_LEN]; + + BOOL rc; + + /* Create an empty list */ + hDevInfo = SetupDiCreateDeviceInfoList((LPGUID) &GUID_DEVCLASS_DISPLAY, + NULL); + + if (hDevInfo == INVALID_HANDLE_VALUE) + return FALSE; + + memset(&DeviceInstallParams, 0, sizeof(SP_DEVINSTALL_PARAMS)); + DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); + + rc=SetupDiGetDeviceInstallParams(hDevInfo, + NULL, + &DeviceInstallParams); + + if(!rc) + return FALSE; + + DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); + DeviceInstallParams.Flags |= DI_NOFILECOPY | /* We did our own file copying */ + DI_DONOTCALLCONFIGMG | + DI_ENUMSINGLEINF; /* .DriverPath specifies an inf file */ + + + /* Path to inf file */ + wsprintf(DeviceInstallParams.DriverPath, + TEXT("%ws\\%ws"), + szDriverDir, TEXT(VBOXGUEST_VIDEO_INF_NAME)); + + rc=SetupDiSetDeviceInstallParams(hDevInfo, + NULL, + &DeviceInstallParams); + if(!rc) + return FALSE; + + /* Read the drivers from the inf file */ + if (!SetupDiBuildDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER)) + { + SetupDiDestroyDeviceInfoList(hDevInfo); + return FALSE; + } + + /* Get the first found driver. + Our Inf file only contains one so this is fine */ + drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA); + if(FALSE==SetupDiEnumDriverInfo(hDevInfo, NULL, SPDIT_CLASSDRIVER, + 0, &drvInfoData)){ + SetupDiDestroyDeviceInfoList(hDevInfo); + return FALSE; + } + + /* Get necessary driver details */ + DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); + if (!(!SetupDiGetDriverInfoDetail(hDevInfo, + NULL, + &drvInfoData, + &DriverInfoDetailData, + DriverInfoDetailData.cbSize, + &cbReqSize) + &&GetLastError()== ERROR_INSUFFICIENT_BUFFER) ) + { + SetupDiDestroyDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER); + SetupDiDestroyDeviceInfoList(hDevInfo); + return FALSE; + } + + hInf = SetupOpenInfFile(DriverInfoDetailData.InfFileName, + NULL, INF_STYLE_WIN4, NULL); + + if (hInf == INVALID_HANDLE_VALUE) + { + SetupDiDestroyDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER); + SetupDiDestroyDeviceInfoList(hDevInfo); + return FALSE; + } + + /* First install the service */ + wsprintf(szServiceSection, TEXT("%ws.Services"), + DriverInfoDetailData.SectionName); + + if(!SetupFindFirstLine(hInf, szServiceSection, NULL, &serviceContext)) + { + /* No service line?? Can't be... */ + closeAndDestroy(hDevInfo, hInf); + return FALSE; + } + + /* Get the name */ + SetupGetStringField(&serviceContext, + 1, + szServiceData, + sizeof(szServiceData), + NULL); + + wsprintf(deviceRegStr, TEXT("Root\\LEGACY_%ws\\0000"), szServiceData); + + memset(&deviceInfoData, 0, sizeof(SP_DEVINFO_DATA)); + deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + if (SetupDiOpenDeviceInfo(hDevInfo, deviceRegStr, NULL, 0, &deviceInfoData) //Check for existing + ||(SetupDiCreateDeviceInfo(hDevInfo, deviceRegStr, //Create new + (LPGUID) &GUID_DEVCLASS_DISPLAY, + NULL, //Do we need a description here? + NULL, //No user interface + 0, + &deviceInfoData) && + SetupDiRegisterDeviceInfo(hDevInfo, + &deviceInfoData, + 0, + NULL, + NULL, + NULL)) ) + { + /* We created a new key in the registry */ + + memset(&DeviceInstallParams, 0,sizeof(SP_DEVINSTALL_PARAMS)); + DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); + + SetupDiGetDeviceInstallParams(hDevInfo, + &deviceInfoData, + &DeviceInstallParams); + + DeviceInstallParams.Flags |= DI_NOFILECOPY | //We already copied the files + DI_DONOTCALLCONFIGMG | + DI_ENUMSINGLEINF; //Use our INF file only + + /* Path to inf file */ + wsprintf(DeviceInstallParams.DriverPath, + TEXT("%ws\\%ws"), + szDriverDir, TEXT(VBOXGUEST_VIDEO_INF_NAME)); + + SetupDiSetDeviceInstallParams(hDevInfo, + &deviceInfoData, + &DeviceInstallParams); + + + if(!SetupDiBuildDriverInfoList(hDevInfo, + &deviceInfoData, + SPDIT_CLASSDRIVER)) + { + closeAndDestroy(hDevInfo, hInf); + return FALSE; + } + + drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA); + if (!SetupDiEnumDriverInfo(hDevInfo, + &deviceInfoData, + SPDIT_CLASSDRIVER, + 0, + &drvInfoData)) + { + closeAndDestroy(hDevInfo, hInf); + return FALSE; + } + + if(!SetupDiSetSelectedDriver(hDevInfo, + &deviceInfoData, + &drvInfoData)) + { + closeAndDestroy(hDevInfo, hInf); + return FALSE; + } + + if(!SetupDiInstallDevice(hDevInfo, + &deviceInfoData)) + { + closeAndDestroy(hDevInfo, hInf); + return FALSE; + } + } + + /* Make sure the device is enabled */ + if (SetupDiGetDeviceRegistryProperty(hDevInfo, + &deviceInfoData, SPDRP_CONFIGFLAGS, + NULL, (LPBYTE) &configFlags, + sizeof(DWORD), + NULL) + && (configFlags & CONFIGFLAG_DISABLED)) + { + configFlags &= ~CONFIGFLAG_DISABLED; + + SetupDiSetDeviceRegistryProperty(hDevInfo, + &deviceInfoData, + SPDRP_CONFIGFLAGS, + (LPBYTE) &configFlags, + sizeof(DWORD)); + } + + wsprintf(regKeyName, + TEXT("System\\CurrentControlSet\\Services\\%ws\\Device%d"), + szServiceData, 0); //We only have one device + + if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, + regKeyName, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hkey, + &disp) == ERROR_SUCCESS) + { + /* Insert description */ + RegSetValueEx(hkey, + TEXT("Device Description"), + 0, + REG_SZ, + (LPBYTE) DriverInfoDetailData.DrvDescription, + (lstrlen(DriverInfoDetailData.DrvDescription) + 1) * + sizeof(TCHAR) ); + + TCHAR szSoftwareSection[LINE_LEN]; + + wsprintf(szSoftwareSection, + TEXT("%ws.SoftwareSettings"), + szServiceData); + + if (!SetupInstallFromInfSection(NULL, + hInf, + szSoftwareSection, + SPINST_REGISTRY, + hkey, + NULL, + 0, + NULL, + NULL, + NULL, + NULL)) + { + RegCloseKey(hkey); + closeAndDestroy(hDevInfo, hInf); + return FALSE; + } + + RegCloseKey(hkey); + } + + /* Install OpenGL stuff */ + if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, + TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers"), + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hkey, + &disp) == ERROR_SUCCESS) + { + /* Do installation here if ever necessary. Currently there is no OpenGL stuff */ + + RegCloseKey(hkey); + } + + + /* Cleanup */ + closeAndDestroy(hDevInfo, hInf); + +#if 0 + /* If this key is inserted into the registry, windows will show the desktop + applet on next boot. We decide in the installer if we want that so the code + is disabled here. */ + /* Set registry keys so windows picks up the changes */ + if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers\\NewDisplay"), + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hkey, + &disp) == ERROR_SUCCESS) + { + RegCloseKey(hkey); + } +#endif + + /* We must reboot at some point */ + if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers\\RebootNecessary"), + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hkey, + &disp) == ERROR_SUCCESS) + { + RegCloseKey(hkey); + } + + return TRUE; +} + + +void displayHelpAndExit(char *programName) +{ + printf("Installs VirtualBox Guest Additions for Windows NT 4.0\n\n"); + printf("Syntax: %s [/i|/u]\n", programName); + printf("\n\t/i - perform Guest Additions installation\n"); + printf("\t/u: - perform Guest Additions uninstallation\n"); + exit(1); +} + +/** + * Check if we are running on NT4. + * + * @returns TRUE if NT 4. + * @returns FALSE otherwise. + */ +BOOL isNT4(void) +{ + OSVERSIONINFO osVersion; + + osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osVersion); + + switch (osVersion.dwPlatformId) + { + case VER_PLATFORM_WIN32s: + case VER_PLATFORM_WIN32_WINDOWS: + return FALSE; + case VER_PLATFORM_WIN32_NT: + if (osVersion.dwMajorVersion == 4) + return TRUE; + else + return FALSE; + default: + break; + } + return FALSE; +} + +/** + * Video driver uninstallation will be added later if necessary. + */ +int uninstallDrivers(void) +{ + return 0; +} + + +int main(int argc, char **argv) +{ + BOOL rc=FALSE; + TCHAR szInstallDir[MAX_PATH]; + HMODULE hExe = GetModuleHandle(NULL); + + /** @todo r=bird: + * And by the way, we're only missing the coding style dmik uses now + * and this file would contain the complete set. */ + if(2!=argc || (stricmp(argv[1], "/i") && stricmp(argv[1], "/u"))) + displayHelpAndExit(argv[0]); + + /* This program is only for installing drivers on NT4 */ + if(!isNT4()){ + printf("This program only runs on NT4\n"); + return -1; + } + + if (!GetModuleFileName(hExe, &szInstallDir[0], sizeof(szInstallDir))) + { + printf("GetModuleFileName failed! rc = %d\n", GetLastError()); + return -1; + } + + TCHAR *lastBackslash = wcsrchr(szInstallDir, L'\\'); + + if (!lastBackslash) + { + printf("Invalid path name!\n"); + return -1; + } + + *lastBackslash=L'\0'; + + /* Install video driver. Mouse driver installation is done by overwriting + the image path in the setup script. */ + if(!stricmp(argv[1], "/i")){ + rc=installVideoDriver(szInstallDir); + } + else{ + /* No video driver uninstallation yet. Do we need it? */ + } + + if(FALSE==rc) + printf("Some failure occurred during driver installation.\n"); + return !rc; /* Return != 0 on failure. */ +} diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.rc b/src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.rc new file mode 100644 index 00000000000..4e3769ffa26 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.rc @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2006-2007 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +#include <windows.h> +#include <VBox/version.h> + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + PRODUCTVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + FILEFLAGSMASK 0x3fL + FILEFLAGS 0x0L + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", VBOX_RC_COMPANY_NAME + VALUE "FileDescription", "VirtualBox Guest Driver Installer\0" + VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + VALUE "InternalName", "VBoxGuestDrvInst\0" + VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "VBoxGuestDrvInst.exe\0" + VALUE "ProductName", "VirtualBox Guest Additions\0" + VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/VBox/Additions/WINNT/Installer/VBoxWHQLFake.au3 b/src/VBox/Additions/WINNT/Installer/VBoxWHQLFake.au3 new file mode 100644 index 00000000000..f121d010024 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/VBoxWHQLFake.au3 @@ -0,0 +1,59 @@ +; VBoxFakeWHQL - Turns off / on the WHQL for installing unsigned drivers. +; Currently only tested with Win2K / XP! +; +; Copyright (C) 2008-2010 Oracle Corporation +; +; Oracle Corporation confidential +; All rights reserved +; + +; Strings for localization +; When using an OS with another language, you have to provide the correct +; strings for it. English and German is provided below. +; +; @todo Needs to be improved to handle the stuff without language strings in +; the future! + +;$sysprop_Title = "System Properties" +;$drvsig_Title = "Driver Signing Options" + +$sysprop_Title = "Systemeigenschaften" +$drvsig_Title = "Treibersignaturoptionen" + +$ok_Title = "OK" + +If $CmdLine[0] < 1 Then + MsgBox ( 0, "ERROR", "Please specify 'ignore', 'warn' or 'block' as parameter!" ) + Exit +EndIf + +Run("control.exe sysdm.cpl") +If WinWait($sysprop_Title, "", 5) = 0 Then + WinClose("[ACTIVE]", "") + Exit +EndIf + +ControlCommand($sysprop_Title, "", "SysTabControl321", "TabRight", "") +ControlCommand($sysprop_Title, "", "SysTabControl321", "TabRight", "") + +Sleep(200) ; Wait a while for tab switchig above +ControlClick($sysprop_Title, "", 14007) ; Button 'Driver Signing' + +WinWait($drvsig_Title, "", 5) + +If $CmdLine[1] = "ignore" Then + ControlClick($drvsig_Title, "", 1000) ; 'Ignore' radio button +ElseIf $CmdLine[1] = "warn" Then + ControlClick($drvsig_Title, "", 1001) ; 'Warn' radio button +ElseIf $CmdLine[1] = "block" Then + ControlClick($drvsig_Title, "", 1002) ; 'Block' radio button +Else + Exit +EndIf + +ControlClick($drvsig_Title, "", 1) ; 'OK' button (ID=1) of dialog 'Driver Signing Options' + +WinWait($sysprop_Title, "", 5) +ControlClick($sysprop_Title, "", 1) ; 'OK' button (ID=1) of 'System Properties' + + diff --git a/src/VBox/Additions/WINNT/Installer/dumplog.nsh b/src/VBox/Additions/WINNT/Installer/dumplog.nsh new file mode 100644 index 00000000000..059f189ae3f --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/dumplog.nsh @@ -0,0 +1,50 @@ +!define LVM_GETITEMCOUNT 0x1004 +!define LVM_GETITEMTEXT 0x102D + +!macro DumpLog un +Function ${un}DumpLog + Exch $5 + Push $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $6 + + FindWindow $0 "#32770" "" $HWNDPARENT + GetDlgItem $0 $0 1016 + StrCmp $0 0 error + FileOpen $5 $5 "w" + StrCmp $5 0 error + SendMessage $0 ${LVM_GETITEMCOUNT} 0 0 $6 + System::Alloc ${NSIS_MAX_STRLEN} + Pop $3 + StrCpy $2 0 + System::Call "*(i, i, i, i, i, i, i, i, i) i \ + (0, 0, 0, 0, 0, r3, ${NSIS_MAX_STRLEN}) .r1" + loop: StrCmp $2 $6 done + System::Call "User32::SendMessageA(i, i, i, i) i \ + ($0, ${LVM_GETITEMTEXT}, $2, r1)" + System::Call "*$3(&t${NSIS_MAX_STRLEN} .r4)" + FileWrite $5 "$4$\r$\n" + IntOp $2 $2 + 1 + Goto loop + done: + FileClose $5 + System::Free $1 + System::Free $3 + Goto exit + error: + MessageBox MB_OK "Could not create Log-File!" /SD IDOK + exit: + Pop $6 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 + Exch $5 +FunctionEnd +!macroend +!insertmacro DumpLog "" +!insertmacro DumpLog "un." diff --git a/src/VBox/Additions/WINNT/Installer/iexplore.ico b/src/VBox/Additions/WINNT/Installer/iexplore.ico Binary files differnew file mode 100644 index 00000000000..991256b6b0b --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/iexplore.ico diff --git a/src/VBox/Additions/WINNT/Installer/servicepack.nsh b/src/VBox/Additions/WINNT/Installer/servicepack.nsh new file mode 100644 index 00000000000..f1eae515c51 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/servicepack.nsh @@ -0,0 +1,29 @@ +;------------------------------------------------------------------------------- +; GetServicePack +; Author: Alessio Garbi (e-Project srl) <agarbi@e-project.it> +; +; input: +; none +; output: +; top of stack: last service pack major version +; top of stack-1: last service pack minor version +; note: +; If no service pack installed returns major ver "0" and minor ver "0" +; Function tested with Win 95, 98SE, NT4, 2000, XP, 2003 (lang ITA and ENG) + +!macro GetServicePack un +Function ${un}GetServicePack + Push $R0 + Push $R1 + + ReadRegDWORD $R0 HKLM "System\CurrentControlSet\Control\Windows" "CSDVersion" + IntOp $R1 $R0 % 256 ;get minor version + IntOp $R0 $R0 / 256 ;get major version + + Exch $R1 + Exch + Exch $R0 +FunctionEnd +!macroend +!insertmacro GetServicePack "" +!insertmacro GetServicePack "un." diff --git a/src/VBox/Additions/WINNT/Installer/strstr.nsh b/src/VBox/Additions/WINNT/Installer/strstr.nsh new file mode 100644 index 00000000000..58e25476b81 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/strstr.nsh @@ -0,0 +1,306 @@ +; StrStr + ; input, top of stack = string to search for + ; top of stack-1 = string to search in + ; output, top of stack (replaces with the portion of the string remaining) + ; modifies no other variables. + ; + ; Usage: + ; Push "this is a long ass string" + ; Push "ass" + ; Call StrStr + ; Pop $R0 + ; ($R0 at this point is "ass string") + + +!macro StrStr un + Function ${un}StrStr + Exch $R1 ; st=haystack,old$R1, $R1=needle + Exch ; st=old$R1,haystack + Exch $R2 ; st=old$R1,old$R2, $R2=haystack + Push $R3 + Push $R4 + Push $R5 + StrLen $R3 $R1 + StrCpy $R4 0 + ; $R1=needle + ; $R2=haystack + ; $R3=len(needle) + ; $R4=cnt + ; $R5=tmp + loop: + StrCpy $R5 $R2 $R3 $R4 + StrCmp $R5 $R1 done + StrCmp $R5 "" done + IntOp $R4 $R4 + 1 + Goto loop + done: + StrCpy $R1 $R2 "" $R4 + Pop $R5 + Pop $R4 + Pop $R3 + Pop $R2 + Exch $R1 + FunctionEnd +!macroend +!insertmacro StrStr "" +!insertmacro StrStr "un." + +!macro StrStrAdv un +Function ${un}StrStrAdv + + ; After this point: + ; $0 = String (input) + ; $1 = SubString (input) + ; $2 = SearchDirection (input) + ; $3 = StrInclusionDirection (input) + ; $4 = IncludeSubString (input) + ; $5 = Loops (input) + ; $6 = CaseSensitive (input) + ; $7 = StringLength (temp) + ; $8 = StrToSearchLength (temp) + ; $9 = CurrentLoop (temp) + ; $R0 = EndCharPos (temp) + ; $R1 = StartCharPos (temp) + ; $R2 = ResultVar (output) + ; $R3 = Temp (temp) + + ; Get input from user + + Exch $6 + Exch + Exch $5 + Exch + Exch 2 + Exch $4 + Exch 2 + Exch 3 + Exch $3 + Exch 3 + Exch 4 + Exch $2 + Exch 4 + Exch 5 + Exch $1 + Exch 5 + Exch 6 + Exch $0 + Exch 6 + Push $7 + Push $8 + Push $9 + Push $R3 + Push $R2 + Push $R1 + Push $R0 + + ; Clean $R0-$R3 variables + StrCpy $R0 "" + StrCpy $R1 "" + StrCpy $R2 "" + StrCpy $R3 "" + + ; Verify if we have the correct values on the variables + ${If} $0 == `` + SetErrors ;AdvStrStr_StrToSearch not found + Goto AdvStrStr_End + ${EndIf} + + ${If} $1 == `` + SetErrors ;No text to search + Goto AdvStrStr_End + ${EndIf} + + ${If} $2 != < + StrCpy $2 > + ${EndIf} + + ${If} $3 != < + StrCpy $3 > + ${EndIf} + + ${If} $4 <> 0 + StrCpy $4 1 + ${EndIf} + + ${If} $5 <= 0 + StrCpy $5 0 + ${EndIf} + + ${If} $6 <> 1 + StrCpy $6 0 + ${EndIf} + + ; Find "AdvStrStr_String" length + StrLen $7 $0 + + ; Then find "AdvStrStr_SubString" length + StrLen $8 $1 + + ; Now set up basic variables + + ${If} $2 == < + IntOp $R1 $7 - $8 + StrCpy $R2 $7 + ${Else} + StrCpy $R1 0 + StrCpy $R2 $8 + ${EndIf} + + StrCpy $9 0 ; First loop + + ;Let's begin the search + + ${Do} + ; Step 1: If the starting or ending numbers are negative + ; or more than AdvStrStr_StringLen, we return + ; error + + ${If} $R1 < 0 + StrCpy $R1 `` + StrCpy $R2 `` + StrCpy $R3 `` + SetErrors ;AdvStrStr_SubString not found + Goto AdvStrStr_End + ${ElseIf} $R2 > $7 + StrCpy $R1 `` + StrCpy $R2 `` + StrCpy $R3 `` + SetErrors ;AdvStrStr_SubString not found + Goto AdvStrStr_End + ${EndIf} + + ; Step 2: Start the search depending on + ; AdvStrStr_SearchDirection. Chop down not needed + ; characters. + + ${If} $R1 <> 0 + StrCpy $R3 $0 `` $R1 + ${EndIf} + + ${If} $R2 <> $7 + ${If} $R1 = 0 + StrCpy $R3 $0 $8 + ${Else} + StrCpy $R3 $R3 $8 + ${EndIf} + ${EndIf} + + ; Step 3: Make sure that's the string we want + + ; Case-Sensitive Support <- Use "AdvStrStr_Temp" + ; variable because it won't be used anymore + + ${If} $6 == 1 + System::Call `kernel32::lstrcmpA(ts, ts) i.s` `$R3` `$1` + Pop $R3 + ${If} $R3 = 0 + StrCpy $R3 1 ; Continue + ${Else} + StrCpy $R3 0 ; Break + ${EndIf} + ${Else} + ${If} $R3 == $1 + StrCpy $R3 1 ; Continue + ${Else} + StrCpy $R3 0 ; Break + ${EndIf} + ${EndIf} + + ; After the comparasion, confirm that it is the + ; value we want. + + ${If} $R3 = 1 + + ;We found it, return except if the user has set up to + ;search for another one: + ${If} $9 >= $5 + + ;Now, let's see if the user wants + ;AdvStrStr_SubString to appear: + ${If} $4 == 0 + ;Return depends on AdvStrStr_StrInclusionDirection + ${If} $3 == < + ; RTL + StrCpy $R0 $0 $R1 + ${Else} + ; LTR + StrCpy $R0 $0 `` $R2 + ${EndIf} + ${Break} + ${Else} + ;Return depends on AdvStrStr_StrInclusionDirection + ${If} $3 == < + ; RTL + StrCpy $R0 $0 $R2 + ${Else} + ; LTR + StrCpy $R0 $0 `` $R1 + ${EndIf} + ${Break} + ${EndIf} + ${Else} + ;If the user wants to have more loops, let's do it so! + IntOp $9 $9 + 1 + + ${If} $2 == < + IntOp $R1 $R1 - 1 + IntOp $R2 $R2 - 1 + ${Else} + IntOp $R1 $R1 + 1 + IntOp $R2 $R2 + 1 + ${EndIf} + ${EndIf} + ${Else} + ; Step 4: We didn't find it, so do steps 1 thru 3 again + + ${If} $2 == < + IntOp $R1 $R1 - 1 + IntOp $R2 $R2 - 1 + ${Else} + IntOp $R1 $R1 + 1 + IntOp $R2 $R2 + 1 + ${EndIf} + ${EndIf} + ${Loop} + + AdvStrStr_End: + + ;Add 1 to AdvStrStr_EndCharPos to be supportable + ;by "StrCpy" + + IntOp $R2 $R2 - 1 + + ;Return output to user + + Exch $R0 + Exch + Pop $R1 + Exch + Pop $R2 + Exch + Pop $R3 + Exch + Pop $9 + Exch + Pop $8 + Exch + Pop $7 + Exch + Pop $6 + Exch + Pop $5 + Exch + Pop $4 + Exch + Pop $3 + Exch + Pop $2 + Exch + Pop $1 + Exch + Pop $0 + +FunctionEnd +!macroend +!insertmacro StrStrAdv "" +!insertmacro StrStrAdv "un." diff --git a/src/VBox/Additions/WINNT/Installer/welcome.bmp b/src/VBox/Additions/WINNT/Installer/welcome.bmp Binary files differnew file mode 100644 index 00000000000..6596c58dd81 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/welcome.bmp diff --git a/src/VBox/Additions/WINNT/Installer/winver.nsh b/src/VBox/Additions/WINNT/Installer/winver.nsh new file mode 100644 index 00000000000..16defa46c01 --- /dev/null +++ b/src/VBox/Additions/WINNT/Installer/winver.nsh @@ -0,0 +1,103 @@ +; GetWindowsVersion +; +; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/ +; Updated by Joost Verburg +; +; Returns on top of stack +; +; Windows Version (95, 98, ME, NT x.x, 2000, XP, 2003, Vista) +; or +; '' (Unknown Windows Version) +; +; Usage: +; Call GetWindowsVersion +; Pop $R0 +; ; at this point $R0 is "NT 4.0" or whatnot + +!macro GetWindowsVersion un +Function ${un}GetWindowsVersion + + Push $R0 + Push $R1 + + ClearErrors + + ReadRegStr $R0 HKLM \ + "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + + IfErrors 0 lbl_winnt + + ; we are not NT + ReadRegStr $R0 HKLM \ + "SOFTWARE\Microsoft\Windows\CurrentVersion" VersionNumber + + StrCpy $R1 $R0 1 + StrCmp $R1 '4' 0 lbl_error + + StrCpy $R1 $R0 3 + + StrCmp $R1 '4.0' lbl_win32_95 + StrCmp $R1 '4.9' lbl_win32_ME lbl_win32_98 + + lbl_win32_95: + StrCpy $R0 '95' + Goto lbl_done + + lbl_win32_98: + StrCpy $R0 '98' + Goto lbl_done + + lbl_win32_ME: + StrCpy $R0 'ME' + Goto lbl_done + + lbl_winnt: + + StrCpy $R1 $R0 1 + + StrCmp $R1 '3' lbl_winnt_x + StrCmp $R1 '4' lbl_winnt_x + + StrCpy $R1 $R0 3 + + StrCmp $R1 '5.0' lbl_winnt_2000 + StrCmp $R1 '5.1' lbl_winnt_XP + StrCmp $R1 '5.2' lbl_winnt_2003 + StrCmp $R1 '6.0' lbl_winnt_vista + StrCmp $R1 '6.1' lbl_winnt_7 lbl_error + + lbl_winnt_x: + StrCpy $R0 "NT $R0" 6 + Goto lbl_done + + lbl_winnt_2000: + Strcpy $R0 '2000' + Goto lbl_done + + lbl_winnt_XP: + Strcpy $R0 'XP' + Goto lbl_done + + lbl_winnt_2003: + Strcpy $R0 '2003' + Goto lbl_done + + lbl_winnt_vista: + Strcpy $R0 'Vista' + Goto lbl_done + + lbl_winnt_7: + Strcpy $R0 '7' + Goto lbl_done + + lbl_error: + Strcpy $R0 '' + lbl_done: + + Pop $R1 + Exch $R0 + +FunctionEnd +!macroend +!insertmacro GetWindowsVersion "" +!insertmacro GetWindowsVersion "un." diff --git a/src/VBox/Additions/WINNT/SharedFolders/Makefile.kmk b/src/VBox/Additions/WINNT/SharedFolders/Makefile.kmk new file mode 100644 index 00000000000..c00e77d3663 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/Makefile.kmk @@ -0,0 +1,20 @@ +# $Id$ +## @file +# Sub-Makefile for the Windows guest shared folders. +# + +# +# Copyright (C) 2006-2007 Oracle Corporation +# +# Oracle Corporation confidential +# All rights reserved +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# Include sub-makefile(s). +include $(PATH_SUB_CURRENT)/redirector/Makefile.kmk + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/Makefile.kmk b/src/VBox/Additions/WINNT/SharedFolders/redirector/Makefile.kmk new file mode 100644 index 00000000000..6d53a1a3491 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/Makefile.kmk @@ -0,0 +1,21 @@ +# $Id$ +## @file +# Sub-Makefile for the Windows guest shared folder redirectory. +# + +# +# Copyright (C) 2006-2007 Oracle Corporation +# +# Oracle Corporation confidential +# All rights reserved +# + +SUB_DEPTH = ../../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# Include sub-makefiles. +include $(PATH_SUB_CURRENT)/dll/Makefile.kmk +include $(PATH_SUB_CURRENT)/sys/Makefile.kmk + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/Makefile.kmk b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/Makefile.kmk new file mode 100644 index 00000000000..8a3a74f1f24 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/Makefile.kmk @@ -0,0 +1,36 @@ +# $Id$ +## @file +# Sub-Makefile for the VirtualBox Windows Guest Shared Folders Network Provider. +# + +# +# Copyright (C) 2006-2007 Oracle Corporation +# +# Oracle Corporation confidential +# All rights reserved +# + +SUB_DEPTH = ../../../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +DLLS += VBoxMRXNP +VBoxMRXNP_TEMPLATE = VBOXGUESTR3DLL +VBoxMRXNP_SDKS = WINDDK +VBoxMRXNP_DEFS = LOG_TO_BACKDOOR _WIN32_WINNT=0x0500 UNICODE WIN32_LEAN_AND_MEAN=1 + +VBoxMRXNP_INCS = \ + $(PATH_SUB_ROOT)/WINNT/SharedFolders/include + +VBoxMRXNP_SOURCES = \ + dllmain.cpp \ + vboxmrxp.cpp \ + vboxmrxp.rc \ + vboxmrxp.def + +VBoxMRXNP_LIBS = \ + $(VBOX_LIB_IPRT_GUEST_R3) \ + $(VBOX_LIB_VBGL_R3) \ + $(VBOX_LIB_IPRT_GUEST_R3) + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/dllmain.cpp b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/dllmain.cpp new file mode 100644 index 00000000000..a084acfc06f --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/dllmain.cpp @@ -0,0 +1,63 @@ +/*++ + +Copyright (c) 1989-1999 Microsoft Corporation + +Module Name: + + dllmain.c + +Abstract: + + This module implements the initialization routines for network + provider interface + +Notes: + + This module has been built and tested only in UNICODE environment + +--*/ + +#include <windows.h> +#include <process.h> + +#include "vboxmrxp.h" + +// NOTE: +// +// Function: DllMain +// +// Return: TRUE => Success +// FALSE => Failure + +BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved) +{ + BOOL bStatus = TRUE; + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + + RTR3Init(); + VbglR3Init(); + LogRel(("VBOXNP: DLL loaded.\n")); + break; + + case DLL_PROCESS_DETACH: + + LogRel(("VBOXNP: DLL unloaded.\n")); + VbglR3Term(); + /// @todo RTR3Term(); + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + + default: + break; + } + + return(bStatus); +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.cpp b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.cpp new file mode 100644 index 00000000000..ffb1094ced4 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.cpp @@ -0,0 +1,2146 @@ +/*++ + + Copyright (c) 1989-1999 Microsoft Corporation + + Module Name: + + ifsmrxnp.c + + Abstract: + + This module implements the routines required for interaction with network + provider router interface in NT + + Notes: + + This module has been built and tested only in UNICODE environment + + --*/ + +#include <windows.h> +#include <windef.h> +#include <winbase.h> +#include <winsvc.h> +#include <winnetwk.h> +#include <npapi.h> +#include <devioctl.h> +#include <stdio.h> + +#include "vboxmrxp.h" + +#define WNNC_DRIVER( major, minor ) ( major * 0x00010000 + minor ) + +ULONG SendToMiniRdr (IN ULONG IoctlCode, IN PVOID InputDataBuf, IN ULONG InputDataLen, IN PVOID OutputDataBuf, IN PULONG pOutputDataLen) +/*++ + + Routine Description: + + This routine sends a device ioctl to the Mini Rdr. + + Arguments: + + IoctlCode - Function code for the Mini Rdr driver + + InputDataBuf - Input buffer pointer + + InputDataLen - Lenth of the input buffer + + OutputDataBuf - Output buffer pointer + + pOutputDataLen - Pointer to the length of the output buffer + + Return Value: + + WN_SUCCESS if successful, otherwise the appropriate error + + Notes: + + --*/ +{ + HANDLE DeviceHandle; // The mini rdr device handle + BOOL rc; + ULONG Status; + DWORD cbOut = 0; + + if (!pOutputDataLen) + pOutputDataLen = &cbOut; + + Status = WN_SUCCESS; + + // Grab a handle to the redirector device object + + DeviceHandle = CreateFile(DD_MRX_VBOX_USERMODE_DEV_NAME_U, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, (HANDLE)NULL ); + + if (INVALID_HANDLE_VALUE != DeviceHandle) + { + rc = DeviceIoControl(DeviceHandle, IoctlCode, InputDataBuf, InputDataLen, OutputDataBuf, *pOutputDataLen, pOutputDataLen, NULL ); + + if (!rc) + { + Status = GetLastError(); + Log(("VBOXNP: SendToMiniRdr: Returning error from DeviceIoctl! Status = %d \n", Status)); + } + else + { + Log(("VBOXNP: SendToMiniRdr: The DeviceIoctl call succeded\n")); + } + CloseHandle(DeviceHandle); + } + else + { + Status = GetLastError(); + static int sLogged = 0; + if (!sLogged) + { + LogRel(("VBOXNP: SendToMiniRdr: Error opening device! Status = %lx\n", Status)); + sLogged++; + } + } + + return Status; +} + +DWORD APIENTRY +NPGetCaps (DWORD nIndex) +/*++ + + Routine Description: + + This routine returns the capaboilities of the Null Mini redirector + network provider implementation + + Arguments: + + nIndex - category of capabilities desired + + Return Value: + + the appropriate capabilities + + --*/ +{ + DWORD rc = 0; + + Log(("VBOXNP: GetNetCaps: Index = 0x%lx\n", nIndex)); + + switch (nIndex) + { + case WNNC_SPEC_VERSION: + rc = WNNC_SPEC_VERSION51; + break; + + case WNNC_NET_TYPE: + rc = WNNC_NET_RDR2SAMPLE; + break; + + case WNNC_DRIVER_VERSION: + rc = WNNC_DRIVER(1, 0); + break; + + case WNNC_CONNECTION: + SendToMiniRdr(IOCTL_MRX_VBOX_START, NULL, 0, NULL, NULL); + rc = WNNC_CON_GETCONNECTIONS | WNNC_CON_CANCELCONNECTION | WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3; + break; + + case WNNC_ENUMERATION: + rc = WNNC_ENUM_LOCAL | WNNC_ENUM_GLOBAL | WNNC_ENUM_SHAREABLE; + break; + + case WNNC_START: + rc = 1; + break; + + case WNNC_DIALOG: + rc = WNNC_DLG_GETRESOURCEPARENT | WNNC_DLG_GETRESOURCEINFORMATION; + break; + + case WNNC_USER: + case WNNC_ADMIN: + default: + rc = 0; + break; + } + + return rc; +} + +DWORD APIENTRY +NPLogonNotify (PLUID lpLogonId, + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + LPWSTR *lpLogonScript) +/*++ + + Routine Description: + + This routine handles the logon notifications + + Arguments: + + lpLogonId -- the associated LUID + + lpAuthenInfoType - the authentication information type + + lpAuthenInfo - the authentication Information + + lpPreviousAuthentInfoType - the previous aunthentication information type + + lpPreviousAuthentInfo - the previous authentication information + + lpStationName - the logon station name + + LPVOID - logon station handle + + lpLogonScript - the logon script to be executed. + + Return Value: + + WN_SUCCESS + + Notes: + + This capability has not been implemented in the sample. + + --*/ +{ + Log(("VBOXNP: NPLogonNotify: Called.\n")); + *lpLogonScript = NULL; + + return WN_SUCCESS; +} + +DWORD APIENTRY +NPPasswordChangeNotify (LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + DWORD dwChangeInfo) +/*++ + + Routine Description: + + This routine handles the password change notifications + + Arguments: + + lpAuthenInfoType - the authentication information type + + lpAuthenInfo - the authentication Information + + lpPreviousAuthentInfoType - the previous aunthentication information type + + lpPreviousAuthentInfo - the previous authentication information + + lpStationName - the logon station name + + LPVOID - logon station handle + + dwChangeInfo - the password change information. + + Return Value: + + WN_NOT_SUPPORTED + + Notes: + + This capability has not been implemented in the sample. + + --*/ +{ + Log(("VBOXNP: NPPasswordChangeNotify: Called.\n")); + SetLastError(WN_NOT_SUPPORTED); + + return WN_NOT_SUPPORTED; +} + +DWORD APIENTRY +NPAddConnection (LPNETRESOURCE lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName) +/*++ + + Routine Description: + + This routine adds a connection to the list of connections associated + with this network provider + + Arguments: + + lpNetResource - the NETRESOURCE struct + + lpPassword - the password + + lpUserName - the user name + + Return Value: + + WN_SUCCESS if successful, otherwise the appropriate error + + Notes: + + --*/ +{ + Log(("VBOXNP: NPAddConnection: Called.\n")); + return NPAddConnection3(NULL, lpNetResource, lpPassword, lpUserName, 0); +} + +DWORD APIENTRY +NPAddConnection3 (HWND hwndOwner, LPNETRESOURCE lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName, DWORD dwFlags) +/*++ + + Routine Description: + + This routine adds a connection to the list of connections associated + with this network provider + + Arguments: + + hwndOwner - the owner handle + + lpNetResource - the NETRESOURCE struct + + lpPassword - the password + + lpUserName - the user name + + dwFlags - flags for the connection + + Return Value: + + WN_SUCCESS if successful, otherwise the appropriate error + + --*/ +{ + DWORD Status; + WCHAR ConnectionName[128]; + WCHAR wszScratch[128]; + WCHAR LocalName[3]; + DWORD CopyBytes = 0; + BOOLEAN fLocalName = TRUE; + + Log(("VBOXNP: NPAddConnection3: dwFlags = 0x%x\n", dwFlags)); + Log(("VBOXNP: NPAddConnection3: Local Name: %ls\n", lpNetResource->lpLocalName )); + Log(("VBOXNP: NPAddConnection3: Remote Name: %ls\n", lpNetResource->lpRemoteName )); + + Status = WN_SUCCESS; + + if (lpNetResource->dwType != RESOURCETYPE_DISK && lpNetResource->dwType != RESOURCETYPE_ANY) + { + Log(("VBOXNP: NPAddConnection3: Incorrect net resource type %d\n", lpNetResource->dwType)); + return WN_BAD_NETNAME; + } + + // \device\miniredirector\;<DriveLetter>:\Server\Share + + if (lpNetResource->lpLocalName == NULL) + { + fLocalName = FALSE; + lstrcpy(ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U ); + lstrcat(ConnectionName,L"\\;" ); + } + else + if ( lstrlen( lpNetResource->lpLocalName )> 1 ) + { + if ( lpNetResource->lpLocalName[1] == L':' ) + { + // LocalName[0] = (WCHAR) CharUpper( (PWCHAR) MAKELONG( (USHORT) lpNetResource->lpLocalName[0], 0 ) ); + LocalName[0] = (WCHAR) toupper(lpNetResource->lpLocalName[0]); + LocalName[1] = L':'; + LocalName[2] = L'\0'; + lstrcpy( ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U ); + lstrcat( ConnectionName, L"\\;" ); + lstrcat( ConnectionName, LocalName ); + } + else + Status = WN_BAD_LOCALNAME; + } + else + Status = WN_BAD_LOCALNAME; + + // format proper server name + if ( lpNetResource->lpRemoteName[0] == L'\\' && lpNetResource->lpRemoteName[1] == L'\\' ) + { + if (lstrlen (ConnectionName) + lstrlen (lpNetResource->lpRemoteName) <= sizeof (ConnectionName) / sizeof (WCHAR)) + { + /* No need for (lstrlen + 1), because 'lpNetResource->lpRemoteName' leading \ is not copied. */ + lstrcat( ConnectionName, lpNetResource->lpRemoteName + 1 ); + } + else + { + Status = WN_BAD_NETNAME; + } + } + else + { + Status = WN_BAD_NETNAME; + } + + Log(("VBOXNP: NPAddConnection3: Full Connect Name: %ls\n", ConnectionName )); + Log(("VBOXNP: NPAddConnection3: Full Connect Name Length: %d\n", ( lstrlen( ConnectionName ) + 1 ) * sizeof( WCHAR ) )); + + if ( Status == WN_SUCCESS ) + { + if ( fLocalName + && QueryDosDevice( LocalName, wszScratch, sizeof (wszScratch) / sizeof (WCHAR) )) + { + Log(("VBOXNP: NPAddConnection3: Connection \"%ls\" already connected.\n", ConnectionName)); + Status = WN_ALREADY_CONNECTED; + } + else + if ( !fLocalName + || GetLastError() == ERROR_FILE_NOT_FOUND) + { + Status = SendToMiniRdr( IOCTL_MRX_VBOX_ADDCONN, ConnectionName, + ( lstrlen( ConnectionName ) + 1 ) * sizeof( WCHAR ), + NULL, &CopyBytes ); + + if (Status == WN_SUCCESS) + { + if ( fLocalName + && !DefineDosDevice( DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM, + lpNetResource->lpLocalName, + ConnectionName ) ) + { + Status = GetLastError(); + } + } + else Status = WN_BAD_NETNAME; + } + else Status = WN_ALREADY_CONNECTED; + } + + Log(("VBOXNP: NPAddConnection3: Returned 0x%lx\n", Status)); + return Status; +} + +DWORD APIENTRY +NPCancelConnection (LPWSTR lpName, BOOL fForce) +/*++ + + Routine Description: + + This routine cancels ( deletes ) a connection from the list of connections + associated with this network provider + + Arguments: + + lpName - name of the connection + + fForce - forcefully delete the connection + + Return Value: + + WN_SUCCESS if successful, otherwise the appropriate error + + Notes: + + --*/ + +{ + WCHAR LocalName[3]; + WCHAR RemoteName[128]; + WCHAR ConnectionName[128]; + ULONG CopyBytes; + DWORD Status = WN_NOT_CONNECTED; + + Log(("VBOXNP: NPCancelConnection: Name = %ls\n", lpName )); + + if (lstrlen(lpName) > 1) + { + if (lpName[1] == L':') + { + // LocalName[0] = (WCHAR) CharUpper( (PWCHAR) MAKELONG( (USHORT) lpName[0], 0 ) ); + LocalName[0] = (WCHAR)toupper(lpName[0]); + LocalName[1] = L':'; + LocalName[2] = L'\0'; + + CopyBytes = sizeof (RemoteName) - sizeof (WCHAR); /* Trailing NULL. */ + Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETCONN, LocalName, sizeof(LocalName), (PVOID)RemoteName, &CopyBytes); + if (Status == WN_SUCCESS && CopyBytes > 0) + { + RemoteName[CopyBytes] = L'\0'; + + if (lstrlen (DD_MRX_VBOX_FS_DEVICE_NAME_U) + 2 + lstrlen (LocalName) + lstrlen (RemoteName) + 1 > sizeof (ConnectionName) / sizeof (WCHAR)) + { + return WN_BAD_NETNAME; + } + + lstrcpy(ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U ); + lstrcat(ConnectionName,L"\\;" ); + lstrcat( ConnectionName, LocalName ); + lstrcat( ConnectionName, RemoteName ); + CopyBytes = 0; + Status = SendToMiniRdr( IOCTL_MRX_VBOX_DELCONN, ConnectionName, + ( lstrlen( ConnectionName ) + 1 ) * sizeof( WCHAR ), + NULL, &CopyBytes ); + if ( Status == WN_SUCCESS ) + { + if ( !DefineDosDevice( DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE, + LocalName, + ConnectionName ) ) + { + Status = GetLastError( ); + } + } + } + else + { + Status = WN_NOT_CONNECTED; + } + } + else + { + BOOLEAN Verifier; + + Verifier = ( lpName[0] == L'\\' ); + Verifier &= ( lpName[1] == L'V' ) || ( lpName[1] == L'v' ); + Verifier &= ( lpName[2] == L'B' ) || ( lpName[2] == L'b' ); + Verifier &= ( lpName[3] == L'O' ) || ( lpName[3] == L'o' ); + Verifier &= ( lpName[4] == L'X' ) || ( lpName[4] == L'x' ); + Verifier &= ( lpName[5] == L'S' ) || ( lpName[5] == L's' ); + /* Both vboxsvr & vboxsrv are now accepted */ + if (( lpName[6] == L'V' ) || ( lpName[6] == L'v')) + { + Verifier &= ( lpName[6] == L'V' ) || ( lpName[6] == L'v' ); + Verifier &= ( lpName[7] == L'R' ) || ( lpName[7] == L'r' ); + } + else + { + Verifier &= ( lpName[6] == L'R' ) || ( lpName[6] == L'r' ); + Verifier &= ( lpName[7] == L'V' ) || ( lpName[7] == L'v' ); + } + Verifier &= ( lpName[8] == L'\\') || ( lpName[8] == 0 ); + + if (Verifier) + { + /* full remote path */ + if (lstrlen (DD_MRX_VBOX_FS_DEVICE_NAME_U) + 2 + lstrlen (lpName) + 1 > sizeof (ConnectionName) / sizeof (WCHAR)) + { + return WN_BAD_NETNAME; + } + + lstrcpy( ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U ); + lstrcat( ConnectionName, L"\\;" ); + lstrcat( ConnectionName, lpName ); + CopyBytes = 0; + Status = SendToMiniRdr( IOCTL_MRX_VBOX_DELCONN, ConnectionName, + ( lstrlen( ConnectionName ) + 1 ) * sizeof( WCHAR ), + NULL, &CopyBytes ); + } + else + Status = WN_NOT_CONNECTED; + } + } + + Log(("VBOXNP: NPCancelConnection: Returned 0x%lx\n", Status)); + return Status; +} + +DWORD APIENTRY +NPGetConnection (LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpBufferSize) +/*++ + + Routine Description: + + This routine returns the information associated with a connection + + Arguments: + + lpLocalName - local name associated with the connection + + lpRemoteName - the remote name associated with the connection + + lpBufferSize - the remote name buffer size + + Return Value: + + WN_SUCCESS if successful, otherwise the appropriate error + + Notes: + + --*/ +{ + DWORD Status, len; + ULONG CopyBytes; + WCHAR RemoteName[128]; + WCHAR LocalName[3]; + + Status = WN_NOT_CONNECTED; + + Log(("VBOXNP: NPGetConnection: Called\n" )); + Log(("VBOXNP: NPGetConnection: lpLocalName = %ls\n", lpLocalName)); + + if (lstrlen(lpLocalName) > 1) + { + if (lpLocalName[1] == L':') + { + CopyBytes = sizeof (RemoteName) - sizeof (WCHAR); + RemoteName[CopyBytes / sizeof (WCHAR)] = 0; + // LocalName[0] = (WCHAR) CharUpper( (PWCHAR) MAKELONG( (USHORT) lpLocalName[0], 0 ) ); + LocalName[0] = (WCHAR)toupper(lpLocalName[0]); + LocalName[1] = L':'; + LocalName[2] = L'\0'; + Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETCONN, LocalName, 3 * sizeof(WCHAR), (PVOID)RemoteName, &CopyBytes); + if (Status != NO_ERROR) + { + /* The device specified by lpLocalName is not redirected by this provider. */ + Status = WN_NOT_CONNECTED; + } + } + } + if (Status == WN_SUCCESS) + { + if (CopyBytes > 0) + { + /* Return the local name (X:) instead of UNC path \\VBOXSVR\folder to prevent + * VBOXSVR name resolutions and therefore large delays. + */ + + Log(("VBOXNP: NPGetConnection: CopyBytes: %d, RemoteName: %ls\n", CopyBytes, RemoteName)); + + CopyBytes = (lstrlen (RemoteName) + 1) * sizeof (WCHAR); /* Including the trailing 0. */ + + len = sizeof(WCHAR) + CopyBytes; /* Including the leading '\'. */ + + if (*lpBufferSize >= len) + { + lpRemoteName[0] = L'\\'; + CopyMemory( &lpRemoteName[1], RemoteName, CopyBytes ); + + Log(("VBOXNP: NPGetConnection: returning lpRemoteName: %ls\n", lpRemoteName)); + } + else + { + if (*lpBufferSize != 0) + { + /* Log only real errors. Do not log a 0 bytes try. */ + Log(("VBOXNP: NPGetConnection: Buffer overflow: *lpBufferSize = %d, len = %d\n", *lpBufferSize, len)); + } + + Status = WN_MORE_DATA; + } + + *lpBufferSize = len; + } + else + { + Status = WN_NO_NETWORK; + } + } + + if ((Status != WN_SUCCESS) && + (Status != WN_MORE_DATA)) + { + Log(("VBOXNP: NPGetConnection: Returned error 0x%lx\n", Status)); + } + + return Status; +} + +static WCHAR vboxToUpper(WCHAR wc) +{ + /* The CharUpper parameter is a pointer to a null-terminated string, + * or specifies a single character. If the high-order word of this + * parameter is zero, the low-order word must contain a single character to be converted. + */ + return (WCHAR)CharUpper((LPTSTR)wc); +} + +static const WCHAR *vboxSkipServerPrefix(const WCHAR *lpRemoteName, const WCHAR *lpPrefix) +{ + while (*lpPrefix) + { + if (vboxToUpper(*lpPrefix) != vboxToUpper(*lpRemoteName)) + { + /* Not a prefix */ + return NULL; + } + + lpPrefix++; + lpRemoteName++; + } + + return lpRemoteName; +} + +static const WCHAR *vboxSkipServerName(const WCHAR *lpRemoteName) +{ + int cLeadingBackslashes = 0; + while (*lpRemoteName == L'\\') + { + lpRemoteName++; + cLeadingBackslashes++; + } + + if (cLeadingBackslashes == 0 || cLeadingBackslashes == 2) + { + const WCHAR *lpAfterPrefix = vboxSkipServerPrefix(lpRemoteName, MRX_VBOX_SERVER_NAME_U); + + if (!lpAfterPrefix) + { + lpAfterPrefix = vboxSkipServerPrefix(lpRemoteName, MRX_VBOX_SERVER_NAME_ALT_U); + } + + return lpAfterPrefix; + } + + return NULL; +} + +#define NEWENUM + +#ifdef NEWENUM +/* Enumerate shared folders as hierarchy: + * VBOXSVR(container) + * +--------------------+ + * | \ + * Folder1(connectable) FolderN(connectable) + */ +typedef struct _NPENUMCTX +{ + ULONG index; /* Index of last entry returned. */ + DWORD dwScope; + DWORD dwOriginalScope; + DWORD dwType; + DWORD dwUsage; + bool fRoot; +} NPENUMCTX; + +DWORD APIENTRY +NPOpenEnum (DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCE lpNetResource, LPHANDLE lphEnum) +/*++ + + Routine Description: + + This routine opens a handle for enumeration of resources. + + Arguments: + + dwScope - the scope of enumeration (RESOURCE_CONNECTED, RESOURCE_GLOBALNET or RESOURCE_CONTEXT) + + dwType - the type of resources to be enumerated (RESOURCETYPE_DISK only supported) + + dwUsage - the usage parameter (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER, or zero to match all the flags) + + lpNetResource - pointer to the container to perform the enumeration. + If dwScope is RESOURCE_CONNECTED or RESOURCE_CONTEXT, this parameter will be NULL. + + lphEnum - aptr. for passing nack the enumeration handle + + Return Value: + + WN_SUCCESS if successful, otherwise the appropriate error + + Notes: + + --*/ +{ + DWORD Status; + + Log(("VBOXNP: NPOpenEnum: dwScope 0x%08X, dwType 0x%08X, dwUsage 0x%08X, lpNetResource %p\n", + dwScope, dwType, dwUsage, lpNetResource)); + + if (dwUsage == 0) + { + /* The bitmask may be zero to match all of the flags. */ + dwUsage = RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER; + } + + *lphEnum = NULL; + + /* Allocate the context structure. */ + NPENUMCTX *pCtx = (NPENUMCTX *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NPENUMCTX)); + + if (pCtx == NULL) + { + Status = WN_OUT_OF_MEMORY; + } + else + { + if (lpNetResource && lpNetResource->lpRemoteName) + { + Log(("VBOXNP: NPOpenEnum: lpRemoteName %ls\n", lpNetResource->lpRemoteName)); + } + + switch (dwScope) + { + case 6: /* Advertised as WNNC_ENUM_SHAREABLE. This returns C$ system shares. + * NpEnumResource will return NO_MORE_ENTRIES. + */ + { + if (lpNetResource == NULL || lpNetResource->lpRemoteName == NULL) + { + /* If it is NULL or if the lpRemoteName field of the NETRESOURCE is NULL, + * the provider should enumerate the top level of its network. + * But system shares can't be on top level. + */ + Status = WN_NOT_CONTAINER; + break; + } + + const WCHAR *lpAfterName = vboxSkipServerName(lpNetResource->lpRemoteName); + if ( lpAfterName == NULL + || (*lpAfterName != L'\\' && *lpAfterName != 0)) + { + Status = WN_NOT_CONTAINER; + break; + } + + /* Valid server name. */ + + pCtx->index = 0; + pCtx->dwScope = 6; + pCtx->dwOriginalScope = dwScope; + pCtx->dwType = dwType; + pCtx->dwUsage = dwUsage; + + Status = WN_SUCCESS; + break; + } + case RESOURCE_GLOBALNET: /* All resources on the network. */ + { + if (lpNetResource == NULL || lpNetResource->lpRemoteName == NULL) + { + /* If it is NULL or if the lpRemoteName field of the NETRESOURCE is NULL, + * the provider should enumerate the top level of its network. + */ + pCtx->fRoot = true; + } + else + { + /* Enumerate lpNetResource->lpRemoteName container, which can be only the VBOXSVR container. */ + const WCHAR *lpAfterName = vboxSkipServerName(lpNetResource->lpRemoteName); + if ( lpAfterName == NULL + || (*lpAfterName != L'\\' && *lpAfterName != 0)) + { + Status = WN_NOT_CONTAINER; + break; + } + + /* Valid server name. */ + pCtx->fRoot = false; + } + + pCtx->index = 0; + pCtx->dwScope = RESOURCE_GLOBALNET; + pCtx->dwOriginalScope = dwScope; + pCtx->dwType = dwType; + pCtx->dwUsage = dwUsage; + + Status = WN_SUCCESS; + break; + } + + case RESOURCE_CONNECTED: /* All currently connected resources. */ + case RESOURCE_CONTEXT: /* The interpretation of this is left to the provider. Treat this as RESOURCE_GLOBALNET. */ + { + pCtx->index = 0; + pCtx->dwScope = RESOURCE_CONNECTED; + pCtx->dwOriginalScope = dwScope; + pCtx->dwType = dwType; + pCtx->dwUsage = dwUsage; + pCtx->fRoot = false; /* Actually ignored for RESOURCE_CONNECTED. */ + + Status = WN_SUCCESS; + break; + } + + default: + Log(("VBOXNP: NPOpenEnum: unsupported scope 0x%lx\n", dwScope)); + Status = WN_NOT_SUPPORTED; + break; + } + } + + if (Status != WN_SUCCESS) + { + Log(("VBOXNP: NPOpenEnum: Returned error 0x%lx\n", Status)); + if (pCtx) + { + HeapFree(GetProcessHeap(), 0, pCtx); + } + } + else + { + Log(("VBOXNP: NPOpenEnum: pCtx %p\n", pCtx)); + *lphEnum = pCtx; + } + + return (Status); +} + +DWORD APIENTRY +NPEnumResource (HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) +/*++ + + Routine Description: + + This routine uses the handle obtained by a call to NPOpenEnum for + enuerating the connected shares + + Arguments: + + hEnum - the enumeration handle + + lpcCount - the number of resources requested/returned + + lpBuffer - the buffer for passing back the NETRESOURCE entries + + lpBufferSize - the size of the buffer + + Return Value: + + WN_SUCCESS if successful, otherwise the appropriate error + + WN_NO_MORE_ENTRIES - if the enumeration has exhausted the entries + + WN_MORE_DATA - if more data is available + + --*/ +{ + DWORD Status = WN_SUCCESS; + NPENUMCTX *pCtx = (NPENUMCTX *)hEnum; + + BYTE ConnectionList[26]; + ULONG CopyBytes; + WCHAR LocalName[3]; + WCHAR RemoteName[128]; + + ULONG SpaceNeeded; + + Log(("VBOXNP: NPEnumResource: hEnum %p, lpcCount %p, lpBuffer %p, lpBufferSize %p.\n", + hEnum, lpcCount, lpBuffer, lpBufferSize)); + + if (pCtx == NULL) + { + Log(("VBOXNP: NPEnumResource: WN_BAD_HANDLE\n")); + return WN_BAD_HANDLE; + } + + if (lpcCount == NULL || lpBuffer == NULL) + { + Log(("VBOXNP: NPEnumResource: WN_BAD_VALUE\n")); + return WN_BAD_VALUE; + } + + Log(("VBOXNP: NPEnumResource: *lpcCount 0x%x, *lpBufferSize 0x%x, pCtx->index %d\n", + *lpcCount, *lpBufferSize, pCtx->index)); + + LPNETRESOURCE pNetResource = (LPNETRESOURCE)lpBuffer; + ULONG SpaceAvailable = *lpBufferSize; + ULONG EntriesCopied = 0; + PWCHAR StringZone = (PWCHAR)((PBYTE)lpBuffer + *lpBufferSize); + + if (pCtx->dwScope == RESOURCE_CONNECTED) + { + Log(("VBOXNP: NPEnumResource: RESOURCE_CONNECTED\n")); + + memset (ConnectionList, 0, sizeof (ConnectionList)); + CopyBytes = sizeof(ConnectionList); + Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETLIST, NULL, 0, ConnectionList, &CopyBytes); + + if (Status == WN_SUCCESS && CopyBytes > 0) + { + while (EntriesCopied < *lpcCount && pCtx->index < RTL_NUMBER_OF(ConnectionList)) + { + if (ConnectionList[pCtx->index]) + { + LocalName[0] = L'A' + (WCHAR)pCtx->index; + LocalName[1] = L':'; + LocalName[2] = L'\0'; + memset (RemoteName, 0, sizeof (RemoteName)); + CopyBytes = sizeof(RemoteName); + Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETCONN, LocalName, sizeof(LocalName), RemoteName, &CopyBytes); + + if (Status != WN_SUCCESS || CopyBytes == 0) + { + Status = WN_NO_MORE_ENTRIES; + break; + } + + // Determine the space needed for this entry... + SpaceNeeded = sizeof(NETRESOURCE); // resource struct + SpaceNeeded += 3 * sizeof(WCHAR); // local name + SpaceNeeded += 2 * sizeof(WCHAR) + CopyBytes; // remote name: \ + name + 0 + SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); // provider name + + if (SpaceNeeded > SpaceAvailable) + { + break; + } + + SpaceAvailable -= SpaceNeeded; + + pNetResource->dwScope = RESOURCE_CONNECTED; + pNetResource->dwType = RESOURCETYPE_DISK; + pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; + pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE; + + // setup string area at opposite end of buffer + SpaceNeeded -= sizeof(NETRESOURCE); + StringZone = (PWCHAR)((PBYTE)StringZone - SpaceNeeded); + PWCHAR NewStringZone = StringZone; + // copy local name + pNetResource->lpLocalName = StringZone; + *StringZone++ = L'A' + (WCHAR)pCtx->index; + *StringZone++ = L':'; + *StringZone++ = L'\0'; + // copy remote name + pNetResource->lpRemoteName = StringZone; + *StringZone++ = L'\\'; + CopyMemory( StringZone, RemoteName, CopyBytes ); + StringZone += CopyBytes / sizeof(WCHAR); + *StringZone++ = L'\0'; + // copy comment + pNetResource->lpComment = 0; + // copy provider name + pNetResource->lpProvider = StringZone; + CopyMemory(StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof (MRX_VBOX_PROVIDER_NAME_U)); + + EntriesCopied++; + + // set new bottom of string zone + StringZone = NewStringZone; + Log(("VBOXNP: NPEnumResource: lpRemoteName: %ls\n", pNetResource->lpRemoteName)); + + pNetResource++; + } + + pCtx->index++; + } + } + else + { + Status = WN_NO_MORE_ENTRIES; + } + } + else if (pCtx->dwScope == RESOURCE_GLOBALNET) + { + Log(("VBOXNP: NPEnumResource: RESOURCE_GLOBALNET: root %d\n", pCtx->fRoot)); + + if (pCtx->fRoot) + { + /* VBOXSVR container. */ + if (pCtx->index > 0) + { + Status = WN_NO_MORE_ENTRIES; + } + else + { + /* Return VBOXSVR server. + * Determine the space needed for this entry. + */ + SpaceNeeded = sizeof(NETRESOURCE); + SpaceNeeded += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name */ + SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */ + + if (SpaceNeeded > SpaceAvailable) + { + /* Do nothing. */ + } + else + { + SpaceAvailable -= SpaceNeeded; + + memset (pNetResource, 0, sizeof (*pNetResource)); + + pNetResource->dwScope = RESOURCE_GLOBALNET; + pNetResource->dwType = RESOURCETYPE_ANY; + pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; + pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER; + + // setup string area at opposite end of buffer + SpaceNeeded -= sizeof(NETRESOURCE); + StringZone = (PWCHAR)((PBYTE)StringZone - SpaceNeeded); + // local name + pNetResource->lpLocalName = 0; + // remote name + pNetResource->lpRemoteName = StringZone; + *StringZone++ = L'\\'; + *StringZone++ = L'\\'; + CopyMemory( StringZone, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U) ); + StringZone += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR); + // comment + pNetResource->lpComment = 0; + // provider name + pNetResource->lpProvider = StringZone; + CopyMemory(StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof (MRX_VBOX_PROVIDER_NAME_U)); + + EntriesCopied++; + + pCtx->index++; + } + } + } + else + { + /* Shares of VBOXSVR. */ + memset (ConnectionList, 0, sizeof (ConnectionList)); + CopyBytes = sizeof(ConnectionList); + Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETGLOBALLIST, NULL, 0, ConnectionList, &CopyBytes); + + if (Status == WN_SUCCESS && CopyBytes > 0) + { + while (EntriesCopied < *lpcCount && pCtx->index < RTL_NUMBER_OF(ConnectionList)) + { + if (ConnectionList[pCtx->index]) + { + memset (RemoteName, 0, sizeof (RemoteName)); + CopyBytes = sizeof(RemoteName); + Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETGLOBALCONN, &ConnectionList[pCtx->index], sizeof(ConnectionList[pCtx->index]), RemoteName, &CopyBytes); + + if (Status != WN_SUCCESS || CopyBytes == 0) + { + Status = WN_NO_MORE_ENTRIES; + break; + } + + // Determine the space needed for this entry... + SpaceNeeded = sizeof(NETRESOURCE); // resource struct + SpaceNeeded += 3 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U) + CopyBytes; /* remote name: \\ + vboxsvr + \ + name + 0. */ + SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); // provider name + + if (SpaceNeeded > SpaceAvailable) + { + break; + } + + SpaceAvailable -= SpaceNeeded; + + pNetResource->dwScope = pCtx->dwOriginalScope; + pNetResource->dwType = RESOURCETYPE_DISK; + pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; + pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE; + + // setup string area at opposite end of buffer + SpaceNeeded -= sizeof(NETRESOURCE); + StringZone = (PWCHAR)((PBYTE)StringZone - SpaceNeeded); + PWCHAR NewStringZone = StringZone; + // copy local name + pNetResource->lpLocalName = 0; + // copy remote name + pNetResource->lpRemoteName = StringZone; + *StringZone++ = L'\\'; + *StringZone++ = L'\\'; + lstrcpy(StringZone, MRX_VBOX_SERVER_NAME_U ); + StringZone += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR) - 1; + *StringZone++ = L'\\'; + CopyMemory( StringZone, RemoteName, CopyBytes ); + StringZone += CopyBytes / sizeof(WCHAR); + *StringZone++ = L'\0'; + // copy comment + pNetResource->lpComment = 0; + // copy provider name + pNetResource->lpProvider = StringZone; + CopyMemory(StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof (MRX_VBOX_PROVIDER_NAME_U)); + + EntriesCopied++; + + // set new bottom of string zone + StringZone = NewStringZone; + Log(("VBOXNP: NPEnumResource: lpRemoteName: %ls\n", pNetResource->lpRemoteName)); + + pNetResource++; + } + + pCtx->index++; + } + } + else + { + Status = WN_NO_MORE_ENTRIES; + } + } + } + else if (pCtx->dwScope == 6) + { + Log(("VBOXNP: NPEnumResource: dwScope 6\n")); + Status = WN_NO_MORE_ENTRIES; + } + else + { + Log(("VBOXNP: NPEnumResource: invalid dwScope 0x%x\n", pCtx->dwScope)); + return WN_BAD_HANDLE; + } + + *lpcCount = EntriesCopied; + + if (EntriesCopied == 0 && Status == WN_SUCCESS) + { + if (pCtx->index >= RTL_NUMBER_OF(ConnectionList)) + { + Status = WN_NO_MORE_ENTRIES; + } + else + { + Log(("VBOXNP: NPEnumResource: More Data Needed - %d\n", SpaceNeeded)); + *lpBufferSize = SpaceNeeded; + Status = WN_MORE_DATA; + } + } + + Log(("VBOXNP: NPEnumResource: Entries returned - %d, Status %d\n", EntriesCopied, Status)); + return Status; +} +DWORD APIENTRY +NPCloseEnum (HANDLE hEnum) +/*++ + + Routine Description: + + This routine closes the handle for enumeration of resources. + + Arguments: + + hEnum - the enumeration handle + + Return Value: + + WN_SUCCESS if successful, otherwise the appropriate error + + --*/ +{ + DWORD Status = WN_SUCCESS; + NPENUMCTX *pCtx = (NPENUMCTX *)hEnum; + + Log(("VBOXNP: NPCloseEnum: hEnum %p\n", hEnum)); + + if (pCtx) + { + HeapFree(GetProcessHeap(), 0, pCtx); + } + + Log(("VBOXNP: NPCloseEnum: returns\n")); + return WN_SUCCESS; +} +#else +DWORD APIENTRY +NPOpenEnum (DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCE lpNetResource, LPHANDLE lphEnum) +/*++ + + Routine Description: + + This routine opens a handle for enumeration of resources. The only capability + implemented in the sample is for enumerating connected shares + + Arguments: + + dwScope - the scope of enumeration + + dwType - the type of resources to be enumerated + + dwUsage - the usage parameter + + lpNetResource - a pointer to the desired NETRESOURCE struct. + + lphEnum - aptr. for passing nack the enumeration handle + + Return Value: + + WN_SUCCESS if successful, otherwise the appropriate error + + Notes: + + The sample only supports the notion of enumerating connected shares + + The handle passed back is merely the index of the last entry returned + + --*/ +{ + DWORD Status; + + Log(("VBOXNP: NPOpenEnum: Called.\n")); + + *lphEnum = NULL; + + switch (dwScope) + { + case RESOURCE_GLOBALNET: + case RESOURCE_CONNECTED: + { + DWORD *lpdwEnum = NULL; + lpdwEnum = (DWORD *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DWORD) * 2); + + if (lpdwEnum != NULL) + { + lpdwEnum[0] = 0; + lpdwEnum[1] = dwScope; + *lphEnum = lpdwEnum; + + Status = WN_SUCCESS; + } + else + { + Status = WN_OUT_OF_MEMORY; + } + break; + } + break; + + case RESOURCE_CONTEXT: + default: + Status = WN_NOT_SUPPORTED; + break; + } + + if (Status != WN_SUCCESS) + Log(("VBOXNP: NPOpenEnum: Returned error 0x%lx\n", Status)); + + return (Status); +} + +DWORD APIENTRY +NPEnumResource (HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) +/*++ + + Routine Description: + + This routine uses the handle obtained by a call to NPOpenEnum for + enuerating the connected shares + + Arguments: + + hEnum - the enumeration handle + + lpcCount - the number of resources returned + + lpBuffer - the buffere for passing back the entries + + lpBufferSize - the size of the buffer + + Return Value: + + WN_SUCCESS if successful, otherwise the appropriate error + + WN_NO_MORE_ENTRIES - if the enumeration has exhausted the entries + + WN_MORE_DATA - if nmore data is available + + Notes: + + The sample only supports the notion of enumerating connected shares + + The handle passed back is merely the index of the last entry returned + + --*/ +{ + DWORD Status = WN_SUCCESS; + BYTE byConnectionList[26]; + ULONG CopyBytes; + ULONG EntriesCopied; + ULONG i; + LPNETRESOURCE pNetResource; + ULONG SpaceNeeded; + ULONG SpaceAvailable; + WCHAR wzLocalName[3]; + WCHAR wzRemoteName[128]; + PWCHAR pwcStringZone; + DWORD dwScope = 0; + + Log(("VBOXNP: NPEnumResource: Called.\n")); + + if ((lpcCount == NULL) || (lpBufferSize == NULL) || (lpBuffer == NULL)) + { + Log(("VBOXNP: NPEnumResource: Has invalid parameter(s)!\n")); + return WN_NO_MORE_ENTRIES; + } + + if (hEnum != NULL) + dwScope = ((DWORD*)hEnum)[1]; + + Log(("VBOXNP: NPEnumResource: Count Requested %d\n", *lpcCount)); + Log(("VBOXNP: NPEnumResource: Scope %ld\n", dwScope)); + + pNetResource = (LPNETRESOURCE)lpBuffer; + SpaceAvailable = *lpBufferSize; + EntriesCopied = 0; + pwcStringZone = (PWCHAR)((PBYTE)lpBuffer + *lpBufferSize); + + /* + * Returns the already connected resources of each driver letter (A-Z). + */ + if (dwScope == RESOURCE_CONNECTED) + { + Log(("VBOXNP: NPEnumResource: Scope = Resource connected.\n")); + + CopyBytes = 26; + Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETLIST, NULL, 0, (PVOID)byConnectionList, &CopyBytes); + + if (Status == WN_SUCCESS && CopyBytes > 0) + { + for (i = *((PULONG)hEnum); EntriesCopied < *lpcCount, i < 26; i++) + { + if (byConnectionList[i]) + { + CopyBytes = 128; + wzLocalName[0] = L'A' + (WCHAR)i; + wzLocalName[1] = L':'; + wzLocalName[2] = L'\0'; + Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETCONN, wzLocalName, 3 * sizeof(WCHAR), (PVOID)wzRemoteName, &CopyBytes); + + // if something strange happended then just say there are no more entries + if (Status != WN_SUCCESS || CopyBytes == 0) + { + Status = WN_NO_MORE_ENTRIES; + break; + } + // Determine the space needed for this entry... + + SpaceNeeded = sizeof(NETRESOURCE); // resource struct + SpaceNeeded += 3 * sizeof(WCHAR); // local name + SpaceNeeded += 2 * sizeof(WCHAR) + CopyBytes; // remote name + SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); // provider name + + if (SpaceNeeded > SpaceAvailable) + { + break; + } + else + { + SpaceAvailable -= SpaceNeeded; + + pNetResource->dwScope = RESOURCE_CONNECTED; + pNetResource->dwType = RESOURCETYPE_DISK; + pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; + pNetResource->dwUsage = 0; + + // setup string area at opposite end of buffer + SpaceNeeded -= sizeof(NETRESOURCE); + pwcStringZone = (PWCHAR)((PBYTE)pwcStringZone - SpaceNeeded); + // copy local name + pNetResource->lpLocalName = pwcStringZone; + *pwcStringZone++ = L'A' + (WCHAR)i; + *pwcStringZone++ = L':'; + *pwcStringZone++ = L'\0'; + // copy remote name + pNetResource->lpRemoteName = pwcStringZone; + *pwcStringZone++ = L'\\'; + CopyMemory( pwcStringZone, wzRemoteName, CopyBytes ); + pwcStringZone += CopyBytes / sizeof(WCHAR); + *pwcStringZone++ = L'\0'; + // copy comment + pNetResource->lpComment = 0; + // copy provider name + pNetResource->lpProvider = pwcStringZone; + lstrcpy(pwcStringZone, MRX_VBOX_PROVIDER_NAME_U ); + + EntriesCopied++; + // set new bottom of string zone + pwcStringZone = (PWCHAR)((PBYTE)pwcStringZone - SpaceNeeded); + } + pNetResource++; + } + } + } + else + { + Status = WN_NO_MORE_ENTRIES; + } + } + else if (dwScope == RESOURCE_GLOBALNET) + { + Log(("VBOXNP: NPEnumResource: Scope = Resource global net.\n")); + + CopyBytes = 26; + Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETGLOBALLIST, NULL, 0, (PVOID)byConnectionList, &CopyBytes); + + if (Status == WN_SUCCESS && CopyBytes > 0) + { + for (i = *((PULONG)hEnum); EntriesCopied < *lpcCount, i < 26; i++) + { + if (byConnectionList[i]) + { + CopyBytes = 128; + + Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETGLOBALCONN, &byConnectionList[i], sizeof(byConnectionList[i]), (PVOID)wzRemoteName, &CopyBytes); + + // if something strange happended then just say there are no more entries + if (Status != WN_SUCCESS || CopyBytes == 0) + { + Status = WN_NO_MORE_ENTRIES; + break; + } + // Determine the space needed for this entry... + + SpaceNeeded = sizeof(NETRESOURCE); // resource struct + SpaceNeeded += 11 * sizeof(WCHAR) + CopyBytes; // remote name + SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); // provider name + + if (SpaceNeeded > SpaceAvailable) + { + break; + } + else + { + SpaceAvailable -= SpaceNeeded; + + pNetResource->dwScope = RESOURCE_GLOBALNET; + pNetResource->dwType = RESOURCETYPE_DISK; + pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; + pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE; + + // setup string area at opposite end of buffer + SpaceNeeded -= sizeof(NETRESOURCE); + pwcStringZone = (PWCHAR)((PBYTE)pwcStringZone - SpaceNeeded); + // copy local name + pNetResource->lpLocalName = 0; + // copy remote name + pNetResource->lpRemoteName = pwcStringZone; + *pwcStringZone++ = L'\\'; + *pwcStringZone++ = L'\\'; + *pwcStringZone++ = L'V'; + *pwcStringZone++ = L'B'; + *pwcStringZone++ = L'O'; + *pwcStringZone++ = L'X'; + *pwcStringZone++ = L'S'; + *pwcStringZone++ = L'V'; + *pwcStringZone++ = L'R'; + *pwcStringZone++ = L'\\'; + CopyMemory( pwcStringZone, wzRemoteName, CopyBytes ); + pwcStringZone += CopyBytes / sizeof(WCHAR); + *pwcStringZone++ = L'\0'; + // copy comment + pNetResource->lpComment = 0; + // copy provider name + pNetResource->lpProvider = pwcStringZone; + lstrcpy(pwcStringZone, MRX_VBOX_PROVIDER_NAME_U ); + + EntriesCopied++; + // set new bottom of string zone + pwcStringZone = (PWCHAR)((PBYTE)pwcStringZone - SpaceNeeded); + Log(("VBOXNP: NPEnumResource: StringZone: %ls\n", pwcStringZone)); + } + pNetResource++; + } + } + } + else + { + Status = WN_NO_MORE_ENTRIES; + } + } + else return WN_NO_MORE_ENTRIES; + + *lpcCount = EntriesCopied; + if (EntriesCopied == 0 && Status == WN_SUCCESS) + { + if (i > 25) + { + Status = WN_NO_MORE_ENTRIES; + } + else + { + Log(("VBOXNP: NPEnumResource: More Data Needed - %d\n", SpaceNeeded)); + Status = WN_MORE_DATA; + *lpBufferSize = SpaceNeeded; + } + } + // update entry index + *(PULONG)hEnum = i; + + Log(("VBOXNP: NPEnumResource: Entries returned - %d\n", EntriesCopied)); + + return Status; +} + +DWORD APIENTRY +NPCloseEnum (HANDLE hEnum) +/*++ + + Routine Description: + + This routine closes the handle for enumeration of resources. + + Arguments: + + hEnum - the enumeration handle + + Return Value: + + WN_SUCCESS if successful, otherwise the appropriate error + + Notes: + + The sample only supports the notion of enumerating connected shares + + --*/ +{ + Log(("VBOXNP: NPCloseEnum: Called.\n")); + + if (NULL != (PVOID)hEnum) + HeapFree(GetProcessHeap(), 0, (PVOID)hEnum); + + Log(("VBOXNP: NPCloseEnum: Memory freed.\n")); + return WN_SUCCESS; +} +#endif + +DWORD APIENTRY +NPGetResourceParent (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD lpBufferSize) +/*++ + + Routine Description: + + This routine returns the information about net resource parent + + Arguments: + + lpNetResource - the NETRESOURCE struct + + lpBuffer - the buffer for passing back the parent information + + lpBufferSize - the buffer size + + Return Value: + + Notes: + + --*/ +{ + Log(("VBOXNP: NPGetResourceParent: lpNetResource %p, lpBuffer %p, lpBufferSize %p\n", + lpNetResource, lpBuffer, lpBufferSize)); + /* Contruct a new NETRESOURCE which is syntactically a parent of lpNetResource, + * then call NPGetResourceInformation to actually fill the buffer. + */ + if (!lpNetResource || !lpNetResource->lpRemoteName || !lpBufferSize) + { + return WN_BAD_NETNAME; + } + + const WCHAR *lpAfterName = vboxSkipServerName(lpNetResource->lpRemoteName); + if ( lpAfterName == NULL + || (*lpAfterName != L'\\' && *lpAfterName != 0)) + { + Log(("VBOXNP: NPGetResourceParent: WN_BAD_NETNAME\n")); + return WN_BAD_NETNAME; + } + + DWORD RemoteNameLength = lstrlen(lpNetResource->lpRemoteName); + + DWORD SpaceNeeded = sizeof (NETRESOURCE); + SpaceNeeded += (RemoteNameLength + 1) * sizeof (WCHAR); + + NETRESOURCE *pParent = (NETRESOURCE *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SpaceNeeded); + + if (!pParent) + { + return WN_OUT_OF_MEMORY; + } + + pParent->lpRemoteName = (WCHAR *)((PBYTE)pParent + sizeof (NETRESOURCE)); + lstrcpy(pParent->lpRemoteName, lpNetResource->lpRemoteName); + + /* Remove last path component of the pParent->lpRemoteName. */ + WCHAR *pLastSlash = pParent->lpRemoteName + RemoteNameLength; + if (*pLastSlash == L'\\') + { + /* \\server\share\path\, skip last slash immediately. */ + pLastSlash--; + } + + while (pLastSlash != pParent->lpRemoteName) + { + if (*pLastSlash == L'\\') + { + break; + } + + pLastSlash--; + } + + DWORD Status = WN_SUCCESS; + + if ( pLastSlash == pParent->lpRemoteName + || pLastSlash == pParent->lpRemoteName + 1) + { + /* It is a leading backslash. Construct "no parent" NETRESOURCE. */ + NETRESOURCE *pNetResource = (NETRESOURCE *)lpBuffer; + + SpaceNeeded = sizeof(NETRESOURCE); + SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* remote name */ + SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */ + + if (SpaceNeeded > *lpBufferSize) + { + Log(("VBOXNP: NPGetResourceParent: WN_MORE_DATA 0x%x\n", SpaceNeeded)); + *lpBufferSize = SpaceNeeded; + Status = WN_MORE_DATA; + } + else + { + memset (pNetResource, 0, sizeof (*pNetResource)); + + pNetResource->dwType = RESOURCETYPE_ANY; + pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK; + pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER; + + /* Setup string area at opposite end of buffer. */ + WCHAR *StringZone = (WCHAR *)((PBYTE)lpBuffer + *lpBufferSize); + StringZone = (PWCHAR)((PBYTE)StringZone - (SpaceNeeded - sizeof(NETRESOURCE))); + + pNetResource->lpRemoteName = StringZone; + CopyMemory (StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U)); + StringZone += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR); + + /* Provider. */ + pNetResource->lpProvider = StringZone; + CopyMemory (StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U)); + StringZone += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR); + + Log(("VBOXNP: NPGetResourceParent: no parent, strings %p/%p\n", + StringZone, (PBYTE)lpBuffer + *lpBufferSize)); + } + } + else + { + /* Make the parent remote name and get its information. */ + *pLastSlash = 0; + + LPWSTR lpSystem = NULL; + Status = NPGetResourceInformation (pParent, lpBuffer, lpBufferSize, &lpSystem); + } + + if (pParent) + { + HeapFree(GetProcessHeap(), 0, pParent); + } + return Status; +} + +DWORD APIENTRY +NPGetResourceInformation (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD lpBufferSize, LPWSTR *lplpSystem) +/* + + Routine Description: + + Separates the part of a network resource accessed through the WNet API from the part accessed + through APIs specific to the resource type. + + Arguments: + + lpNetResource - network resource for which information is required. + The lpRemoteName field specifies the remote name of the resource. + + lpBuffer - a single NETRESOURCE structure and associated strings. The lpRemoteName field should be + returned in the same format as that returned from an enumeration by the NPEnumResource + function, so that the caller can perform a case-sensitive string comparison. + + lpBufferSize - the buffer size. If the buffer is too small for the result, the function places the + required buffer size at this location and returns the error WN_MORE_DATA. + + lplpSystem - On a successful return, a pointer to a null-terminated string in the output buffer + specifying that part of the resource that is accessed through system APIs specific + to the resource type, rather than through the WNet API. If there is no such part, + lplpSystem is set to NULL. + + */ +{ + Log(("VBOXNP: NPGetResourceInformation: lpNetResource %p, lpBuffer %p, lpBufferSize %p, lplpSystem %p\n", + lpNetResource, lpBuffer, lpBufferSize, lplpSystem)); + + if ( lpNetResource == NULL + || lpNetResource->lpRemoteName == NULL + || lpBufferSize == NULL) + { + Log(("VBOXNP: NPGetResourceInformation: WN_BAD_VALUE\n")); + return WN_BAD_VALUE; + } + + Log(("VBOXNP: NPGetResourceInformation: lpRemoteName %ls, *lpBufferSize 0x%x\n", + lpNetResource->lpRemoteName, *lpBufferSize)); + + const WCHAR *lpAfterName = vboxSkipServerName(lpNetResource->lpRemoteName); + if ( lpAfterName == NULL + || (*lpAfterName != L'\\' && *lpAfterName != 0)) + { + Log(("VBOXNP: NPGetResourceInformation: WN_BAD_NETNAME\n")); + return WN_BAD_NETNAME; + } + + if (lpNetResource->dwType != 0 && lpNetResource->dwType != RESOURCETYPE_DISK) + { + /* The caller passed in a nonzero dwType that does not match + * the actual type of the network resource. + */ + return WN_BAD_DEV_TYPE; + } + + /* + * If the input remote resource name was "\\server\share\dir1\dir2", + * then the output NETRESOURCE contains information about the resource "\\server\share". + * The lpRemoteName, lpProvider, dwType, dwDisplayType, and dwUsage fields are returned + * containing values, all other fields being set to NULL. + */ + DWORD SpaceNeeded; + WCHAR *StringZone = (WCHAR *)((PBYTE)lpBuffer + *lpBufferSize); + NETRESOURCE *pNetResource = (NETRESOURCE *)lpBuffer; + + /* Check what kind of the resource is that by parsing path components. + * lpAfterName points to first WCHAR after a valid server name. + */ + + if (lpAfterName[0] == 0 || lpAfterName[1] == 0) + { + /* "\\VBOXSVR" or "\\VBOXSVR\" */ + SpaceNeeded = sizeof(NETRESOURCE); + SpaceNeeded += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name */ + SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */ + + if (SpaceNeeded > *lpBufferSize) + { + Log(("VBOXNP: NPGetResourceInformation: WN_MORE_DATA 0x%x\n", SpaceNeeded)); + *lpBufferSize = SpaceNeeded; + return WN_MORE_DATA; + } + + memset (pNetResource, 0, sizeof (*pNetResource)); + + pNetResource->dwType = RESOURCETYPE_ANY; + pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; + pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER; + + /* Setup string area at opposite end of buffer. */ + StringZone = (PWCHAR)((PBYTE)StringZone - (SpaceNeeded - sizeof(NETRESOURCE))); + + /* The remote name is the server. */ + pNetResource->lpRemoteName = StringZone; + *StringZone++ = L'\\'; + *StringZone++ = L'\\'; + CopyMemory (StringZone, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U)); + StringZone += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR); + + /* Provider. */ + pNetResource->lpProvider = StringZone; + CopyMemory (StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U)); + StringZone += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR); + + Log(("VBOXNP: NPGetResourceInformation: lpRemoteName: %ls, strings %p/%p\n", + pNetResource->lpRemoteName, StringZone, (PBYTE)lpBuffer + *lpBufferSize)); + + if (lplpSystem) + { + *lplpSystem = NULL; + } + return WN_SUCCESS; + } + + /* *lpAfterName == L'\\', could be share or share + path. + * Check if there are more path components after the share name. + */ + const WCHAR *lp = lpAfterName + 1; + while (*lp && *lp != L'\\') + { + lp++; + } + + if (*lp == 0) + { + /* It is a share only: \\vboxsvr\share */ + SpaceNeeded = sizeof(NETRESOURCE); + SpaceNeeded += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name with trailing nul */ + SpaceNeeded += (lp - lpAfterName) * sizeof(WCHAR); /* The share name with leading \\ */ + SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */ + + if (SpaceNeeded > *lpBufferSize) + { + Log(("VBOXNP: NPGetResourceInformation: WN_MORE_DATA 0x%x\n", SpaceNeeded)); + *lpBufferSize = SpaceNeeded; + return WN_MORE_DATA; + } + + memset (pNetResource, 0, sizeof (*pNetResource)); + + pNetResource->dwType = RESOURCETYPE_DISK; + pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; + pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE; + + /* Setup string area at opposite end of buffer. */ + StringZone = (PWCHAR)((PBYTE)StringZone - (SpaceNeeded - sizeof(NETRESOURCE))); + + /* The remote name is the server + share. */ + pNetResource->lpRemoteName = StringZone; + *StringZone++ = L'\\'; + *StringZone++ = L'\\'; + CopyMemory (StringZone, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U) - sizeof (WCHAR)); + StringZone += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR) - 1; + CopyMemory (StringZone, lpAfterName, (lp - lpAfterName + 1) * sizeof(WCHAR)); + StringZone += lp - lpAfterName + 1; + + /* Provider. */ + pNetResource->lpProvider = StringZone; + CopyMemory (StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U)); + StringZone += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR); + + Log(("VBOXNP: NPGetResourceInformation: lpRemoteName: %ls, strings %p/%p\n", + pNetResource->lpRemoteName, StringZone, (PBYTE)lpBuffer + *lpBufferSize)); + + if (lplpSystem) + { + *lplpSystem = NULL; + } + return WN_SUCCESS; + } + + /* \\vboxsvr\share\path */ + SpaceNeeded = sizeof(NETRESOURCE); + SpaceNeeded += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name with trailing nul */ + SpaceNeeded += (lp - lpAfterName) * sizeof(WCHAR); /* The share name with leading \\ */ + SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */ + SpaceNeeded += (lstrlen(lp) + 1) * sizeof (WCHAR); /* path string for lplpSystem */ + + if (SpaceNeeded > *lpBufferSize) + { + Log(("VBOXNP: NPGetResourceInformation: WN_MORE_DATA 0x%x\n", SpaceNeeded)); + *lpBufferSize = SpaceNeeded; + return WN_MORE_DATA; + } + + memset (pNetResource, 0, sizeof (*pNetResource)); + + pNetResource->dwType = RESOURCETYPE_DISK; + pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; + pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE; + + /* Setup string area at opposite end of buffer. */ + StringZone = (PWCHAR)((PBYTE)StringZone - (SpaceNeeded - sizeof(NETRESOURCE))); + + /* The remote name is the server + share. */ + pNetResource->lpRemoteName = StringZone; + *StringZone++ = L'\\'; + *StringZone++ = L'\\'; + CopyMemory (StringZone, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U) - sizeof (WCHAR)); + StringZone += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR) - 1; + CopyMemory (StringZone, lpAfterName, (lp - lpAfterName) * sizeof(WCHAR)); + StringZone += lp - lpAfterName; + *StringZone++ = 0; + + /* Provider. */ + pNetResource->lpProvider = StringZone; + CopyMemory (StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U)); + StringZone += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR); + + if (lplpSystem) + { + *lplpSystem = StringZone; + } + + lstrcpy(StringZone, lp); + StringZone += lstrlen(lp) + 1; + + Log(("VBOXNP: NPGetResourceInformation: lpRemoteName: %ls, strings %p/%p\n", + pNetResource->lpRemoteName, StringZone, (PBYTE)lpBuffer + *lpBufferSize)); + Log(("VBOXNP: NPGetResourceInformation: *lplpSystem: %ls\n", *lplpSystem)); + + return WN_SUCCESS; +} + +DWORD APIENTRY +NPGetUniversalName (LPCWSTR lpLocalPath, DWORD dwInfoLevel, LPVOID lpBuffer, LPDWORD lpBufferSize) +/*++ + + Routine Description: + + This routine returns the information associated net resource + + Arguments: + + lpLocalPath - the local path name + + dwInfoLevel - the desired info level + + lpBuffer - the buffer for the univeral name + + lpBufferSize - the buffer size + + Return Value: + + WN_SUCCESS if successful + + Notes: + + --*/ +{ + DWORD dwStatus; + + DWORD BufferRequired = 0; + DWORD RemoteNameLength = 0; + DWORD RemainingPathLength = 0; + + WCHAR LocalDrive[3]; + + const WCHAR *lpRemainingPath; + WCHAR *lpString; + + Log(("VBOXNP: NPGetUniversalName: lpLocalPath = %ls, InfoLevel = %d, *lpBufferSize = %d\n", lpLocalPath, dwInfoLevel, *lpBufferSize)); + + /* Check is input parameter is OK. */ + if ( dwInfoLevel != UNIVERSAL_NAME_INFO_LEVEL + && dwInfoLevel != REMOTE_NAME_INFO_LEVEL) + { + Log(("VBOXNP: NPGetUniversalName: Bad dwInfoLevel value: %d\n", dwInfoLevel)); + return WN_BAD_LEVEL; + } + + /* The 'lpLocalPath' is "X:\something". Extract the "X:" to pass to NPGetConnection. */ + if ( lpLocalPath == NULL + || lpLocalPath[0] == 0 + || lpLocalPath[1] != L':') + { + Log(("VBOXNP: NPGetUniversalName: Bad lpLocalPath.\n")); + return WN_BAD_LOCALNAME; + } + + LocalDrive[0] = lpLocalPath[0]; + LocalDrive[1] = lpLocalPath[1]; + LocalDrive[2] = 0; + + /* Length of the original path without the driver letter, including trailing NULL. */ + lpRemainingPath = &lpLocalPath[2]; + RemainingPathLength = (DWORD)((wcslen (lpRemainingPath) + 1) * sizeof(WCHAR)); + + /* Build the required structure in place of the supplied buffer. */ + if (dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL) + { + LPUNIVERSAL_NAME_INFOW pUniversalNameInfo = (LPUNIVERSAL_NAME_INFOW)lpBuffer; + + BufferRequired = sizeof (UNIVERSAL_NAME_INFOW); + + if (*lpBufferSize >= BufferRequired) + { + /* Enough place for the structure. */ + pUniversalNameInfo->lpUniversalName = (PWCHAR)((PBYTE)lpBuffer + sizeof(UNIVERSAL_NAME_INFOW)); + + /* At least so many bytes are available for obtaining the remote name. */ + RemoteNameLength = *lpBufferSize - BufferRequired; + } + else + { + RemoteNameLength = 0; + } + + /* Put the remote name directly to the buffer if possible and get the name length. */ + dwStatus = NPGetConnection (LocalDrive, RemoteNameLength? pUniversalNameInfo->lpUniversalName: NULL, &RemoteNameLength); + + if ( dwStatus != WN_SUCCESS + && dwStatus != WN_MORE_DATA) + { + if (dwStatus != WN_NOT_CONNECTED) + { + Log(("VBOXNP: NPGetUniversalName: NPGetConnection returned error 0x%lx\n", dwStatus)); + } + return dwStatus; + } + + if (RemoteNameLength < sizeof (WCHAR)) + { + Log(("VBOXNP: NPGetUniversalName: Remote name is empty.\n")); + return WN_NO_NETWORK; + } + + /* Adjust for actual remote name length. */ + BufferRequired += RemoteNameLength; + + /* And for required place for remaining path. */ + BufferRequired += RemainingPathLength; + + if (*lpBufferSize < BufferRequired) + { + Log(("VBOXNP: NPGetUniversalName: WN_MORE_DATA BufferRequired: %d\n", BufferRequired)); + *lpBufferSize = BufferRequired; + return WN_MORE_DATA; + } + + /* Enough memory in the buffer. Add '\' and remaining path to the remote name. */ + lpString = &pUniversalNameInfo->lpUniversalName[RemoteNameLength / sizeof (WCHAR)]; + lpString--; /* Trailing NULL */ + + CopyMemory( lpString, lpRemainingPath, RemainingPathLength); + } + else + { + LPREMOTE_NAME_INFOW pRemoteNameInfo = (LPREMOTE_NAME_INFOW)lpBuffer; + WCHAR *lpDelimiter; + + BufferRequired = sizeof (REMOTE_NAME_INFOW); + + if (*lpBufferSize >= BufferRequired) + { + /* Enough place for the structure. */ + pRemoteNameInfo->lpUniversalName = (PWCHAR)((PBYTE)lpBuffer + sizeof(REMOTE_NAME_INFOW)); + pRemoteNameInfo->lpConnectionName = NULL; + pRemoteNameInfo->lpRemainingPath = NULL; + + /* At least so many bytes are available for obtaining the remote name. */ + RemoteNameLength = *lpBufferSize - BufferRequired; + } + else + { + RemoteNameLength = 0; + } + + /* Put the remote name directly to the buffer if possible and get the name length. */ + dwStatus = NPGetConnection (LocalDrive, RemoteNameLength? pRemoteNameInfo->lpUniversalName: NULL, &RemoteNameLength); + + if ( dwStatus != WN_SUCCESS + && dwStatus != WN_MORE_DATA) + { + if (dwStatus != WN_NOT_CONNECTED) + { + Log(("VBOXNP: NPGetUniversalName: NPGetConnection returned error 0x%lx\n", dwStatus)); + } + return dwStatus; + } + + if (RemoteNameLength < sizeof (WCHAR)) + { + Log(("VBOXNP: NPGetUniversalName: Remote name is empty.\n")); + return WN_NO_NETWORK; + } + + /* Adjust for actual remote name length. */ + BufferRequired += RemoteNameLength; + + /* And for required place for remaining path. */ + BufferRequired += RemainingPathLength; + + /* lpConnectionName, which is the remote name. */ + BufferRequired += RemoteNameLength; + + /* lpRemainingPath. */ + BufferRequired += RemainingPathLength; + + if (*lpBufferSize < BufferRequired) + { + Log(("VBOXNP: NPGetUniversalName: WN_MORE_DATA BufferRequired: %d\n", BufferRequired)); + *lpBufferSize = BufferRequired; + return WN_MORE_DATA; + } + + /* Enough memory in the buffer. Add \ and remaining path to the remote name. */ + lpString = &pRemoteNameInfo->lpUniversalName[RemoteNameLength / sizeof (WCHAR)]; + lpString--; /* Trailing NULL */ + + lpDelimiter = lpString; /* Delimiter will be inserted later. For now keep the NULL terminated string. */ + + CopyMemory( lpString, lpRemainingPath, RemainingPathLength); + lpString += RemainingPathLength / sizeof (WCHAR); + + *lpDelimiter = 0; + + pRemoteNameInfo->lpConnectionName = lpString; + CopyMemory( lpString, pRemoteNameInfo->lpUniversalName, RemoteNameLength); + lpString += RemoteNameLength / sizeof (WCHAR); + + pRemoteNameInfo->lpRemainingPath = lpString; + CopyMemory( lpString, lpRemainingPath, RemainingPathLength); + + *lpDelimiter = L'\\'; + } + + Log(("VBOXNP: NPGetUniversalName: WN_SUCCESS\n")); + return WN_SUCCESS; +} diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.def b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.def new file mode 100644 index 00000000000..0c8e90d7db6 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.def @@ -0,0 +1,24 @@ +; +; Copyright (C) 2006-2007 Oracle Corporation +; +; Oracle Corporation confidential +; All rights reserved +; + +LIBRARY VBOXMRXNP + +EXPORTS + NPGetCaps @13 + NPAddConnection @17 + NPAddConnection3 @38 + NPCancelConnection @18 + NPGetConnection @12 + NPOpenEnum @33 + NPEnumResource @34 + NPCloseEnum @35 + NPGetUniversalName @40 + NPGetResourceParent @41 + NPGetResourceInformation @52 + NPLogonNotify @500 + NPPasswordChangeNotify @501 + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.h new file mode 100644 index 00000000000..83f9e73d2be --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.h @@ -0,0 +1,43 @@ +/*++ + + Copyright (c) 1989-1999 Microsoft Corporation + + Module Name: + + nulmrxnp.h + + Abstract: + + This module includes all network provider router interface related + definitions for the sample + + Notes: + + This module has been built and tested only in UNICODE environment + + --*/ + +#ifndef _NULMRXNP_H_ +#define _NULMRXNP_H_ + +#include "..\sys\nulmrx.h" + +#include <iprt/alloc.h> +#include <iprt/initterm.h> +#include <iprt/string.h> +#include <iprt/log.h> +#include <VBox/version.h> +#include <VBox/VMMDev.h> +#include <VBox/VBoxGuestLib.h> +#include <VBox/Log.h> + +#define MRX_VBOX_SERVER_NAME_U L"VBOXSVR" +#define MRX_VBOX_SERVER_NAME_ALT_U L"VBOXSRV" + +typedef struct _NULMRXNP_ENUMERATION_HANDLE_ +{ + INT LastIndex; +} NULMRXNP_ENUMERATION_HANDLE, *PNULMRXNP_ENUMERATION_HANDLE; + +#endif + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.rc b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.rc new file mode 100644 index 00000000000..575a52ae1dd --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.rc @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2006-2007 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +#include <windows.h> +#include <VBox/version.h> + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + PRODUCTVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + FILEFLAGSMASK 0x3fL + FILEFLAGS 0x0L + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", VBOX_RC_COMPANY_NAME + VALUE "FileDescription", "VirtualBox Shared Folders Minirdr NP\0" + VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + VALUE "InternalName", "VBoxMRXNP.DLL\0" + VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "VBoxMRXNP.DLL\0" + VALUE "ProductName", "VirtualBox Guest Additions\0" + VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/Makefile.kmk b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/Makefile.kmk new file mode 100644 index 00000000000..ab375ee3c1e --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/Makefile.kmk @@ -0,0 +1,90 @@ +# $Id$ +## @file +# Sub-Makefile for the VirtualBox Windows Guest Shared Folders FSD. +# + +# +# Copyright (C) 2006-2007 Oracle Corporation +# +# Oracle Corporation confidential +# All rights reserved +# + +SUB_DEPTH = ../../../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# +# rdbss +# +LIBRARIES += rdbss +rdbss_TEMPLATE = VBOXGUESTR0 +rdbss_SOURCES = rdbss/rdbss.def + +# +# VBoxSF +# +SYSMODS += VBoxSF +VBoxSF_TEMPLATE = VBOXGUESTR0 +VBoxSF_DEFS = LOG_TO_BACKDOOR VBOX_WITH_HGCM IN_RING0 VBOX_GUEST +VBoxSF_DEFS += VBOX_ASYNC_RW VBOX_FAIL_FASTIO + +VBoxSF_SDKS.x86 = WINDDKW2K +VBoxSF_SDKS.amd64 = WINDDKWLH + +VBoxSF_INCS = \ + ../../../../common/VBoxGuestLib +VBoxSF_LDFLAGS.x86 = -Entry:DriverEntry@8 +VBoxSF_LDFLAGS.amd64 = -Entry:DriverEntry +VBoxSF_CFLAGS = -wd4005 +VBoxSF_SOURCES = \ + devctrl.c \ + devfcb.c \ + downlvli.c \ + ea.c \ + fileinfo.c \ + init.c \ + locks.c \ + netroot.c \ + notimpl.c \ + openclos.c \ + read.c \ + rename.c \ + srvcall.c \ + transprt.c \ + write.c \ + vbsfhlp.c \ + wmlkm.c \ + rdbss_vbox.c \ + VBoxSF.rc + +VBoxSF_LIBS.x86 = \ + $(PATH_SDK_WINDDKW2K_LIB.x86)/fre/rxce.lib \ + $(PATH_SDK_WINDDKW2K_LIB.x86)/fre/rdbsslib.lib \ + $(PATH_SDK_WINDDKW2K_LIB.x86)/fre/copysup.lib \ + $(PATH_SDK_WINDDKW2K_LIB.x86)/ntoskrnl.lib \ + $(PATH_SDK_WINDDKW2K_LIB.x86)/hal.lib \ + $(PATH_SDK_WINDDKW2K_LIB.x86)/ksecdd.lib \ + $(PATH_SDK_WINDDKW2K_LIB.x86)/BufferOverflowK.lib + +VBoxSF_LIBS.amd64 = \ + $(PATH_SDK_WINDDKWLH_LIB.amd64)/rxce.lib \ + $(PATH_SDK_WINDDKWLH_LIB.amd64)/rdbsslib.lib \ + $(PATH_SDK_WINDDKWLH_LIB.amd64)/copysup.lib \ + $(PATH_SDK_WINDDKWLH_LIB.amd64)/ntoskrnl.lib \ + $(PATH_SDK_WINDDKWLH_LIB.amd64)/hal.lib \ + $(PATH_SDK_WINDDKWLH_LIB.amd64)/ksecdd.lib \ + $(PATH_SDK_WINDDKWLH_LIB.amd64)/BufferOverflowK.lib + +VBoxSF_LIBS = \ + $(VBOX_LIB_VBGL_R0) \ + $(VBOX_LIB_IPRT_GUEST_R0) + +## Use with checked RDBSS libraries +## $(PATH_SDK_W2K3DDKX86_LIB)/bufferoverflowk.lib \ + +## rdbss.asm \ +## $(PATH_LIB)/rdbss$(VBOXW32GUEST_SUFF_LIB) + + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.inf b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.inf new file mode 100644 index 00000000000..bd87205dad6 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.inf @@ -0,0 +1,77 @@ +; +; INF file for installing the VirtualBox Windows guest driver +; +; Copyright (C) 2006-2007 Oracle Corporation +; +; Oracle Corporation confidential +; All rights reserved +; + +[Version] +Signature="$Windows NT$" +Class=System +ClassGuid={ce4a90b5-1d8c-435d-b349-232ce55cb17f} +Provider=%SUN% +;edit-DriverVer=08/26/2008,2.00.0000 +DriverPackageType=Network +;cat CatalogFile=VBoxSF.cat + +;cat [SourceDisksNames] +;cat 1 = %VBoxSF.MediaDesc% +;cat +;cat [SourceDisksFiles] +;cat VBoxSF.sys = 1 + +[DestinationDirs] +DefaultDestDir = 12 ; drivers +VBoxMRXNP_CopyFiles = 11 ; system32 + +[Manufacturer] +;x86 %SUN%=VBoxSF +;amd64 %SUN%=VBoxSF, NTamd64 + +;x86 [VBoxSF] +;amd64 [VBoxSF.NTamd64] +%VBoxSF.DeviceDesc%=VBoxSF_Install,PCI\VEN_80ee&DEV_cafe + +[VBoxSF_Install] +CopyFiles = VBoxSF_CopyFiles, VBoxMRXNP_CopyFiles +AddReg = VBoxMRXNP_Add_Reg + +[VBoxSF_CopyFiles] +VBoxSF.sys + +[VBoxMRXNP_CopyFiles] +VBoxMRXNP.dll + +[VBoxSF_Install.Services] +AddService = VBoxSF, 0x00000002, VBoxSF_ServiceInstallSection +DelService = VBoxMRXNP, 0x00000004 + +[VBoxSF_ServiceInstallSection] +DisplayName = %VBoxSF_svcdesc% +ServiceType = 0x00000001 ; kernel driver +StartType = 0x00000003 ; demand start +ErrorControl = 0x00000001 ; normal error handling +ServiceBinary = %12%\VBoxSF.sys + +[VBoxMRXNP_Add_Reg] +HKLM, SOFTWARE\Microsoft\Windows\CurrentVersion\Run, VBoxMRXNP, 0x00000000, %11%\VBoxMRXNP.exe + +[VBoxSF_Install.CoInstallers] +AddReg = VBoxSF_Install_CoInstallers_reg +CopyFiles = VBox_CoInstaller_CopyFiles + +[VBox_CoInstaller_CopyFiles] +vbcoinst.dll + +[VBoxSF_Install_CoInstallers_reg] +HKR,,CoInstallers32,0x00010000,"vbcoinst.dll,VBoxCoInstaller" + +[Strings] +SUN = "Sun Microsystems, Inc." +VBoxSF.DeviceDesc = "VirtualBox Device" +VBoxSF_svcdesc = "VirtualBox Shared Folders Driver" +VBoxMRXNP_svcdesc = "VirtualBox Network Provider Service" + + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.rc b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.rc new file mode 100644 index 00000000000..cdff579ac9d --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.rc @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2006-2007 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +#include <windows.h> +#include <VBox/version.h> + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + PRODUCTVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + FILEFLAGSMASK 0x3fL + FILEFLAGS 0x0L + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", VBOX_RC_COMPANY_NAME + VALUE "FileDescription", "VirtualBox Shared Folders Minirdr\0" + VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + VALUE "InternalName", "VBoxSF.sys\0" + VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "VBoxSF.sys\0" + VALUE "ProductName", "VirtualBox Guest Additions\0" + VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devctrl.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devctrl.c new file mode 100644 index 00000000000..e5198c486f7 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devctrl.c @@ -0,0 +1,76 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + devctrl.c + + Abstract: + + This module implements DeviceIoControl operations. + + --*/ + +#include "precomp.h" +#pragma hdrstop + +// +// The local debug trace level +// + +RXDT_DefineCategory (DEVCTRL); + +#define Dbg (DEBUG_TRACE_DEVCTRL) + +// +// forwards & code allocation pragmas +// +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, VBoxMRxIoCtl) +#endif + +NTSTATUS VBoxMRxIoCtl (IN OUT PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine performs an IOCTL operation. + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation + + Notes: + + + --*/ +{ + NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; + RxCaptureFcb; + RxCaptureFobx; + PMRX_SRV_OPEN pSrvOpen = capFobx->pSrvOpen; + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; + PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall; +#ifndef VBOX + UNICODE_STRING RootName; +#endif + VBoxMRxGetDeviceExtension(RxContext,pDeviceExtension); + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + ULONG IoControlCode = LowIoContext->ParamsFor.FsCtl.FsControlCode; + PUNICODE_STRING RemainingName = pSrvOpen->pAlreadyPrefixedName; +#ifndef VBOX + UNICODE_STRING StatsFile; +#endif + VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension); + + Log(("VBOXSF: VBoxMRxIoCtl: IoControlCode = 0x%x\n", IoControlCode)); + PAGED_CODE(); + + return Status; +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devfcb.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devfcb.c new file mode 100644 index 00000000000..fdd67fc8dc3 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devfcb.c @@ -0,0 +1,741 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + devfcb.c + + Abstract: + + This module implements the mechanism for deleting an established connection + + --*/ + +#include "precomp.h" +#pragma hdrstop +#include "rdbss_vbox.h" + +// +// The local debug trace level +// + +#define Dbg (DEBUG_TRACE_DEVFCB) + +//#define FIXED_CONNECT_NAME L"\\;0:\\vboxsvr\\share" +#define FIXED_CONNECT_NAME L"\\;0:" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, VBoxMRxDevFcbXXXControlFile) +#endif + +NTSYSAPI +NTSTATUS NTAPI +ZwSetSecurityObject (IN HANDLE Handle, IN SECURITY_INFORMATION SecurityInformation, IN PSECURITY_DESCRIPTOR SecurityDescriptor); + +NTSTATUS VBoxMRxDevFcbXXXControlFile (IN OUT PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine handles all the device FCB related FSCTL's in the mini rdr + + Arguments: + + RxContext - Describes the Fsctl and Context. + + Return Value: + + a valid NTSTATUS code. + + Notes: + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + RxCaptureFobx; + UCHAR MajorFunctionCode = RxContext->MajorFunction; + VBoxMRxGetDeviceExtension(RxContext,pDeviceExtension); + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + ULONG ControlCode = 0; + + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: MajorFunctionCode = %x\n", MajorFunctionCode)); + + switch (MajorFunctionCode) + { + case IRP_MJ_FILE_SYSTEM_CONTROL: + { + switch (LowIoContext->ParamsFor.FsCtl.MinorFunction) + { + case IRP_MN_USER_FS_REQUEST: + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IRP_MN_USER_FS_REQUEST: ControlCode = %x\n", ControlCode)); + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + + default: //minor function != IRP_MN_USER_FS_REQUEST + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + break; + } + + case IRP_MJ_DEVICE_CONTROL: + { + + ControlCode = LowIoContext->ParamsFor.IoCtl.IoControlCode; + + switch (ControlCode) + { + case IOCTL_MRX_VBOX_ADDCONN: + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_ADDCONN\n")); + Status = VBoxMRxCreateConnection(RxContext, &RxContext->PostRequest); + break; + + case IOCTL_MRX_VBOX_DELCONN: + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_DELCONN\n")); + Status = VBoxMRxDeleteConnection(RxContext, &RxContext->PostRequest); + break; + + case IOCTL_MRX_VBOX_GETLIST: + { + ULONG cbOut = LowIoContext->ParamsFor.IoCtl.OutputBufferLength; + PVOID pbOut = LowIoContext->ParamsFor.IoCtl.pOutputBuffer; + + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETLIST\n")); + + if ((cbOut >= _MRX_MAX_DRIVE_LETTERS) && (NULL != pbOut)) + { + BOOLEAN GotMutex = FALSE; + + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETLIST: Copying local connections ...\n")); + + if (NULL == pDeviceExtension) + break; + + GotMutex = ExTryToAcquireFastMutex(&pDeviceExtension->mtxLocalCon); + + RtlCopyMemory (pbOut, pDeviceExtension->cLocalConnections, _MRX_MAX_DRIVE_LETTERS); + + if (GotMutex) + ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon); + + RxContext->InformationToReturn = _MRX_MAX_DRIVE_LETTERS; + } + else + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETLIST: Nothing to copy, cbOut is too small (%d bytes)\n", cbOut)); + RxContext->InformationToReturn = 0; + } + + Status = STATUS_SUCCESS; + break; + } + + /* + * Returns the root IDs of shared folder mappings. + */ + case IOCTL_MRX_VBOX_GETGLOBALLIST: + { + ULONG cbOut = LowIoContext->ParamsFor.IoCtl.OutputBufferLength; + uint8_t *pbOut = (uint8_t *)LowIoContext->ParamsFor.IoCtl.pOutputBuffer; + + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETGLOBALLIST\n")); + + if (NULL == pDeviceExtension) + break; + + RxContext->InformationToReturn = 0; + if ((cbOut >= _MRX_MAX_DRIVE_LETTERS) && (NULL != pbOut)) + { + SHFLMAPPING mappings[_MRX_MAX_DRIVE_LETTERS]; + uint32_t cMappings = RT_ELEMENTS(mappings); + int vboxRC; + + vboxRC = vboxCallQueryMappings(&pDeviceExtension->hgcmClient, mappings, &cMappings); + if (vboxRC == VINF_SUCCESS) + { + uint32_t i; + + RtlZeroMemory(pbOut, _MRX_MAX_DRIVE_LETTERS); + for (i = 0; i < RT_MIN(cMappings, cbOut); i++) + { + pbOut[i] = mappings[i].root; + pbOut[i] |= 0x80; /* mark active *//** @todo fix properly */ + } + + RxContext->InformationToReturn = _MRX_MAX_DRIVE_LETTERS; + } + else + { + Status = VBoxErrorToNTStatus(vboxRC); + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETGLOBALLIST Error: 0x%08x\n", Status)); + } + } + + Status = STATUS_SUCCESS; + break; + } + + /* + * Translates a local connection name (e.g. drive "S:") to the + * corresponding remote name (e.g. \\vboxsrv\share). + */ + case IOCTL_MRX_VBOX_GETCONN: + { + ULONG ulConnectNameLen = LowIoContext->ParamsFor.IoCtl.InputBufferLength; + PWCHAR pwcConnectName = (PWCHAR)LowIoContext->ParamsFor.IoCtl.pInputBuffer; + + ULONG ulRemoteNameLen = LowIoContext->ParamsFor.IoCtl.OutputBufferLength; + PULONG pulRemoteName = (PULONG)LowIoContext->ParamsFor.IoCtl.pOutputBuffer; + + Log( + ("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: ConnectName = %.*ls, Len = %d, RemoteName = 0x%x, Len = %d\n", ulConnectNameLen / sizeof(WCHAR), pwcConnectName, ulConnectNameLen, pulRemoteName, ulRemoteNameLen)); + + if (NULL == pDeviceExtension) + { + Status = STATUS_INVALID_PARAMETER; + break; + } + + /* Insert the local connection name. */ + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Looking up connection name and connections ...\n")); + if ((ulConnectNameLen > sizeof(WCHAR)) && (NULL != pwcConnectName)) + { + ULONG ulLocalConnectionNameLen; + + uint32_t idx = *pwcConnectName - L'A'; + + ExAcquireFastMutex(&pDeviceExtension->mtxLocalCon); + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Index = %d\n", idx)); + + if ((idx < 0) || (idx >= RTL_NUMBER_OF(pDeviceExtension->wszLocalConnectionName))) + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Index is invalid!\n")); + ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (NULL == pDeviceExtension->wszLocalConnectionName[idx]) + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: LocalConnectionName is NULL!\n")); + ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon); + Status = STATUS_BAD_NETWORK_NAME; + break; + } + + ulLocalConnectionNameLen = pDeviceExtension->wszLocalConnectionName[idx]->Length; + + Log( + ("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: LocalConnectionName = %.*ls\n", ulLocalConnectionNameLen / sizeof(WCHAR), pDeviceExtension->wszLocalConnectionName[idx]->Buffer)); + + if ((pDeviceExtension->cLocalConnections[idx]) && (ulLocalConnectionNameLen <= ulRemoteNameLen)) + { + RtlZeroMemory (pulRemoteName, ulRemoteNameLen); + RtlCopyMemory (pulRemoteName, pDeviceExtension->wszLocalConnectionName[idx]->Buffer, ulLocalConnectionNameLen); + + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Remote name = %.*ls, Size = %d\n", ulLocalConnectionNameLen / sizeof(WCHAR), pulRemoteName, ulLocalConnectionNameLen)); + RxContext->InformationToReturn = ulLocalConnectionNameLen; + } + else + { + Status = STATUS_BUFFER_TOO_SMALL; + RxContext->InformationToReturn = ulLocalConnectionNameLen; + } + + ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon); + } + else + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: No connection name found!\n")); + Status = STATUS_BAD_NETWORK_NAME; + } + + break; + } + + case IOCTL_MRX_VBOX_GETGLOBALCONN: + { + ULONG ReturnedSize = 0; + uint8_t *pConnectId = (uint8_t *)LowIoContext->ParamsFor.IoCtl.pInputBuffer; + ULONG RemoteNameLen = LowIoContext->ParamsFor.IoCtl.OutputBufferLength; + PULONG RemoteName = (PULONG)LowIoContext->ParamsFor.IoCtl.pOutputBuffer; + PSHFLSTRING pString; + int vboxRC; + uint32_t cbString = sizeof(SHFLSTRING) + RemoteNameLen; + + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETGLOBALCONN: Connection ID = %d, RemoteName = 0x%x, Len = %d\n", *pConnectId, RemoteName, RemoteNameLen)); + + pString = (PSHFLSTRING)vbsfAllocNonPagedMem(cbString); + if (!pString) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + memset(pString, 0, cbString); + ShflStringInitBuffer(pString, RemoteNameLen); /** @todo r=andy This function does not have an effect ...? */ + + vboxRC = vboxCallQueryMapName(&pDeviceExtension->hgcmClient, (*pConnectId) & ~0x80 /** @todo fix properly */, pString, cbString); + if (vboxRC == VINF_SUCCESS) + { + if (pString->u16Length < RemoteNameLen) + { + ReturnedSize = pString->u16Length; + RtlCopyMemory( RemoteName, pString->String.ucs2, pString->u16Length); + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETGLOBALCONN: Returned name = %.*ls, Size = %d\n", ReturnedSize / sizeof(WCHAR), RemoteName, ReturnedSize)); + } + } + else + Status = VBoxErrorToNTStatus(vboxRC); + + vbsfFreeNonPagedMem(pString); + + if (ReturnedSize) + { + Status = STATUS_SUCCESS; + } + else + { + Status = STATUS_BAD_NETWORK_NAME; + } + RxContext->InformationToReturn = ReturnedSize; + break; + } + + case IOCTL_MRX_VBOX_START: + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: Called.\n")); + switch (VBoxMRxState) + { + case MRX_VBOX_STARTABLE: + + /* The correct sequence of start events issued by the workstation + service would have avoided this. We can recover from this + by actually invoking RxStartMiniRdr. */ + + if (capFobx) + { + Status = STATUS_INVALID_DEVICE_REQUEST; + break;; + } + + /* Set global VBoxMRxState variable to MRX_VBOX_STARTABLE and fall through to the next case. */ + InterlockedCompareExchange((PLONG) & VBoxMRxState, MRX_VBOX_START_IN_PROGRESS, MRX_VBOX_STARTABLE); + + /* Lack of break is intentional. */ + + case MRX_VBOX_START_IN_PROGRESS: + Status = VBoxRxStartMinirdr(RxContext, &RxContext->PostRequest); + + if (Status == STATUS_REDIRECTOR_STARTED) + Status = STATUS_SUCCESS; + else if (Status == STATUS_PENDING && RxContext->PostRequest == TRUE) + Status = STATUS_MORE_PROCESSING_REQUIRED; + + /* Allow restricted users to use shared folders; works only in XP and Vista. (@@todo hack) */ + if (Status == STATUS_SUCCESS) + { + SECURITY_DESCRIPTOR SecurityDescriptor; + OBJECT_ATTRIBUTES InitializedAttributes; + HANDLE hDevice; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING UserModeDeviceName; + + RtlInitUnicodeString(&UserModeDeviceName, DD_MRX_VBOX_USERMODE_SHADOW_DEV_NAME_U); + + /* Create empty security descriptor */ + RtlZeroMemory (&SecurityDescriptor, sizeof (SecurityDescriptor)); + Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); + if (Status != STATUS_SUCCESS) + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_START_IN_PROGRESS: RtlCreateSecurityDescriptor failed with 0x%x!\n", Status)); + return Status; + } + RtlZeroMemory (&InitializedAttributes, sizeof (InitializedAttributes)); + InitializeObjectAttributes(&InitializedAttributes, &UserModeDeviceName, OBJ_KERNEL_HANDLE, 0, 0); + + /* Open our symbolic link device name */ + Status = ZwOpenFile(&hDevice, WRITE_DAC, &InitializedAttributes, &IoStatusBlock, 0, 0); + if (Status != STATUS_SUCCESS) + { + Log( + ("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_START_IN_PROGRESS: ZwOpenFile %ls failed with 0x%x!\n", DD_MRX_VBOX_USERMODE_SHADOW_DEV_NAME_U, Status)); + return Status; + } + + /* Override the discretionary access control list (DACL) settings */ + Status = ZwSetSecurityObject(hDevice, DACL_SECURITY_INFORMATION, &SecurityDescriptor); + if (Status != STATUS_SUCCESS) + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_START_IN_PROGRESS: ZwSetSecurityObject failed with 0x%x!\n", Status)); + return Status; + } + + Status = ZwClose(hDevice); + if (Status != STATUS_SUCCESS) + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_START_IN_PROGRESS: ZwClose failed with 0x%x\n", Status)); + return Status; + } + } + break; + + case MRX_VBOX_STARTED: + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_STARTED: Already started\n")); + Status = STATUS_SUCCESS; + break; + + default: + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: Invalid state (%d)!\n", VBoxMRxState)); + Status = STATUS_INVALID_PARAMETER; + break; + } + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: Returned 0x%x\n", Status)); + break; + } + + case IOCTL_MRX_VBOX_STOP: + { + MRX_VBOX_STATE CurrentState; + + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_STOP: Called.\n")); + if (capFobx) + { + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + if (RxContext->RxDeviceObject->NumberOfActiveFcbs > 0) + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_STOP: Open handles = %d\n", RxContext->RxDeviceObject->NumberOfActiveFcbs)); + Status = STATUS_REDIRECTOR_HAS_OPEN_HANDLES; + break; + } + + CurrentState = (MRX_VBOX_STATE)InterlockedCompareExchange((PLONG) & VBoxMRxState, MRX_VBOX_STARTABLE, MRX_VBOX_STARTED); + + Status = VBoxRxStopMinirdr(RxContext, &RxContext->PostRequest); + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_STOP: Returned 0x%x\n", Status)); + + if (Status == STATUS_PENDING && RxContext->PostRequest == TRUE) + Status = STATUS_MORE_PROCESSING_REQUIRED; + + break; + } + + default: + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + break; + } + + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + { + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + default: + AssertMsgFailed(("VBOXSF: VBoxMRxDevFcbXXXControlFile: Unimplemented major function!")); + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: Status = %08lx, Info = %08lx\n", Status, RxContext->InformationToReturn)); + return Status; +} + +HANDLE GetConnectionHandle (IN PUNICODE_STRING ConnectionName) +{ + + NTSTATUS Status; + HANDLE Handle; + IO_STATUS_BLOCK IoStatusBlock; + OBJECT_ATTRIBUTES ObjectAttributes; +#ifndef VBOX + UNICODE_STRING FileName; +#endif + + // Connection name should get checked to be certain our device is in the path + + Log(("VBOXSF: GetConnectionHandle: Called.\n")); + + InitializeObjectAttributes(&ObjectAttributes, ConnectionName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + Status = ZwCreateFile(&Handle, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, // Allocation size + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, NULL, // Ptr to EA Buffer + 0); // Length of EA buffer + + Log(("VBOXSF: GetConnectionHandle: ZwCreateFile returned 0x%x\n", Status)); + + if ((STATUS_SUCCESS == Status) && (INVALID_HANDLE_VALUE != Handle)) + { + Log(("VBOXSF: GetConnectionHandle: ZwCreateFile returned success\n")); + } + else + { + Handle = INVALID_HANDLE_VALUE; + Log(("VBOXSF: GetConnectionHandle: ZwCreateFile returned invalid handle!\n")); + } + + return Handle; +} + +NTSTATUS DoCreateConnection (IN PRX_CONTEXT RxContext, ULONG CreateDisposition) +{ + + NTSTATUS Status = STATUS_SUCCESS; + HANDLE Handle; + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + ULONG ConnectNameLen = LowIoContext->ParamsFor.IoCtl.InputBufferLength; + PWCHAR ConnectName = (PWCHAR)LowIoContext->ParamsFor.IoCtl.pInputBuffer; + UNICODE_STRING FileName; + + VBoxMRxGetDeviceExtension(RxContext,pDeviceExtension); + + if (NULL == pDeviceExtension) + return STATUS_INVALID_PARAMETER; + + if ((0 == ConnectNameLen) || (NULL == ConnectName)) + { + Log(("VBOXSF: DoCreateConnection: Connection name / length is invalid!\n")); + return STATUS_INVALID_PARAMETER; + } + + // The sample code passes in only the filename in the Ioctl data buffer. + // An actual implementation could pass in stuff like EAs, security + // credentials, etc + + Log(("VBOXSF: DoCreateConnection: Name = %.*ls, Length = %d\n", ConnectNameLen / sizeof(WCHAR), ConnectName, ConnectNameLen)); + + FileName.Buffer = ConnectName; + FileName.Length = (USHORT)ConnectNameLen; + FileName.MaximumLength = (USHORT)ConnectNameLen; + + Handle = GetConnectionHandle(&FileName); + + if (INVALID_HANDLE_VALUE != Handle) + { + PWCHAR pwcLC; + ULONG i; + + Log(("VBOXSF: DoCreateConnection: GetConnectionHandle returned success!\n")); + ZwClose(Handle); + + /* Skip the "\Device\VBoxMiniRdr\;X:" of the string "\Device\VBoxMiniRdr\;X:\vboxsrv\sf" */ + pwcLC = (PWCHAR)ConnectName; + for (i = 0; i < ConnectNameLen && *pwcLC != L':'; i += sizeof(WCHAR), pwcLC++) + ; + + if (i >= sizeof(WCHAR) && i < ConnectNameLen) + { + pwcLC--; /* Go back to the drive letter, "X" for example. */ + if (*pwcLC >= L'A' && *pwcLC <= L'Z') /* Are we in range? */ + { + uint32_t idx = *pwcLC - L'A'; /* Get the index based on the driver letter numbers (26). */ + PUNICODE_STRING pRemoteName; + + ExAcquireFastMutex(&pDeviceExtension->mtxLocalCon); + + if ((idx < 0) || (idx >= RTL_NUMBER_OF(pDeviceExtension->cLocalConnections))) + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Index is invalid!\n")); + ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon); + return STATUS_BAD_NETWORK_NAME; + } + + pDeviceExtension->cLocalConnections[idx] = TRUE; + + if (NULL != pDeviceExtension->wszLocalConnectionName[idx]) + Log(("VBOXSF: DoCreateConnection: LocalConnectionName at index %d is NOT empty!\n", idx)); + + /*pDeviceExtension->LocalConnectionName[idx] = (PUNICODE_STRING)ExAllocatePool(PagedPool, sizeof(UNICODE_STRING) + ConnectNameLen /* more than enough );*/ + pDeviceExtension->wszLocalConnectionName[idx] = (PUNICODE_STRING)vbsfAllocNonPagedMem(sizeof(UNICODE_STRING) + ConnectNameLen); + + if (NULL == pDeviceExtension->wszLocalConnectionName[idx]) + Log(("VBOXSF: DoCreateConnection: LocalConnectionName at index %d NOT allocated!\n", idx)); + + pRemoteName = pDeviceExtension->wszLocalConnectionName[idx]; + + pRemoteName->Buffer = (PWSTR)(pRemoteName + 1); + pRemoteName->Length = (USHORT)(ConnectNameLen - i - sizeof(WCHAR)); + pRemoteName->MaximumLength = pRemoteName->Length; + RtlCopyMemory(&pRemoteName->Buffer[0], pwcLC+2, pRemoteName->Length); + + Log(("VBOXSF: DoCreateConnection: RemoteName %.*ls, Len = %d\n", pRemoteName->Length / sizeof(WCHAR), pRemoteName->Buffer, pRemoteName->Length)); + ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon); + } + } + } + else + { + Log(("VBOXSF: DoCreateConnection: GetConnectionHandle returned failure!\n")); + Status = STATUS_BAD_NETWORK_NAME; + } + + return (Status); +} + +NTSTATUS VBoxMRxCreateConnection (IN PRX_CONTEXT RxContext, OUT PBOOLEAN PostToFsp) +/*++ + + Routine Description: + + + Arguments: + + IN PRX_CONTEXT RxContext - Describes the Fsctl and Context....for later when i need the buffers + + Return Value: + + RXSTATUS + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT); + BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP); + + PAGED_CODE(); + + Log(("VBOXSF: VBoxMRxCreateConnection: Called.\n")); + + if (!Wait) + { + //just post right now! + *PostToFsp = TRUE; + return STATUS_PENDING; + } + + Status = DoCreateConnection(RxContext, (ULONG)FILE_OPEN_IF); + return Status; +} + +NTSTATUS DoDeleteConnection (PUNICODE_STRING FileName) +{ + HANDLE Handle; + NTSTATUS Status; + PFILE_OBJECT pFileObject; + PNET_ROOT NetRoot; + PV_NET_ROOT VNetRoot; + PFOBX Fobx; + + Log(("VBOXSF: DoDeleteConnection: Called.\n")); + + Handle = GetConnectionHandle(FileName); + + if (INVALID_HANDLE_VALUE != Handle) + { + Log(("VBOXSF: DoDeleteConnection: GetConnectionHandle returned success\n")); + + Status = ObReferenceObjectByHandle(Handle, 0L, NULL, KernelMode, (PVOID *)&pFileObject, NULL); + + Log(("VBOXSF: DoDeleteConnection: ObReferenceObjectByHandle Status 0x%08X\n", Status)); + if (NT_SUCCESS(Status)) + { + + // Got the FileObject. Now get an Fobx + Fobx = (PFOBX)pFileObject->FsContext2; + if (NodeType(Fobx) == RDBSS_NTC_V_NETROOT) + { + VNetRoot = (PV_NET_ROOT)(Fobx); + NetRoot = (PNET_ROOT)VNetRoot->NetRoot; + Log(("Calling RxFinalizeConnection\n")); + Status = VBoxRxFinalizeConnection(NetRoot, VNetRoot, TRUE); + } + else + { + ASSERT(FALSE); + Status = STATUS_INVALID_DEVICE_REQUEST; + } + + ObDereferenceObject(pFileObject); + } + + ZwClose(Handle); + } + + return Status; +} + +NTSTATUS VBoxMRxDeleteConnection (IN PRX_CONTEXT RxContext, OUT PBOOLEAN PostToFsp) +/*++ + + Routine Description: + + This routine deletes a single vnetroot. + + Arguments: + + IN PRX_CONTEXT RxContext - Describes the Fsctl and Context....for later when i need the buffers + + Return Value: + + RXSTATUS + + --*/ +{ + NTSTATUS Status; + UNICODE_STRING FileName; + BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT); + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + PWCHAR ConnectName = (PWCHAR)LowIoContext->ParamsFor.IoCtl.pInputBuffer; + ULONG ConnectNameLen = LowIoContext->ParamsFor.IoCtl.InputBufferLength; + VBoxMRxGetDeviceExtension(RxContext,pDeviceExtension); + + PAGED_CODE(); + + Log(("VBOXSF: VBoxMRxDeleteConnection: ConnectName = %.*ls\n", ConnectNameLen / sizeof(WCHAR), ConnectName)); + + if (!Wait) + { + //just post right now! + *PostToFsp = TRUE; + return (STATUS_PENDING); + } + + FileName.Buffer = ConnectName; + FileName.Length = (USHORT)ConnectNameLen; + FileName.MaximumLength = (USHORT)ConnectNameLen; + + Status = DoDeleteConnection(&FileName); + + if (NT_SUCCESS(Status)) + { + PWCHAR pwcLC; + ULONG i; + + for (i = 0, pwcLC = ConnectName; i < ConnectNameLen && *pwcLC != L':'; i += sizeof(WCHAR), pwcLC++) + ; + + if (i >= sizeof(WCHAR) && i < ConnectNameLen) + { + pwcLC--; + if (*pwcLC >= L'A' && *pwcLC <= L'Z') + { + uint32_t idx = *pwcLC - L'A'; + + ExAcquireFastMutex(&pDeviceExtension->mtxLocalCon); + + pDeviceExtension->cLocalConnections[idx] = FALSE; + + /* Free saved name */ + /*Assert(pDeviceExtension->LocalConnectionName[idx]); + ExFreePool(pDeviceExtension->LocalConnectionName[idx]); + pDeviceExtension->LocalConnectionName[idx] = NULL;*/ + if (pDeviceExtension->wszLocalConnectionName[idx]) + { + vbsfFreeNonPagedMem(pDeviceExtension->wszLocalConnectionName[idx]); + pDeviceExtension->wszLocalConnectionName[idx] = NULL; + } + + ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon); + } + } + } + + return Status; +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/downlvli.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/downlvli.c new file mode 100644 index 00000000000..2356e065816 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/downlvli.c @@ -0,0 +1,157 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + DownLvlI.c + + Abstract: + + This module implements downlevel fileinfo, volinfo, and dirctrl. + + --*/ + +#include "precomp.h" +#include <iprt/fs.h> +#pragma hdrstop + +// +// The local debug trace level +// + +RXDT_DefineCategory (DOWNLVLI); +#define Dbg (DEBUG_TRACE_DOWNLVLI) + +NTSTATUS VBoxMRxSetEndOfFile (IN OUT struct _RX_CONTEXT * RxContext, IN OUT PLARGE_INTEGER pNewFileSize, OUT PLARGE_INTEGER pNewAllocationSize) +/*++ + + Routine Description: + + This routine handles requests to truncate or extend the file + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + RxCaptureFcb; + RxCaptureFobx; + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); + VBoxMRxGetNetRootExtension(capFcb->pNetRoot, pNetRootExtension); + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + PRTFSOBJINFO pObjInfo = 0; + uint32_t cbBuffer; + int vboxRC; + + Log(("VBOXSF: VBoxMRxSetEndOfFile: New size = %RX64 (0x%x), pNewAllocationSize = 0x%x\n", pNewFileSize->QuadPart, pNewFileSize, pNewAllocationSize)); + + cbBuffer = sizeof(RTFSOBJINFO); + pObjInfo = (PRTFSOBJINFO)vbsfAllocNonPagedMem(cbBuffer); + if (pObjInfo == 0) + { + AssertFailed(); + return STATUS_NO_MEMORY; + } + memset(pObjInfo, 0, cbBuffer); + + pObjInfo->cbObject = pNewFileSize->QuadPart; + Assert(pVBoxFobx && pNetRootExtension && pDeviceExtension); + vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, SHFL_INFO_SET | SHFL_INFO_SIZE, &cbBuffer, (PSHFLDIRINFO)pObjInfo); + AssertRC(vboxRC); + + Log(("VBOXSF: VBoxMRxSetEndOfFile: vboxCallFSInfo returned %d\n", vboxRC)); + + Status = VBoxErrorToNTStatus(vboxRC); + if (Status == STATUS_SUCCESS) + { + Log(("VBOXSF: VBoxMRxSetEndOfFile: vboxCallFSInfo new allocation size = %RX64\n", pObjInfo->cbAllocated)); + + /* Return new allocation size */ + pNewAllocationSize->QuadPart = pObjInfo->cbAllocated; + } + + if (pObjInfo) + vbsfFreeNonPagedMem((PVOID)pObjInfo); + + Log(("VBOXSF: VBoxMRxSetEndOfFile: Returned %d\n", Status)); + return Status; +} + +NTSTATUS VBoxMRxTruncateFile (IN OUT struct _RX_CONTEXT * RxContext) +/*++ + + Routine Description: + + This routine handles requests to truncate the file + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + Log(("VBOXSF: VBoxMRxTruncateFile not implemented!\n")); + return STATUS_NOT_IMPLEMENTED; +} + +ULONG VBoxMRxExtendFile (IN OUT struct _RX_CONTEXT * RxContext, IN OUT PLARGE_INTEGER pNewFileSize, OUT PLARGE_INTEGER pNewAllocationSize) +/*++ + + Routine Description: + + This routine handles requests to extend the file for cached IO. + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + Log(("VBOXSF: VBoxMRxExtendFile new size = %RX64\n", pNewFileSize->QuadPart)); + return VBoxMRxSetEndOfFile(RxContext, pNewFileSize, pNewAllocationSize); +} + +NTSTATUS VBoxMRxExtendStub (IN OUT struct _RX_CONTEXT * RxContext, IN OUT PLARGE_INTEGER pNewFileSize, OUT PLARGE_INTEGER pNewAllocationSize) +/*++ + +Routine Description: + + This routine handles MRxExtendForCache and MRxExtendForNonCache requests. Since the write + itself will extend the file, we can pretty much just get out quickly. + +Arguments: + + RxContext - the RDBSS context + +Return Value: + + RXSTATUS - The return status for the operation + +--*/ +{ + /* Note: On Windows hosts VBoxMRxSetEndOfFile returns ACCESS_DENIED if the file has been + * opened in APPEND mode. Therefore it is better to not call host at all and implement + * this MrxExtend* request just like in mrxsmb DDK sample. + */ + Log(("VBOXSF: VBoxMRxExtendStub new size = %RX64\n", pNewFileSize->QuadPart)); + + pNewAllocationSize->QuadPart = pNewFileSize->QuadPart; + + return(STATUS_SUCCESS); +} diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/ea.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/ea.c new file mode 100644 index 00000000000..03ce645315b --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/ea.c @@ -0,0 +1,109 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + ea.c + + Abstract: + + This module implements 'extended attributes' on a file handle + + --*/ + +#include "precomp.h" +#pragma hdrstop + +// +// The local debug trace level +// + +#define Dbg (DEBUG_TRACE_EA) + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, VBoxMRxQueryEaInformation) +#endif + +#ifdef VBOX +/* + * We don't support extended attributes as the host OS might not know the concept at all + * + */ +#endif + +// +// Extended Attributes (EA) functionality +// + +NTSTATUS VBoxMRxQueryEaInformation (IN OUT PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine queries IFS for extended attributes like + scatter-gather list and filename for an IFS handle. + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation + + Notes: + + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + RxCaptureFcb; + RxCaptureFobx; + RxCaptureParamBlock; + + PMRX_SRV_OPEN pSrvOpen = capFobx->pSrvOpen; + PFILE_FULL_EA_INFORMATION pEaInfo = (PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer; + ULONG BufferLength = RxContext->Info.LengthRemaining; + ULONG UserEaListLength = RxContext->QueryEa.UserEaListLength; + PUCHAR UserEaList = RxContext->QueryEa.UserEaList; + PFILE_GET_EA_INFORMATION pGetEaInfo = (PFILE_GET_EA_INFORMATION)UserEaList; + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; + VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension); + + PAGED_CODE(); + + Log(("VBOXSF: VBoxMRxQueryEaInformation: Ea buffer len remaining is %d\n", RxContext->Info.LengthRemaining)); + + return (Status); +} + +NTSTATUS VBoxMRxSetEaInformation (IN OUT PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine sets the EA information for this FCB + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation + + Notes: + + + --*/ +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(RxContext); + + Log(("VBOXSF: VBoxMRxSetEaInformation: Not implemented!\n")); + return STATUS_NOT_IMPLEMENTED; +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/fileinfo.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/fileinfo.c new file mode 100644 index 00000000000..cc8e8a7d125 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/fileinfo.c @@ -0,0 +1,1684 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + fileinfo.c + + Abstract: + + This module implements the mini redirector call down routines pertaining to retrieval/ + update of file/directory/volume information. + + --*/ + +#include "precomp.h" +#pragma hdrstop + +/** Macro for copying a SHFLSTRING file name into a FILE_DIRECTORY_INFORMATION structure. */ +#define INIT_FILE_NAME(obj, str) \ + do { \ + ULONG cbLength = (str).u16Length; \ + (obj)->FileNameLength = cbLength; \ + RtlCopyMemory((obj)->FileName, &(str).String.ucs2[0], cbLength + 2); \ + } while (0) + +NTSTATUS VBoxMRxQueryDirectory (IN OUT PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine does a directory query. Only the NT-->NT path is implemented. + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + FILE_INFORMATION_CLASS FileInformationClass; + PCHAR Buffer; + PLONG pLengthRemaining; + LONG CopySize; + RxCaptureFobx; + RxCaptureFcb; + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); + VBoxMRxGetNetRootExtension(capFcb->pNetRoot, pNetRootExtension); + PUNICODE_STRING DirectoryName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext); + PUNICODE_STRING Template = &capFobx->UnicodeQueryTemplate; + int vboxRC; + uint8_t *pHGCMBuffer; + uint32_t index, fSFFlags, cFiles, u32BufSize; + LONG cbHGCMBuffer, cbMaxSize; + PSHFLDIRINFO pDirEntry; + ULONG *pNextOffset = 0; + PSHFLSTRING ParsedPath = 0; + + if (NULL == pVBoxFobx) + { + Log(("VBOXSF: QueryDirectory: pVBoxFobx is invalid!\n")); + return STATUS_INVALID_PARAMETER; + } + + FileInformationClass = RxContext->Info.FileInformationClass; + Log(("VBOXSF: QueryDirectory: FileInformationClass %d\n", FileInformationClass)); + + Buffer = (PCHAR)RxContext->Info.Buffer; + cbMaxSize = RxContext->Info.Length; + pLengthRemaining = (PULONG) & RxContext->Info.LengthRemaining; + + Log(("VBOXSF: QueryDirectory: vboxFobx = 0x%08x VBox file handle = 0x%08x\n", pVBoxFobx, pVBoxFobx->hFile)); + + if (NULL == DirectoryName) + return STATUS_INVALID_PARAMETER; + + if (DirectoryName->Length == 0) + { + Log(("VBOXSF: QueryDirectory: DirectoryName = \\ (null string)\n")); + } + else Log(("VBOXSF: QueryDirectory: DirectoryName = %.*ls\n", DirectoryName->Length / sizeof(WCHAR), DirectoryName->Buffer)); + + if (NULL == Template) + return STATUS_INVALID_PARAMETER; + + if (Template->Length == 0) + { + Log(("VBOXSF: QueryDirectory: Template = \\ (null string)\n")); + } + else Log(("VBOXSF: QueryDirectory: Template = %.*ls\n", Template->Length / sizeof(WCHAR), Template->Buffer)); + + cbHGCMBuffer = RT_MAX(cbMaxSize, PAGE_SIZE); + Log(("VBOXSF: QueryDirectory: Allocating HGCMBuffer = %d\n", cbHGCMBuffer)); + pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbHGCMBuffer); + if (pHGCMBuffer == NULL) + { + AssertFailed(); + return STATUS_NO_MEMORY; + } + + /* Assume start from the beginning. */ + index = 0; + if (RxContext->QueryDirectory.IndexSpecified == TRUE) + { + Log(("VBOXSF: QueryDirectory: Index specified %d\n", index)); + index = RxContext->QueryDirectory.FileIndex; + } + fSFFlags = SHFL_LIST_NONE; + if (RxContext->QueryDirectory.ReturnSingleEntry == TRUE) + { + Log(("VBOXSF: QueryDirectory: Query single entry\n")); + fSFFlags |= SHFL_LIST_RETURN_ONE; + } + + if (Template->Length) + { + ULONG ParsedPathSize, len; + + /* Calculate length required for parsed path. */ + ParsedPathSize = sizeof(*ParsedPath) + (DirectoryName->Length + Template->Length + 3 * sizeof(WCHAR)); + Log(("VBOXSF: QueryDirectory: ParsedPathSize = %d\n", ParsedPathSize)); + + ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize); + if (!ParsedPath) + { + Status = STATUS_NO_MEMORY; + goto end; + } + RtlZeroMemory (ParsedPath, ParsedPathSize); + ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING)); + + ParsedPath->u16Size = DirectoryName->Length + Template->Length + sizeof(WCHAR); + ParsedPath->u16Length = ParsedPath->u16Size - sizeof(WCHAR); /* Without terminating null. */ + + len = 0; + if (DirectoryName->Length) + { + /* Copy directory name into ParsedPath. */ + RtlCopyMemory (ParsedPath->String.ucs2, DirectoryName->Buffer, DirectoryName->Length); + len = DirectoryName->Length / sizeof(WCHAR); + + /* Add terminating backslash. */ + ParsedPath->String.ucs2[len] = L'\\'; + len++; + ParsedPath->u16Length += sizeof(WCHAR); + ParsedPath->u16Size += sizeof(WCHAR); + } + RtlCopyMemory (&ParsedPath->String.ucs2[len], Template->Buffer, Template->Length); + Log(("VBOXSF: QueryDirectory: ParsedPath = %.*ls\n", ParsedPath->u16Length / sizeof(WCHAR), ParsedPath->String.ucs2)); + } + + cFiles = 0; + /* vboxCallDirInfo requires a pointer to uint32_t. */ + u32BufSize = cbHGCMBuffer; + + Log(("VBOXSF: QueryDirectory: CallDirInfo: File = 0x%08x, Flags = 0x%08x, Index = %d\n", pVBoxFobx->hFile, fSFFlags, index)); + Log(("VBOXSF: QueryDirectory: u32BufSize before CallDirInfo = %d\n", u32BufSize)); + vboxRC = vboxCallDirInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, ParsedPath, fSFFlags, index, &u32BufSize, (PSHFLDIRINFO)pHGCMBuffer, &cFiles); + Log(("VBOXSF: QueryDirectory: u32BufSize after CallDirInfo = %d\n", u32BufSize)); + Log(("VBOXSF: QueryDirectory: CallDirInfo returned %Rrc\n", vboxRC)); + + switch (vboxRC) + { + case VINF_SUCCESS: + /* Nothing to do here. */ + break; + case VERR_NO_TRANSLATION: + Log(("VBOXSF: QueryDirectory: Host could not translate entry!\n")); + break; + case VERR_NO_MORE_FILES: + if (cFiles <= 0) /* VERR_NO_MORE_FILES appears at the first lookup when just returning the current dir ".". + * So we also have to check for the cFiles counter. */ + { + /* Not an error, but we have to handle the return value. */ + Log(("VBOXSF: QueryDirectory: Host reported no more files!\n")); + + if (RxContext->QueryDirectory.InitialQuery) + { + /* First call. MSDN on FindFirstFile: "If the function fails because no matching files + * can be found, the GetLastError function returns ERROR_FILE_NOT_FOUND." + * So map this rc to file not found. + */ + Status = STATUS_NO_SUCH_FILE; + } + else + { + /* Search continued. */ + Status = STATUS_NO_MORE_FILES; + } + } + break; + case VERR_FILE_NOT_FOUND: + Status = STATUS_NO_SUCH_FILE; + Log(("VBOXSF: QueryDirectory: no such file!\n")); + break; + default: + Status = VBoxErrorToNTStatus(vboxRC); + Log(("VBOXSF: QueryDirectory: Error %Rrc from CallDirInfo (cFiles=%d)!\n", vboxRC, cFiles)); + break; + } + + if (Status != STATUS_SUCCESS) + goto end; + + /* Verify that the returned buffer length is not greater than the original one. */ + if (u32BufSize > (uint32_t)cbHGCMBuffer) + { + Log(("VBOXSF: QueryDirectory: returned buffer size (%u) is invalid!!!\n", u32BufSize)); + Status = STATUS_INVALID_NETWORK_RESPONSE; + goto end; + } + + /* How many bytes remain in the buffer. */ + cbHGCMBuffer = u32BufSize; + + pDirEntry = (PSHFLDIRINFO)pHGCMBuffer; + Status = STATUS_SUCCESS; + + Log(("VBOXSF: QueryDirectory: cFiles=%d, Length=%d\n", cFiles, cbHGCMBuffer)); + while ((*pLengthRemaining) && (cFiles > 0) && (pDirEntry != NULL)) + { + int cbEntry = RT_OFFSETOF(SHFLDIRINFO, name.String) + pDirEntry->name.u16Size; + + if (cbEntry > cbHGCMBuffer) + { + Log(("VBOXSF: QueryDirectory: Entry size (%d) exceeds the buffer size (%d)!!!\n", cbEntry, cbHGCMBuffer)); + Status = STATUS_INVALID_NETWORK_RESPONSE; + goto end; + } + + switch (FileInformationClass) + { + case FileDirectoryInformation: + { + PFILE_DIRECTORY_INFORMATION pDirInfo = (PFILE_DIRECTORY_INFORMATION)Buffer; + CopySize = sizeof(FILE_DIRECTORY_INFORMATION); + + /* Struct already contains one char for null terminator. */ + CopySize += pDirEntry->name.u16Size; + + Log(("VBOXSF: QueryDirectory: FileDirectoryInformation Buffer=%08x\n", Buffer)); + if (*pLengthRemaining >= CopySize) + { + RtlZeroMemory( pDirInfo, CopySize ); + + pDirInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */ + pDirInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime); + pDirInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime); + pDirInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime); + pDirInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated; + pDirInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject; + + pDirInfo->FileIndex = index; + pDirInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode); + + INIT_FILE_NAME(pDirInfo, pDirEntry->name); + + /* Align to 8 byte boundary */ + CopySize = RT_ALIGN(CopySize, sizeof(LONGLONG)); + pDirInfo->NextEntryOffset = CopySize; + pNextOffset = &pDirInfo->NextEntryOffset; + } + else + { + pDirInfo->NextEntryOffset = 0; /* last item */ + Status = STATUS_BUFFER_OVERFLOW; + } + break; + } + + case FileFullDirectoryInformation: + { + PFILE_FULL_DIR_INFORMATION pDirInfo = (PFILE_FULL_DIR_INFORMATION)Buffer; + CopySize = sizeof(FILE_FULL_DIR_INFORMATION); + + /* Struct already contains one char for null terminator. */ + CopySize += pDirEntry->name.u16Size; + + Log(("VBOXSF: QueryDirectory: FileFullDirectoryInformation Buffer=%08x\n", Buffer)); + if (*pLengthRemaining >= CopySize) + { + RtlZeroMemory( pDirInfo, CopySize ); + + pDirInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */ + pDirInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime); + pDirInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime); + pDirInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime); + pDirInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated; + pDirInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject; + + pDirInfo->EaSize = 0; + pDirInfo->FileIndex = index; + pDirInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode); + + INIT_FILE_NAME(pDirInfo, pDirEntry->name); + + /* Align to 8 byte boundary */ + CopySize = RT_ALIGN(CopySize, sizeof(LONGLONG)); + pDirInfo->NextEntryOffset = CopySize; + pNextOffset = &pDirInfo->NextEntryOffset; + } + else + { + pDirInfo->NextEntryOffset = 0; /* last item */ + Status = STATUS_BUFFER_OVERFLOW; + } + break; + } + + case FileBothDirectoryInformation: + { + PFILE_BOTH_DIR_INFORMATION pDirInfo = (PFILE_BOTH_DIR_INFORMATION)Buffer; + CopySize = sizeof(FILE_BOTH_DIR_INFORMATION); + /* struct already contains one char for null terminator */ + CopySize += pDirEntry->name.u16Size; + + Log(("VBOXSF: QueryDirectory: FileBothDirectoryInformation Buffer=%08x\n", Buffer)); + if (*pLengthRemaining >= CopySize) + { + RtlZeroMemory( pDirInfo, CopySize ); + + pDirInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */ + pDirInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime); + pDirInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime); + pDirInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime); + pDirInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated; + pDirInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject; + + pDirInfo->EaSize = 0; + pDirInfo->ShortNameLength = 0; /* @todo ? */ + pDirInfo->FileIndex = index; + pDirInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode); + + INIT_FILE_NAME(pDirInfo, pDirEntry->name); + + Log(("VBOXSF: QueryDirectory: FileBothDirectoryInformation cbAlloc = %x cbObject = %x\n", pDirEntry->Info.cbAllocated, pDirEntry->Info.cbObject)); + Log(("VBOXSF: QueryDirectory: FileBothDirectoryInformation CopySize = %d, name size=%d name len=%d\n", CopySize, pDirEntry->name.u16Size, pDirEntry->name.u16Length)); + Log(("VBOXSF: QueryDirectory: FileBothDirectoryInformation File name %.*ls (DirInfo)\n", pDirInfo->FileNameLength / sizeof(WCHAR), pDirInfo->FileName)); + Log(("VBOXSF: QueryDirectory: FileBothDirectoryInformation File name %.*ls (DirEntry)\n", pDirEntry->name.u16Size / sizeof(WCHAR), pDirEntry->name.String.ucs2)); + + /* Align to 8 byte boundary. */ + CopySize = RT_ALIGN(CopySize, sizeof(LONGLONG)); + pDirInfo->NextEntryOffset = CopySize; + pNextOffset = &pDirInfo->NextEntryOffset; + } + else + { + pDirInfo->NextEntryOffset = 0; /* Last item. */ + Status = STATUS_BUFFER_OVERFLOW; + } + break; + } + + case FileIdBothDirectoryInformation: + { + PFILE_ID_BOTH_DIR_INFORMATION pDirInfo = (PFILE_ID_BOTH_DIR_INFORMATION)Buffer; + CopySize = sizeof(FILE_ID_BOTH_DIR_INFORMATION); + /* struct already contains one char for null terminator */ + CopySize += pDirEntry->name.u16Size; + + Log(("VBOXSF: QueryDirectory: FileIdBothDirectoryInformation Buffer=%08x\n", Buffer)); + if (*pLengthRemaining >= CopySize) + { + RtlZeroMemory( pDirInfo, CopySize ); + + pDirInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */ + pDirInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime); + pDirInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime); + pDirInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime); + pDirInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated; + pDirInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject; + + pDirInfo->EaSize = 0; + pDirInfo->ShortNameLength = 0; /* @todo ? */ + pDirInfo->EaSize = 0; + pDirInfo->FileId.QuadPart = 0; + pDirInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode); + + INIT_FILE_NAME(pDirInfo, pDirEntry->name); + + Log(("VBOXSF: QueryDirectory: FileIdBothDirectoryInformation cbAlloc = %x cbObject = %x\n", pDirEntry->Info.cbAllocated, pDirEntry->Info.cbObject)); + Log(("VBOXSF: QueryDirectory: FileIdBothDirectoryInformation CopySize = %d, name size=%d name len=%d\n", CopySize, pDirEntry->name.u16Size, pDirEntry->name.u16Length)); + Log(("VBOXSF: QueryDirectory: FileIdBothDirectoryInformation File name %.*ls (DirInfo)\n", pDirInfo->FileNameLength / sizeof(WCHAR), pDirInfo->FileName)); + Log(("VBOXSF: QueryDirectory: FileIdBothDirectoryInformation File name %.*ls (DirEntry)\n", pDirEntry->name.u16Size / sizeof(WCHAR), pDirEntry->name.String.ucs2)); + + /* Align to 8 byte boundary. */ + CopySize = RT_ALIGN(CopySize, sizeof(LONGLONG)); + pDirInfo->NextEntryOffset = CopySize; + pNextOffset = &pDirInfo->NextEntryOffset; + } + else + { + pDirInfo->NextEntryOffset = 0; /* Last item. */ + Status = STATUS_BUFFER_OVERFLOW; + } + break; + } + + case FileNamesInformation: + { + PFILE_NAMES_INFORMATION pDirInfo = (PFILE_NAMES_INFORMATION)Buffer; + CopySize = sizeof(FILE_NAMES_INFORMATION); + + /* Struct already contains one char for null terminator. */ + CopySize += pDirEntry->name.u16Size; + + Log(("VBOXSF: QueryDirectory: FileNamesInformation Buffer=%08x\n", Buffer)); + if (*pLengthRemaining >= CopySize) + { + RtlZeroMemory( pDirInfo, CopySize ); + + pDirInfo->FileIndex = index; + + INIT_FILE_NAME(pDirInfo, pDirEntry->name); + + Log(("VBOXSF: QueryDirectory: FileNamesInformation File name %.*ls\n", pDirInfo->FileNameLength / sizeof(WCHAR), pDirInfo->FileName)); + + /* Align to 8 byte boundary. */ + CopySize = RT_ALIGN(CopySize, sizeof(LONGLONG)); + pDirInfo->NextEntryOffset = CopySize; + pNextOffset = &pDirInfo->NextEntryOffset; + } + else + { + pDirInfo->NextEntryOffset = 0; /* Last item. */ + Status = STATUS_BUFFER_OVERFLOW; + } + break; + } + + default: + Log(("VBOXSF: QueryDirectory: Invalid FS information class %d!\n", FileInformationClass)); + Status = STATUS_INVALID_PARAMETER; + goto end; + } + + cbHGCMBuffer -= cbEntry; + pDirEntry = (PSHFLDIRINFO)((uintptr_t)pDirEntry + cbEntry); + Log(("VBOXSF: QueryDirectory: %d bytes left in HGCM buffer\n", cbHGCMBuffer)); + + if (*pLengthRemaining >= CopySize) + { + Buffer += CopySize; + *pLengthRemaining -= CopySize; + } + else break; + + if (RxContext->QueryDirectory.ReturnSingleEntry) + break; + + /* More left? */ + if (cbHGCMBuffer <= 0) + break; + + index++; /* File Index. */ + + cFiles--; + } + if (pNextOffset) + *pNextOffset = 0; /* Last pDirInfo->NextEntryOffset should be set to zero! */ + + end: if (pHGCMBuffer) + vbsfFreeNonPagedMem(pHGCMBuffer); + + if (ParsedPath) + vbsfFreeNonPagedMem(ParsedPath); + + Log(("VBOXSF: QueryDirectory: Returned 0x%x\n", Status)); + return (Status); +} + +NTSTATUS VBoxMRxQueryVolumeInformationWithFullBuffer (IN OUT PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine queries the volume information + + Arguments: + + pRxContext - the RDBSS context + + FsInformationClass - the kind of Fs information desired. + + pBuffer - the buffer for copying the information + + pBufferLength - the buffer length ( set to buffer length on input and set + to the remaining length on output) + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_INVALID_PARAMETER; + RxCaptureFcb; + RxCaptureFobx; + VBoxMRxGetNetRootExtension(capFcb->pNetRoot, pNetRootExtension); + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); + ULONG OriginalLength = RxContext->Info.LengthRemaining; + FS_INFORMATION_CLASS FsInformationClass = RxContext->Info.FsInformationClass; + PVOID OriginalBuffer = RxContext->Info.Buffer; + ULONG BytesToCopy, cbMaxSize; + + if (NULL != pVBoxFobx) + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: vboxFobx = %p, Handle = 0x%08x\n", pVBoxFobx, pVBoxFobx->hFile)); + + cbMaxSize = RxContext->Info.Length; + + switch (FsInformationClass) + { + case FileFsVolumeInformation: + { + PFILE_FS_VOLUME_INFORMATION pVolInfo = (PFILE_FS_VOLUME_INFORMATION)OriginalBuffer; + PWCHAR pRootName; + ULONG RootNameLength; + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; + PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall; + PSHFLVOLINFO pSHFLVolInfo; + uint32_t cbHGCMBuffer; + uint8_t *pHGCMBuffer = NULL; + int vboxRC; + + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsVolumeInformation: OriginalBuffer = %p, LenRemaining = %d\n", OriginalBuffer, RxContext->Info.LengthRemaining)); + if (RxContext->Info.LengthRemaining < sizeof(FILE_FS_VOLUME_INFORMATION)) + { + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsVolumeInformation: Insufficient buffer size (%d)\n", RxContext->Info.LengthRemaining)); + Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + if (NULL == pVBoxFobx) + { + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: pVBoxFobx is invalid!\n")); + return STATUS_INVALID_PARAMETER; + } + + RtlZeroMemory( pVolInfo, sizeof(FILE_FS_VOLUME_INFORMATION) ); + + RootNameLength = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length; + RootNameLength -= 2; /* remove leading backslash */ + + pRootName = (PWCHAR)(pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR))); + pRootName++; /* remove leading backslash */ + + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsVolumeInformation: Root name = %.*ls\n", RootNameLength / sizeof(WCHAR), pRootName)); + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsVolumeInformation: Prefix %ls has %d elements\n", VBOX_VOLNAME_PREFIX, RT_ELEMENTS(VBOX_VOLNAME_PREFIX))); + + /* Query serial number. */ + cbHGCMBuffer = sizeof(SHFLVOLINFO); + pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbHGCMBuffer); + if (pHGCMBuffer == 0) + { + AssertFailed(); + Status = STATUS_NO_MEMORY; + break; + } + + vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbHGCMBuffer, (PSHFLDIRINFO)pHGCMBuffer); + AssertRC(vboxRC); + + if (vboxRC != VINF_SUCCESS) + { + Status = VBoxErrorToNTStatus(vboxRC); + vbsfFreeNonPagedMem(pHGCMBuffer); + break; + } + + pSHFLVolInfo = (PSHFLVOLINFO)pHGCMBuffer; + pVolInfo->VolumeSerialNumber = pSHFLVolInfo->ulSerial; + vbsfFreeNonPagedMem(pHGCMBuffer); + + pVolInfo->VolumeCreationTime.QuadPart = 0; + pVolInfo->VolumeLabelLength = RootNameLength + VBOX_VOLNAME_PREFIX_SIZE; + pVolInfo->SupportsObjects = FALSE; + + RxContext->Info.LengthRemaining -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel[0]); + + if (RxContext->Info.LengthRemaining >= (LONG)pVolInfo->VolumeLabelLength) + { + BytesToCopy = pVolInfo->VolumeLabelLength; + + /* Copy prefix */ + RtlCopyMemory( &pVolInfo->VolumeLabel[0], (PVOID)VBOX_VOLNAME_PREFIX, VBOX_VOLNAME_PREFIX_SIZE); + + /* Copy share name (- 1 for zero terminator) */ + RtlCopyMemory( &pVolInfo->VolumeLabel[RT_ELEMENTS(VBOX_VOLNAME_PREFIX) - 1], (PVOID)pRootName, RootNameLength ); + } + else + { + BytesToCopy = RxContext->Info.LengthRemaining; + + /* Copy prefix */ + RtlCopyMemory( &pVolInfo->VolumeLabel[0], (PVOID)VBOX_VOLNAME_PREFIX, RT_MIN(BytesToCopy, VBOX_VOLNAME_PREFIX_SIZE) ); + + if (BytesToCopy > VBOX_VOLNAME_PREFIX_SIZE) + { + /* Copy share name (- 1 for zero terminator) */ + RtlCopyMemory( &pVolInfo->VolumeLabel[RT_ELEMENTS(VBOX_VOLNAME_PREFIX) - 1], (PVOID)pRootName, BytesToCopy - VBOX_VOLNAME_PREFIX_SIZE ); + } + } + + RxContext->Info.LengthRemaining -= BytesToCopy; + pVolInfo->VolumeLabelLength = BytesToCopy; + + Status = STATUS_SUCCESS; + break; + } + + case FileFsLabelInformation: + { + PFILE_FS_LABEL_INFORMATION pLabelInfo = (PFILE_FS_LABEL_INFORMATION)OriginalBuffer; + PWCHAR pRootName; + ULONG RootNameLength; + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; + PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall; + + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsLabelInformation: OriginalBuffer = %p, LenRemaining = %d\n", OriginalBuffer, RxContext->Info.LengthRemaining)); + if (RxContext->Info.LengthRemaining < sizeof(PFILE_FS_LABEL_INFORMATION)) + { + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsLabelInformation: Insufficient buffer size (%d)\n", RxContext->Info.LengthRemaining)); + Status = STATUS_BUFFER_TOO_SMALL; + break; + } + RtlZeroMemory( pLabelInfo, sizeof(FILE_FS_LABEL_INFORMATION) ); + + RootNameLength = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length; + RootNameLength -= 2; /* remove leading backslash */ + + pRootName = (PWCHAR)(pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR))); + pRootName++; /* remove leading backslash */ + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsLabelInformation: Root name = %.*ls\n", RootNameLength / sizeof(WCHAR), pRootName)); + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsLabelInformation: Prefix %ls has %d elements\n", VBOX_VOLNAME_PREFIX, RT_ELEMENTS(VBOX_VOLNAME_PREFIX))); + + pLabelInfo->VolumeLabelLength = RootNameLength + VBOX_VOLNAME_PREFIX_SIZE; + RxContext->Info.LengthRemaining -= FIELD_OFFSET(FILE_FS_LABEL_INFORMATION, VolumeLabel[0]); + + if (RxContext->Info.LengthRemaining >= (LONG)pLabelInfo->VolumeLabelLength) + { + BytesToCopy = pLabelInfo->VolumeLabelLength; + + /* Copy prefix */ + RtlCopyMemory( &pLabelInfo->VolumeLabel[0], (PVOID)VBOX_VOLNAME_PREFIX, VBOX_VOLNAME_PREFIX_SIZE); + + /* Copy share name (- 1 for zero terminator) */ + RtlCopyMemory( &pLabelInfo->VolumeLabel[RT_ELEMENTS(VBOX_VOLNAME_PREFIX) - 1], (PVOID)pRootName, RootNameLength ); + } + else + { + BytesToCopy = RxContext->Info.LengthRemaining; + + /* Copy prefix */ + RtlCopyMemory( &pLabelInfo->VolumeLabel[0], (PVOID)VBOX_VOLNAME_PREFIX, RT_MIN(BytesToCopy, VBOX_VOLNAME_PREFIX_SIZE) ); + + if (BytesToCopy > VBOX_VOLNAME_PREFIX_SIZE) + { + /* Copy share name (- 1 for zero terminator) */ + RtlCopyMemory( &pLabelInfo->VolumeLabel[RT_ELEMENTS(VBOX_VOLNAME_PREFIX) - 1], (PVOID)pRootName, BytesToCopy - VBOX_VOLNAME_PREFIX_SIZE ); + } + } + RxContext->Info.LengthRemaining -= BytesToCopy; + pLabelInfo->VolumeLabelLength = BytesToCopy; + + Status = STATUS_SUCCESS; + break; + } + + case FileFsFullSizeInformation: + case FileFsSizeInformation: + { + PFILE_FS_FULL_SIZE_INFORMATION pFullSizeInfo = (PFILE_FS_FULL_SIZE_INFORMATION)OriginalBuffer; + PFILE_FS_SIZE_INFORMATION pSizeInfo = (PFILE_FS_SIZE_INFORMATION)OriginalBuffer; + uint32_t cbHGCMBuffer; + uint8_t *pHGCMBuffer = NULL; + int vboxRC; + PSHFLVOLINFO pVolInfo; + + if (FsInformationClass == FileFsFullSizeInformation) + { + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsFullSizeInformation: OriginalBuffer = %p, LenRemaining = %d\n", OriginalBuffer, RxContext->Info.LengthRemaining)); + BytesToCopy = sizeof(FILE_FS_FULL_SIZE_INFORMATION); + } + else + { + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsSizeInformation: OriginalBuffer = %p, LenRemaining = %d\n", OriginalBuffer, RxContext->Info.LengthRemaining)); + BytesToCopy = sizeof(FILE_FS_SIZE_INFORMATION); + } + + if (RxContext->Info.LengthRemaining < (LONG)BytesToCopy) + { + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsFullSizeInformation/FileFsSizeInformation: Insufficient buffer size (%d)!\n", RxContext->Info.LengthRemaining)); + Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + if (NULL == pVBoxFobx) + { + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: pVBoxFobx is invalid!\n")); + return STATUS_INVALID_PARAMETER; + } + + RtlZeroMemory( pSizeInfo, BytesToCopy ); + + cbHGCMBuffer = sizeof(SHFLVOLINFO); + pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbHGCMBuffer); + if (pHGCMBuffer == 0) + { + AssertFailed(); + Status = STATUS_NO_MEMORY; + break; + } + + vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbHGCMBuffer, (PSHFLDIRINFO)pHGCMBuffer); + AssertRC(vboxRC); + + if (vboxRC != VINF_SUCCESS) + { + Status = VBoxErrorToNTStatus(vboxRC); + vbsfFreeNonPagedMem(pHGCMBuffer); + break; + } + + pVolInfo = (PSHFLVOLINFO)pHGCMBuffer; + + if (FsInformationClass == FileFsFullSizeInformation) + { + pFullSizeInfo->SectorsPerAllocationUnit = pVolInfo->ulBytesPerAllocationUnit / pVolInfo->ulBytesPerSector; + pFullSizeInfo->BytesPerSector = pVolInfo->ulBytesPerSector; + pFullSizeInfo->ActualAvailableAllocationUnits.QuadPart = pVolInfo->ullAvailableAllocationBytes / pVolInfo->ulBytesPerAllocationUnit; + pFullSizeInfo->CallerAvailableAllocationUnits.QuadPart = pFullSizeInfo->ActualAvailableAllocationUnits.QuadPart; + pFullSizeInfo->TotalAllocationUnits.QuadPart = pVolInfo->ullTotalAllocationBytes / pVolInfo->ulBytesPerAllocationUnit; + + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsFullSizeInformation: SectorsPerAllocationUnit %08x\n", (ULONG)pFullSizeInfo->SectorsPerAllocationUnit)); + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsFullSizeInformation: BytesPerSector %08x\n", (ULONG)pFullSizeInfo->BytesPerSector)); + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsFullSizeInformation: ActualAvailableAllocationUnits %RX64\n", pFullSizeInfo->ActualAvailableAllocationUnits.QuadPart)); + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsFullSizeInformation: TotalAllocationUnits %RX64\n", pFullSizeInfo->TotalAllocationUnits.QuadPart)); + } + else + { + pSizeInfo->SectorsPerAllocationUnit = pVolInfo->ulBytesPerAllocationUnit / pVolInfo->ulBytesPerSector; + pSizeInfo->BytesPerSector = pVolInfo->ulBytesPerSector; + pSizeInfo->AvailableAllocationUnits.QuadPart = pVolInfo->ullAvailableAllocationBytes / pVolInfo->ulBytesPerAllocationUnit; + pSizeInfo->TotalAllocationUnits.QuadPart = pVolInfo->ullTotalAllocationBytes / pVolInfo->ulBytesPerAllocationUnit; + + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsSizeInformation: SectorsPerAllocationUnit %08x\n", (ULONG)pSizeInfo->SectorsPerAllocationUnit)); + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsSizeInformation: BytesPerSector %08x\n", (ULONG)pSizeInfo->BytesPerSector)); + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsSizeInformation: AvailableAllocationUnits %RX64\n", pSizeInfo->AvailableAllocationUnits.QuadPart)); + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsSizeInformation: TotalAllocationUnits %RX64\n", pSizeInfo->TotalAllocationUnits.QuadPart)); + } + + if (pHGCMBuffer) + vbsfFreeNonPagedMem(pHGCMBuffer); + + RxContext->Info.LengthRemaining -= BytesToCopy; + Status = STATUS_SUCCESS; + break; + } + + case FileFsDeviceInformation: + { + PFILE_FS_DEVICE_INFORMATION pDevInfo = (PFILE_FS_DEVICE_INFORMATION)OriginalBuffer; + PMRX_NET_ROOT NetRoot = capFcb->pNetRoot; + + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsDeviceInformation: Type = 0x%x\n", NetRoot->DeviceType)); + Status = STATUS_SUCCESS; + + BytesToCopy = sizeof(FILE_FS_DEVICE_INFORMATION); + if (RxContext->Info.LengthRemaining >= (LONG)BytesToCopy) + { + pDevInfo->DeviceType = NetRoot->DeviceType; + pDevInfo->Characteristics = FILE_REMOTE_DEVICE; + + if (NetRoot->Type == NET_ROOT_PIPE) + { + NetRoot->DeviceType = RxDeviceType(NAMED_PIPE); + Status = STATUS_INVALID_PARAMETER; + break; + } + + RxContext->Info.LengthRemaining -= BytesToCopy; + } + else + { + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsDeviceInformation: Buffer too small (%d vs %d)!\n", RxContext->Info.LengthRemaining, BytesToCopy)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileFsAttributeInformation: + { + PFILE_FS_ATTRIBUTE_INFORMATION pAttribInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)OriginalBuffer; + + BytesToCopy = sizeof(MRX_VBOX_FILESYS_NAME_U) + FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[0]); + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsAttributeInformation: BytesToCopy = %d\n", BytesToCopy)); + if (RxContext->Info.LengthRemaining < (LONG)BytesToCopy) + { + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsAttributeInformation: Buffer too small (%d)!\n", RxContext->Info.LengthRemaining)); + Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + /** @todo set unicode, case sensitive etc? */ + pAttribInfo->FileSystemAttributes = 0; + pAttribInfo->MaximumComponentNameLength = 255; /** @todo should query from the host */ + pAttribInfo->FileSystemNameLength = sizeof(MRX_VBOX_FILESYS_NAME_U); + RtlCopyMemory( pAttribInfo->FileSystemName, MRX_VBOX_FILESYS_NAME_U, pAttribInfo->FileSystemNameLength); + + RxContext->Info.LengthRemaining -= BytesToCopy; + Status = STATUS_SUCCESS; + break; + } + + case FileFsControlInformation: + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsControlInformation (skipping ...)\n")); + break; + + case FileFsObjectIdInformation: + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsObjectIdInformation (skipping ...)\n")); + break; + + case FileFsMaximumInformation: + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsMaximumInformation (skipping ...)\n")); + break; + + default: + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: Invalid parameter!\n")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: Returned 0x%x\n", Status)); + return (Status); +} + +NTSTATUS VBoxMRxQueryVolumeInformation (IN OUT PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine queries the volume information. Since the NT server does not + handle bufferoverflow gracefully on query-fs-info, we allocate a buffer here + that is big enough to hold anything passed back; then we call the "real" + queryvolinfo routine. + + Arguments: + + pRxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status; + RxCaptureFcb; + RxCaptureFobx; + PVOID OriginalBuffer = RxContext->Info.Buffer; + ULONG OriginalLength = RxContext->Info.LengthRemaining; + ULONG ReturnedLength; + + BOOLEAN UsingSideBuffer = FALSE; + uint32_t cbSideBuffer = 0; + + typedef struct + { + union + { + FILE_FS_LABEL_INFORMATION labelinfo; + FILE_FS_VOLUME_INFORMATION volumeinfo; + FILE_FS_SIZE_INFORMATION sizeinfo; + FILE_FS_DEVICE_INFORMATION deviceinfo; + FILE_FS_ATTRIBUTE_INFORMATION attributeinfo; + } Info; + WCHAR VolumeName[MAXIMUM_FILENAME_LENGTH]; + } SideBuffer; + + SideBuffer *pSideBuffer = NULL; + + PAGED_CODE(); + + Log( + ("VBOXSF: VBoxMRxQueryVolumeInformation: rxContextBufferAddr = 0x%x, rxContextBufferLengthRem = %d, (SideBufferSize = %d)\n", RxContext->Info.Buffer, RxContext->Info.LengthRemaining, sizeof(SideBuffer))); + if (RxContext->Info.LengthRemaining < sizeof(SideBuffer)) + { + /* I replace the buffer and length in the context with my stuff. */ + Log(("VBOXSF: VBoxMRxQueryVolumeInformation: Using Sidebuffer ...\n")); + UsingSideBuffer = TRUE; + RxContext->Info.Buffer = vbsfAllocNonPagedMem(sizeof(SideBuffer)); + pSideBuffer = (SideBuffer *)RxContext->Info.Buffer; + RxContext->Info.LengthRemaining = sizeof(SideBuffer); + } + + Status = VBoxMRxQueryVolumeInformationWithFullBuffer(RxContext); + Assert(Status != STATUS_PENDING); + + Log(("VBOXSF: VBoxMRxQueryVolumeInformation: RxContext->Info.LengthRemaining = %d\n", RxContext->Info.LengthRemaining)); + + if (Status != STATUS_SUCCESS) + { + RxContext->Info.Buffer = OriginalBuffer; + RxContext->Info.LengthRemaining = OriginalLength; + + Log(("VBOXSF: VBoxMRxQueryVolumeInformation: VBoxMRxQueryVolumeInformationWithFullBuffer failed with 0x%x\n", Status)); + goto FINALLY; + } + + if (UsingSideBuffer == TRUE) + { + ReturnedLength = sizeof(SideBuffer) - RxContext->Info.LengthRemaining; + } + else + { + ReturnedLength = OriginalLength - RxContext->Info.LengthRemaining; + } + + Log(("VBOXSF: VBoxMRxQueryVolumeInformation: ReturnedLength = %d, OriginalLength = %d\n", ReturnedLength, OriginalLength)); + if (ReturnedLength > OriginalLength) + { + Status = STATUS_BUFFER_OVERFLOW; + ReturnedLength = OriginalLength; + } + + if (UsingSideBuffer == TRUE) + { + RtlCopyMemory(OriginalBuffer, pSideBuffer, ReturnedLength); + } + + RxContext->Info.Buffer = OriginalBuffer; + RxContext->Info.LengthRemaining = OriginalLength - ReturnedLength; + Log(("VBOXSF: VBoxMRxQueryVolumeInformation: OriginalLength = %d, LengthRemaining = %d, Status = 0x%x\n", OriginalLength, RxContext->Info.LengthRemaining, Status)); + Log(("VBOXSF: VBoxMRxQueryVolumeInformation: Final rxContextBufferAddr = 0x%x, rxContextBufferLengthRem = %d\n", RxContext->Info.Buffer, RxContext->Info.LengthRemaining)); + + FINALLY: + + if (NULL != pSideBuffer) + vbsfFreeNonPagedMem(pSideBuffer); + + return Status; +} + +NTSTATUS VBoxMRxSetVolumeInformation (IN OUT PRX_CONTEXT pRxContext) +/*++ + + Routine Description: + + This routine sets the volume information + + Arguments: + + pRxContext - the RDBSS context + + FsInformationClass - the kind of Fs information desired. + + pBuffer - the buffer for copying the information + + BufferLength - the buffer length + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + + Log(("VBOXSF: VBoxMRxSetVolumeInformation called.\n")); + return (Status); +} + +NTSTATUS VBoxMRxQueryFileInformation (IN PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine does a query file info. Only the NT-->NT path is implemented. + + The NT-->NT path works by just remoting the call basically without further ado. + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + ULONG CopySize = 0; + RxCaptureFcb; + RxCaptureFobx; + FILE_INFORMATION_CLASS FunctionalityRequested = RxContext->Info.FileInformationClass; + + VBoxMRxGetNetRootExtension(capFcb->pNetRoot, pNetRootExtension); + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); + PUNICODE_STRING FileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext); + + uint8_t *pHGCMBuffer = 0; + int vboxRC = 0; + uint32_t cbHGCMBuffer, cbMaxSize = 0; + PRTFSOBJINFO pFileEntry = NULL; + PCHAR pInfoBuffer = NULL; + ULONG *pLengthRemaining = NULL; + + pInfoBuffer = (PCHAR)RxContext->Info.Buffer; + cbMaxSize = RxContext->Info.Length; + pLengthRemaining = (PULONG) & RxContext->Info.LengthRemaining; + + if (NULL == pLengthRemaining) + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: Invalid length pointer detected!\n")); + return STATUS_INVALID_PARAMETER; + } + + Log(("VBOXSF: VBoxMRxQueryFileInformation: InfoBuffer = 0x%08x, Size = %d bytes, LenRemain = %d bytes\n", pInfoBuffer, cbMaxSize, *pLengthRemaining)); + + if (NULL == pVBoxFobx) + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: pVBoxFobx is invalid!\n")); + return STATUS_INVALID_PARAMETER; + } + + if (NULL == pInfoBuffer) + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: Invalid information buffer detected!\n")); + return STATUS_INVALID_PARAMETER; + } + + if (pVBoxFobx->FileStandardInfo.Directory == TRUE) + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: Directory -> Copy info retrieved during the create call\n")); + Status = STATUS_SUCCESS; + + switch (FunctionalityRequested) + { + + case FileBasicInformation: + { + PFILE_BASIC_INFORMATION pFileInfo = (PFILE_BASIC_INFORMATION)pInfoBuffer; + CopySize = sizeof(FILE_BASIC_INFORMATION); + + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileBasicInformation: Buffer = 0x%08x\n", pFileInfo)); + if (*pLengthRemaining >= CopySize) + { + *pFileInfo = pVBoxFobx->FileBasicInfo; + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileBasicInformation: File attributes: 0x%x\n", pFileInfo->FileAttributes)); + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileBasicInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileStandardInformation: + { + PFILE_STANDARD_INFORMATION pFileInfo = (PFILE_STANDARD_INFORMATION)pInfoBuffer; + CopySize = sizeof(FILE_STANDARD_INFORMATION); + + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileStandardInformation: Buffer = 0x%08x\n", pFileInfo)); + if (*pLengthRemaining >= CopySize) + { + *pFileInfo = pVBoxFobx->FileStandardInfo; + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileStandardInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileNamesInformation: + { + PFILE_NAMES_INFORMATION pFileInfo = (PFILE_NAMES_INFORMATION)pInfoBuffer; + CopySize = sizeof(FILE_NAMES_INFORMATION); + + /* Struct already contains one char for null terminator. */ + CopySize += (FileName->Length + 1) * sizeof(WCHAR); + + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNamesInformation: Buffer = %08x\n", pFileInfo)); + if (*pLengthRemaining >= CopySize) + { + RtlZeroMemory (pFileInfo, CopySize); + + pFileInfo->FileIndex = 0; + pFileInfo->FileNameLength = FileName->Length * sizeof(WCHAR); + RtlCopyMemory(pFileInfo->FileName, FileName->Buffer, pFileInfo->FileNameLength); + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNamesInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileInternalInformation: + { + PFILE_INTERNAL_INFORMATION UsersBuffer = (PFILE_INTERNAL_INFORMATION)pInfoBuffer; + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileInternalInformation: Buffer = 0x%08x\n", pInfoBuffer)); + + /* + * Note: We use the address of the FCB to determine the + * index number of the file. If we have to maintain persistance between + * file opens for this request, then we might have to do something + * like checksuming the reserved fields on a FUNIQUE SMB response. + * + + * + * NT64: the address of capFcb used to be stuffed into + * IndexNumber.LowPart, with HighPart being zeroed. + * + * Whoever is asking for this pointer value should be + * prepared to deal with the returned 64-bit value. + */ + + CopySize = sizeof(FILE_INTERNAL_INFORMATION); + + if (*pLengthRemaining >= CopySize) + { + UsersBuffer->IndexNumber.QuadPart = (ULONG_PTR)capFcb; + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileInternalInformation: Buffer overflow (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + case FileEaInformation: + { + PFILE_EA_INFORMATION EaBuffer = (PFILE_EA_INFORMATION)pInfoBuffer; + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileEaInformation: Buffer = 0x%08x\n", pInfoBuffer)); + + CopySize = sizeof(FILE_EA_INFORMATION); + if (*pLengthRemaining >= CopySize) + { + EaBuffer->EaSize = 0; + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileEaInformation: Buffer overflow (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileNetworkOpenInformation: + { + PFILE_NETWORK_OPEN_INFORMATION pFileInfo = (PFILE_NETWORK_OPEN_INFORMATION)pInfoBuffer; + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNetworkOpenInformation: Buffer = 0x%08x\n", pInfoBuffer)); + + CopySize = sizeof(FILE_NETWORK_OPEN_INFORMATION); + if (*pLengthRemaining >= CopySize) + { + pFileInfo->CreationTime = pVBoxFobx->FileBasicInfo.CreationTime; + pFileInfo->LastAccessTime = pVBoxFobx->FileBasicInfo.LastAccessTime; + pFileInfo->LastWriteTime = pVBoxFobx->FileBasicInfo.LastWriteTime; + pFileInfo->ChangeTime = pVBoxFobx->FileBasicInfo.ChangeTime; + pFileInfo->AllocationSize.QuadPart = 0; /* This is a directory, attribute not needed. */ + pFileInfo->EndOfFile.QuadPart = 0; /* This is a directory, attribute not needed. */ + pFileInfo->FileAttributes = pVBoxFobx->FileBasicInfo.FileAttributes; + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNetworkOpenInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + default: + + Log(("VBOXSF: VBoxMRxQueryFileInformation: Invalid filesystem information class %d!\n", FunctionalityRequested)); + Status = STATUS_NOT_IMPLEMENTED; + goto end; + } + } + else /* Entry is a file. */ + { + cbHGCMBuffer = RT_MAX(cbMaxSize, PAGE_SIZE); + pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbHGCMBuffer); + + if (pHGCMBuffer == 0) + return STATUS_NO_MEMORY; + + Assert(pVBoxFobx && pNetRootExtension && pDeviceExtension); + vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, SHFL_INFO_GET | SHFL_INFO_FILE, &cbHGCMBuffer, (PSHFLDIRINFO)pHGCMBuffer); + + if (vboxRC != VINF_SUCCESS) + { + Status = VBoxErrorToNTStatus(vboxRC); + goto end; + } + + pFileEntry = (PRTFSOBJINFO)pHGCMBuffer; + Status = STATUS_SUCCESS; + + switch (FunctionalityRequested) + { + + case FileBasicInformation: + { + PFILE_BASIC_INFORMATION pFileInfo = (PFILE_BASIC_INFORMATION)pInfoBuffer; + CopySize = sizeof(FILE_BASIC_INFORMATION); + + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileBasicInformation: Buffer = 0x%08x\n", pInfoBuffer)); + if (*pLengthRemaining >= CopySize) + { + pFileInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->BirthTime); /* Ridiculous name. */ + pFileInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->AccessTime); + pFileInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->ModificationTime); + pFileInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->ChangeTime); + + pFileInfo->FileAttributes = VBoxToNTFileAttributes(pFileEntry->Attr.fMode); + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileBasicInformation: File attributes = 0x%x\n", pFileInfo->FileAttributes)); + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileBasicInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileStandardInformation: + { + PFILE_STANDARD_INFORMATION pFileInfo = (PFILE_STANDARD_INFORMATION)pInfoBuffer; + CopySize = sizeof(FILE_STANDARD_INFORMATION); + + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileStandardInformation: Buffer = 0x%08x\n", pInfoBuffer)); + if (*pLengthRemaining >= CopySize) + { + pFileInfo->AllocationSize.QuadPart = pFileEntry->cbAllocated; + pFileInfo->EndOfFile.QuadPart = pFileEntry->cbObject; + + pFileInfo->NumberOfLinks = 1; /* @todo 0? */ + pFileInfo->DeletePending = FALSE; + + if (pFileEntry->Attr.fMode & RTFS_DOS_DIRECTORY) + pFileInfo->Directory = TRUE; + else pFileInfo->Directory = FALSE; + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileStandardInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileNamesInformation: + { + PFILE_NAMES_INFORMATION pFileInfo = (PFILE_NAMES_INFORMATION)pInfoBuffer; + + CopySize = sizeof(FILE_NAMES_INFORMATION); + + /* Struct already contains one char for null terminator */ + CopySize += (FileName->Length + 1) * sizeof(WCHAR); + + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNamesInformation: Buffer = 0x%08x\n", pInfoBuffer)); + if (*pLengthRemaining >= CopySize) + { + RtlZeroMemory (pFileInfo, CopySize); + + pFileInfo->FileIndex = 0; + pFileInfo->FileNameLength = FileName->Length * sizeof(WCHAR); + RtlCopyMemory(pFileInfo->FileName, FileName->Buffer, pFileInfo->FileNameLength); + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNamesInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileInternalInformation: + { + PFILE_INTERNAL_INFORMATION UsersBuffer = (PFILE_INTERNAL_INFORMATION)pInfoBuffer; + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileInternalInformation: Buffer = 0x%08x\n", pInfoBuffer)); + + /* Note: We use the address of the FCB to determine the + index number of the file. If we have to maintain persistance between + file opens for this request, then we might have to do something + like checksuming the reserved fields on a FUNIQUE SMB response. + + NT64: the address of capFcb used to be stuffed into + IndexNumber.LowPart, with HighPart being zeroed. + + Whoever is asking for this pointer value should be + prepared to deal with the returned 64-bit value. */ + CopySize = sizeof(FILE_INTERNAL_INFORMATION); + + if (*pLengthRemaining >= CopySize) + { + UsersBuffer->IndexNumber.QuadPart = (ULONG_PTR)capFcb; + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileInternalInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileEaInformation: + { + PFILE_EA_INFORMATION EaBuffer = (PFILE_EA_INFORMATION)pInfoBuffer; + + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileEaInformation: Buffer = 0x%08x\n", pInfoBuffer)); + CopySize = sizeof(FILE_EA_INFORMATION); + + if (*pLengthRemaining >= CopySize) + { + EaBuffer->EaSize = 0; + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileEaInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileAttributeTagInformation: + { + PFILE_ATTRIBUTE_TAG_INFORMATION pAttrTag = (PFILE_ATTRIBUTE_TAG_INFORMATION)pInfoBuffer; + + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileAttributeTagInformation: Buffer = 0x%08x\n", pInfoBuffer)); + CopySize = sizeof(FILE_ATTRIBUTE_TAG_INFORMATION); + if (*pLengthRemaining >= CopySize) + { + pAttrTag->FileAttributes = VBoxToNTFileAttributes(pFileEntry->Attr.fMode); + pAttrTag->ReparseTag = 0; + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileAttributeTagInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileEndOfFileInformation: + { + PFILE_END_OF_FILE_INFORMATION pEndOfFileInfo = (PFILE_END_OF_FILE_INFORMATION)pInfoBuffer; + + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileEndOfFileInformation: Buffer = %08x\n", pInfoBuffer)); + + CopySize = sizeof(FILE_END_OF_FILE_INFORMATION); + if (*pLengthRemaining >= CopySize) + { + pEndOfFileInfo->EndOfFile.QuadPart = pFileEntry->cbObject; + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileEndOfFileInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileAllocationInformation: + { + PFILE_ALLOCATION_INFORMATION pAllocInfo = (PFILE_ALLOCATION_INFORMATION)pInfoBuffer; + + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileAllocationInformation: Buffer = 0x%08x\n", pInfoBuffer)); + + CopySize = sizeof(FILE_ALLOCATION_INFORMATION); + if (*pLengthRemaining >= CopySize) + { + pAllocInfo->AllocationSize.QuadPart = pFileEntry->cbAllocated; + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileAllocationInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + case FileNetworkOpenInformation: + { + PFILE_NETWORK_OPEN_INFORMATION pFileInfo = (PFILE_NETWORK_OPEN_INFORMATION)pInfoBuffer; + CopySize = sizeof(FILE_NETWORK_OPEN_INFORMATION); + + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNetworkOpenInformation: Buffer = 0x%08x\n", pInfoBuffer)); + if (*pLengthRemaining >= CopySize) + { + pFileInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->BirthTime); /* Ridiculous name. */ + pFileInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->AccessTime); + pFileInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->ModificationTime); + pFileInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->ChangeTime); + pFileInfo->AllocationSize.QuadPart = pFileEntry->cbAllocated; + pFileInfo->EndOfFile.QuadPart = pFileEntry->cbObject; + pFileInfo->FileAttributes = VBoxToNTFileAttributes(pFileEntry->Attr.fMode); + } + else + { + Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNetworkOpenInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + + default: + Log(("VBOXSF: VBoxMRxQueryFileInformation: Unknown functionality requested (0x%x)!\n", FunctionalityRequested)); + Status = STATUS_NOT_IMPLEMENTED; + goto end; + } + } + + if (Status == STATUS_SUCCESS) + { + if (*pLengthRemaining < CopySize) + { + /* This situation must be already taken into account by the above code. */ + AssertMsgFailed(("VBOXSF: VBoxMRxQueryFileInformation: Length remaing is below 0! (%d - %d)!\n", *pLengthRemaining, CopySize)); + Status = STATUS_BUFFER_TOO_SMALL; + } + else + { + pInfoBuffer += CopySize; + *pLengthRemaining -= CopySize; + } + } + + end: if (Status == STATUS_BUFFER_TOO_SMALL) + RxContext->InformationToReturn = CopySize; + + if (pHGCMBuffer) + vbsfFreeNonPagedMem(pHGCMBuffer); + + if (Status == STATUS_SUCCESS) + Log(("VBOXSF: VBoxMRxQueryFileInformation: Success! Remaining length = %d\n", *pLengthRemaining)); + + Log(("VBOXSF: VBoxMRxQueryFileInformation: Returned 0x%x\n", Status)); + return Status; +} + +NTSTATUS VBoxMRxSetFileInformation (IN PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine does a set file info. Only the NT-->NT path is implemented. + + The NT-->NT path works by just remoting the call basically without further ado. + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + RxCaptureFcb; + RxCaptureFobx; + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); + VBoxMRxGetNetRootExtension(capFcb->pNetRoot, pNetRootExtension); + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + FILE_INFORMATION_CLASS FunctionalityRequested = RxContext->Info.FileInformationClass; + PVOID pBuffer = (PVOID)RxContext->Info.Buffer; + uint8_t *pHGCMBuffer = 0; + uint32_t cbBuffer = 0; + int vboxRC; + + Log(("VBOXSF: VBoxMRxSetFileInformation called.\n")); + + switch (FunctionalityRequested) + { + case FileBasicInformation: + { + PFILE_BASIC_INFORMATION pFileInfo = (PFILE_BASIC_INFORMATION)pBuffer; + PRTFSOBJINFO pSHFLFileInfo; + + Log(("VBOXSF: VBoxMRxSetFileInformation: FileBasicInformation: CreationTime %RX64\n", pFileInfo->CreationTime.QuadPart)); + Log(("VBOXSF: VBoxMRxSetFileInformation: FileBasicInformation: LastAccessTime %RX64\n", pFileInfo->LastAccessTime.QuadPart)); + Log(("VBOXSF: VBoxMRxSetFileInformation: FileBasicInformation: LastWriteTime %RX64\n", pFileInfo->LastWriteTime.QuadPart)); + Log(("VBOXSF: VBoxMRxSetFileInformation: FileBasicInformation: ChangeTime %RX64\n", pFileInfo->ChangeTime.QuadPart)); + Log(("VBOXSF: VBoxMRxSetFileInformation: FileBasicInformation: FileAttributes %RX32\n", pFileInfo->FileAttributes)); + + /* When setting file attributes, a value of -1 indicates to the server that it MUST NOT change this attribute + * for all subsequent operations on the same file handle. + */ + if (pFileInfo->CreationTime.QuadPart == -1) + { + pVBoxFobx->fKeepCreationTime = TRUE; + } + if (pFileInfo->LastAccessTime.QuadPart == -1) + { + pVBoxFobx->fKeepLastAccessTime = TRUE; + } + if (pFileInfo->LastWriteTime.QuadPart == -1) + { + pVBoxFobx->fKeepLastWriteTime = TRUE; + } + if (pFileInfo->ChangeTime.QuadPart == -1) + { + pVBoxFobx->fKeepChangeTime = TRUE; + } + + cbBuffer = sizeof(RTFSOBJINFO); + pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbBuffer); + if (pHGCMBuffer == 0) + { + AssertFailed(); + return STATUS_NO_MEMORY; + } + RtlZeroMemory(pHGCMBuffer, cbBuffer); + pSHFLFileInfo = (PRTFSOBJINFO)pHGCMBuffer; + + Log(("VBOXSF: VBoxMRxSetFileInformation: FileBasicInformation: keeps %d %d %d %d\n", + pVBoxFobx->fKeepCreationTime, pVBoxFobx->fKeepLastAccessTime, pVBoxFobx->fKeepLastWriteTime, pVBoxFobx->fKeepChangeTime)); + + /* The properties, that need to be changed, are set to something other than zero */ + if (pFileInfo->CreationTime.QuadPart && !pVBoxFobx->fKeepCreationTime) + RTTimeSpecSetNtTime(&pSHFLFileInfo->BirthTime, pFileInfo->CreationTime.QuadPart); + if (pFileInfo->LastAccessTime.QuadPart && !pVBoxFobx->fKeepLastAccessTime) + RTTimeSpecSetNtTime(&pSHFLFileInfo->AccessTime, pFileInfo->LastAccessTime.QuadPart); + if (pFileInfo->LastWriteTime.QuadPart && !pVBoxFobx->fKeepLastWriteTime) + RTTimeSpecSetNtTime(&pSHFLFileInfo->ModificationTime, pFileInfo->LastWriteTime.QuadPart); + if (pFileInfo->ChangeTime.QuadPart && !pVBoxFobx->fKeepChangeTime) + RTTimeSpecSetNtTime(&pSHFLFileInfo->ChangeTime, pFileInfo->ChangeTime.QuadPart); + if (pFileInfo->FileAttributes) + pSHFLFileInfo->Attr.fMode = NTToVBoxFileAttributes(pFileInfo->FileAttributes); + + Assert(pVBoxFobx && pNetRootExtension && pDeviceExtension); + vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, SHFL_INFO_SET | SHFL_INFO_FILE, &cbBuffer, (PSHFLDIRINFO)pSHFLFileInfo); + AssertRC(vboxRC); + + if (vboxRC != VINF_SUCCESS) + { + Status = VBoxErrorToNTStatus(vboxRC); + goto end; + } + else + { + /* Update our internal copy */ + pVBoxFobx->FileBasicInfo = *pFileInfo; + } + + break; + } + + case FileDispositionInformation: + { + PFILE_DISPOSITION_INFORMATION pDispInfo = (PFILE_DISPOSITION_INFORMATION)pBuffer; + + Log(("VBOXSF: VBoxMRxSetFileInformation: FileDispositionInformation: Delete = %d\n", pDispInfo->DeleteFile)); + if (pDispInfo->DeleteFile && capFcb->OpenCount == 1) + Status = VBoxMRxRemove(RxContext); + else Status = STATUS_SUCCESS; + break; + } + + case FilePositionInformation: + { + PFILE_POSITION_INFORMATION pPosInfo = (PFILE_POSITION_INFORMATION)pBuffer; + + Log(("VBOXSF: VBoxMRxSetFileInformation: FilePositionInformation: CurrentByteOffset = %RX64\n", pPosInfo->CurrentByteOffset.QuadPart)); + + /* Unsupported */ + Status = STATUS_INVALID_PARAMETER; + break; + } + + case FileAllocationInformation: + { + PFILE_ALLOCATION_INFORMATION pAllocInfo = (PFILE_ALLOCATION_INFORMATION)pBuffer; + + Log(("VBOXSF: VBoxMRxSetFileInformation: FileAllocationInformation: AllocSize = %RX64\n", pAllocInfo->AllocationSize.QuadPart)); + + /* Pretend success */ + Status = STATUS_SUCCESS; + break; + } + + case FileEndOfFileInformation: + { + PFILE_END_OF_FILE_INFORMATION pEndOfFileInfo = (PFILE_END_OF_FILE_INFORMATION)pBuffer; + LARGE_INTEGER NewAllocationSize; + + Log(("VBOXSF: VBoxMRxSetFileInformation: FileEndOfFileInformation: FileSize = %RX64\n", capFcb->Header.AllocationSize.QuadPart)); + if (pEndOfFileInfo->EndOfFile.QuadPart > capFcb->Header.AllocationSize.QuadPart) + { + Status = VBoxMRxExtendFile(RxContext, &pEndOfFileInfo->EndOfFile, &NewAllocationSize); + + Log(("VBOXSF: VBoxMRxSetFileInformation: FileEndOfFileInformation: AllocSize = %d AllocSizeHigh = %d\n", NewAllocationSize.LowPart, NewAllocationSize.HighPart)); + + // + // Change the file allocation + // + capFcb->Header.AllocationSize.QuadPart = NewAllocationSize.QuadPart; + } + else + { + Status = VBoxMRxSetEndOfFile(RxContext, &pEndOfFileInfo->EndOfFile, &NewAllocationSize); + } + /** @todo is this really necessary? */ + RxContext->Info.LengthRemaining -= sizeof(FILE_END_OF_FILE_INFORMATION); + break; + } + + case FileLinkInformation: + { + PFILE_RENAME_INFORMATION pRenameInfo = (PFILE_RENAME_INFORMATION)pBuffer; + + Log( + ("VBOXSF: VBoxMRxSetFileInformation: FileLinkInformation: ReplaceIfExists = %d, RootDirectory = 0x%x = %.*ls\n", pRenameInfo->ReplaceIfExists, pRenameInfo->RootDirectory, pRenameInfo->FileNameLength + / sizeof(WCHAR), pRenameInfo->FileName)); + Status = STATUS_NOT_IMPLEMENTED; + break; + } + + case FileRenameInformation: + { + PFILE_RENAME_INFORMATION pRenameInfo = (PFILE_RENAME_INFORMATION)pBuffer; + + Log( + ("VBOXSF: VBoxMRxSetFileInformation: FileRenameInformation: ReplaceIfExists = %d, RootDirectory = 0x%x = %.*ls\n", pRenameInfo->ReplaceIfExists, pRenameInfo->RootDirectory, pRenameInfo->FileNameLength + / sizeof(WCHAR), pRenameInfo->FileName)); + Status = VBoxMRxRename(RxContext, FileRenameInformation, pBuffer, RxContext->Info.Length); + break; + } + + default: + Log(("VBOXSF: VBoxMRxSetFileInformation: Unknown functionality requested (0x%x)!\n", FunctionalityRequested)); + Status = STATUS_INVALID_PARAMETER; + break; + } + + end: + + if (pHGCMBuffer) + vbsfFreeNonPagedMem(pHGCMBuffer); + + Log(("VBOXSF: VBoxMRxSetFileInformation: Returned 0x%x\n", Status)); + return Status; +} + +NTSTATUS VBoxMRxSetFileInformationAtCleanup (IN PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine sets the file information on cleanup. the old rdr just swallows this operation (i.e. + it doesn't generate it). we are doing the same.......... + + Arguments: + + pRxContext - the RDBSS context + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + + Log(("VBOXSF: VBoxMRxSetFileInformationAtCleanup\n")); + return (Status); +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/init.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/init.c new file mode 100644 index 00000000000..01f5188b724 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/init.c @@ -0,0 +1,1771 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + Init.c + + Abstract: + + This module implements the DRIVER_INITIALIZATION routine for + the null mini rdr. + + --*/ + +#include "precomp.h" +#include "rdbss_vbox.h" +#pragma hdrstop + +#include "ntverp.h" +#include "nulmrx.h" + +#ifdef VBOX +#include "VBoxGuestR0LibSharedFolders.h" + +#if defined(DEBUG) || defined (LOG_ENABLED) +static PCHAR MajorFunctionString(UCHAR MajorFunction, LONG MinorFunction); +#endif +#endif + +// +// Global data declarations. +// + +MRX_VBOX_STATE VBoxMRxState = MRX_VBOX_STARTABLE; + +// +// Mini Redirector global variables. +// + +// +// LogRate +// +ULONG LogRate = 0; + +// +// This is the minirdr dispatch table. It is initialized by +// VBoxMRxInitializeTables. This table will be used by the wrapper to call +// into this minirdr +// + +struct _MINIRDR_DISPATCH VBoxMRxDispatch; + +// +// Pointer to the device Object for this minirdr. Since the device object is +// created by the wrapper when this minirdr registers, this pointer is +// initialized in the DriverEntry routine below (see RxRegisterMinirdr) +// + +PRDBSS_DEVICE_OBJECT VBoxMRxDeviceObject; + +#define VBOX_SF_STATIC_LIB + +// +// declare the shadow debugtrace controlpoints +// + +RXDT_DefineCategory (CREATE); +RXDT_DefineCategory (CLEANUP); +RXDT_DefineCategory (CLOSE); +RXDT_DefineCategory (READ); +RXDT_DefineCategory (WRITE); +RXDT_DefineCategory (LOCKCTRL); +RXDT_DefineCategory (FLUSH); +RXDT_DefineCategory (PREFIX); +RXDT_DefineCategory (FCBSTRUCTS); +RXDT_DefineCategory (DISPATCH); +RXDT_DefineCategory (EA); +RXDT_DefineCategory (DEVFCB); +RXDT_DefineCategory (INIT); + +// +// The following enumerated values signify the current state of the minirdr +// initialization. With the aid of this state information, it is possible +// to determine which resources to deallocate, whether deallocation comes +// as a result of a normal stop/unload, or as the result of an exception +// + +typedef enum _MRX_VBOX_INIT_STATES +{ + MRX_VBOXINIT_UNINT, MRX_VBOXINIT_ALL_INITIALIZATION_COMPLETED, MRX_VBOXINIT_MINIRDR_REGISTERED, MRX_VBOXINIT_START +} MRX_VBOX_INIT_STATES; + +// +// function prototypes +// + +NTSTATUS VBoxMRxInitializeTables (void); + +VOID VBoxMRxUnload (IN PDRIVER_OBJECT DriverObject); + +VOID VBoxMRxInitUnwind (IN PDRIVER_OBJECT DriverObject, IN MRX_VBOX_INIT_STATES VBoxMRxInitState); + +NTSTATUS VBoxMRxFsdDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); + +VOID VBoxMRxReadRegistryParameters (); + +#ifdef VBOX +static int +vboxCtlGuestFilterMask (uint32_t u32OrMask, uint32_t u32NotMask) +{ + int rc; + VMMDevCtlGuestFilterMask *req; + + rc = VbglGRAlloc ((VMMDevRequestHeader**) &req, sizeof (*req), + VMMDevReq_CtlGuestFilterMask); + + if (RT_FAILURE (rc)) + { + Log (("VBOXSF: vboxCtlGuestFilterMask: " + "VbglGRAlloc (CtlGuestFilterMask) failed rc=%Rrc\n", rc)); + return -1; + } + + req->u32OrMask = u32OrMask; + req->u32NotMask = u32NotMask; + + rc = VbglGRPerform (&req->header); + VbglGRFree (&req->header); + if (RT_FAILURE (rc)) + { + Log (("VBOXSF: vboxCtlGuestFilterMask: " + "VbglGRPerform (CtlGuestFilterMask) failed rc=%Rrc\n", rc)); + return -1; + } + return 0; +} +#endif + +static PFAST_IO_DISPATCH pfnRDBSSTable = NULL; + +BOOLEAN VBoxMrxFastIoRead (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject) +{ +#ifdef VBOX_FAIL_FASTIO + Log(("VBOXSF: VBoxMrxFastIoRead\n")); + IoStatus->Information = 0; + IoStatus->Status = STATUS_NOT_IMPLEMENTED; + return FALSE; +#else + BOOLEAN ret = FALSE; + + Log(("VBOXSF: VBoxMrxFastIoRead: FileObject = 0x%x, QuadPart = %RX64, Len = %d, Buffer = 0x%x\n", FileObject, FileOffset->QuadPart, Length, Buffer)); + if (pfnRDBSSTable && pfnRDBSSTable->FastIoRead) + { + /* Necessary to satisfy the driver verifier. APCs must be turned off when ExAcquireResourceExclusiveLite is called */ + FsRtlEnterFileSystem(); + ret = pfnRDBSSTable->FastIoRead(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject); + FsRtlExitFileSystem(); + } + + Log(("VBOXSF: VBoxMrxFastIoRead: Returned 0x%x\n", ret)); + return ret; +#endif /* !VBOX_FAIL_FASTIO */ +} + +BOOLEAN VBoxMrxFastIoWrite (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject) +{ +#ifdef VBOX_FAIL_FASTIO + Log(("VBOXSF: VBoxMrxFastIoWrite\n")); + IoStatus->Information = 0; + IoStatus->Status = STATUS_NOT_IMPLEMENTED; + return FALSE; +#else + BOOLEAN ret = FALSE; + + Log(("VBOXSF: VBoxMrxFastIoWrite: FileObject = 0x%x, QuadPart = %RX64, Len = %d, Buffer = 0x%x\n", FileObject, FileOffset->QuadPart, Length, Buffer)); + if (pfnRDBSSTable && pfnRDBSSTable->FastIoWrite) + { + /* Necessary to satisfy the driver verifier. APCs must be turned off when ExAcquireResourceExclusiveLite is called */ + FsRtlEnterFileSystem(); + ret = pfnRDBSSTable->FastIoWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject); + FsRtlExitFileSystem(); + } + + Log(("VBOXSF: VBoxMrxFastIoWrite: Returned 0x%x\n", ret)); + return ret; +#endif /* !VBOX_FAIL_FASTIO */ +} + +BOOLEAN VBoxMrxFastIoCheckIfPossible (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN BOOLEAN CheckForReadOperation, + OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->FastIoCheckIfPossible) + { + ret = pfnRDBSSTable->FastIoCheckIfPossible(FileObject, FileOffset, Length, Wait, LockKey, CheckForReadOperation, IoStatus, DeviceObject); + Log(("VBOXSF: VBoxMrxFastIoCheckIfPossible: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxFastIoQueryBasicInfo (IN struct _FILE_OBJECT *FileObject, IN BOOLEAN Wait, OUT PFILE_BASIC_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->FastIoQueryBasicInfo) + { + ret = pfnRDBSSTable->FastIoQueryBasicInfo(FileObject, Wait, Buffer, IoStatus, DeviceObject); + Log(("VBOXSF: VBoxMrxFastIoQueryBasicInfo: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxFastIoQueryStandardInfo (IN struct _FILE_OBJECT *FileObject, IN BOOLEAN Wait, OUT PFILE_STANDARD_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->FastIoQueryStandardInfo) + { + ret = pfnRDBSSTable->FastIoQueryStandardInfo(FileObject, Wait, Buffer, IoStatus, DeviceObject); + Log(("VBOXSF: VBoxMrxFastIoQueryStandardInfo: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxFastIoLock (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key, BOOLEAN FailImmediately, BOOLEAN ExclusiveLock, + OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->FastIoLock) + { + ret = pfnRDBSSTable->FastIoLock(FileObject, FileOffset, Length, ProcessId, Key, FailImmediately, ExclusiveLock, IoStatus, DeviceObject); + Log(("VBOXSF: VBoxMrxFastIoLock: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxFastIoUnlockSingle (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->FastIoUnlockSingle) + { + ret = pfnRDBSSTable->FastIoUnlockSingle(FileObject, FileOffset, Length, ProcessId, Key, IoStatus, DeviceObject); + Log(("VBOXSF: VBoxMrxFastIoUnlockSingle: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxFastIoUnlockAll (IN struct _FILE_OBJECT *FileObject, PEPROCESS ProcessId, OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->FastIoUnlockAll) + { + ret = pfnRDBSSTable->FastIoUnlockAll(FileObject, ProcessId, IoStatus, DeviceObject); + Log(("VBOXSF: VBoxMrxFastIoUnlockAll: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxFastIoUnlockAllByKey (IN struct _FILE_OBJECT *FileObject, PVOID ProcessId, ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->FastIoUnlockAllByKey) + { + ret = pfnRDBSSTable->FastIoUnlockAllByKey(FileObject, ProcessId, Key, IoStatus, DeviceObject); + Log(("VBOXSF: VBoxMrxFastIoUnlockAllByKey: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxFastIoDeviceControl (IN struct _FILE_OBJECT *FileObject, IN BOOLEAN Wait, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength, + IN ULONG IoControlCode, OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->FastIoDeviceControl) + { + ret = pfnRDBSSTable->FastIoDeviceControl(FileObject, Wait, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, IoControlCode, IoStatus, DeviceObject); + Log(("VBOXSF: VBoxMrxFastIoDeviceControl: Returned 0x%x\n", ret)); + } + return ret; +} + +VOID VBoxMrxAcquireFileForNtCreateSection (IN struct _FILE_OBJECT *FileObject) +{ + if (pfnRDBSSTable && pfnRDBSSTable->AcquireFileForNtCreateSection) + { + pfnRDBSSTable->AcquireFileForNtCreateSection(FileObject); + Log(("VBOXSF: VBoxMrxAcquireFileForNtCreateSection: Called.\n")); + } +} + +VOID VBoxMrxReleaseFileForNtCreateSection (IN struct _FILE_OBJECT *FileObject) +{ + if (pfnRDBSSTable && pfnRDBSSTable->ReleaseFileForNtCreateSection) + { + pfnRDBSSTable->ReleaseFileForNtCreateSection(FileObject); + Log(("VBOXSF: VBoxMrxReleaseFileForNtCreateSection: Called.\n")); + } +} + +VOID VBoxMrxFastIoDetachDevice (IN struct _DEVICE_OBJECT *SourceDevice, IN struct _DEVICE_OBJECT *TargetDevice) +{ + if (pfnRDBSSTable && pfnRDBSSTable->FastIoDetachDevice) + { + pfnRDBSSTable->FastIoDetachDevice(SourceDevice, TargetDevice); + Log(("VBOXSF: VBoxMrxFastIoDetachDevice: Called.\n")); + } +} + +BOOLEAN VBoxMrxFastIoQueryNetworkOpenInfo (IN struct _FILE_OBJECT *FileObject, IN BOOLEAN Wait, OUT struct _FILE_NETWORK_OPEN_INFORMATION *Buffer, OUT struct _IO_STATUS_BLOCK *IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->FastIoQueryNetworkOpenInfo) + { + ret = pfnRDBSSTable->FastIoQueryNetworkOpenInfo(FileObject, Wait, Buffer, IoStatus, DeviceObject); + Log(("VBOXSF: VBoxMrxFastIoQueryNetworkOpenInfo: Called.\n")); + } + return ret; +} + +BOOLEAN VBoxMrxMdlRead (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey, OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->MdlRead) + { + ret = pfnRDBSSTable->MdlRead(FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject); + Log(("VBOXSF: VBoxMrxMdlRead: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxMdlReadComplete (IN struct _FILE_OBJECT *FileObject, IN PMDL MdlChain, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->MdlReadComplete) + { + ret = pfnRDBSSTable->MdlReadComplete(FileObject, MdlChain, DeviceObject); + Log(("VBOXSF: VBoxMrxMdlReadComplete: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxPrepareMdlWrite (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey, OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->PrepareMdlWrite) + { + ret = pfnRDBSSTable->PrepareMdlWrite(FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject); + Log(("VBOXSF: VBoxMrxPrepareMdlWrite: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxMdlWriteComplete (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN PMDL MdlChain, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->MdlWriteComplete) + { + ret = pfnRDBSSTable->MdlWriteComplete(FileObject, FileOffset, MdlChain, DeviceObject); + Log(("VBOXSF: VBoxMrxMdlWriteComplete: Returned 0x%x\n", ret)); + } + return ret; +} + +NTSTATUS VBoxMrxAcquireForModWrite (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER EndingOffset, OUT struct _ERESOURCE **ResourceToRelease, IN struct _DEVICE_OBJECT *DeviceObject) +{ + NTSTATUS ret = STATUS_NOT_IMPLEMENTED; + + if (pfnRDBSSTable && pfnRDBSSTable->AcquireForModWrite) + { + ret = pfnRDBSSTable->AcquireForModWrite(FileObject, EndingOffset, ResourceToRelease, DeviceObject); + Log(("VBOXSF: VBoxMrxAcquireForModWrite: Returned 0x%x\n", ret)); + } + return ret; +} + +NTSTATUS VBoxMrxReleaseForModWrite (IN struct _FILE_OBJECT *FileObject, IN struct _ERESOURCE *ResourceToRelease, IN struct _DEVICE_OBJECT *DeviceObject) +{ + NTSTATUS ret = STATUS_NOT_IMPLEMENTED; + + if (pfnRDBSSTable && pfnRDBSSTable->ReleaseForModWrite) + { + ret = pfnRDBSSTable->ReleaseForModWrite(FileObject, ResourceToRelease, DeviceObject); + Log(("VBOXSF: VBoxMrxReleaseForModWrite: Returned 0x%x\n", ret)); + } + return ret; +} + +NTSTATUS VBoxMrxAcquireForCcFlush (IN struct _FILE_OBJECT *FileObject, IN struct _DEVICE_OBJECT *DeviceObject) +{ + NTSTATUS ret = STATUS_NOT_IMPLEMENTED; + + if (pfnRDBSSTable && pfnRDBSSTable->AcquireForCcFlush) + { + ret = pfnRDBSSTable->AcquireForCcFlush(FileObject, DeviceObject); + Log(("VBOXSF: VBoxMrxAcquireForCcFlush: Returned 0x%x\n", ret)); + } + return ret; +} + +NTSTATUS VBoxMrxReleaseForCcFlush (IN struct _FILE_OBJECT *FileObject, IN struct _DEVICE_OBJECT *DeviceObject) +{ + NTSTATUS ret = STATUS_NOT_IMPLEMENTED; + + if (pfnRDBSSTable && pfnRDBSSTable->ReleaseForCcFlush) + { + ret = pfnRDBSSTable->ReleaseForCcFlush(FileObject, DeviceObject); + Log(("VBOXSF: VBoxMrxReleaseForCcFlush: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxFastIoReadCompressed (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey, OUT PVOID Buffer, OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, OUT struct _COMPRESSED_DATA_INFO *CompressedDataInfo, IN ULONG CompressedDataInfoLength, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->FastIoReadCompressed) + { + ret = pfnRDBSSTable->FastIoReadCompressed(FileObject, FileOffset, Length, LockKey, Buffer, MdlChain, IoStatus, CompressedDataInfo, CompressedDataInfoLength, DeviceObject); + Log(("VBOXSF: VBoxMrxFastIoReadCompressed: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxFastIoWriteCompressed (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey, IN PVOID Buffer, OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, IN struct _COMPRESSED_DATA_INFO *CompressedDataInfo, IN ULONG CompressedDataInfoLength, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->FastIoWriteCompressed) + { + ret = pfnRDBSSTable->FastIoWriteCompressed(FileObject, FileOffset, Length, LockKey, Buffer, MdlChain, IoStatus, CompressedDataInfo, CompressedDataInfoLength, DeviceObject); + Log(("VBOXSF: VBoxMrxFastIoWriteCompressed: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxMdlReadCompleteCompressed (IN struct _FILE_OBJECT *FileObject, IN PMDL MdlChain, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->MdlReadCompleteCompressed) + { + ret = pfnRDBSSTable->MdlReadCompleteCompressed(FileObject, MdlChain, DeviceObject); + Log(("VBOXSF: VBoxMrxMdlReadCompleteCompressed: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxMdlWriteCompleteCompressed (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN PMDL MdlChain, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->MdlWriteCompleteCompressed) + { + ret = pfnRDBSSTable->MdlWriteCompleteCompressed(FileObject, FileOffset, MdlChain, DeviceObject); + Log(("VBOXSF: VBoxMrxMdlWriteCompleteCompressed: Returned 0x%x\n", ret)); + } + return ret; +} + +BOOLEAN VBoxMrxFastIoQueryOpen (IN struct _IRP *Irp, OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation, IN struct _DEVICE_OBJECT *DeviceObject) +{ + BOOLEAN ret = FALSE; + + if (pfnRDBSSTable && pfnRDBSSTable->FastIoQueryOpen) + { + ret = pfnRDBSSTable->FastIoQueryOpen(Irp, NetworkInformation, DeviceObject); + Log(("VBOXSF: VBoxMrxFastIoQueryOpen: Returned 0x%x\n", ret)); + } + return ret; +} + + +static FAST_IO_DISPATCH dispatchTable = +{ + sizeof(FAST_IO_DISPATCH), + VBoxMrxFastIoCheckIfPossible, + VBoxMrxFastIoRead, + VBoxMrxFastIoWrite, + VBoxMrxFastIoQueryBasicInfo, + VBoxMrxFastIoQueryStandardInfo, + VBoxMrxFastIoLock, + VBoxMrxFastIoUnlockSingle, + VBoxMrxFastIoUnlockAll, + VBoxMrxFastIoUnlockAllByKey, + VBoxMrxFastIoDeviceControl, + VBoxMrxAcquireFileForNtCreateSection, + VBoxMrxReleaseFileForNtCreateSection, + VBoxMrxFastIoDetachDevice, + VBoxMrxFastIoQueryNetworkOpenInfo, + VBoxMrxAcquireForModWrite, + VBoxMrxMdlRead, + VBoxMrxMdlReadComplete, + VBoxMrxPrepareMdlWrite, + VBoxMrxMdlWriteComplete, + VBoxMrxFastIoReadCompressed, + VBoxMrxFastIoWriteCompressed, + VBoxMrxMdlReadCompleteCompressed, + VBoxMrxMdlWriteCompleteCompressed, + VBoxMrxFastIoQueryOpen, + VBoxMrxReleaseForModWrite, + VBoxMrxAcquireForCcFlush, + VBoxMrxReleaseForCcFlush +}; + +static BOOL vboxIsPrefixOK (const WCHAR *FilePathName, ULONG PathNameLength) +{ + BOOL PrefixOK; + + /* The FilePathName here looks like: \vboxsrv\... */ + if (PathNameLength >= 8 * sizeof (WCHAR)) /* Number of bytes in '\vboxsrv'unicode string. */ + { + PrefixOK = (FilePathName[0] == L'\\'); + PrefixOK &= (FilePathName[1] == L'V') || (FilePathName[1] == L'v'); + PrefixOK &= (FilePathName[2] == L'B') || (FilePathName[2] == L'b'); + PrefixOK &= (FilePathName[3] == L'O') || (FilePathName[3] == L'o'); + PrefixOK &= (FilePathName[4] == L'X') || (FilePathName[4] == L'x'); + PrefixOK &= (FilePathName[5] == L'S') || (FilePathName[5] == L's'); + /* Both vboxsvr & vboxsrv are now accepted */ + if ((FilePathName[6] == L'V') || (FilePathName[6] == L'v')) + { + PrefixOK &= (FilePathName[6] == L'V') || (FilePathName[6] == L'v'); + PrefixOK &= (FilePathName[7] == L'R') || (FilePathName[7] == L'r'); + } + else + { + PrefixOK &= (FilePathName[6] == L'R') || (FilePathName[6] == L'r'); + PrefixOK &= (FilePathName[7] == L'V') || (FilePathName[7] == L'v'); + } + if (PathNameLength > 8 * sizeof (WCHAR)) + { + /* There is something after '\vboxsrv'. */ + PrefixOK &= (FilePathName[8] == L'\\') || (FilePathName[8] == 0); + } + } + else + { + PrefixOK = FALSE; + } + + return PrefixOK; +} + +#if 0 +static BOOL vboxIsPathToIntercept (const WCHAR *FilePathName, ULONG PathNameLength) +{ + BOOL PathToIntercept = FALSE; + + /* Detect '\vboxsrv' */ + if (PathNameLength == 8 * sizeof (WCHAR)) /* Number of bytes in '\vboxsrv' unicode string. */ + { + PathToIntercept = TRUE; + } + + if (!PathToIntercept) + { + /* Detect '\vboxsrv\ipc$' */ + if (PathNameLength >= 13 * sizeof (WCHAR)) /* Number of bytes in '\vboxsrv\ipc$' unicode string. */ + { + const WCHAR *FilePathNameSuffix = &FilePathName[8]; + + PathToIntercept = (FilePathNameSuffix[0] == L'\\'); + PathToIntercept &= (FilePathNameSuffix[1] == L'I') || (FilePathNameSuffix[1] == L'i'); + PathToIntercept &= (FilePathNameSuffix[2] == L'P') || (FilePathNameSuffix[2] == L'p'); + PathToIntercept &= (FilePathNameSuffix[3] == L'C') || (FilePathNameSuffix[3] == L'c'); + PathToIntercept &= (FilePathNameSuffix[4] == L'$') || (FilePathNameSuffix[4] == L'$'); + if (PathNameLength > 13 * sizeof (WCHAR)) + { + /* There is something after '\vboxsrv\IPC$'. */ + PathToIntercept &= (FilePathNameSuffix[5] == L'\\') || (FilePathNameSuffix[5] == 0); + } + } + } + + return PathToIntercept; +} +#endif + +static NTSTATUS VBoxMRXDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp) +{ + NTSTATUS Status = STATUS_SUCCESS; + + QUERY_PATH_REQUEST *pReq = NULL; + QUERY_PATH_REQUEST_EX *pReqEx = NULL; + QUERY_PATH_RESPONSE *pResp = NULL; + + BOOL PrefixOK = FALSE; + + PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp); + + /* Make a local copy, it will be needed after the Irp completion. */ + ULONG IoControlCode = pStack->Parameters.DeviceIoControl.IoControlCode; + + PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = (PMRX_VBOX_DEVICE_EXTENSION)((PBYTE)pDevObj + sizeof(RDBSS_DEVICE_OBJECT)); + + Log(("VBoxSF::VBoxMRXDeviceControl: pDevObj %p, pDeviceExtension %p, code %x\n", + pDevObj, pDevObj->DeviceExtension, IoControlCode)); + + switch (IoControlCode) + { + case IOCTL_REDIR_QUERY_PATH_EX: /* Vista */ + case IOCTL_REDIR_QUERY_PATH: /* XP and earlier */ + { + /* This IOCTL is intercepted for 2 reasons: + * 1) Claim the vboxsvr and vboxsrv prefixes. All name-based operations for them + * will be routed to the VBox provider automatically without any prefix resolution + * since the prefix is already in the prefix cache. + * 2) Reject other prefixes immediately to speed up the UNC path resolution a bit, + * because RDBSS will not be involved then. + */ + + const WCHAR *FilePathName = NULL; + ULONG PathNameLength = 0; + + if (pIrp->RequestorMode != KernelMode) + { + /* MSDN: Network redirectors should only honor kernel-mode senders of this IOCTL, by verifying + * that RequestorMode member of the IRP structure is KernelMode. + */ + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_REDIR_QUERY_PATH(_EX): not kernel mode!!!\n", + pStack->Parameters.DeviceIoControl.InputBufferLength)); + /* Continue to RDBSS. */ + break; + } + + if (IoControlCode == IOCTL_REDIR_QUERY_PATH) + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_REDIR_QUERY_PATH: Called (pid %x).\n", IoGetCurrentProcess())); + + if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(QUERY_PATH_REQUEST)) + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_REDIR_QUERY_PATH: short input buffer %d.\n", + pStack->Parameters.DeviceIoControl.InputBufferLength)); + /* Continue to RDBSS. */ + break; + } + + pReq = (QUERY_PATH_REQUEST *)pStack->Parameters.DeviceIoControl.Type3InputBuffer; + + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: PathNameLength = %d.\n", pReq->PathNameLength)); + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: SecurityContext = %p.\n", pReq->SecurityContext)); + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: FilePathName = %.*ls.\n", pReq->PathNameLength / sizeof (WCHAR), pReq->FilePathName)); + + FilePathName = pReq->FilePathName; + PathNameLength = pReq->PathNameLength; + } + else + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_REDIR_QUERY_PATH_EX: Called.\n")); + + if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(QUERY_PATH_REQUEST_EX)) + { + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_REDIR_QUERY_PATH_EX: short input buffer %d.\n", + pStack->Parameters.DeviceIoControl.InputBufferLength)); + /* Continue to RDBSS. */ + break; + } + + pReqEx = (QUERY_PATH_REQUEST_EX *)pStack->Parameters.DeviceIoControl.Type3InputBuffer; + + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: pSecurityContext = %p.\n", pReqEx->pSecurityContext)); + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: EaLength = %d.\n", pReqEx->EaLength)); + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: pEaBuffer = %p.\n", pReqEx->pEaBuffer)); + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: PathNameLength = %d.\n", pReqEx->PathName.Length)); + Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: FilePathName = %.*ls.\n", pReqEx->PathName.Length / sizeof (WCHAR), pReqEx->PathName.Buffer)); + + FilePathName = pReqEx->PathName.Buffer; + PathNameLength = pReqEx->PathName.Length; + } + + pResp = (QUERY_PATH_RESPONSE *)pIrp->UserBuffer; + + PrefixOK = vboxIsPrefixOK (FilePathName, PathNameLength); + Log(("VBoxSF::VBoxMRXDeviceControl PrefixOK %d\n", PrefixOK)); + + if (!PrefixOK) + { + /* Immediately fail the IOCTL with STATUS_BAD_NETWORK_NAME as recommended by MSDN. + * No need to involve RDBSS. + */ + Status = STATUS_BAD_NETWORK_NAME; + + pIrp->IoStatus.Status = Status; + pIrp->IoStatus.Information = 0; + + IoCompleteRequest(pIrp, IO_NO_INCREMENT); + + Log(("VBoxSF::VBoxMRXDeviceControl: returned STATUS_BAD_NETWORK_NAME\n")); + return Status; + } + + Log(("VBoxSF::VBoxMRXDeviceControl pResp %p verifying the path.\n", pResp)); + if (pResp) + { + /* Always claim entire \vboxsrv prefix. The LengthAccepted initially is equal to entire path. + * Here it is assigned to the length of \vboxsrv prefix. + */ + pResp->LengthAccepted = 8 * sizeof (WCHAR); + + Status = STATUS_SUCCESS; + + pIrp->IoStatus.Status = Status; + pIrp->IoStatus.Information = 0; + + IoCompleteRequest(pIrp, IO_NO_INCREMENT); + + Log(("VBoxSF::VBoxMRXDeviceControl: claiming the path.\n")); + return Status; + } + + /* No pResp pointer, should not happen. Just a precaution. */ + Status = STATUS_INVALID_PARAMETER; + + pIrp->IoStatus.Status = Status; + pIrp->IoStatus.Information = 0; + + IoCompleteRequest(pIrp, IO_NO_INCREMENT); + + Log(("VBoxSF::VBoxMRXDeviceControl: returned STATUS_INVALID_PARAMETER\n")); + return Status; + } + + default: + break; + } + + /* Pass the IOCTL to RDBSS. */ + if (pDeviceExtension && pDeviceExtension->pfnRDBSSDeviceControl) + { + Log(("VBoxSF::VBoxMRXDeviceControl calling RDBSS %p\n", pDeviceExtension->pfnRDBSSDeviceControl)); + Status = pDeviceExtension->pfnRDBSSDeviceControl (pDevObj, pIrp); + Log(("VBoxSF::VBoxMRXDeviceControl RDBSS status %x\n", Status)); + } + else + { + /* No RDBSS, should not happen. Just a precaution. */ + Status = STATUS_NOT_IMPLEMENTED; + + pIrp->IoStatus.Status = Status; + pIrp->IoStatus.Information = 0; + + IoCompleteRequest(pIrp, IO_NO_INCREMENT); + + Log(("VBoxSF::VBoxMRXDeviceControl: returned STATUS_NOT_IMPLEMENTED\n")); + } + + return Status; +} + + +NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +/*++ + + Routine Description: + + This is the initialization routine for the mini redirector + + Arguments: + + DriverObject - Pointer to driver object created by the system. + + Return Value: + + RXSTATUS - The function value is the final status from the initialization + operation. + + --*/ +{ + NTSTATUS Status; + ULONG Controls = 0; + MRX_VBOX_INIT_STATES VBoxMRxInitState = MRX_VBOXINIT_UNINT; + UNICODE_STRING VBoxMRxName; + UNICODE_STRING UserModeDeviceName; + PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension; + ULONG i; +#ifdef VBOX + int vboxRC; + VBSFCLIENT hgcmClient = + { 0}; +#endif + + Log(("VBOXSF: DriverEntry: Driver object 0x%08lx loaded!\n", DriverObject)); + +#ifdef VBOX + /* Initialize VBox subsystem. */ + vboxRC = vboxInit(); + if (RT_FAILURE(vboxRC)) + { + Status = STATUS_UNSUCCESSFUL; + Log(("VBOXSF: DriverEntry: ERROR while initializing Vbox subsystem (%Rrc)!\n", vboxRC)); + return Status; + } + + /* Set filter mask */ + if (vboxCtlGuestFilterMask (VMMDEV_EVENT_HGCM, 0)) /** @todo r=bird: Why are we doing this? And more importantely, why are we clearing it further down. We're not the only HGCM user, are we? */ + { + Log (("VBOXSF: DriverEntry: ERROR while setting guest event filter mask!\n")); + return STATUS_UNSUCCESSFUL; + } + + /* Connect the HGCM client */ + vboxRC = vboxConnect(&hgcmClient); + if (RT_FAILURE (vboxRC)) + { + Status = STATUS_UNSUCCESSFUL; + Log(("VBOXSF: DriverEntry: ERROR while connecting to host (%Rrc)!\n", vboxRC)); + vboxCtlGuestFilterMask (0, VMMDEV_EVENT_HGCM); + vboxUninit(); + return Status; + } +#endif + + if (DriverObject == NULL) + { + Status = STATUS_UNSUCCESSFUL; + Log(("VBOXSF: DriverEntry: Invalid driver object detected!\n")); + vboxCtlGuestFilterMask(0, VMMDEV_EVENT_HGCM); + vboxUninit(); + return Status; + } + + // + // Setup Unload Routine + // + + DriverObject->DriverUnload = VBoxMRxUnload; + DriverObject->FastIoDispatch = NULL; + DriverObject->DriverStartIo = NULL; + + // + //setup the driver dispatch for people who come in here directly....like the browser + // + + for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) + { + DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)VBoxMRxFsdDispatch; + } + +#ifdef VBOX_SF_STATIC_LIB + Status = RxDriverEntry(DriverObject, RegistryPath); + if (Status != STATUS_SUCCESS) + { + Log(("VBOXSF: DriverEntry: Wrapper failed to initialize. Status = 0x%08lx\n", Status)); + goto failure; + } +#endif + + try + { + VBoxMRxInitState = MRX_VBOXINIT_START; + + // + // Register this minirdr with the connection engine. Registration makes the connection + // engine aware of the device name, driver object, and other characteristics. + // If registration is successful, a new device object is returned + // + // + + + RtlInitUnicodeString(&VBoxMRxName, DD_MRX_VBOX_FS_DEVICE_NAME_U); + /* don't set RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS or else UNC mappings don't work (including Windows explorer browsing) */ + + /** @todo set RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER and the system will crash on boot */ + SetFlag(Controls,RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS); + + Status = VBoxRxRegisterMinirdr( + &VBoxMRxDeviceObject, // where the new device object goes + DriverObject, // the Driver Object to register + &VBoxMRxDispatch, // the dispatch table for this driver + Controls, // dont register with unc and for mailslots + &VBoxMRxName, // the device name for this minirdr + sizeof(MRX_VBOX_DEVICE_EXTENSION), // IN ULONG DeviceExtensionSize, + FILE_DEVICE_NETWORK_FILE_SYSTEM, // IN ULONG DeviceType - disk ? + FILE_REMOTE_DEVICE // IN ULONG DeviceCharacteristics + ); + + if (Status!=STATUS_SUCCESS) + { + Log(("VBOXSF: DriverEntry: Registering mini reader failed: 0x%08lx!\n", Status )); + try_return(Status); + } + + // + // Init the device extension data + // NOTE: the device extension actually points to fields + // in the RDBSS_DEVICE_OBJECT. Our space is past the end + // of this struct !! + // + + pDeviceExtension = (PMRX_VBOX_DEVICE_EXTENSION) + ((PBYTE)(VBoxMRxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT)); + + pDeviceExtension->pDeviceObject = VBoxMRxDeviceObject; + + // initialize local connection list + for (i = 0; i < RTL_NUMBER_OF(pDeviceExtension->cLocalConnections); i++) + { + pDeviceExtension->cLocalConnections[i] = FALSE; + } + // Mutex for synchronizining our connection list + ExInitializeFastMutex( &pDeviceExtension->mtxLocalCon ); + + // The device object has been created. Need to setup a symbolic + // link so that the device may be accessed from a Win32 user mode + // application. + + RtlInitUnicodeString(&UserModeDeviceName, DD_MRX_VBOX_USERMODE_SHADOW_DEV_NAME_U); + Log(("VBOXSF: DriverEntry: Calling IoCreateSymbolicLink ...\n")); + Status = IoCreateSymbolicLink( &UserModeDeviceName, &VBoxMRxName); + if (Status != STATUS_SUCCESS) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Failed calling IoCreateSymbolicLink: 0x%08lx\n", Status )); + try_return(Status); + } + Log(("VBOXSF: DriverEntry: Symbolic link created.\n")); + + VBoxMRxInitState = MRX_VBOXINIT_MINIRDR_REGISTERED; + + // + // Build the dispatch tables for the minirdr + // + + Status = VBoxMRxInitializeTables(); + + if (!NT_SUCCESS( Status )) + { + Log(("VBOXSF: VBoxMRxDriverEntry: VBoxMRxInitializeTables failed: 0x%08lx\n", Status )); + try_return(Status); + } + + // + // Get information from the registry + // + VBoxMRxReadRegistryParameters(); + + Log(("VBOXSF: VBoxMRxDriverEntry: First phase done!\n")); + + try_exit: + NOTHING; + } + finally + { + if (Status != STATUS_SUCCESS) + { + VBoxMRxInitUnwind(DriverObject,VBoxMRxInitState); + } + } + + if (Status != STATUS_SUCCESS) + { + + Log(("VBOXSF: VBoxMRxDriverEntry: VBoxSF.sys failed to start with Status = 0x%08lx, VBoxMRxInitState = 0x%08lx\n", Status, VBoxMRxInitState)); + goto failure; + } + +#ifdef VBOX + pDeviceExtension->pDriverObject = DriverObject; + pDeviceExtension->hgcmClient = hgcmClient; +#endif + + Log(("VBOXSF: VBoxMRxDriverEntry: FastIoDispatch address = 0x%x, DriverStartIo address = 0x%x\n", DriverObject->FastIoDispatch, DriverObject->DriverStartIo)); + + /* Wrap the fast io path */ + if (DriverObject->FastIoDispatch) + { + Log(("VBOXSF: VBoxMRxDriverEntry: SizeOfFastIoDispatch = 0x%x (expected = 0x%x)\n", DriverObject->FastIoDispatch->SizeOfFastIoDispatch, sizeof(dispatchTable))); + pfnRDBSSTable = DriverObject->FastIoDispatch; + DriverObject->FastIoDispatch = &dispatchTable; + + if (pfnRDBSSTable->FastIoCheckIfPossible == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoCheckIfPossible == NULL\n")); + dispatchTable.FastIoCheckIfPossible = NULL; + } + if (pfnRDBSSTable->FastIoRead == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoRead == NULL\n")); + dispatchTable.FastIoRead = NULL; + } + if (pfnRDBSSTable->FastIoWrite == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoWrite == NULL\n")); + dispatchTable.FastIoWrite = NULL; + } + if (pfnRDBSSTable->FastIoQueryBasicInfo == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoQueryBasicInfo == NULL\n")); + dispatchTable.FastIoQueryBasicInfo = NULL; + } + if (pfnRDBSSTable->FastIoQueryStandardInfo == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoQueryStandardInfo == NULL\n")); + dispatchTable.FastIoQueryStandardInfo = NULL; + } + if (pfnRDBSSTable->FastIoLock == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoLock == NULL\n")); + dispatchTable.FastIoLock = NULL; + } + if (pfnRDBSSTable->FastIoUnlockSingle == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoUnlockSingle == NULL\n")); + dispatchTable.FastIoUnlockSingle = NULL; + } + if (pfnRDBSSTable->FastIoUnlockAll == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoUnlockAll == NULL\n")); + dispatchTable.FastIoUnlockAll = NULL; + } + if (pfnRDBSSTable->FastIoUnlockAllByKey == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoUnlockAllByKey == NULL\n")); + dispatchTable.FastIoUnlockAllByKey = NULL; + } + if (pfnRDBSSTable->FastIoDeviceControl == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoDeviceControl == NULL\n")); + dispatchTable.FastIoDeviceControl = NULL; + } + if (pfnRDBSSTable->AcquireFileForNtCreateSection == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: AcquireFileForNtCreateSection == NULL\n")); + dispatchTable.AcquireFileForNtCreateSection = NULL; + } + if (pfnRDBSSTable->ReleaseFileForNtCreateSection == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: ReleaseFileForNtCreateSection == NULL\n")); + dispatchTable.ReleaseFileForNtCreateSection = NULL; + } + if (pfnRDBSSTable->FastIoDetachDevice == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoDetachDevice == NULL\n")); + dispatchTable.FastIoDetachDevice = NULL; + } + if (pfnRDBSSTable->FastIoQueryNetworkOpenInfo == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoQueryNetworkOpenInfo == NULL\n")); + dispatchTable.FastIoQueryNetworkOpenInfo = NULL; + } + if (pfnRDBSSTable->AcquireForModWrite == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: AcquireForModWrite == NULL\n")); + dispatchTable.AcquireForModWrite = NULL; + } + if (pfnRDBSSTable->MdlRead == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: MdlRead == NULL\n")); + dispatchTable.MdlRead = NULL; + } + if (pfnRDBSSTable->MdlReadComplete == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: MdlReadComplete == NULL\n")); + dispatchTable.MdlReadComplete = NULL; + } + if (pfnRDBSSTable->PrepareMdlWrite == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: PrepareMdlWrite == NULL\n")); + dispatchTable.PrepareMdlWrite = NULL; + } + if (pfnRDBSSTable->MdlWriteComplete == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: MdlWriteComplete == NULL\n")); + dispatchTable.MdlWriteComplete = NULL; + } + if (pfnRDBSSTable->FastIoReadCompressed == NULL) + { + Log(("VVBOXSF: VBoxMRxDriverEntry: Function Table: FastIoReadCompressed == NULL\n")); + dispatchTable.FastIoReadCompressed = NULL; + } + if (pfnRDBSSTable->FastIoWriteCompressed == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoWriteCompressed == NULL\n")); + dispatchTable.FastIoWriteCompressed = NULL; + } + if (pfnRDBSSTable->MdlReadCompleteCompressed == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: MdlReadCompleteCompressed == NULL\n")); + dispatchTable.MdlReadCompleteCompressed = NULL; + } + if (pfnRDBSSTable->MdlWriteCompleteCompressed == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: MdlWriteCompleteCompressed == NULL\n")); + dispatchTable.MdlWriteCompleteCompressed = NULL; + } + if (pfnRDBSSTable->FastIoQueryOpen == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoQueryOpen == NULL\n")); + dispatchTable.FastIoQueryOpen = NULL; + } + if (pfnRDBSSTable->ReleaseForModWrite == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: ReleaseForModWrite == NULL\n")); + dispatchTable.ReleaseForModWrite = NULL; + } + if (pfnRDBSSTable->AcquireForCcFlush == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: AcquireForCcFlush == NULL\n")); + dispatchTable.AcquireForCcFlush = NULL; + } + if (pfnRDBSSTable->ReleaseForCcFlush == NULL) + { + Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: ReleaseForCcFlush == NULL\n")); + dispatchTable.ReleaseForCcFlush = NULL; + } + } + + /* The redirector driver must intercept the IOCTL to avoid VBOXSVR name resolution + * by other redirectors. These additional name resolutions cause long delays. + */ + Log(("VBOXSF: VBoxMRxDriverEntry: VBoxMRxDeviceObject = %p, rdbss %p, devext %p\n", + VBoxMRxDeviceObject, DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL], pDeviceExtension)); + pDeviceExtension->pfnRDBSSDeviceControl = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxMRXDeviceControl; + + Log(("VBOXSF: VBoxMRxDriverEntry: Init successful!\n")); + return STATUS_SUCCESS; + + failure: + +#ifdef VBOX + Log(("VBOXSF: VBoxMRxDriverEntry: Failure! Status = 0x%08X\n", Status)); + + vboxDisconnect (&hgcmClient); + vboxCtlGuestFilterMask (0, VMMDEV_EVENT_HGCM); + vboxUninit(); +#endif + VBoxMRxInitUnwind(DriverObject, VBoxMRxInitState); + + return Status; +} + +VOID VBoxMRxInitUnwind (IN PDRIVER_OBJECT DriverObject, IN MRX_VBOX_INIT_STATES VBoxMRxInitState) +/*++ + + Routine Description: + + This routine does the common uninit work for unwinding from a bad driver entry or for unloading. + + Arguments: + + VBoxMRxInitState - tells how far we got into the intialization + + Return Value: + + None + + --*/ + +{ + PAGED_CODE(); + + Log(("VBOXSF: VBoxMRxInitUnwind: VBoxMRxInitState = 0x%x\n", VBoxMRxInitState)); + switch (VBoxMRxInitState) + { + case MRX_VBOXINIT_ALL_INITIALIZATION_COMPLETED: + + //Nothing extra to do...this is just so that the constant in RxUnload doesn't change....... + //lack of break intentional + + case MRX_VBOXINIT_MINIRDR_REGISTERED: + VBoxRxUnregisterMinirdr(VBoxMRxDeviceObject); + + //lack of break intentional + + case MRX_VBOXINIT_START: + break; + } + +} + +VOID VBoxMRxUnload (IN PDRIVER_OBJECT DriverObject) +/*++ + + Routine Description: + + This is the unload routine for the Exchange mini redirector. + + Arguments: + + DriverObject - pointer to the driver object for the VBoxMRx + + Return Value: + + None + + --*/ + +{ + PRX_CONTEXT RxContext; + NTSTATUS Status; + UNICODE_STRING UserModeDeviceName; + PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension; + + PAGED_CODE(); + + Log(("VBOXSF: VBoxMRxUnload: Called.\n")); +#ifdef VBOX + pDeviceExtension = (PMRX_VBOX_DEVICE_EXTENSION) + ((PBYTE)(VBoxMRxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT)); + + vboxDisconnect (&pDeviceExtension->hgcmClient); + vboxUninit (); + vboxCtlGuestFilterMask (0, VMMDEV_EVENT_HGCM); +#endif + + VBoxMRxInitUnwind(DriverObject, MRX_VBOXINIT_ALL_INITIALIZATION_COMPLETED); + RxContext = VBoxRxCreateRxContext(NULL, VBoxMRxDeviceObject, RX_CONTEXT_FLAG_IN_FSP); + + if (RxContext != NULL) + { + Status = VBoxRxStopMinirdr(RxContext, &RxContext->PostRequest); + + if (Status == STATUS_SUCCESS) + { + MRX_VBOX_STATE State; + + State = (MRX_VBOX_STATE)InterlockedCompareExchange((LONG *)&VBoxMRxState, MRX_VBOX_STARTABLE, MRX_VBOX_STARTED); + + if (State != MRX_VBOX_STARTABLE) + { + Status = STATUS_REDIRECTOR_STARTED; + } + } + + VBoxRxDereferenceAndDeleteRxContext(RxContext); + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + RtlInitUnicodeString(&UserModeDeviceName, DD_MRX_VBOX_USERMODE_SHADOW_DEV_NAME_U); + Status = IoDeleteSymbolicLink(&UserModeDeviceName); + if (Status != STATUS_SUCCESS) + { + Log(("VBOXSF: VBoxMRxUnload: Could not delete symbolic link!\n")); + } + +#ifdef VBOX_SF_STATIC_LIB + RxUnload(DriverObject); +#endif + Log(("VBOXSF: VBoxMRxUnload: VBoxSF.sys driver object 0x%08lx unoaded\n", DriverObject)); +} + +NTSTATUS VBoxMRxInitializeTables (void) +/*++ + + Routine Description: + + This routine sets up the mini redirector dispatch vector and also calls + to initialize any other tables needed. + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + Log(("VBOXSF: VBoxMRxInitializeTables: Called.\n")); + + // + // Ensure that the Exchange mini redirector context satisfies the size constraints + // + //ASSERT(sizeof(MRX_VBOX_RX_CONTEXT) <= MRX_CONTEXT_SIZE); + + // + // Build the local minirdr dispatch table and initialize + // + + ZeroAndInitializeNodeType(&VBoxMRxDispatch, RDBSS_NTC_MINIRDR_DISPATCH, sizeof(MINIRDR_DISPATCH)); + + // + // null mini redirector extension sizes and allocation policies. + // + + + VBoxMRxDispatch.MRxFlags = (RDBSS_MANAGE_NET_ROOT_EXTENSION | RDBSS_MANAGE_FOBX_EXTENSION); + + VBoxMRxDispatch.MRxSrvCallSize = 0; + VBoxMRxDispatch.MRxNetRootSize = sizeof(MRX_VBOX_NETROOT_EXTENSION); + VBoxMRxDispatch.MRxVNetRootSize = 0; + VBoxMRxDispatch.MRxFcbSize = 0; + VBoxMRxDispatch.MRxSrvOpenSize = 0; + VBoxMRxDispatch.MRxFobxSize = sizeof(MRX_VBOX_FOBX); + + // Mini redirector cancel routine .. + + VBoxMRxDispatch.MRxCancel = NULL; + + // + // Mini redirector Start/Stop. Each mini-rdr can be started or stopped + // while the others continue to operate. + // + + VBoxMRxDispatch.MRxStart = VBoxMRxStart; + VBoxMRxDispatch.MRxStop = VBoxMRxStop; + VBoxMRxDispatch.MRxDevFcbXXXControlFile = VBoxMRxDevFcbXXXControlFile; + + // + // Mini redirector name resolution. + // + + VBoxMRxDispatch.MRxCreateSrvCall = VBoxMRxCreateSrvCall; + VBoxMRxDispatch.MRxSrvCallWinnerNotify = VBoxMRxSrvCallWinnerNotify; + VBoxMRxDispatch.MRxCreateVNetRoot = VBoxMRxCreateVNetRoot; + VBoxMRxDispatch.MRxUpdateNetRootState = VBoxMRxUpdateNetRootState; + VBoxMRxDispatch.MRxExtractNetRootName = VBoxMRxExtractNetRootName; + VBoxMRxDispatch.MRxFinalizeSrvCall = VBoxMRxFinalizeSrvCall; + VBoxMRxDispatch.MRxFinalizeNetRoot = VBoxMRxFinalizeNetRoot; + VBoxMRxDispatch.MRxFinalizeVNetRoot = VBoxMRxFinalizeVNetRoot; + + // + // File System Object Creation/Deletion. + // + + VBoxMRxDispatch.MRxCreate = VBoxMRxCreate; + VBoxMRxDispatch.MRxCollapseOpen = VBoxMRxCollapseOpen; + VBoxMRxDispatch.MRxShouldTryToCollapseThisOpen = VBoxMRxShouldTryToCollapseThisOpen; + VBoxMRxDispatch.MRxExtendForCache = VBoxMRxExtendStub; + VBoxMRxDispatch.MRxExtendForNonCache = VBoxMRxExtendStub; + VBoxMRxDispatch.MRxTruncate = VBoxMRxTruncate; + VBoxMRxDispatch.MRxCleanupFobx = VBoxMRxCleanupFobx; + VBoxMRxDispatch.MRxCloseSrvOpen = VBoxMRxCloseSrvOpen; + VBoxMRxDispatch.MRxFlush = VBoxMRxFlush; + VBoxMRxDispatch.MRxForceClosed = VBoxMRxForcedClose; + VBoxMRxDispatch.MRxDeallocateForFcb = VBoxMRxDeallocateForFcb; + VBoxMRxDispatch.MRxDeallocateForFobx = VBoxMRxDeallocateForFobx; + + // + // File System Objects query/Set + // + + VBoxMRxDispatch.MRxQueryDirectory = VBoxMRxQueryDirectory; + VBoxMRxDispatch.MRxQueryVolumeInfo = VBoxMRxQueryVolumeInformation; + VBoxMRxDispatch.MRxQueryEaInfo = VBoxMRxQueryEaInformation; + VBoxMRxDispatch.MRxSetEaInfo = VBoxMRxSetEaInformation; + VBoxMRxDispatch.MRxQuerySdInfo = VBoxMRxQuerySecurityInformation; + VBoxMRxDispatch.MRxSetSdInfo = VBoxMRxSetSecurityInformation; + VBoxMRxDispatch.MRxQueryFileInfo = VBoxMRxQueryFileInformation; + VBoxMRxDispatch.MRxSetFileInfo = VBoxMRxSetFileInformation; + VBoxMRxDispatch.MRxSetFileInfoAtCleanup = VBoxMRxSetFileInformationAtCleanup; + + // + // Buffering state change + // + + VBoxMRxDispatch.MRxComputeNewBufferingState = VBoxMRxComputeNewBufferingState; + + // + // File System Object I/O + // + + VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_READ] = VBoxMRxRead; + VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_WRITE] = VBoxMRxWrite; + VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_SHAREDLOCK] = VBoxMRxLocks; + VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_EXCLUSIVELOCK] = VBoxMRxLocks; + VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_UNLOCK] = VBoxMRxLocks; + VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_UNLOCK_MULTIPLE] = VBoxMRxLocks; + VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_FSCTL] = VBoxMRxFsCtl; + VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_IOCTL] = VBoxMRxIoCtl; + + VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_NOTIFY_CHANGE_DIRECTORY] = VBoxMRxNotifyChangeDirectory; + + // + // Miscellanous + // + + VBoxMRxDispatch.MRxCompleteBufferingStateChangeRequest = VBoxMRxCompleteBufferingStateChangeRequest; + + Log(("VBOXSF: VBoxMRxInitializeTables: Success.\n")); + return (STATUS_SUCCESS); +} + +NTSTATUS VBoxMRxStart (PRX_CONTEXT RxContext, IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject) +/*++ + + Routine Description: + + This routine completes the initialization of the mini redirector fromn the + RDBSS perspective. Note that this is different from the initialization done + in DriverEntry. Any initialization that depends on RDBSS should be done as + part of this routine while the initialization that is independent of RDBSS + should be done in the DriverEntry routine. + + Arguments: + + RxContext - Supplies the Irp that was used to startup the rdbss + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + MRX_VBOX_STATE CurrentState; + + Log(("VBOXSF: VBoxMRxStart: Called.\n")); + + CurrentState = (MRX_VBOX_STATE)InterlockedCompareExchange((PLONG) & VBoxMRxState, MRX_VBOX_STARTED, MRX_VBOX_START_IN_PROGRESS); + + if (CurrentState == MRX_VBOX_START_IN_PROGRESS) + { + Log(("VBOXSF: VBoxMRxStart: Start in progress -> started\n")); + Status = STATUS_SUCCESS; + } + else if (VBoxMRxState == MRX_VBOX_STARTED) + { + Log(("VBOXSF: VBoxMRxStart: Already started!\n")); + Status = STATUS_REDIRECTOR_STARTED; + } + else + { + Log(("VBOXSF: VBoxMRxStart: Bad state! VBoxMRxState = %d\n", VBoxMRxState)); + Status = STATUS_UNSUCCESSFUL; + } + + return Status; +} + +NTSTATUS VBoxMRxStop (PRX_CONTEXT RxContext, IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject) +/*++ + + Routine Description: + + This routine is used to activate the mini redirector from the RDBSS perspective + + Arguments: + + RxContext - the context that was used to start the mini redirector + + pContext - the null mini rdr context passed in at registration time. + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + Log(("VBOXSF: VBoxMRxStop: Called.\n")); + return (STATUS_SUCCESS); +} + +NTSTATUS VBoxMRxInitializeSecurity (VOID) +/*++ + + Routine Description: + + This routine initializes the null miniredirector security . + + Arguments: + + None. + + Return Value: + + None. + + Note: + + This API can only be called from a FS process. + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + Log(("VBOXSF: VBoxMRxInitializeSecurity: Called.\n")); + return Status; +} + +NTSTATUS VBoxMRxUninitializeSecurity (VOID) +/*++ + + Routine Description: + + Arguments: + + None. + + Return Value: + + None. + + Note: + + This API can only be called from a FS process. + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + Log(("VBOXSF: VBoxMRxUninitializeSecurity: Called.\n")); + return Status; +} + +NTSTATUS VBoxMRxFsdDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) + +/*++ + + Routine Description: + + This routine implements the FSD dispatch for the mini DRIVER object. + + Arguments: + + DeviceObject - Supplies the device object for the packet being processed. + + Irp - Supplies the Irp being processed + + Return Value: + + RXSTATUS - The Fsd status for the Irp + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + UCHAR MajorFunctionCode = IrpSp->MajorFunction; + ULONG MinorFunctionCode = IrpSp->MinorFunction; + + Log(("VBOXSF: VBoxMRxFsdDispatch: Called.\n")); + + Assert(DeviceObject == (PDEVICE_OBJECT)VBoxMRxDeviceObject); + if (DeviceObject != (PDEVICE_OBJECT)VBoxMRxDeviceObject) + { + Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + Log(("VBOXSF: VBoxMRxFsdDispatch: Invalid device request detected, this in no error!\n")); + return STATUS_INVALID_DEVICE_REQUEST; + } + + Log(("%s\n", MajorFunctionString(MajorFunctionCode, MinorFunctionCode))); + + Status = VBoxRxFsdDispatch((PRDBSS_DEVICE_OBJECT)VBoxMRxDeviceObject, Irp); + Log(("VBOXSF: VBoxMRxFsdDispatch: Returned 0x%x\n", Status)); + return Status; +} + +NTSTATUS VBoxMRxGetUlongRegistryParameter (HANDLE ParametersHandle, PWCHAR ParameterName, PULONG ParamUlong, BOOLEAN LogFailure) +/*++ + + Routine Description: + + This routine is called to read a ULONG param from t he registry. + + Arguments: + + ParametersHandle - the handle of the containing registry "folder" + ParameterName - name of the parameter to be read + ParamUlong - where to store the value, if successful + LogFailure - if TRUE and the registry stuff fails, log an error + + Return Value: + + RXSTATUS - STATUS_SUCCESS + + --*/ +{ + ULONG Storage[16]; + PKEY_VALUE_PARTIAL_INFORMATION Value; + ULONG ValueSize; + UNICODE_STRING UnicodeString; + NTSTATUS Status; + ULONG BytesRead; + + PAGED_CODE(); //INIT + + Log(("VBOXSF: VBoxMRxGetUlongRegistryParameter: Called.\n")); + + Value = (PKEY_VALUE_PARTIAL_INFORMATION)Storage; + ValueSize = sizeof(Storage); + + RtlInitUnicodeString(&UnicodeString, ParameterName); + + Status = ZwQueryValueKey(ParametersHandle, &UnicodeString, KeyValuePartialInformation, Value, ValueSize, &BytesRead); + + if (NT_SUCCESS(Status)) + { + if (Value->Type == REG_DWORD) + { + PULONG ConfigValue = (PULONG) & Value->Data[0]; + *ParamUlong = *((PULONG)ConfigValue); + Log(("BOXSF: VBoxMRxGetUlongRegistryParameter: Read registry value %.*ls = 0x%08lx\n", UnicodeString.Length / sizeof(WCHAR), UnicodeString.Buffer, *ParamUlong)); + return (STATUS_SUCCESS); + } + else + { + Status = STATUS_INVALID_PARAMETER; + } + } + + if (LogFailure) + Log(("VBOXSF: VBoxMRxGetUlongRegistryParameter: Failure!\n")); + + return Status; +} + +VOID VBoxMRxReadRegistryParameters () +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING ParametersRegistryKeyName; + HANDLE ParametersHandle; + ULONG Temp; + + Log(("VBOXSF: VBoxMRxReadRegistryParameters: Called.\n")); + RtlInitUnicodeString(&ParametersRegistryKeyName, NULL_MINIRDR_PARAMETERS); + InitializeObjectAttributes(&ObjectAttributes, &ParametersRegistryKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL + ); + + Status = ZwOpenKey(&ParametersHandle, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + Status = VBoxMRxGetUlongRegistryParameter(ParametersHandle,L"LogRate" , + (PULONG)&Temp, + FALSE + ); + } + if (NT_SUCCESS(Status)) LogRate = Temp; + + ZwClose(ParametersHandle); +} + +#if defined(DEBUG) || defined (LOG_ENABLED) +static PCHAR PnPMinorFunctionString(LONG MinorFunction) +{ + switch (MinorFunction) + { + case IRP_MN_START_DEVICE: + return "IRP_MJ_PNP - IRP_MN_START_DEVICE"; + case IRP_MN_QUERY_REMOVE_DEVICE: + return "IRP_MJ_PNP - IRP_MN_QUERY_REMOVE_DEVICE"; + case IRP_MN_REMOVE_DEVICE: + return "IRP_MJ_PNP - IRP_MN_REMOVE_DEVICE"; + case IRP_MN_CANCEL_REMOVE_DEVICE: + return "IRP_MJ_PNP - IRP_MN_CANCEL_REMOVE_DEVICE"; + case IRP_MN_STOP_DEVICE: + return "IRP_MJ_PNP - IRP_MN_STOP_DEVICE"; + case IRP_MN_QUERY_STOP_DEVICE: + return "IRP_MJ_PNP - IRP_MN_QUERY_STOP_DEVICE"; + case IRP_MN_CANCEL_STOP_DEVICE: + return "IRP_MJ_PNP - IRP_MN_CANCEL_STOP_DEVICE"; + case IRP_MN_QUERY_DEVICE_RELATIONS: + return "IRP_MJ_PNP - IRP_MN_QUERY_DEVICE_RELATIONS"; + case IRP_MN_QUERY_INTERFACE: + return "IRP_MJ_PNP - IRP_MN_QUERY_INTERFACE"; + case IRP_MN_QUERY_CAPABILITIES: + return "IRP_MJ_PNP - IRP_MN_QUERY_CAPABILITIES"; + case IRP_MN_QUERY_RESOURCES: + return "IRP_MJ_PNP - IRP_MN_QUERY_RESOURCES"; + case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: + return "IRP_MJ_PNP - IRP_MN_QUERY_RESOURCE_REQUIREMENTS"; + case IRP_MN_QUERY_DEVICE_TEXT: + return "IRP_MJ_PNP - IRP_MN_QUERY_DEVICE_TEXT"; + case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: + return "IRP_MJ_PNP - IRP_MN_FILTER_RESOURCE_REQUIREMENTS"; + case IRP_MN_READ_CONFIG: + return "IRP_MJ_PNP - IRP_MN_READ_CONFIG"; + case IRP_MN_WRITE_CONFIG: + return "IRP_MJ_PNP - IRP_MN_WRITE_CONFIG"; + case IRP_MN_EJECT: + return "IRP_MJ_PNP - IRP_MN_EJECT"; + case IRP_MN_SET_LOCK: + return "IRP_MJ_PNP - IRP_MN_SET_LOCK"; + case IRP_MN_QUERY_ID: + return "IRP_MJ_PNP - IRP_MN_QUERY_ID"; + case IRP_MN_QUERY_PNP_DEVICE_STATE: + return "IRP_MJ_PNP - IRP_MN_QUERY_PNP_DEVICE_STATE"; + case IRP_MN_QUERY_BUS_INFORMATION: + return "IRP_MJ_PNP - IRP_MN_QUERY_BUS_INFORMATION"; + case IRP_MN_DEVICE_USAGE_NOTIFICATION: + return "IRP_MJ_PNP - IRP_MN_DEVICE_USAGE_NOTIFICATION"; + case IRP_MN_SURPRISE_REMOVAL: + return "IRP_MJ_PNP - IRP_MN_SURPRISE_REMOVAL"; + default: + return "IRP_MJ_PNP - unknown_pnp_irp"; + } +} + +static PCHAR MajorFunctionString(UCHAR MajorFunction, LONG MinorFunction) +{ + switch (MinorFunction) + { + case IRP_MJ_CREATE: + return "IRP_MJ_CREATE"; + case IRP_MJ_CREATE_NAMED_PIPE: + return "IRP_MJ_CREATE_NAMED_PIPE"; + case IRP_MJ_CLOSE: + return "IRP_MJ_CLOSE"; + case IRP_MJ_READ: + return "IRP_MJ_READ"; + case IRP_MJ_WRITE: + return "IRP_MJ_WRITE"; + case IRP_MJ_QUERY_INFORMATION: + return "IRP_MJ_QUERY_INFORMATION"; + case IRP_MJ_SET_INFORMATION: + return "IRP_MJ_SET_INFORMATION"; + case IRP_MJ_QUERY_EA: + return "IRP_MJ_QUERY_EA"; + case IRP_MJ_SET_EA: + return "IRP_MJ_SET_EA"; + case IRP_MJ_FLUSH_BUFFERS: + return "IRP_MJ_FLUSH_BUFFERS"; + case IRP_MJ_QUERY_VOLUME_INFORMATION: + return "IRP_MJ_QUERY_VOLUME_INFORMATION"; + case IRP_MJ_SET_VOLUME_INFORMATION: + return "IRP_MJ_SET_VOLUME_INFORMATION"; + case IRP_MJ_DIRECTORY_CONTROL: + return "IRP_MJ_DIRECTORY_CONTROL"; + case IRP_MJ_FILE_SYSTEM_CONTROL: + return "IRP_MJ_FILE_SYSTEM_CONTROL"; + case IRP_MJ_DEVICE_CONTROL: + return "IRP_MJ_DEVICE_CONTROL"; + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + return "IRP_MJ_INTERNAL_DEVICE_CONTROL"; + case IRP_MJ_SHUTDOWN: + return "IRP_MJ_SHUTDOWN"; + case IRP_MJ_LOCK_CONTROL: + return "IRP_MJ_LOCK_CONTROL"; + case IRP_MJ_CLEANUP: + return "IRP_MJ_CLEANUP"; + case IRP_MJ_CREATE_MAILSLOT: + return "IRP_MJ_CREATE_MAILSLOT"; + case IRP_MJ_QUERY_SECURITY: + return "IRP_MJ_QUERY_SECURITY"; + case IRP_MJ_SET_SECURITY: + return "IRP_MJ_SET_SECURITY"; + case IRP_MJ_POWER: + return "IRP_MJ_POWER"; + case IRP_MJ_SYSTEM_CONTROL: + return "IRP_MJ_SYSTEM_CONTROL"; + case IRP_MJ_DEVICE_CHANGE: + return "IRP_MJ_DEVICE_CHANGE"; + case IRP_MJ_QUERY_QUOTA: + return "IRP_MJ_QUERY_QUOTA"; + case IRP_MJ_SET_QUOTA: + return "IRP_MJ_SET_QUOTA"; + case IRP_MJ_PNP: + return PnPMinorFunctionString(MinorFunction); + + default: + return "unknown_pnp_irp"; + } +} + +#endif diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/locks.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/locks.c new file mode 100644 index 00000000000..e6374bfbb1e --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/locks.c @@ -0,0 +1,173 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + locks.c + + Abstract: + + This module implements the mini redirector call down routines pertaining to locks + of file system objects. + + --*/ + +#include "precomp.h" +#pragma hdrstop + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, VBoxMRxLocks) +#pragma alloc_text(PAGE, VBoxMRxCompleteBufferingStateChangeRequest) +#pragma alloc_text(PAGE, VBoxMRxFlush) +#endif + +NTSTATUS VBoxMRxLocks (IN PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine handles network requests for filelocks + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + RxCaptureFcb; + RxCaptureFobx; + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; +#ifndef VBOX + PDEVICE_OBJECT deviceObject; +#endif + + PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen; + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); + PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = (PMRX_VBOX_NETROOT_EXTENSION)pNetRoot->Context; + uint32_t fLock = 0; + + int vboxRC; + + Log(("VBOXSF: VBoxMRxLocks: Called.\n")); + + switch (LowIoContext->Operation) + { + default: + AssertMsgFailed(("VBOXSF: VBoxMRxLocks: Unsupported lock/unlock type %d detected!\n", LowIoContext->Operation)); + return STATUS_NOT_IMPLEMENTED; + + case LOWIO_OP_UNLOCK_MULTIPLE: + /* @todo Remove multiple locks listed in LowIoContext.ParamsFor.Locks.LockList. */ + Log(("VBOXSF: VBoxMRxLocks: Unsupported lock/unlock type %d detected!\n", LowIoContext->Operation)); + return STATUS_NOT_IMPLEMENTED; + + /* Reading is allowed, writing isn't */ + case LOWIO_OP_SHAREDLOCK: + fLock = SHFL_LOCK_SHARED | SHFL_LOCK_PARTIAL; + break; + + /* Reading and writing not allowed */ + case LOWIO_OP_EXCLUSIVELOCK: + fLock = SHFL_LOCK_EXCLUSIVE | SHFL_LOCK_PARTIAL; + break; + + case LOWIO_OP_UNLOCK: + fLock = SHFL_LOCK_CANCEL | SHFL_LOCK_PARTIAL; + break; + } + + if (LowIoContext->ParamsFor.Locks.Flags & LOWIO_LOCKSFLAG_FAIL_IMMEDIATELY) + { + fLock |= SHFL_LOCK_NOWAIT; + } + else + { + fLock |= SHFL_LOCK_WAIT; + } + + /* Do the actual flushing of file buffers */ + vboxRC = vboxCallLock(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, LowIoContext->ParamsFor.Locks.ByteOffset, LowIoContext->ParamsFor.Locks.Length, fLock); + AssertRC(vboxRC); + Status = VBoxErrorToNTStatus(vboxRC); + + Log(("VBOXSF: VBoxMRxLocks: Returned 0x%x\n", Status)); + return (Status); +} + +NTSTATUS VBoxMRxCompleteBufferingStateChangeRequest (IN OUT PRX_CONTEXT RxContext, IN OUT PMRX_SRV_OPEN SrvOpen, IN PVOID pContext) +/*++ + + Routine Description: + + This routine is called to assert the locks that the wrapper has buffered. currently, it is synchronous! + + + Arguments: + + RxContext - the open instance + SrvOpen - tells which fcb is to be used. + LockEnumerator - the routine to call to get the locks + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + + Log(("VBOXSF: VBoxMRxCompleteBufferingStateChangeRequest: Called.\n")); + return (Status); +} + +NTSTATUS VBoxMRxFlush (IN PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine handles network requests for file flush + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + RxCaptureFcb; + RxCaptureFobx; + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; +#ifndef VBOX + PDEVICE_OBJECT deviceObject; +#endif + + PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen; + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); + PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = (PMRX_VBOX_NETROOT_EXTENSION)pNetRoot->Context; + + int vboxRC; + + Log(("VBOXSF: VBoxMRxFlush: Called.\n")); + + /* Do the actual flushing of file buffers */ + vboxRC = vboxCallFlush(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile); + AssertRC(vboxRC); + + Status = VBoxErrorToNTStatus(vboxRC); + + return (Status); +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/minip.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/minip.h new file mode 100644 index 00000000000..57a39afbda5 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/minip.h @@ -0,0 +1,76 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + minip.h + + Abstract: + + Macros and definitions private to the null mini driver. + + Notes: + + This module has been built and tested only in UNICODE environment + + --*/ + +#ifndef _NULLMINIP_H_ +#define _NULLMINIP_H_ + +NTHALAPI +VOID +KeStallExecutionProcessor ( + IN ULONG MicroSeconds +); + +#ifndef min +#define min(a, b) ((a) > (b) ? (b) : (a)) +#endif + +#define RX_VERIFY( f ) if( (f) ) ; else ASSERT( 1==0 ) + +// +// Set or Validate equal +// +#define SetOrValidate(x,y,f) \ + if( f ) (x) = (y); else ASSERT( (x) == (y) ) + +// +// RXCONTEXT data - mini-rdr context stored for async completions +// NOTE: sizeof this struct should be == MRX_CONTEXT_SIZE !! +// + +typedef struct _MRX_VBOX_COMPLETION_CONTEXT +{ + // + // IoStatus.Information + // + ULONG Information; + + // + // IoStatus.Status + // + NTSTATUS Status; + + // + // Outstanding I/Os + // + ULONG OutstandingIOs; + + // + // I/O type + // + ULONG IoType; + +} MRX_VBOX_COMPLETION_CONTEXT, *PMRX_VBOX_COMPLETION_CONTEXT; + +#define IO_TYPE_SYNCHRONOUS 0x00000001 +#define IO_TYPE_ASYNC 0x00000010 + +#define VBoxMRxGetMinirdrContext(pRxContext) \ + ((PMRX_VBOX_COMPLETION_CONTEXT)(&(pRxContext)->MRxContext[0])) + +#endif // _NULLMINIP_H_ + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxglobs.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxglobs.h new file mode 100644 index 00000000000..e30e01520c5 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxglobs.h @@ -0,0 +1,463 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + mrxglobs.h + + Abstract: + + The global include file for MRX_VBOX mini-redirector + + --*/ + +#ifndef _MRXGLOBS_H_ +#define _MRXGLOBS_H_ + +#ifdef VBOX +#include "VBoxGuestR0LibSharedFolders.h" +#endif + +extern PRDBSS_DEVICE_OBJECT VBoxMRxDeviceObject; +#define RxNetNameTable (*(*___MINIRDR_IMPORTS_NAME).pRxNetNameTable) + +// The following enum type defines the various states associated with the null +// mini redirector. This is used during initialization + +typedef enum _MRX_VBOX_STATE_ +{ + MRX_VBOX_STARTABLE, MRX_VBOX_START_IN_PROGRESS, MRX_VBOX_STARTED +} MRX_VBOX_STATE, *PMRX_VBOX_STATE; + +extern MRX_VBOX_STATE VBoxMRxState; +extern ULONG LogRate; +extern ULONG VBoxMRxVersion; + +// +// Reg keys +// +#define NULL_MINIRDR_PARAMETERS \ + L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\VBoxMRx\\Parameters" + +/* + * Maximum drive letters (A - Z). + */ +#define _MRX_MAX_DRIVE_LETTERS 26 + +// +// typedef our device extension - stores state global to the driver +// +typedef struct _MRX_VBOX_DEVICE_EXTENSION +{ + // + // Back-pointer to owning device object + // + PRDBSS_DEVICE_OBJECT pDeviceObject; + + // + // Count of active nodes + // Driver can be unloaded if ActiveNodes == 0 + // + ULONG ulActiveNodes; + + /* + * Keep a list of local connections used. + * The size (_MRX_MAX_DRIVE_LETTERS = 26) of the array presents the available drive letters C: - Z: of Windows. + */ + CHAR cLocalConnections[_MRX_MAX_DRIVE_LETTERS]; + PUNICODE_STRING wszLocalConnectionName[_MRX_MAX_DRIVE_LETTERS]; + FAST_MUTEX mtxLocalCon; + +#ifdef VBOX + /* The HGCM client information. */ + VBSFCLIENT hgcmClient; + /* Poller thread flags */ + ULONG ulPollerThreadFlags; + + /* Poller thread handle */ + PKTHREAD pPollerThread; + + /* Redirector driver object pointer */ + PDRIVER_OBJECT pDriverObject; +#endif + + NTSTATUS (* pfnRDBSSDeviceControl) (PDEVICE_OBJECT pDevObj, PIRP pIrp); + +} MRX_VBOX_DEVICE_EXTENSION, *PMRX_VBOX_DEVICE_EXTENSION; + +// +// NET_ROOT extension - stores state global to a root +// +typedef struct _MRX_VBOX_NETROOT_EXTENSION +{ + /* The HGCM client information. */ + VBSFCLIENT *phgcmClient; + VBSFMAP map; + +} MRX_VBOX_NETROOT_EXTENSION, *PMRX_VBOX_NETROOT_EXTENSION; + +// A pointer to an instance of MRX_VBOX_FOBX is stored in the context field +// of MRX_FOBXs handled by the SMB mini rdr. Depending upon the file type +// i.e., file or directory the appropriate context information is stored. + +typedef struct _MRX_VBOX_FOBX_ +{ + SHFLHANDLE hFile; + PMRX_SRV_CALL pSrvCall; + FILE_BASIC_INFORMATION FileBasicInfo; + FILE_STANDARD_INFORMATION FileStandardInfo; + BOOLEAN fKeepCreationTime; + BOOLEAN fKeepLastAccessTime; + BOOLEAN fKeepLastWriteTime; + BOOLEAN fKeepChangeTime; + +} MRX_VBOX_FOBX, *PMRX_VBOX_FOBX; + +// +// Macros to get & validate extensions +// + +#define VBoxMRxGetDeviceExtension(RxContext,pExt) \ + PMRX_VBOX_DEVICE_EXTENSION pExt = (PMRX_VBOX_DEVICE_EXTENSION)((PBYTE)(RxContext->RxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT)) + +#define VBoxMRxGetNetRootExtension(pNetRoot,pExt) \ + PMRX_VBOX_NETROOT_EXTENSION pExt = (((pNetRoot) == NULL) ? NULL : (PMRX_VBOX_NETROOT_EXTENSION)((pNetRoot)->Context)) + +#define VBoxMRxGetFcbExtension(pFcb,pExt) \ + PMRX_VBOX_FCB_EXTENSION pExt = (((pFcb) == NULL) ? NULL : (PMRX_VBOX_FCB_EXTENSION)((pFcb)->Context)) + +#define VBoxMRxGetSrvOpenExtension(pSrvOpen) \ + (((pSrvOpen) == NULL) ? NULL : (PMRX_VBOX_SRV_OPEN)((pSrvOpen)->Context)) + +#define VBoxMRxGetFileObjectExtension(pFobx) \ + (((pFobx) == NULL) ? NULL : (PMRX_VBOX_FOBX)((pFobx)->Context)) + +// +// forward declarations for all dispatch vector methods. +// + +#ifdef __cplusplus +extern "C" +{ +#endif + +extern NTSTATUS +VBoxMRxStart ( + IN OUT struct _RX_CONTEXT * RxContext, + IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject +); + +extern NTSTATUS +VBoxMRxStop ( + IN OUT struct _RX_CONTEXT * RxContext, + IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject +); + +extern NTSTATUS +VBoxMRxMinirdrControl ( + IN OUT PRX_CONTEXT RxContext, + IN OUT PVOID pContext, + IN OUT PUCHAR SharedBuffer, + IN ULONG InputBufferLength, + IN ULONG OutputBufferLength, + OUT PULONG CopyBackLength +); + +extern NTSTATUS +VBoxMRxDevFcb ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxDevFcbXXXControlFile ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxCreate ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxCollapseOpen ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxShouldTryToCollapseThisOpen ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxRead ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxWrite ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxLocks( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxFlush( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxFsCtl( + IN OUT PRX_CONTEXT RxContext +); + +NTSTATUS +VBoxMRxIoCtl( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxNotifyChangeDirectory( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxComputeNewBufferingState( + IN OUT PMRX_SRV_OPEN pSrvOpen, + IN PVOID pMRxContext, + OUT ULONG *pNewBufferingState); + +extern NTSTATUS +VBoxMRxFlush ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxCloseWithDelete ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxZeroExtend ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxSetEndOfFile( + IN OUT struct _RX_CONTEXT * RxContext, + IN OUT PLARGE_INTEGER pNewFileSize, + OUT PLARGE_INTEGER pNewAllocationSize +); + +extern NTSTATUS +VBoxMRxTruncate ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxCleanupFobx ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxCloseSrvOpen ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxClosedSrvOpenTimeOut ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxQueryDirectory ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxQueryEaInformation ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxSetEaInformation ( + IN OUT struct _RX_CONTEXT * RxContext +); + +extern NTSTATUS +VBoxMRxQuerySecurityInformation ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxSetSecurityInformation ( + IN OUT struct _RX_CONTEXT * RxContext +); + +extern NTSTATUS +VBoxMRxQueryVolumeInformation ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxSetVolumeInformation ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxLowIOSubmit ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxCreateVNetRoot( + IN OUT PMRX_CREATENETROOT_CONTEXT pContext +); + +extern NTSTATUS +VBoxMRxFinalizeVNetRoot( + IN OUT PMRX_V_NET_ROOT pVirtualNetRoot, + IN PBOOLEAN ForceDisconnect); + +extern NTSTATUS +VBoxMRxFinalizeNetRoot( + IN OUT PMRX_NET_ROOT pNetRoot, + IN PBOOLEAN ForceDisconnect); + +extern NTSTATUS +VBoxMRxUpdateNetRootState( + IN PMRX_NET_ROOT pNetRoot); + +VOID +VBoxMRxExtractNetRootName( + IN PUNICODE_STRING FilePathName, + IN PMRX_SRV_CALL SrvCall, + OUT PUNICODE_STRING NetRootName, + OUT PUNICODE_STRING RestOfName OPTIONAL +); + +extern NTSTATUS +VBoxMRxCreateSrvCall( + PMRX_SRV_CALL pSrvCall, + PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext); + +extern NTSTATUS +VBoxMRxFinalizeSrvCall( + PMRX_SRV_CALL pSrvCall, + BOOLEAN Force); + +extern NTSTATUS +VBoxMRxSrvCallWinnerNotify( + IN OUT PMRX_SRV_CALL pSrvCall, + IN BOOLEAN ThisMinirdrIsTheWinner, + IN OUT PVOID pSrvCallContext); + +extern NTSTATUS +VBoxMRxQueryFileInformation ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxQueryNamedPipeInformation ( + IN OUT PRX_CONTEXT RxContext, + IN FILE_INFORMATION_CLASS FileInformationClass, + IN OUT PVOID Buffer, + IN OUT PULONG pLengthRemaining +); + +extern NTSTATUS +VBoxMRxSetFileInformation ( + IN OUT PRX_CONTEXT RxContext +); + +extern NTSTATUS +VBoxMRxSetNamedPipeInformation ( + IN OUT PRX_CONTEXT RxContext, + IN FILE_INFORMATION_CLASS FileInformationClass, + IN PVOID pBuffer, + IN ULONG BufferLength +); + +NTSTATUS +VBoxMRxSetFileInformationAtCleanup( + IN OUT PRX_CONTEXT RxContext +); + +NTSTATUS +VBoxMRxDeallocateForFcb ( + IN OUT PMRX_FCB pFcb +); + +NTSTATUS +VBoxMRxDeallocateForFobx ( + IN OUT PMRX_FOBX pFobx +); + +extern NTSTATUS +VBoxMRxForcedClose ( + IN OUT PMRX_SRV_OPEN SrvOpen +); + +extern ULONG +VBoxMRxExtendFile ( + IN OUT struct _RX_CONTEXT * RxContext, + IN OUT PLARGE_INTEGER pNewFileSize, + OUT PLARGE_INTEGER pNewAllocationSize +); + +extern NTSTATUS +VBoxMRxExtendStub ( + IN OUT struct _RX_CONTEXT * RxContext, + IN OUT PLARGE_INTEGER pNewFileSize, + OUT PLARGE_INTEGER pNewAllocationSize +); + +extern NTSTATUS +VBoxMRxTruncateFile( + IN OUT struct _RX_CONTEXT * RxContext +); + +extern NTSTATUS +VBoxMRxCompleteBufferingStateChangeRequest ( + IN OUT PRX_CONTEXT RxContext, + IN OUT PMRX_SRV_OPEN SrvOpen, + IN PVOID pContext +); + +extern NTSTATUS +VBoxMRxExtendForCache ( + IN OUT PRX_CONTEXT RxContext, + IN OUT PFCB Fcb, + OUT PLONGLONG pNewFileSize +); + +extern +NTSTATUS +VBoxMRxInitializeSecurity (VOID); + +extern +NTSTATUS +VBoxMRxUninitializeSecurity (VOID); + +extern +NTSTATUS +VBoxMRxInitializeTransport(VOID); + +extern +NTSTATUS +VBoxMRxUninitializeTransport(VOID); + +#ifdef __cplusplus +} +; +#endif + +#define VBoxMRxMakeSrvOpenKey(Tid,Fid) \ + (PVOID)(((ULONG)(Tid) << 16) | (ULONG)(Fid)) + +#include "mrxprocs.h" // crossreferenced routines +#endif _MRXGLOBS_H_ + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxprocs.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxprocs.h new file mode 100644 index 00000000000..d79547606b4 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxprocs.h @@ -0,0 +1,50 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + mrxprocs.h + + Abstract: + + The module contains the prototype definitions for all cross referenced + routines. + + --*/ + +#ifndef _MRXPROCS_H_ +#define _MRXPROCS_H_ + +//cross-referenced internal routines + +//from rename.c +NTSTATUS VBoxMRxRename( + IN PRX_CONTEXT RxContext, + IN FILE_INFORMATION_CLASS FileInformationClass, + IN PVOID pBuffer, + IN ULONG BufferLength); + +NTSTATUS VBoxMRxRemove(IN PRX_CONTEXT RxContext); + +// from usrcnnct.c +NTSTATUS +VBoxMRxDeleteConnection ( +IN PRX_CONTEXT RxContext, +OUT PBOOLEAN PostToFsp +); + +NTSTATUS +VBoxMRxCreateConnection ( +IN PRX_CONTEXT RxContext, +OUT PBOOLEAN PostToFsp +); + +NTSTATUS +VBoxMRxDoConnection( +IN PRX_CONTEXT RxContext, +ULONG CreateDisposition +); + +#endif // _MRXPROCS_H_ + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/netroot.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/netroot.c new file mode 100644 index 00000000000..8bd2e523c72 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/netroot.c @@ -0,0 +1,456 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + netroot.c + + Abstract: + + This module implements the routines for creating the net root. + + --*/ + +#include "precomp.h" +#pragma hdrstop + +// +// Forward declarations ... +// + +NTSTATUS VBoxMRxUpdateNetRootState (IN OUT PMRX_NET_ROOT pNetRoot) +/*++ + + Routine Description: + + This routine updates the mini redirector state associated with a net root. + + Arguments: + + pNetRoot - the net root instance. + + Return Value: + + NTSTATUS - The return status for the operation + + Notes: + + By diffrentiating the mini redirector state from the net root condition it is possible + to permit a variety of reconnect strategies. It is conceivable that the RDBSS considers + a net root to be good while the underlying mini redirector might mark it as invalid + and reconnect on the fly. + + --*/ +{ + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + + Log(("VBOXSF: VBoxMRxUpdateNetRootState: Called.\n")); + return (Status); +} + +NTSTATUS VBoxMRxInitializeNetRootEntry (IN PMRX_NET_ROOT pNetRoot) +/*++ + + Routine Description: + + This routine initializes a new net root. + It also validates rootnames. Eg: attempts to create a + file in a root that has not been created will fail. + + Arguments: + + pNetRoot - the net root + + Return Value: + + NTSTATUS - The return status for the operation + + Notes: + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall; + PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = (PMRX_VBOX_NETROOT_EXTENSION)pNetRoot->Context; + + Log(("VBOXSF: VBoxMRxInitializeNetRootEntry: Called.\n")); + return Status; +} + +NTSTATUS VBoxUpdateNetRoot (PMRX_NET_ROOT pNetRoot) +/*++ + + Routine Description: + + This routine initializes the wrapper data structure corresponding to a + given net root entry. + + Arguments: + + pNetRootEntry - the server entry + + Return Value: + + STATUS_SUCCESS if successful + + --*/ +{ + PAGED_CODE(); + + Log(("VBOXSF: VBoxUpdateNetRoot: NetRoot = 0x%x Type = 0x%x\n", pNetRoot, pNetRoot->Type)); + + switch (pNetRoot->Type) + { + case NET_ROOT_DISK: + pNetRoot->DeviceType = RxDeviceType(DISK); + break; + + case NET_ROOT_PIPE: + pNetRoot->DeviceType = RxDeviceType(NAMED_PIPE); + break; + case NET_ROOT_COMM: + pNetRoot->DeviceType = RxDeviceType(SERIAL_PORT); + break; + case NET_ROOT_PRINT: + pNetRoot->DeviceType = RxDeviceType(PRINTER); + break; + case NET_ROOT_MAILSLOT: + pNetRoot->DeviceType = RxDeviceType(MAILSLOT); + break; + case NET_ROOT_WILD: + /* We get this type when for example Windows Media player opens an MP3 file. + * This NetRoot has the same remote path (\\vboxsrv\dir) as other NetRoots, + * which were created earlier and which were NET_ROOT_DISK. + * + * In the beginning of the function (UpdateNetRoot) the DDK sample sets + * pNetRoot->Type of newly created NetRoots using a value previously + * pstored in a NetRootExtension. One NetRootExtensions is used for a single + * remote path and reused by a few NetRoots, if they point to the same path. + * + * To simplify things we just set the type to DISK here (we do not support + * anything else anyway), and update the DeviceType correspondingly. + */ + pNetRoot->Type = NET_ROOT_DISK; + pNetRoot->DeviceType = RxDeviceType(DISK); + break; + default: + AssertMsgFailed(("VBOXSF: VBoxUpdateNetRoot: Invalid net root type! Type = 0x%x\n", pNetRoot->Type)); + break; + } + + Log(("VBOXSF: VBoxUpdateNetRoot: leaving pNetRoot->DeviceType = 0x%x\n", pNetRoot->DeviceType)); + return STATUS_SUCCESS; +} + +NTSTATUS VBoxMRxCreateVNetRoot (IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext) +/*++ + + Routine Description: + + This routine patches the RDBSS created net root instance with the information required + by the mini redirector. + + Arguments: + + pVNetRoot - the virtual net root instance. + + pCreateNetRootContext - the net root context for calling back + + Return Value: + + NTSTATUS - The return status for the operation + + Notes: + + --*/ +{ + NTSTATUS Status; + PRX_CONTEXT pRxContext = pCreateNetRootContext->RxContext; + PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)pCreateNetRootContext->pVNetRoot; + VBoxMRxGetDeviceExtension(pRxContext, pDeviceExtension); + VBoxMRxGetNetRootExtension(pVNetRoot->pNetRoot, pNetRootExtension); + + PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot; + PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall; + + BOOLEAN fTreeConnectOpen = TRUE; // RxContext->Create.ThisIsATreeConnectOpen; + BOOLEAN fInitializeNetRoot; + + Log(("VBOXSF: VBoxMRxCreateVNetRoot: pNetRoot = %p, fTreeConnectOpen = %d\n", pNetRoot, pRxContext->Create.ThisIsATreeConnectOpen)); + + /* IMPORTANT: + * + * This function must always call 'pCreateNetRootContext->Callback(pCreateNetRootContext)' before + * returning and then return STATUS_PENDING. Otherwise Win64 will hang. + */ + + if (pNetRoot->Type == NET_ROOT_MAILSLOT || pNetRoot->Type == NET_ROOT_PIPE) + { + /* DDK sample returns this status code. And our driver does get such NetRoots. */ + Log(("VBOXSF: VBoxMRxCreateVNetRoot: Mailslot or Pipe open (%d) not supported!\n", pNetRoot->Type)); + pVNetRoot->Context = NULL; + + Status = STATUS_NOT_SUPPORTED; + goto l_Exit; + } + + // The V_NET_ROOT is associated with a NET_ROOT. The two cases of interest are as + // follows + // 1) the V_NET_ROOT and the associated NET_ROOT are being newly created. + // 2) a new V_NET_ROOT associated with an existing NET_ROOT is being created. + // + // These two cases can be distinguished by checking if the context associated with + // NET_ROOT is NULL. Since the construction of NET_ROOT's/V_NET_ROOT's are serialized + // by the wrapper this is a safe check. + // ( The wrapper cannot have more then one thread tryingto initialize the same + // NET_ROOT). + // + // The above is not really true in our case. Since we have asked the wrapper, + // to manage our netroot extension, the netroot context will always be non-NULL. + // We will distinguish the cases by checking our root state in the context... + // + + if (pNetRoot->Context == NULL) + { + fInitializeNetRoot = TRUE; + } + else + { + VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension); + /* Detect an already initialized NetRoot. + * pNetRootExtension is actually the pNetRoot->Context and it is not null. + */ + fInitializeNetRoot = pNetRootExtension->phgcmClient == NULL; + } + + Assert((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) && (NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL)); + + Status = STATUS_SUCCESS; + + // update the net root state to be good. + + if (fInitializeNetRoot) + { + PWCHAR pRootName; + ULONG RootNameLength; + int vboxRC; + PSHFLSTRING ParsedPath = 0; + ULONG ParsedPathSize; + + pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD; + + // validate the fixed netroot name + + RootNameLength = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length; + if (!RootNameLength) + { + /* Refuse a netroot path with an empty shared folder name */ + Log(("VBOXSF: VBoxMRxCreateVNetRoot: Invalid shared folder name! (length=0)\n")); + pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR; + + Status = STATUS_BAD_NETWORK_NAME; + goto l_Exit; + } + + RootNameLength -= 2; /* remove leading backslash */ + + pRootName = (PWCHAR)(pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR))); + pRootName++; /* remove leading backslash */ + + if (pNetRootExtension->phgcmClient == NULL) + { + Log(("VBOXSF: VBoxMRxCreateVNetRoot: Initialize netroot length = %d, name = %.*ls\n", RootNameLength, RootNameLength / sizeof(WCHAR), pRootName)); + + /* Calculate length required for parsed path. + */ + ParsedPathSize = sizeof(*ParsedPath) + RootNameLength + sizeof(WCHAR); + + ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize); + if (!ParsedPath) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto l_Exit; + } + memset(ParsedPath, 0, ParsedPathSize); + + ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING)); + + ParsedPath->u16Size = (uint16_t)RootNameLength + sizeof(WCHAR); + ParsedPath->u16Length = ParsedPath->u16Size - sizeof(WCHAR); /* without terminating null */ + RtlCopyMemory(ParsedPath->String.ucs2, pRootName, ParsedPath->u16Length); + + vboxRC = vboxCallMapFolder(&pDeviceExtension->hgcmClient, ParsedPath, &pNetRootExtension->map); + vbsfFreeNonPagedMem(ParsedPath); + if (vboxRC != VINF_SUCCESS) + { + Log(("VBOXSF: VBoxMRxCreateVNetRoot: vboxCallMapFolder failed with %d\n", vboxRC)); + Status = STATUS_BAD_NETWORK_NAME; + } + else + { + Status = STATUS_SUCCESS; + pNetRootExtension->phgcmClient = &pDeviceExtension->hgcmClient; + } + } + } + else Log(("VBOXSF: VBoxMRxCreateVNetRoot: Creating V_NET_ROOT on existing NET_ROOT!\n")); + + if ((Status == STATUS_SUCCESS) && fInitializeNetRoot) + { + // + // A new NET_ROOT and associated V_NET_ROOT are being created ! + // + Status = VBoxMRxInitializeNetRootEntry(pNetRoot); + Log(("VBOXSF: VBoxMRxCreateVNetRoot: NulMRXInitializeNetRootEntry called, Status = 0x%lx\n", Status)); + } + + VBoxUpdateNetRoot(pNetRoot); + +l_Exit: + if (Status != STATUS_PENDING) + { + Log(("VBOXSF: VBoxMRxCreateVNetRoot: Returning 0x%lx\n", Status)); + pCreateNetRootContext->VirtualNetRootStatus = Status; + if (fInitializeNetRoot) + pCreateNetRootContext->NetRootStatus = Status; + else pCreateNetRootContext->NetRootStatus = Status; + + // Callback the RDBSS for resumption. + pCreateNetRootContext->Callback(pCreateNetRootContext); + + // Map the error code to STATUS_PENDING since this triggers + // the synchronization mechanism in the RDBSS. + Status = STATUS_PENDING; + } + + Log(("VBOXSF: VBoxMRxCreateVNetRoot: Returned STATUS_PENDING\n")); + return Status; +} + +NTSTATUS VBoxMRxFinalizeVNetRoot (IN PMRX_V_NET_ROOT pVNetRoot, IN PBOOLEAN ForceDisconnect) +/*++ + + Routine Description: + + + Arguments: + + pVNetRoot - the virtual net root + + ForceDisconnect - disconnect is forced + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot; + VBoxMRxGetNetRootExtension(pVNetRoot->pNetRoot, pNetRootExtension); + int vboxRC; + + Log(("VBOXSF: VBoxMRxFinalizeVNetRoot: Address = 0x%lx\n", pVNetRoot)); + + if (pNetRootExtension->phgcmClient) + { + vboxRC = vboxCallUnmapFolder(pNetRootExtension->phgcmClient, &pNetRootExtension->map); + if (vboxRC != VINF_SUCCESS) + { + Log(("VBOXSF: VBoxMRxFinalizeVNetRoot: vboxCallMapFolder failed with %d\n", vboxRC)); + } + pNetRootExtension->phgcmClient = NULL; + } + + // + // This is called when all outstanding handles on this + // root have been cleaned up ! We can now zap the netroot + // extension... + // + + return Status; +} + +NTSTATUS VBoxMRxFinalizeNetRoot (IN PMRX_NET_ROOT pNetRoot, IN PBOOLEAN ForceDisconnect) +/*++ + + Routine Description: + + + Arguments: + + pVirtualNetRoot - the virtual net root + + ForceDisconnect - disconnect is forced + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + Log(("VBOXSF: VBoxMRxFinalizeNetRoot: Called.\n")); + // + // This is called when all outstanding handles on this + // root have been cleaned up ! We can now zap the netroot + // extension... + // + return (Status); +} + +VOID VBoxMRxExtractNetRootName (IN PUNICODE_STRING FilePathName, IN PMRX_SRV_CALL SrvCall, OUT PUNICODE_STRING NetRootName, OUT PUNICODE_STRING RestOfName OPTIONAL + ) +/*++ + + Routine Description: + + This routine parses the input name into srv, netroot, and the + rest. + + Arguments: + + + --*/ +{ + UNICODE_STRING xRestOfName; + + ULONG length = FilePathName->Length; + PWCH w = FilePathName->Buffer; + PWCH wlimit = (PWCH)(((PCHAR)w) + length); + PWCH wlow; + + Log(("VBOXSF: VBoxMRxExtractNetRootName: Called.\n")); + + w += (SrvCall->pSrvCallName->Length / sizeof(WCHAR)); + NetRootName->Buffer = wlow = w; + for (;;) + { + if (w >= wlimit) + break; + if ((*w == OBJ_NAME_PATH_SEPARATOR) && (w != wlow)) + { + break; + } + w++; + } + + NetRootName->Length = NetRootName->MaximumLength = (USHORT)((PCHAR)w - (PCHAR)wlow); + + //w = FilePathName->Buffer; + //NetRootName->Buffer = w++; + + if (!RestOfName) + RestOfName = &xRestOfName; + RestOfName->Buffer = w; + RestOfName->Length = (USHORT)RestOfName->MaximumLength = (USHORT)((PCHAR)wlimit - (PCHAR)w); + + Log(("VBOXSF: VBoxMRxExtractNetRootName: FilePath = %.*ls\n", FilePathName->Length / sizeof(WCHAR), FilePathName->Buffer)); + Log(("VBOXSF: VBoxMRxExtractNetRootName: Srv = %.*ls, Root = %.*ls, Rest = %.*ls\n", SrvCall->pSrvCallName->Length / sizeof(WCHAR), SrvCall->pSrvCallName->Buffer, NetRootName->Length + / sizeof(WCHAR), NetRootName->Buffer, RestOfName->Length / sizeof(WCHAR), RestOfName->Buffer)); + + return; +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/notimpl.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/notimpl.c new file mode 100644 index 00000000000..71370019607 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/notimpl.c @@ -0,0 +1,110 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + notimpl.c + + Abstract: + + This module includes prototypes of the functionality that has not been + implemented in the null mini rdr. + + --*/ + +#include "precomp.h" +#pragma hdrstop + +// +// File System Control funcitonality +// + + +NTSTATUS VBoxMRxFsCtl (IN OUT PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine performs an FSCTL operation (remote) on a file across the network + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation + + + --*/ +{ + NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; + + Log(("VBOXSF: VBoxMRxFsCtl: Returned 0x%08lx\n", Status)); + return Status; +} + +NTSTATUS VBoxMRxNotifyChangeDirectoryCancellation (PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine is invoked when a directory change notification operation is cancelled. + This example doesn't support it. + + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + + UNREFERENCED_PARAMETER(RxContext); + + Log(("VBoxMRxNotifyChangeDirectoryCancellation\n")); + return STATUS_SUCCESS; +} + +NTSTATUS VBoxMRxNotifyChangeDirectory (IN OUT PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine performs a directory change notification operation. + This example doesn't support it. + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation [not implemented] + + --*/ +{ + + UNREFERENCED_PARAMETER(RxContext); + + Log(("VBoxMRxNotifyChangeDirectory\n")); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS VBoxMRxQuerySecurityInformation (IN OUT PRX_CONTEXT RxContext) +{ + Log(("VBoxMRxQuerySecurityInformation \n")); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS VBoxMRxSetSecurityInformation (IN OUT struct _RX_CONTEXT * RxContext) +{ + Log(("VBoxMRxSetSecurityInformation \n")); + return STATUS_NOT_IMPLEMENTED; +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/nulmrx.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/nulmrx.h new file mode 100644 index 00000000000..2c5708fea93 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/nulmrx.h @@ -0,0 +1,119 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + nulmrx.h + + Abstract: + + This header exports all symbols and definitions shared between + user-mode clients of nulmrx and the driver itself. + + Notes: + + This module has been built and tested only in UNICODE environment + + --*/ + +#ifndef _MRX_VBOX_H_ +#define _MRX_VBOX_H_ + +/** ULONG tags used by the FSD. */ +#define TAG_PP 'PfsV' +#define TAG_FCB 'FfsV' +#define TAG_CCB 'CfsV' +#define TAG_IRPCTX 'IfsV' + +// Device name for this driver +#define MRX_VBOX_DEVICE_NAME_A "VBoxMiniRdr" +#define MRX_VBOX_DEVICE_NAME_U L"VBoxMiniRdr" + +// Provider name for this driver +#define MRX_VBOX_PROVIDER_NAME_A "VirtualBox Shared Folders" +#define MRX_VBOX_PROVIDER_NAME_U L"VirtualBox Shared Folders" + +// File system name +#define MRX_VBOX_FILESYS_NAME_A "VBoxSharedFolderFS" +#define MRX_VBOX_FILESYS_NAME_U L"VBoxSharedFolderFS" + +// The following constant defines the length of the above name. +#define MRX_VBOX_DEVICE_NAME_A_LENGTH (15) + +// The following constant defines the path in the ob namespace +#define DD_MRX_VBOX_FS_DEVICE_NAME_U L"\\Device\\VBoxMiniRdr" + +/* File system volume name prefix */ +#define VBOX_VOLNAME_PREFIX L"VBOX_" +#define VBOX_VOLNAME_PREFIX_SIZE (sizeof(VBOX_VOLNAME_PREFIX) - sizeof(VBOX_VOLNAME_PREFIX[0])) + +#ifndef MRX_VBOX_DEVICE_NAME +#define MRX_VBOX_DEVICE_NAME + +// +// The Devicename string required to access the nullmini device +// from User-Mode. Clients should use DD_MRX_VBOX_USERMODE_DEV_NAME_U. +// +// WARNING The next two strings must be kept in sync. Change one and you must +// change the other. These strings have been chosen such that they are +// unlikely to coincide with names of other drivers. +// +#define DD_MRX_VBOX_USERMODE_SHADOW_DEV_NAME_U L"\\??\\VBoxMiniRdrDN" +#define DD_MRX_VBOX_USERMODE_DEV_NAME_U L"\\\\.\\VBoxMiniRdrDN" + +// +// Prefix needed for disk filesystems +// +#define DD_MRX_VBOX_MINIRDR_PREFIX L"\\;E:" + +#endif // MRX_VBOX_DEVICE_NAME +// +// BEGIN WARNING WARNING WARNING WARNING +// The following are from the ddk include files and cannot be changed + +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 // from ddk\inc\ntddk.h +#define METHOD_BUFFERED 0 +#define FILE_ANY_ACCESS 0 + +// END WARNING WARNING WARNING WARNING + +#define IOCTL_MRX_VBOX_BASE FILE_DEVICE_NETWORK_FILE_SYSTEM + +#define _MRX_VBOX_CONTROL_CODE(request, method, access) \ + CTL_CODE(IOCTL_MRX_VBOX_BASE, request, method, access) + +// +// IOCTL codes supported by NullMini Device. +// + +#define IOCTL_CODE_ADDCONN 100 +#define IOCTL_CODE_GETCONN 101 +#define IOCTL_CODE_DELCONN 102 +#define IOCTL_CODE_GETLIST 103 +#define IOCTL_CODE_GETGLOBALLIST 104 +#define IOCTL_CODE_GETGLOBALCONN 105 +#define IOCTL_CODE_START 106 +#define IOCTL_CODE_STOP 107 + +// +// Following is the IOCTL definition and associated structs. +// for IOCTL_CODE_SAMPLE1 +// +#define IOCTL_MRX_VBOX_ADDCONN _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_ADDCONN, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_MRX_VBOX_GETCONN _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_GETCONN, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_MRX_VBOX_DELCONN _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_DELCONN, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_MRX_VBOX_GETLIST _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_GETLIST, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_MRX_VBOX_GETGLOBALLIST _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_GETGLOBALLIST, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_MRX_VBOX_GETGLOBALCONN _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_GETGLOBALCONN, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_MRX_VBOX_START _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_START, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_MRX_VBOX_STOP _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_STOP, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#endif // _MRX_VBOX_H_ + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/openclos.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/openclos.c new file mode 100644 index 00000000000..153e06bedd2 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/openclos.c @@ -0,0 +1,1526 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + openclos.c + + Abstract: + + This module implements the mini redirector call down routines pertaining to opening/ + closing of file/directories. + + --*/ + +#include "precomp.h" +#include "rdbss_vbox.h" +#pragma hdrstop + +static UNICODE_STRING UnicodeBackslash = { 2, 4,L"\\" }; + +// +// forwards & pragmas +// + +#ifdef __cplusplus +extern "C" +{ +#endif + +NTSTATUS VBoxMRxProcessCreate (IN PRX_CONTEXT RxContext, IN PUNICODE_STRING RemainingName, IN FILE_BASIC_INFORMATION *pFileBasicInfo, IN FILE_STANDARD_INFORMATION *pFileStandardInfo, + IN PVOID EaBuffer, IN ULONG EaLength, OUT ULONG *pulCreateAction, OUT SHFLHANDLE *pHandle); + +NTSTATUS VBoxMRxCreateFileSuccessTail (PRX_CONTEXT RxContext, PBOOLEAN MustRegainExclusiveResource, RX_FILE_TYPE StorageType, ULONG CreateAction, FILE_BASIC_INFORMATION* pFileBasicInfo, + FILE_STANDARD_INFORMATION* pFileStandardInfo, SHFLHANDLE Handle); + +VOID VBoxMRxSetSrvOpenFlags (PRX_CONTEXT RxContext, RX_FILE_TYPE StorageType, PMRX_SRV_OPEN SrvOpen); + +#ifdef __cplusplus +} +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, VBoxMRxCreate) +#pragma alloc_text(PAGE, VBoxMRxShouldTryToCollapseThisOpen) +#pragma alloc_text(PAGE, VBoxMRxProcessCreate) +#pragma alloc_text(PAGE, VBoxMRxCreateFileSuccessTail) +#pragma alloc_text(PAGE, VBoxMRxSetSrvOpenFlags) +#endif + +NTSTATUS VBoxMRxShouldTryToCollapseThisOpen (IN PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine determines if the mini knows of a good reason not + to try collapsing on this open. Presently, the only reason would + be if this were a copychunk open. + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + NTSTATUS - The return status for the operation + SUCCESS --> okay to try collapse + other (MORE_PROCESSING_REQUIRED) --> dont collapse + + --*/ +{ +#ifdef VBOX_SHFL_WITH_COLLAPSE + NTSTATUS Status = STATUS_SUCCESS; +#else + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; +#endif + + Log(("VBoxMRxShouldTryToCollapseThisOpen returned %x\n", Status)); + + PAGED_CODE(); + + return Status; +} + +BOOLEAN VBoxMRxIsStreamFile (PUNICODE_STRING FileName, PUNICODE_STRING AdjustFileName) +/*++ + + Routine Description: + + This routine checks if it is a stream file and return the root file name if true. + + Arguments: + + FileName - the file name needs to be parsed + AdjustFileName - the file name contains only root name of the stream + + Return Value: + + BOOLEAN - stream file + + --*/ +{ + USHORT i; + BOOLEAN IsStream = FALSE; + NTSTATUS Status = STATUS_SUCCESS; + + Log(("VBoxMRxIsStreamFile %.*ls\n", FileName->Length / sizeof(WCHAR), FileName->Buffer)); + + for (i = 0; i < FileName->Length / sizeof(WCHAR); i++) + { + if (FileName->Buffer[i] == L':') + { + IsStream = TRUE; + break; + } + } + + if (AdjustFileName != NULL) + { + if (IsStream) + { + AdjustFileName->Length = AdjustFileName->MaximumLength = i * sizeof(WCHAR); + AdjustFileName->Buffer = FileName->Buffer; + } + else + { + AdjustFileName->Length = AdjustFileName->MaximumLength = 0; + AdjustFileName->Buffer = NULL; + } + } + + return IsStream; +} + +#define NulMRxGetFcbExtension(pFcb,pExt) \ + PNULMRX_FCB_EXTENSION pExt = (((pFcb) == NULL) ? NULL : (PNULMRX_FCB_EXTENSION)((pFcb)->Context)) + +#define NulMRxGetNetRootExtension(pNetRoot,pExt) \ + PNULMRX_NETROOT_EXTENSION pExt = (((pNetRoot) == NULL) ? NULL : (PNULMRX_NETROOT_EXTENSION)((pNetRoot)->Context)) + +typedef struct _NULMRX_FCB_EXTENSION_ +{ + // + // Node type code and size + // + NODE_TYPE_CODE NodeTypeCode; + NODE_BYTE_SIZE NodeByteSize; + +} NULMRX_FCB_EXTENSION, *PNULMRX_FCB_EXTENSION; + +// +// NET_ROOT extension - stores state global to a root +// +typedef struct _NULMRX_NETROOT_EXTENSION +{ + // + // Node type code and size + // + NODE_TYPE_CODE NodeTypeCode; + NODE_BYTE_SIZE NodeByteSize; + +} NULMRX_NETROOT_EXTENSION, *PNULMRX_NETROOT_EXTENSION; + +NTSTATUS NulMRxProcessCreate (IN PNULMRX_FCB_EXTENSION pFcbExtension, IN PVOID EaBuffer, IN ULONG EaLength, OUT PLONGLONG pEndOfFile, OUT PLONGLONG pAllocationSize) +/*++ + + Routine Description: + + This routine processes a create calldown. + + Arguments: + + pFcbExtension - ptr to the FCB extension + EaBuffer - ptr to the EA param buffer + EaLength - len of EaBuffer + pEndOfFile - return end of file value + pAllocationSize - return allocation size (which maybe > EOF) + + Notes: + + It is possible to create a file with no EAs + + Return Value: + + None + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + RxDbgTrace(0, Dbg, ("NulMRxInitializeFcbExtension\n")); + + *pAllocationSize = *pEndOfFile = 0; + return Status; +} + +VOID NulMRxSetSrvOpenFlags (PRX_CONTEXT RxContext, RX_FILE_TYPE StorageType, PMRX_SRV_OPEN SrvOpen) +{ + PMRX_SRV_CALL SrvCall = (PMRX_SRV_CALL)RxContext->Create.pSrvCall; + + // + // set this only if cache manager will be used for mini-rdr handles ! + // + SrvOpen->BufferingFlags |= (FCB_STATE_FILESIZECACHEING_ENABLED | FCB_STATE_FILETIMECACHEING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED | FCB_STATE_LOCK_BUFFERING_ENABLED + | FCB_STATE_READBUFFERING_ENABLED | +#if (NTDDI_VERSION >= NTDDI_VISTA) /* Correct spelling for Vista 6001 SDK. */ + FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_READCACHING_ENABLED); +#else + FCB_STATE_WRITECACHEING_ENABLED | + FCB_STATE_READCACHEING_ENABLED); +#endif +} + +NTSTATUS NulMRxCreateFileSuccessTail (PRX_CONTEXT RxContext, PBOOLEAN MustRegainExclusiveResource, RX_FILE_TYPE StorageType, ULONG CreateAction, FILE_BASIC_INFORMATION* pFileBasicInfo, + FILE_STANDARD_INFORMATION* pFileStandardInfo) +/*++ + + Routine Description: + + This routine finishes the initialization of the fcb and srvopen for a + successful open. + + Arguments: + + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + RxCaptureFcb; + PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + + FCB_INIT_PACKET InitPacket; + + RxDbgTrace(0, Dbg, ("MRxExCreateFileSuccessTail\n")); + PAGED_CODE(); + + ASSERT(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN); + ASSERT(NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT); + + if (*MustRegainExclusiveResource) + { //this is required because of oplock breaks + RxAcquireExclusiveFcb(RxContext, capFcb); + *MustRegainExclusiveResource = FALSE; + } + + // This Fobx should be cleaned up by the wrapper + RxContext->pFobx = RxCreateNetFobx(RxContext, SrvOpen); + if (RxContext->pFobx == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + ASSERT(RxIsFcbAcquiredExclusive(capFcb)); + RxDbgTrace(0, Dbg, ("Storagetype %08lx/Action %08lx\n", StorageType, CreateAction)); + + RxContext->Create.ReturnedCreateInformation = CreateAction; + + RxFormInitPacket(InitPacket, &pFileBasicInfo->FileAttributes, &pFileStandardInfo->NumberOfLinks, &pFileBasicInfo->CreationTime, &pFileBasicInfo->LastAccessTime, &pFileBasicInfo->LastWriteTime, + &pFileBasicInfo->ChangeTime, &pFileStandardInfo->AllocationSize, &pFileStandardInfo->EndOfFile, &pFileStandardInfo->EndOfFile); + + if (capFcb->OpenCount == 0) + { + RxFinishFcbInitialization(capFcb, RDBSS_STORAGE_NTC(StorageType), &InitPacket); + } + else + { + + ASSERT(StorageType == 0 || NodeType(capFcb) == RDBSS_STORAGE_NTC(StorageType)); + + } + + NulMRxSetSrvOpenFlags(RxContext, StorageType, SrvOpen); + + RxContext->pFobx->OffsetOfNextEaToReturn = 1; + //transition happens later + + return Status; +} + +NTSTATUS VBoxMRxCreate (IN OUT PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine opens a file across the network + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + BOOLEAN fMustRegainExclusiveResource = FALSE; + RX_FILE_TYPE StorageType = FileTypeFile; + ULONG CreateAction = FILE_CREATED; + FILE_BASIC_INFORMATION FileBasicInfo; + FILE_STANDARD_INFORMATION FileStandardInfo; + RxCaptureFcb; + RxCaptureFobx; + PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall; + PMRX_NET_ROOT NetRoot = capFcb->pNetRoot; + PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext); + PVOID EaBuffer = RxContext->Create.EaBuffer; + ULONG EaLength = RxContext->Create.EaLength; + VBoxMRxGetNetRootExtension(NetRoot,pNetRootExtension); + SHFLHANDLE Handle = SHFL_HANDLE_NIL; + + PAGED_CODE(); + + Log(("VBOXSF: VBoxMRxCreate: %x length=%d\n", RemainingName, RemainingName->Length)); + + if (RemainingName->Length) + { +#ifdef VBOX_GUEST + Log(("VBOXSF: VBoxMRxCreate: Attempt to open %.*ls Len is %d\n", RemainingName->Length/sizeof(WCHAR), RemainingName->Buffer, RemainingName->Length )); +#else + Log(("VBOXSF: VBoxMRxCreate: Attempt to open %wZ Len is %d\n", RemainingName, RemainingName->Length)); +#endif + } + else + { + if (FlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH)) + { + Log(("VBOXSF: VBoxMRxCreate: Empty name -> Only backslash used\n")); + RemainingName = &UnicodeBackslash; + } + } + + switch (NetRoot->Type) + { + case NET_ROOT_MAILSLOT: + case NET_ROOT_PIPE: + case NET_ROOT_PRINT: + default: + Log(("VBOXSF: VBoxMRxCreate: Type %d not supported or invalid open\n", NetRoot->Type)); + Status = STATUS_NOT_SUPPORTED; + goto Exit; + + case NET_ROOT_WILD: /** @todo what's this?? */ + case NET_ROOT_DISK: + break; + } + + FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; + + // + // Squirrel away the scatter list in the FCB extension. + // This is done only for data files. + // + Status = VBoxMRxProcessCreate(RxContext, RemainingName, &FileBasicInfo, &FileStandardInfo, EaBuffer, EaLength, &CreateAction, &Handle); + if (Status != STATUS_SUCCESS) + { + // + // error.. + // + Log(("VBOXSF: VBoxMRxCreate: Failed to initialize scatter list!\n")); + goto Exit; + } + + // + // Complete CreateFile contract + // + Log(("VBOXSF: VBoxMRxCreate: EOF is %d AllocSize is %d\n", (ULONG)FileStandardInfo.EndOfFile.QuadPart, (ULONG)FileStandardInfo.AllocationSize.QuadPart)); + + Status = VBoxMRxCreateFileSuccessTail(RxContext, &fMustRegainExclusiveResource, StorageType, CreateAction, &FileBasicInfo, &FileStandardInfo, Handle); + + if (Status != STATUS_SUCCESS) + { + // + // alloc error.. + // + Log(("VBOXSF: VBoxMRxCreate: Failed to allocate Fobx!\n")); + goto Exit; + } + + if (!RxIsFcbAcquiredExclusive(capFcb)) + { + Assert(!RxIsFcbAcquiredShared(capFcb)); + VboxRxAcquireExclusiveFcbResourceInMRx(capFcb); + } + + Assert(Status != (STATUS_PENDING)); + Assert(RxIsFcbAcquiredExclusive(capFcb)); + + Log(("VBOXSF: VBoxMRxCreate: NetRoot is 0x%x, Fcb is 0x%x, SrvOpen is 0x%x, Fobx is 0x%x\n", NetRoot, capFcb, SrvOpen, RxContext->pFobx)); + Log(("VBOXSF: VBoxMRxCreate: Exit with status=%08lx\n", Status)); + + Exit: return (Status); +} + +NTSTATUS VBoxMRxProcessCreate (IN PRX_CONTEXT RxContext, IN PUNICODE_STRING RemainingName, IN FILE_BASIC_INFORMATION *pFileBasicInfo, IN FILE_STANDARD_INFORMATION *pFileStandardInfo, + IN PVOID EaBuffer, IN ULONG EaLength, OUT ULONG *pulCreateAction, OUT SHFLHANDLE *pHandle) +/*++ + + Routine Description: + + This routine processes a create calldown. + + Arguments: + + pFcbExtension - ptr to the FCB extension + EaBuffer - ptr to the EA param buffer + EaLength - len of EaBuffer + pEndOfFile - return end of file value + pAllocationSize - return allocation size (which maybe > EOF) + + Notes: + + It is possible to create a file with no EAs + + Return Value: + + None + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + RxCaptureFcb; + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + VBoxMRxGetNetRootExtension(capFcb->pNetRoot,pNetRootExtension); + + int vboxRC = VINF_SUCCESS; + + /* Various boolean flags. */ + struct + { + ULONG CreateDirectory :1; + ULONG SequentialOnly :1; + ULONG NoIntermediateBuffering :1; + ULONG OpenDirectory :1; + ULONG IsPagingFile :1; + ULONG OpenTargetDirectory :1; + ULONG DirectoryFile :1; + ULONG NonDirectoryFile :1; + ULONG NoEaKnowledge :1; + ULONG DeleteOnClose :1; + ULONG TemporaryFile :1; + ULONG FileNameOpenedDos :1; + ULONG PostIrp :1; + ULONG OplockPostIrp :1; + ULONG TrailingBackslash :1; + ULONG FirstLoop :1; + ULONG SeparatorEncountered :1; + ULONG DriveAcquired :1; + } bf; + + ACCESS_MASK DesiredAccess; + ULONG Options; + UCHAR FileAttributes; + ULONG ShareAccess; + ULONG CreateDisposition; + SHFLCREATEPARMS *pCreateParms = 0; + + Log(("VBOXSF: VBoxMRxProcessCreate\n")); + Log(("VBOXSF: VBoxMRxProcessCreate: FileAttributes = %08x\n", RxContext->Create.NtCreateParameters.FileAttributes)); + Log(("VBOXSF: VBoxMRxProcessCreate: CreateOptions = %08x\n", RxContext->Create.NtCreateParameters.CreateOptions)); + + RtlZeroMemory (&bf, sizeof (bf)); + + DesiredAccess = RxContext->Create.NtCreateParameters.DesiredAccess; + Options = RxContext->Create.NtCreateParameters.CreateOptions & FILE_VALID_OPTION_FLAGS; + FileAttributes = (UCHAR)(RxContext->Create.NtCreateParameters.FileAttributes & ~FILE_ATTRIBUTE_NORMAL); + ShareAccess = RxContext->Create.NtCreateParameters.ShareAccess; + + /* Extended attributes are not supported! */ + if (EaLength) + { + Log(("VBOXSF: VBoxMRxProcessCreate: Unsupported: extended attributes!\n")); + Status = STATUS_NOT_SUPPORTED; + goto failure; + } + + /* We do not support opens by file ids yet. */ + if (FlagOn(Options, FILE_OPEN_BY_FILE_ID)) + { + Log(("VBOXSF: VBoxMRxProcessCreate: Unsupported: file open by id!\n")); + Status = STATUS_NOT_IMPLEMENTED; + goto failure; + } + + /* Mask out unsupported attribute bits. */ + FileAttributes &= (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE); + + bf.DirectoryFile = BooleanFlagOn(Options, FILE_DIRECTORY_FILE); + bf.NonDirectoryFile = BooleanFlagOn(Options, FILE_NON_DIRECTORY_FILE); + bf.SequentialOnly = BooleanFlagOn(Options, FILE_SEQUENTIAL_ONLY); + bf.NoIntermediateBuffering = BooleanFlagOn(Options, FILE_NO_INTERMEDIATE_BUFFERING); + bf.NoEaKnowledge = BooleanFlagOn(Options, FILE_NO_EA_KNOWLEDGE); + bf.DeleteOnClose = BooleanFlagOn(Options, FILE_DELETE_ON_CLOSE); + if (bf.DeleteOnClose) + Log(("VBOXSF: VBoxMRxProcessCreate: Delete on close!\n")); + + CreateDisposition = RxContext->Create.NtCreateParameters.Disposition; + + bf.IsPagingFile = BooleanFlagOn(capFcb->FcbState, FCB_STATE_PAGING_FILE); + if (bf.IsPagingFile) + { + Log(("VBOXSF: VBoxMRxProcessCreate: Unsupported: paging file!\n")); + Status = STATUS_NOT_IMPLEMENTED; + goto failure; + } + + bf.CreateDirectory = (BOOLEAN)(bf.DirectoryFile && ((CreateDisposition == FILE_CREATE) || (CreateDisposition == FILE_OPEN_IF))); + + bf.OpenDirectory = (BOOLEAN)(bf.DirectoryFile && ((CreateDisposition == FILE_OPEN) || (CreateDisposition == FILE_OPEN_IF))); + + bf.TemporaryFile = BooleanFlagOn(RxContext->Create.NtCreateParameters.FileAttributes, FILE_ATTRIBUTE_TEMPORARY ); + + if (FlagOn(capFcb->FcbState, FCB_STATE_TEMPORARY)) + bf.TemporaryFile = TRUE; + + Log(("VBOXSF: VBoxMRxProcessCreate: bf.TemporaryFile %d, bf.CreateDirectory %d, bf.DirectoryFile = %d\n", (ULONG)bf.TemporaryFile, (ULONG)bf.CreateDirectory, (ULONG)bf.DirectoryFile)); + + /* Check consistency in specified flags. */ + if (bf.TemporaryFile && bf.CreateDirectory) /* Directories with temporary flag set are not allowed! */ + { + Log(("VBOXSF: VBoxMRxProcessCreate: Not allowed: Temporary directories!\n")); + Status = STATUS_INVALID_PARAMETER; + goto failure; + } + + if (bf.DirectoryFile && bf.NonDirectoryFile) + { + AssertMsgFailed(("VBOXSF: VBoxMRxProcessCreate: Unsupported combination: dir && !dir\n")); + Status = STATUS_INVALID_PARAMETER; + goto failure; + } + + /* Initialize create parameters. */ + pCreateParms = (SHFLCREATEPARMS *)vbsfAllocNonPagedMem(sizeof(SHFLCREATEPARMS)); + if (!pCreateParms) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto failure; + } + + RtlZeroMemory (pCreateParms, sizeof (SHFLCREATEPARMS)); + + pCreateParms->Handle = SHFL_HANDLE_NIL; + pCreateParms->Result = SHFL_NO_RESULT; + + if (bf.OpenTargetDirectory) + { + pCreateParms->CreateFlags |= SHFL_CF_OPEN_TARGET_DIRECTORY; + } + + if (bf.DirectoryFile) + { + if (CreateDisposition != FILE_CREATE && CreateDisposition != FILE_OPEN && CreateDisposition != FILE_OPEN_IF) + { + AssertMsgFailed(("VBOXSF: VBoxMRxProcessCreate: Invalid disposition %x for directory!\n", CreateDisposition)); + Status = STATUS_INVALID_PARAMETER; + goto failure; + } + + pCreateParms->CreateFlags |= SHFL_CF_DIRECTORY; + } + + Log(("VBOXSF: VBoxMRxProcessCreate: CreateDisposition = %08x\n", CreateDisposition)); + + switch (CreateDisposition) + { + case FILE_SUPERSEDE: + pCreateParms->CreateFlags |= SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW; + Log(("VBOXSF: VBoxMRxProcessCreate: CreateFlags |= SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n")); + break; + + case FILE_OPEN: + pCreateParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW; + Log(("VBOXSF: VBoxMRxProcessCreate: CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW\n")); + break; + + case FILE_CREATE: + pCreateParms->CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW; + Log(("VBOXSF: VBoxMRxProcessCreate: CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n")); + break; + + case FILE_OPEN_IF: + pCreateParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW; + Log(("VBOXSF: VBoxMRxProcessCreate: CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n")); + break; + + case FILE_OVERWRITE: + pCreateParms->CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW; + Log(("VBOXSF: VBoxMRxProcessCreate: CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW\n")); + break; + + case FILE_OVERWRITE_IF: + pCreateParms->CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW; + Log(("VBOXSF: VBoxMRxProcessCreate: CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n")); + break; + + default: + AssertMsgFailed(("VBOXSF: VBoxMRxProcessCreate: Unexpected create disposition: 0x%08X\n", CreateDisposition)); + Status = STATUS_INVALID_PARAMETER; + goto failure; + } + + Log(("VBOXSF: VBoxMRxProcessCreate: DesiredAccess = 0x%08x\n", DesiredAccess)); + Log(("VBOXSF: VBoxMRxProcessCreate: ShareAccess = 0x%08x\n", ShareAccess)); + + if (DesiredAccess & FILE_READ_DATA) + { + Log(("VBOXSF: VBoxMRxProcessCreate: FILE_READ_DATA\n")); + pCreateParms->CreateFlags |= SHFL_CF_ACCESS_READ; + } + + if (DesiredAccess & FILE_WRITE_DATA) + { + Log(("VBOXSF: VBoxMRxProcessCreate: FILE_WRITE_DATA\n")); + /* FILE_WRITE_DATA means write access regardless of FILE_APPEND_DATA bit. + */ + pCreateParms->CreateFlags |= SHFL_CF_ACCESS_WRITE; + } + else if (DesiredAccess & FILE_APPEND_DATA) + { + Log(("VBOXSF: VBoxMRxProcessCreate: FILE_APPEND_DATA\n")); + /* FILE_APPEND_DATA without FILE_WRITE_DATA means append only mode. + * + * Both write and append access flags are required for shared folders, + * as on Windows FILE_APPEND_DATA implies write access. + */ + pCreateParms->CreateFlags |= SHFL_CF_ACCESS_WRITE | SHFL_CF_ACCESS_APPEND; + } + + if (DesiredAccess & FILE_READ_ATTRIBUTES) + pCreateParms->CreateFlags |= SHFL_CF_ACCESS_ATTR_READ; + if (DesiredAccess & FILE_WRITE_ATTRIBUTES) + pCreateParms->CreateFlags |= SHFL_CF_ACCESS_ATTR_WRITE; + + if (ShareAccess & (FILE_SHARE_READ | FILE_SHARE_WRITE)) + pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYNONE; + else if (ShareAccess & FILE_SHARE_READ) + pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYWRITE; + else if (ShareAccess & FILE_SHARE_WRITE) + pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYREAD; + else pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYALL; + + /* Set initial allocation size. */ + pCreateParms->Info.cbObject = RxContext->Create.NtCreateParameters.AllocationSize.QuadPart; + + if (FileAttributes == 0) + FileAttributes = FILE_ATTRIBUTE_NORMAL; + + pCreateParms->Info.Attr.fMode = NTToVBoxFileAttributes(FileAttributes); + +#ifdef VBOX_FAKE_IO_CREATE + { + LARGE_INTEGER liSystemTime; + pFileBasicInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL; + KeQuerySystemTime(&liSystemTime); + pFileBasicInfo->CreationTime = liSystemTime; + pFileBasicInfo->LastAccessTime = liSystemTime; + pFileBasicInfo->LastWriteTime = liSystemTime; + pFileBasicInfo->ChangeTime = liSystemTime; + pFileStandardInfo->AllocationSize.QuadPart = 0; + pFileStandardInfo->EndOfFile.QuadPart = 0; + pFileStandardInfo->NumberOfLinks = 0; + + *pulCreateAction = FILE_CREATED; + + *pHandle = (SHFLHANDLE)0xABCDEF00; + } +#else + { + PSHFLSTRING ParsedPath = 0; + ULONG ParsedPathSize; + + /* Calculate length required for parsed path. + */ + ParsedPathSize = sizeof(*ParsedPath) + (RemainingName->Length + sizeof(WCHAR)); + + Log(("VBOXSF: VBoxMRxProcessCreate: ParsedPathSize = %d\n", ParsedPathSize)); + + ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize); + if (NULL == ParsedPath) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto failure; + } + + ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING)); + + ParsedPath->u16Size = RemainingName->Length + sizeof(WCHAR); + ParsedPath->u16Length = ParsedPath->u16Size - sizeof(WCHAR); /* without terminating null */ + RtlCopyMemory (ParsedPath->String.ucs2, RemainingName->Buffer, ParsedPath->u16Length); + Log(("ParsedPath: %.*ls\n", ParsedPath->u16Length / sizeof(WCHAR), ParsedPath->String.ucs2)); + + /* Call host. */ + Log(("VBOXSF: VBoxMRxProcessCreate: vboxCallCreate called.\n")); + vboxRC = vboxCallCreate(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, ParsedPath, pCreateParms); + vbsfFreeNonPagedMem(ParsedPath); + } + + Log(("VBOXSF: VBoxMRxProcessCreate: vboxCallCreate returns vboxRC = %Rrc, Result = %x\n", vboxRC, pCreateParms->Result)); + if (RT_FAILURE(vboxRC)) + { + Log(("VBOXSF: VBoxMRxProcessCreate: vboxCallCreate failed with %Rrc\n", vboxRC)); + /* Map some VBoxRC to STATUS codes expected by the system. */ + switch (vboxRC) + { + + case VERR_ALREADY_EXISTS: + { + *pulCreateAction = FILE_EXISTS; + Status = STATUS_OBJECT_NAME_COLLISION; + } + goto failure; + break; + + /* On POSIX systems, the "mkdir" command returns VERR_FILE_NOT_FOUND when + doing a recursive directory create. Handle this case in the next switch below. */ + case VERR_FILE_NOT_FOUND: + + pCreateParms->Result = SHFL_PATH_NOT_FOUND; + break; + + default: + { + *pulCreateAction = FILE_DOES_NOT_EXIST; + Status = VBoxErrorToNTStatus(vboxRC); + } + goto failure; + break; + } + } + + /* + * The request succeeded. Analyze host response, + */ + switch (pCreateParms->Result) + { + case SHFL_PATH_NOT_FOUND: + { + /* Path to object does not exist. */ + Log(("VBOXSF: VBoxMRxProcessCreate: Path not found\n")); + *pulCreateAction = FILE_DOES_NOT_EXIST; + Status = STATUS_OBJECT_PATH_NOT_FOUND; + goto failure; + } + + case SHFL_FILE_NOT_FOUND: + { + Log(("VBOXSF: VBoxMRxProcessCreate: File not found\n")); + *pulCreateAction = FILE_DOES_NOT_EXIST; + if (pCreateParms->Handle == SHFL_HANDLE_NIL) + { + Status = STATUS_OBJECT_NAME_NOT_FOUND; + goto failure; + } + + /* Here we can only have the OpenTargetDirectory mode. */ + if (!bf.OpenTargetDirectory) + { + Log(("VBOXSF: VBoxMRxProcessCreate: File not found but have a handle!\n")); + Status = STATUS_UNSUCCESSFUL; + goto failure; + } + /* File components does not exist but target directory was opened. */ + break; + } + + case SHFL_FILE_EXISTS: + { + Log(("VBOXSF: VBoxMRxProcessCreate: File exists, Handle = %08x\n", pCreateParms->Handle)); + if (pCreateParms->Handle == SHFL_HANDLE_NIL) + { + *pulCreateAction = FILE_EXISTS; + if (CreateDisposition == FILE_CREATE) + { + /* File was not opened because we requested a create. */ + Status = STATUS_OBJECT_NAME_COLLISION; + goto failure; + } + + /* Actually we should not go here, unless we have no rights to open the object. */ + Log(("VBOXSF: VBoxMRxProcessCreate: Existing file was not opened!\n")); + Status = STATUS_ACCESS_DENIED; + goto failure; + } + + if (bf.OpenTargetDirectory) + { + *pulCreateAction = FILE_EXISTS; + } + else + { + *pulCreateAction = FILE_OPENED; + } + + /* Existing file was opened. Go check flags and create FCB. */ + break; + } + + case SHFL_FILE_CREATED: + { + /* A new file was created. */ + + Assert(pCreateParms->Handle != SHFL_HANDLE_NIL); + + *pulCreateAction = FILE_CREATED; + + /* Go check flags and create FCB. */ + break; + } + + case SHFL_FILE_REPLACED: + { + /* Existing file was replaced or overwriting. */ + + Assert(pCreateParms->Handle != SHFL_HANDLE_NIL); + + if (CreateDisposition == FILE_SUPERSEDE) + { + *pulCreateAction = FILE_SUPERSEDED; + } + else + { + *pulCreateAction = FILE_OVERWRITTEN; + } + /* Go check flags and create FCB. */ + break; + } + + default: + { + Log(("VBOXSF: VBoxMRxProcessCreate: Invalid CreateResult from host (0x%08X)\n", pCreateParms->Result)); + *pulCreateAction = FILE_DOES_NOT_EXIST; + Status = STATUS_OBJECT_PATH_NOT_FOUND; + goto failure; + } + } + + /* Check flags. */ + if (bf.NonDirectoryFile && FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY)) + { + /* Caller wanted only a file, but the object is a directory. */ + Log(("VBOXSF: VBoxMRxProcessCreate: File is a directory!\n")); + Status = STATUS_FILE_IS_A_DIRECTORY; + goto failure; + } + + if (bf.DirectoryFile && !FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY)) + { + /* Caller wanted only a directory, but the object is not a directory. */ + Log(("VBOXSF: VBoxMRxProcessCreate: File is not a directory!\n")); + Status = STATUS_NOT_A_DIRECTORY; + goto failure; + } + + *pHandle = pCreateParms->Handle; + + /* Translate attributes */ + pFileBasicInfo->FileAttributes = VBoxToNTFileAttributes(pCreateParms->Info.Attr.fMode); + + /* Translate file times */ + pFileBasicInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pCreateParms->Info.BirthTime); /* ridiculous name */ + pFileBasicInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pCreateParms->Info.AccessTime); + pFileBasicInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pCreateParms->Info.ModificationTime); + pFileBasicInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pCreateParms->Info.ChangeTime); + + if (!FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY)) + { + Assert(!FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY)); + pFileStandardInfo->AllocationSize.QuadPart = pCreateParms->Info.cbAllocated; + pFileStandardInfo->EndOfFile.QuadPart = pCreateParms->Info.cbObject; + pFileStandardInfo->Directory = FALSE; + + Log(("VBOXSF: VBoxMRxProcessCreate: AllocationSize = %RX64, EndOfFile = %RX64\n", pCreateParms->Info.cbAllocated, pCreateParms->Info.cbObject)); + } + else + { + Assert(FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY)); + pFileStandardInfo->AllocationSize.QuadPart = 0; + pFileStandardInfo->EndOfFile.QuadPart = 0; + pFileStandardInfo->Directory = TRUE; + } + pFileStandardInfo->NumberOfLinks = 0; + pFileStandardInfo->DeletePending = FALSE; +#endif + + vbsfFreeNonPagedMem(pCreateParms); + return Status; + + failure: + + Log(("VBOXSF: VBoxMRxProcessCreate: Returned with status = 0x%08lx\n", Status)); + if (pCreateParms && pCreateParms->Handle != SHFL_HANDLE_NIL) + { +#ifndef VBOX_FAKE_IO_CREATE + vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pCreateParms->Handle); +#endif + *pHandle = SHFL_HANDLE_NIL; + } + + if (pCreateParms) + vbsfFreeNonPagedMem(pCreateParms); + + return Status; +} + +VOID VBoxMRxSetSrvOpenFlags (PRX_CONTEXT RxContext, RX_FILE_TYPE StorageType, PMRX_SRV_OPEN SrvOpen) +{ + PMRX_SRV_CALL SrvCall = (PMRX_SRV_CALL)RxContext->Create.pSrvCall; + + // + // set this only if cache manager will be used for mini-rdr handles ! + // + Log(("VBoxMRxSetSrvOpenFlags %x\n", SrvOpen->BufferingFlags)); +#if 0 + /* This seems to be the root cause of the strange bug checks when enabling + * the driver verifier. + */ + SrvOpen->BufferingFlags |= (FCB_STATE_WRITECACHEING_ENABLED | + FCB_STATE_FILESIZECACHEING_ENABLED | + FCB_STATE_FILETIMECACHEING_ENABLED | + FCB_STATE_WRITEBUFFERING_ENABLED | + FCB_STATE_LOCK_BUFFERING_ENABLED | + FCB_STATE_READBUFFERING_ENABLED | + FCB_STATE_READCACHEING_ENABLED); +#endif +} + +NTSTATUS VBoxMRxCreateFileSuccessTail (PRX_CONTEXT RxContext, PBOOLEAN MustRegainExclusiveResource, RX_FILE_TYPE StorageType, ULONG CreateAction, FILE_BASIC_INFORMATION* pFileBasicInfo, + FILE_STANDARD_INFORMATION* pFileStandardInfo, SHFLHANDLE Handle) +/*++ + + Routine Description: + + This routine finishes the initialization of the fcb and srvopen for a + successful open. + + Arguments: + + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + RxCaptureFcb; + PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PMRX_VBOX_FOBX pVBoxFobx; + + FCB_INIT_PACKET InitPacket; + + Log(("VBOXSF: VBoxMRxCreateFileSuccessTail\n")); + PAGED_CODE(); + + Assert(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN); + Assert(NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT); + + if (*MustRegainExclusiveResource) + { //this is required because of oplock breaks + VboxRxAcquireExclusiveFcbResourceInMRx(capFcb); + *MustRegainExclusiveResource = FALSE; + } + + // This Fobx should be cleaned up by the wrapper + RxContext->pFobx = VboxRxCreateNetFobx(RxContext, SrvOpen); + if (RxContext->pFobx == NULL) + { + AssertFailed(); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Assert(VBoxRxIsFcbAcquiredExclusive(capFcb)); + Log(("VBOXSF: VBoxMRxCreateFileSuccessTail: StorageType = 0x%08lx, Action = 0x%08lx\n", StorageType, CreateAction)); + + RxContext->Create.ReturnedCreateInformation = CreateAction; + + RxFormInitPacket(InitPacket, &pFileBasicInfo->FileAttributes, &pFileStandardInfo->NumberOfLinks, &pFileBasicInfo->CreationTime, &pFileBasicInfo->LastAccessTime, &pFileBasicInfo->LastWriteTime, + &pFileBasicInfo->ChangeTime, &pFileStandardInfo->AllocationSize, &pFileStandardInfo->EndOfFile, &pFileStandardInfo->EndOfFile); + + if (capFcb->OpenCount == 0) + { + VboxRxFinishFcbInitialization(capFcb, RDBSS_STORAGE_NTC(StorageType), &InitPacket); + } + else + { + Assert(StorageType == 0 || NodeType(capFcb) == RDBSS_STORAGE_NTC(StorageType)); + } + + VBoxMRxSetSrvOpenFlags(RxContext, StorageType, SrvOpen); + + RxContext->pFobx->OffsetOfNextEaToReturn = 1; + //transition happens later + + pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx); + Assert(pVBoxFobx); + if (pVBoxFobx) + { + Log(("VBOXSF: VBoxMRxCreateFileSuccessTail: VBoxFobx = %p\n", pVBoxFobx)); + pVBoxFobx->hFile = Handle; + pVBoxFobx->pSrvCall = RxContext->Create.pSrvCall; + pVBoxFobx->FileStandardInfo = *pFileStandardInfo; + pVBoxFobx->FileBasicInfo = *pFileBasicInfo; + pVBoxFobx->fKeepCreationTime = FALSE; + pVBoxFobx->fKeepLastAccessTime = FALSE; + pVBoxFobx->fKeepLastWriteTime = FALSE; + pVBoxFobx->fKeepChangeTime = FALSE; + } + else return STATUS_INSUFFICIENT_RESOURCES; + + return Status; +} + +NTSTATUS VBoxMRxCollapseOpen (IN OUT PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine collapses a open locally + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ +#ifdef VBOX_SHFL_WITH_COLLAPSE + NTSTATUS Status; + + RxCaptureFcb; + RxCaptureRequestPacket; + + PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall; + PMRX_NET_ROOT NetRoot = capFcb->pNetRoot; + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx); + + Log(("VBOXSF: VBoxMRxCollapseOpen: Old Fobx = %p, old VBoxFobx = %p\n", RxContext->pFobx, pVBoxFobx)); + + RxContext->pFobx = (PMRX_FOBX)RxCreateNetFobx( RxContext, SrvOpen); + pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx); + + Log(("VBOXSF: VBoxMRxCollapseOpen: New Fobx = %p, new VBoxFobx = %p\n", RxContext->pFobx, pVBoxFobx)); + + if (RxContext->pFobx != NULL) + { + SHFLCREATEPARMS CreateParms; + PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext); + int vboxRC; + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + VBoxMRxGetNetRootExtension(capFcb->pNetRoot,pNetRootExtension); + FILE_BASIC_INFORMATION * pFileBasicInfo; + FILE_STANDARD_INFORMATION* pFileStandardInfo; + + Assert(RxIsFcbAcquiredExclusive(capFcb)); + + RxContext->pFobx->OffsetOfNextEaToReturn = 1; + capReqPacket->IoStatus.Information = FILE_OPENED; + Status = STATUS_SUCCESS; + + /* Initialize create parameters. */ + RtlZeroMemory (&CreateParms, sizeof (SHFLCREATEPARMS)); + + CreateParms.Handle = SHFL_HANDLE_NIL; + CreateParms.Result = SHFL_NO_RESULT; + + /* Assume it's a directory; open existing, read-only access, deny-none sharing */ + --> incorrect + CreateParms.CreateFlags = SHFL_CF_OPEN_TARGET_DIRECTORY + | SHFL_CF_DIRECTORY + | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW + | SHFL_CF_ACCESS_READ + | SHFL_CF_ACCESS_DENYNONE; + { + PSHFLSTRING ParsedPath = 0; + ULONG ParsedPathSize; + + /* Calculate length required for parsed path. + */ + ParsedPathSize = sizeof(*ParsedPath) + (RemainingName->Length + sizeof(WCHAR)); + + Log(("ParsedPathSize %d\n", ParsedPathSize)); + + ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize); + if (NULL == ParsedPath) + return STATUS_INSUFFICIENT_RESOURCES; + + ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING)); + + ParsedPath->u16Size = RemainingName->Length + sizeof(WCHAR); + ParsedPath->u16Length = ParsedPath->u16Size - sizeof(WCHAR); /* without terminating null */ + RtlCopyMemory (ParsedPath->String.ucs2, RemainingName->Buffer, ParsedPath->u16Length); + + /* Call host. */ + vboxRC = vboxCallCreate (&pDeviceExtension->hgcmClient, &pNetRootExtension->map, ParsedPath, &CreateParms); + + if (ParsedPath) + vbsfFreeNonPagedMem (ParsedPath); + } + + Log(("VBoxMRxCollapseOpen result %Rrc Result=%x\n", vboxRC, CreateParms.Result)); + if (RT_FAILURE(vboxRC)) + { + /* A host/guest communication error occurred while processing the request. */ + AssertMsgFailed(("VBOXSF: vboxCallCreate failed with %Rrc\n", vboxRC)); + return STATUS_UNSUCCESSFUL; + } + + /* + * The request succeeded. Analyze host response, + */ + switch (CreateParms.Result) + { + case SHFL_PATH_NOT_FOUND: + { + /* Path to object does not exist. */ + Log(("VBOXSF: Path not found\n")); + return STATUS_OBJECT_PATH_NOT_FOUND; + } + + case SHFL_FILE_NOT_FOUND: + { + Log(("VBOXSF: File not found\n")); + return STATUS_OBJECT_NAME_NOT_FOUND; + } + case SHFL_FILE_EXISTS: + { + Log(("VBOXSF: Object exists.\n")); + break; /* existing dir opened */ + } + + default: + { + Log(("VBOXSF: VBoxSF: invalid CreateResult from host %08X\n", CreateParms.Result)); + return STATUS_OBJECT_PATH_NOT_FOUND; + } + } + + pFileBasicInfo = &pVBoxFobx->FileBasicInfo; + pFileStandardInfo = &pVBoxFobx->FileStandardInfo; + + /* Translate attributes */ + pFileBasicInfo->FileAttributes = VBoxToNTFileAttributes(CreateParms.Info.Attr.fMode); + + /* Translate file times */ + pFileBasicInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&CreateParms.Info.BirthTime); /* ridiculous name */ + pFileBasicInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&CreateParms.Info.AccessTime); + pFileBasicInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&CreateParms.Info.ModificationTime); + pFileBasicInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&CreateParms.Info.ChangeTime); + + Assert(FlagOn(CreateParms.Info.Attr.fMode, RTFS_DOS_DIRECTORY)); + pFileStandardInfo->AllocationSize.QuadPart = 0; + pFileStandardInfo->EndOfFile.QuadPart = 0; + pFileStandardInfo->Directory = TRUE; + pFileStandardInfo->NumberOfLinks = 0; + pFileStandardInfo->DeletePending = FALSE; + + Log(("VBOXSF: VBoxMRxCollapseOpen VBoxFobx=%p\n", pVBoxFobx)); + pVBoxFobx->hFile = CreateParms.Handle; + pVBoxFobx->pSrvCall = RxContext->Create.pSrvCall; + pVBoxFobx->FileStandardInfo = *pFileStandardInfo; + pVBoxFobx->FileBasicInfo = *pFileBasicInfo; + } + else + { + Status = (STATUS_INSUFFICIENT_RESOURCES); + AssertFailed(); + } + + return Status; +#else + +#ifdef DEBUG + RxCaptureFcb; + RxCaptureRequestPacket; + + PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall; + PMRX_NET_ROOT NetRoot = capFcb->pNetRoot; + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx); + + Log(("VBOXSF: VBoxMRxCollapseOpen: Old Fobx = %p, old VBoxFobx = %p -> Not implemented!\n", RxContext->pFobx, pVBoxFobx)); +#endif + return STATUS_NOT_IMPLEMENTED; +#endif +} + +NTSTATUS VBoxMRxComputeNewBufferingState (IN OUT PMRX_SRV_OPEN pMRxSrvOpen, IN PVOID pMRxContext, OUT PULONG pNewBufferingState) +/*++ + + Routine Description: + + This routine maps specific oplock levels into the appropriate RDBSS + buffering state flags + + Arguments: + + pMRxSrvOpen - the MRX SRV_OPEN extension + + pMRxContext - the context passed to RDBSS at Oplock indication time + + pNewBufferingState - the place holder for the new buffering state + + Return Value: + + + Notes: + + --*/ +{ + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + + Log(("VBOXSF: VBoxMRxComputeNewBufferingState \n")); + return (Status); +} + +NTSTATUS VBoxMRxDeallocateForFcb (IN OUT PMRX_FCB pFcb) +{ + NTSTATUS Status = STATUS_SUCCESS; + + Log(("VBOXSF: VBoxMRxDeallocateForFcb\n")); + + return (Status); +} + +NTSTATUS VBoxMRxTruncate (IN PRX_CONTEXT pRxContext) +/*++ + + Routine Description: + + This routine truncates the contents of a file system object + + Arguments: + + pRxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + Log(("VBoxMRxTruncate\n")); + AssertMsgFailed(("Found a truncate")); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS VBoxMRxCleanupFobx (IN PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine cleansup a file system object...normally a noop. unless it's a pipe in which case + we do the close at cleanup time and mark the file as being not open. + + Arguments: + + pRxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + RxCaptureFcb; + RxCaptureFobx; + + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx); + NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb); + PMRX_SRV_OPEN pSrvOpen = NULL; + BOOLEAN SearchHandleOpen = FALSE; + + PAGED_CODE(); + + Log(("VBOXSF: VBoxMRxCleanupFobx: capFcb = %p, capFobx = %p\n", capFcb, capFobx)); + Assert(capFcb); + Assert(capFobx); + + pSrvOpen = capFobx->pSrvOpen; + Assert(pSrvOpen); + + Assert(NodeType(pSrvOpen) == RDBSS_NTC_SRVOPEN); + Assert(NodeTypeIsFcb(capFcb)); + + if (NULL == pVBoxFobx) + return STATUS_INVALID_PARAMETER; + + Log(("VBOXSF: VBoxMRxCleanupFobx: vboxFobx = %p, Handle = 0x%08x\n", pVBoxFobx, pVBoxFobx->hFile)); + + /* Close file */ + if (!((capFcb->pNetRoot->Type != NET_ROOT_PIPE) && !SearchHandleOpen)) + { + if (pVBoxFobx->hFile != SHFL_HANDLE_NIL) + { + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; + VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension); + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + +#ifndef VBOX_FAKE_IO_CREATE + int vboxRC = vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile); + AssertRC(vboxRC); +#endif + + pVBoxFobx->hFile = SHFL_HANDLE_NIL; + } + } + + if (FlagOn(capFcb->FcbState, FCB_STATE_ORPHANED)) + { + Log(("VBOXSF: VBoxMRxCleanupFobx: File orphaned\n")); + return (STATUS_SUCCESS); + } + + if ((capFcb->pNetRoot->Type != NET_ROOT_PIPE) && !SearchHandleOpen) + { + Log(("VBOXSF: VBoxMRxCleanupFobx: File not for closing at cleanup\n")); + return (STATUS_SUCCESS); + } + + Log(("VBOXSF: VBoxMRxCleanupFobx: Returned with status = 0x%08lx\n", Status)); + return Status; +} + +NTSTATUS VBoxMRxForcedClose (IN PMRX_SRV_OPEN pSrvOpen) +/*++ + + Routine Description: + + This routine closes a file system object + + Arguments: + + pSrvOpen - the instance to be closed + + Return Value: + + RXSTATUS - The return status for the operation + + Notes: + + + + --*/ +{ + Log(("VBOXSF: VBoxMRxForcedClose\n")); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS VBoxMRxCloseSrvOpen (IN PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine closes a file across the network + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + RxCaptureFcb; + RxCaptureFobx; + + int vboxRC = 0; + PMRX_SRV_OPEN pSrvOpen = NULL; + PUNICODE_STRING RemainingName = NULL; + NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb); + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; + + VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension); + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); + + PAGED_CODE(); + + Log(("VBOXSF: VBoxMRxCloseSrvOpen: capFcb = %p, capFobx = %p\n", capFcb, capFobx)); + Log(("VBOXSF: VBoxMRxCloseSrvOpen: pVBoxFobx = 0x%08x\n", pVBoxFobx)); + + Assert(capFcb); + Assert(capFobx); + + pSrvOpen = capFobx->pSrvOpen; + Assert(pSrvOpen); + + RemainingName = pSrvOpen->pAlreadyPrefixedName; + Log(("VBOXSF: VBoxMRxCloseSrvOpen: Remaining name = %.*ls, Len = %d\n", RemainingName->Length / sizeof(WCHAR), RemainingName->Buffer, RemainingName->Length)); + + if (NULL == pVBoxFobx) + return STATUS_INVALID_PARAMETER; + + /* If we renamed or delete the file/dir, then it's already closed */ + if (FlagOn(pSrvOpen->Flags, (SRVOPEN_FLAG_FILE_RENAMED | SRVOPEN_FLAG_FILE_DELETED))) + { + Assert(pVBoxFobx->hFile == SHFL_HANDLE_NIL); + + Log(("VBOXSF: VBoxMRxCloseSrvOpen: File was renamed; ignore close!\n")); + return STATUS_SUCCESS; + } + + /* Close file */ + if (pVBoxFobx->hFile != SHFL_HANDLE_NIL) + { +#ifndef VBOX_FAKE_IO_CREATE + vboxRC = vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile); + AssertRC(vboxRC); +#endif + pVBoxFobx->hFile = SHFL_HANDLE_NIL; + } + + if (capFcb->FcbState & FCB_STATE_DELETE_ON_CLOSE) + Log(("VBOXSF: VBoxMRxCloseSrvOpen: Delete on close. Open count = %d\n", capFcb->OpenCount)); + + /* Remove file or directory if delete action is pending. */ + if ((capFcb->FcbState & FCB_STATE_DELETE_ON_CLOSE) && capFcb->OpenCount == 0) + { + Status = VBoxMRxRemove(RxContext); + } + + return (Status); +} + +NTSTATUS VBoxMRxDeallocateForFobx (IN OUT PMRX_FOBX pFobx) +{ + Log(("VBOXSF: VBoxMRxDeallocateForFobx\n")); + + return (STATUS_SUCCESS); +} + +NTSTATUS VBoxMRxRemove (IN PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine removes a file or directory + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + RxCaptureFcb; + RxCaptureFobx; + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; + VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension); + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); + PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext); + int vboxRC; + PSHFLSTRING ParsedPath = 0; + ULONG ParsedPathSize; + PMRX_SRV_OPEN pSrvOpen = capFobx->pSrvOpen; + NTSTATUS Status = STATUS_SUCCESS; + + Log(("VBOXSF: VBoxMRxRemove Delete %.*ls. open count = %d!!\n", RemainingName->Length / sizeof(WCHAR), RemainingName->Buffer, capFcb->OpenCount)); + + /* Close file first if not already done. */ + if (pVBoxFobx->hFile != SHFL_HANDLE_NIL) + { +#ifndef VBOX_FAKE_IO_CREATE + vboxRC = vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile); + AssertRC(vboxRC); +#endif + pVBoxFobx->hFile = SHFL_HANDLE_NIL; + } + + /* Calculate length required for parsed path. + */ + ParsedPathSize = sizeof(*ParsedPath) + (RemainingName->Length + sizeof(WCHAR)); + + Log(("ParsedPathSize %d\n", ParsedPathSize)); + + ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize); + if (!ParsedPath) + return STATUS_INSUFFICIENT_RESOURCES; + + ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING)); + + Log(("Setup ParsedPath\n")); + ParsedPath->u16Size = RemainingName->Length + sizeof(WCHAR); + ParsedPath->u16Length = ParsedPath->u16Size - sizeof(WCHAR); /* without terminating null */ + RtlCopyMemory (ParsedPath->String.ucs2, RemainingName->Buffer, ParsedPath->u16Length); + + /* Call host. */ +#ifdef VBOX_FAKE_IO_DELETE + vboxRC = VINF_SUCCESS; +#else + vboxRC = vboxCallRemove(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, ParsedPath, (pVBoxFobx->FileStandardInfo.Directory) ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE); +#endif + + if (ParsedPath) + vbsfFreeNonPagedMem(ParsedPath); + + Status = VBoxErrorToNTStatus(vboxRC); + if (vboxRC != VINF_SUCCESS) + Log(("vboxCallRemove failed with %d (status=%d)\n", vboxRC, Status)); + + if (vboxRC == VINF_SUCCESS) + SetFlag(pSrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED); + + return Status; +} diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/precomp.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/precomp.h new file mode 100644 index 00000000000..7cd8691cf9b --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/precomp.h @@ -0,0 +1,39 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + + --*/ + +#define MINIRDR__NAME NulMRx +#define ___MINIRDR_IMPORTS_NAME (NulMRxDeviceObject->RdbssExports) + +#include <ntifs.h> + +#include "rx.h" + +#include "nodetype.h" +#include "netevent.h" + +#include <windef.h> + +#include "nulmrx.h" +#include "minip.h" +#include <lmcons.h> // from the Win32 SDK +#include "mrxglobs.h" + +#ifdef VBOX +#define try __try +#define leave __leave +#define finally __finally +#define except __except +/* bird: Added this to kill warnings about using unprototyped functions. + * I hope it doesn't break anything... */ +#include "vbsfhlp.h" + +////#define VBOX_FAKE_IO +////#define VBOX_FAKE_IO_READ_WRITE +////#define VBOX_FAKE_IO_CREATE +////#define VBOX_FAKE_IO_DELETE + +#endif diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss.asm b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss.asm new file mode 100644 index 00000000000..cf0c6a2bfe5 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss.asm @@ -0,0 +1,92 @@ +; +; Export definitions +; +; Copyright (C) 2006-2007 Oracle Corporation +; +; Oracle Corporation confidential +; All rights reserved +; + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "VBox/asmdefs.mac" + +extern __imp__RxAcquireExclusiveFcbResourceInMRx +extern __imp__RxCreateNetFobx +extern __imp__RxCreateRxContext +extern __imp__RxDereferenceAndDeleteRxContext_Real +extern __imp__RxDispatchToWorkerThread +extern __imp__RxFinalizeConnection +extern __imp__RxFinishFcbInitialization +extern __imp__RxFsdDispatch +extern __imp__RxGetFileSizeWithLock +extern __imp__RxGetFileSizeWithLock +extern __imp__RxLowIoGetBufferAddress +extern __imp__RxRegisterMinirdr +extern __imp__RxStartMinirdr +extern __imp__RxStopMinirdr +extern __imp__RxpUnregisterMinirdr +extern __imp__RxGetRDBSSProcess + + +BEGINPROC RxAcquireExclusiveFcbResourceInMRx@4 + jmp dword [__imp__RxAcquireExclusiveFcbResourceInMRx] +ENDPROC RxAcquireExclusiveFcbResourceInMRx@4 + +BEGINPROC RxCreateNetFobx@8 + jmp dword [__imp__RxCreateNetFobx] +ENDPROC RxCreateNetFobx@8 + +BEGINPROC RxCreateRxContext@12 + jmp dword [__imp__RxCreateRxContext] +ENDPROC RxCreateRxContext@12 + +BEGINPROC RxDereferenceAndDeleteRxContext_Real@4 + jmp dword [__imp__RxDereferenceAndDeleteRxContext_Real] +ENDPROC RxDereferenceAndDeleteRxContext_Real@4 + +BEGINPROC RxDispatchToWorkerThread@16 + jmp dword [__imp__RxDispatchToWorkerThread] +ENDPROC RxDispatchToWorkerThread@16 + +BEGINPROC RxFinalizeConnection@12 + jmp dword [__imp__RxFinalizeConnection] +ENDPROC RxFinalizeConnection@12 + +BEGINPROC RxFinishFcbInitialization@12 + jmp dword [__imp__RxFinishFcbInitialization] +ENDPROC RxFinishFcbInitialization@12 + +BEGINPROC RxFsdDispatch@8 + jmp dword [__imp__RxFsdDispatch] +ENDPROC RxFsdDispatch@8 + +BEGINPROC RxGetFileSizeWithLock@8 + jmp dword [__imp__RxGetFileSizeWithLock] +ENDPROC RxGetFileSizeWithLock@8 + +BEGINPROC RxGetRDBSSProcess@0 + jmp dword [__imp__RxGetRDBSSProcess] +ENDPROC RxGetRDBSSProcess@0 + +BEGINPROC RxLowIoGetBufferAddress@4 + jmp dword [__imp__RxLowIoGetBufferAddress] +ENDPROC RxLowIoGetBufferAddress@4 + +BEGINPROC RxRegisterMinirdr@32 + jmp dword [__imp__RxRegisterMinirdr] +ENDPROC RxRegisterMinirdr@32 + +BEGINPROC RxStartMinirdr@8 + jmp dword [__imp__RxStartMinirdr] +ENDPROC RxStartMinirdr@8 + +BEGINPROC RxStopMinirdr@8 + jmp dword [__imp__RxStopMinirdr] +ENDPROC RxStopMinirdr@8 + +BEGINPROC RxpUnregisterMinirdr@4 + jmp dword [__imp__RxpUnregisterMinirdr] +ENDPROC RxpUnregisterMinirdr@4 + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/Makefile.kup b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/Makefile.kup new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/Makefile.kup diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/rdbss.def b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/rdbss.def new file mode 100644 index 00000000000..d849dfac17f --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/rdbss.def @@ -0,0 +1,134 @@ +; +; Export definitions +; +; Copyright (C) 2006-2007 Oracle Corporation +; +; Oracle Corporation confidential +; All rights reserved +; + +LIBRARY RDBSS.SYS + +EXPORTS + RxAcquireExclusiveFcbResourceInMRx + RxAcquireSharedFcbResourceInMRx + RxAcquireSharedFcbResourceInMRxEx + RxAssert + RxAssociateContextWithMid + RxCancelTimerRequest + RxCeAllocateIrpWithMDL + RxCeBuildAddress + RxCeBuildConnection + RxCeBuildConnectionOverMultipleTransports + RxCeBuildTransport + RxCeBuildVC + RxCeCancelConnectRequest + RxCeFreeIrp + RxCeInitiateVCDisconnect + RxCeQueryAdapterStatus + RxCeQueryInformation + RxCeQueryTransportInformation + RxCeSend + RxCeSendDatagram + RxCeTearDownAddress + RxCeTearDownConnection + RxCeTearDownTransport + RxCeTearDownVC + RxChangeBufferingState + RxCompleteRequest + RxCompleteRequest_Real + RxCreateMidAtlas + RxCreateNetFcb + RxCreateNetFobx + RxCreateNetRoot + RxCreateRxContext + RxCreateSrvCall + RxCreateSrvOpen + RxCreateVNetRoot + RxDbgBreakPoint + RxDereference + RxDereferenceAndDeleteRxContext_Real + RxDestroyMidAtlas + RxDispatchToWorkerThread + RxFinalizeConnection + RxFinalizeNetFcb + RxFinalizeNetFobx + RxFinalizeNetRoot + RxFinalizeSrvCall + RxFinalizeSrvOpen + RxFinalizeVNetRoot + RxFinishFcbInitialization + RxForceFinalizeAllVNetRoots + RxFsdDispatch + RxFsdPostRequest + RxGetFileSizeWithLock + RxGetRDBSSProcess + RxIndicateChangeOfBufferingState + RxIndicateChangeOfBufferingStateForSrvOpen + RxInferFileType + RxInitializeContext + RxLockEnumerator + RxLogEventDirect + RxLogEventWithAnnotation + RxLogEventWithBufferDirect + RxLowIoCompletion + RxLowIoGetBufferAddress + RxMakeLateDeviceAvailable + RxMapAndDissociateMidFromContext + RxMapMidToContext + RxMapSystemBuffer + RxNameCacheActivateEntry + RxNameCacheAddNameCacheControlToGlobalList + RxNameCacheCheckEntry + RxNameCacheCreateEntry + RxNameCacheExpireAndFinalizeEx + RxNameCacheExpireEntry + RxNameCacheExpireEntryWithShortName + RxNameCacheFetchEntry + RxNameCacheFinalize + RxNameCacheFinalizeEx + RxNameCacheFreeActiveListEntries + RxNameCacheFreeEntry + RxNameCacheFreeNotifiedFreeList + RxNameCacheInitialize + RxNameCacheInitializeEx + RxNameCacheNotifyFreeListEntries + RxNameCacheRemoveNameCacheCtlFromGlobalList + RxNameCacheScavengeNameCaches + RxNewMapUserBuffer + RxPostOneShotTimerRequest + RxPostRecurrentTimerRequest + RxPostToWorkerThread + RxPrefixTableLookupName + RxPrepareContextForReuse + RxPrepareToReparseSymbolicLink + RxPurgeAllFobxs + RxPurgeRelatedFobxs + RxReassociateMid + RxReference + RxRegisterMinirdr + RxReleaseFcbResourceForThreadInMRx + RxReleaseFcbResourceInMRx + RxResumeBlockedOperations_Serially + RxScavengeAllFobxs + RxScavengeFobxsForNetRoot + RxSetDomainForMailslotBroadcast + RxSetMinirdrCancelRoutine + RxSetSrvCallDomainName + RxSpinDownMRxDispatcher + RxStartMinirdr = _RxStartMinirdr@8 + RxStopMinirdr + RxpAcquirePrefixTableLockExclusive + RxpAcquirePrefixTableLockShared + RxpDereferenceAndFinalizeNetFcb + RxpDereferenceNetFcb + RxpReferenceNetFcb + RxpReleasePrefixTableLock + RxpTrackDereference + RxpTrackReference + RxpUnregisterMinirdr + _RxAllocatePoolWithTag + _RxCheckMemoryBlock + _RxFreePool + __RxFillAndInstallFastIoDispatch + __RxSynchronizeBlockingOperationsMaybeDroppingFcbLock diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.c new file mode 100644 index 00000000000..a742098cc14 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.c @@ -0,0 +1,99 @@ +#include "rdbss_vbox.h" +#pragma hdrstop + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* KeXXXXXXX or ExXXXXXXXXX */ + +NTSTATUS VBoxRxRegisterMinirdr (PRDBSS_DEVICE_OBJECT *DeviceObject, PDRIVER_OBJECT DriverObject, PMINIRDR_DISPATCH MrdrDispatch, ULONG Controls, PUNICODE_STRING DeviceName, ULONG DeviceExtensionSize, + DEVICE_TYPE DeviceType, ULONG DeviceCharacteristics) +{ + return RxRegisterMinirdr(DeviceObject, DriverObject, MrdrDispatch, Controls, DeviceName, DeviceExtensionSize, DeviceType, DeviceCharacteristics); + return STATUS_SUCCESS; +} + +VOID VBoxRxUnregisterMinirdr (PRDBSS_DEVICE_OBJECT RxDeviceObject) +{ + RxUnregisterMinirdr(RxDeviceObject); +} + +NTSTATUS VBoxRxStartMinirdr (PRX_CONTEXT RxContext, PBOOLEAN PostToFsp) +{ + return RxStartMinirdr(RxContext, PostToFsp); + return STATUS_SUCCESS; +} + +NTSTATUS VBoxRxStopMinirdr (PRX_CONTEXT RxContext, PBOOLEAN PostToFsp) +{ + return RxStopMinirdr(RxContext, PostToFsp); + return STATUS_SUCCESS; +} + +PRX_CONTEXT VBoxRxCreateRxContext (PIRP Irp, PRDBSS_DEVICE_OBJECT RxDeviceObject, ULONG InitialContextFlags) +{ + return RxCreateRxContext(Irp, RxDeviceObject, InitialContextFlags); +} + +VOID VBoxRxDereferenceAndDeleteRxContext (PRX_CONTEXT RxContext) +{ + RxDereferenceAndDeleteRxContext(RxContext); +} + +NTSTATUS VBoxRxFinalizeConnection (OUT PNET_ROOT NetRoot, OUT PV_NET_ROOT VNetRoot, LOGICAL Level) +{ + return RxFinalizeConnection(NetRoot, VNetRoot, Level); + return STATUS_SUCCESS; +} + +NTSTATUS VBoxRxFsdDispatch (PRDBSS_DEVICE_OBJECT RxDeviceObject, PIRP Irp) +{ + return RxFsdDispatch(RxDeviceObject, Irp); + return STATUS_SUCCESS; +} + +VOID VBoxRxGetFileSizeWithLock (PFCB Fcb, OUT PLONGLONG FileSize) +{ + RxGetFileSizeWithLock(Fcb, FileSize); +} + +PVOID VBoxRxLowIoGetBufferAddress (IN PRX_CONTEXT RxContext) +{ + return RxLowIoGetBufferAddress(RxContext); +} + +NTSTATUS VBoxRxDispatchToWorkerThread (OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject, WORK_QUEUE_TYPE WorkQueueType, PRX_WORKERTHREAD_ROUTINE Routine, PVOID pContext) +{ + return RxDispatchToWorkerThread(pMRxDeviceObject, WorkQueueType, Routine, pContext); + return STATUS_SUCCESS; +} + +/* FCB stuff */ + +VOID VboxRxFinishFcbInitialization (PMRX_FCB MrxFcb, RDBSS_STORAGE_TYPE_CODES RdbssStorageType, PFCB_INIT_PACKET InitPacket) +{ + RxFinishFcbInitialization(MrxFcb, RdbssStorageType, InitPacket); +} + +NTSTATUS VboxRxAcquireExclusiveFcbResourceInMRx (PMRX_FCB pFcb) +{ + return RxAcquireExclusiveFcbResourceInMRx(pFcb); + return STATUS_SUCCESS; +} + +BOOLEAN VBoxRxIsFcbAcquiredExclusive (PMRX_FCB pFcb) +{ + // ExIsResourceAcquiredExclusive is obsolete since W2K and XP! + return ExIsResourceAcquiredExclusiveLite(RX_GET_MRX_FCB(pFcb)->Header.Resource); +} + +/* FOBX stuff */ + +PMRX_FOBX VboxRxCreateNetFobx (OUT PRX_CONTEXT RxContext, IN PMRX_SRV_OPEN MrxSrvOpen) +{ + return RxCreateNetFobx(RxContext, MrxSrvOpen); + return NULL; +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.h new file mode 100644 index 00000000000..5bb0b98badb --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.h @@ -0,0 +1,32 @@ +#include "precomp.h" + +NTSTATUS VBoxRxRegisterMinirdr (PRDBSS_DEVICE_OBJECT *DeviceObject, PDRIVER_OBJECT DriverObject, PMINIRDR_DISPATCH MrdrDispatch, ULONG Controls, PUNICODE_STRING DeviceName, ULONG DeviceExtensionSize, + DEVICE_TYPE DeviceType, ULONG DeviceCharacteristics); + +VOID VBoxRxUnregisterMinirdr (PRDBSS_DEVICE_OBJECT RxDeviceObject); + +NTSTATUS VBoxRxStartMinirdr (PRX_CONTEXT RxContext, PBOOLEAN PostToFsp); + +NTSTATUS VBoxRxStopMinirdr (PRX_CONTEXT RxContext, PBOOLEAN PostToFsp); + +PRX_CONTEXT VBoxRxCreateRxContext (PIRP Irp, PRDBSS_DEVICE_OBJECT RxDeviceObject, ULONG InitialContextFlags); + +VOID VBoxRxDereferenceAndDeleteRxContext_Real (PRX_CONTEXT RxContext); + +NTSTATUS VBoxRxFinalizeConnection (OUT PNET_ROOT NetRoot, OUT PV_NET_ROOT VNetRoot, LOGICAL Level); + +NTSTATUS VBoxRxFsdDispatch (PRDBSS_DEVICE_OBJECT RxDeviceObject, PIRP Irp); + +VOID VBoxRxGetFileSizeWithLock (PFCB Fcb, OUT PLONGLONG FileSize); + +PVOID VBoxRxLowIoGetBufferAddress (IN PRX_CONTEXT RxContext); + +NTSTATUS VBoxRxDispatchToWorkerThread (OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject, WORK_QUEUE_TYPE WorkQueueType, PRX_WORKERTHREAD_ROUTINE Routine, PVOID pContext); + +VOID VboxRxFinishFcbInitialization (PMRX_FCB MrxFcb, RDBSS_STORAGE_TYPE_CODES RdbssStorageType, PFCB_INIT_PACKET InitPacket); + +NTSTATUS VboxRxAcquireExclusiveFcbResourceInMRx (PMRX_FCB pFcb); + +BOOLEAN VBoxRxIsFcbAcquiredExclusive (PMRX_FCB pFcb); + +PMRX_FOBX VboxRxCreateNetFobx (OUT PRX_CONTEXT RxContext, IN PMRX_SRV_OPEN MrxSrvOpen); diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/read.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/read.c new file mode 100644 index 00000000000..d2868526bc2 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/read.c @@ -0,0 +1,189 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + read.c + + Abstract: + + This module implements the mini redirector call down routines pertaining to read + of file system objects. + + --*/ + +#include "precomp.h" +#include <VBox/log.h> +#include "rdbss_vbox.h" + +#pragma hdrstop + +static NTSTATUS VBoxMRxReadInternal (IN PRX_CONTEXT RxContext) +/*++ + + Routine Description: + + This routine handles network read requests. + + Arguments: + + RxContext - the RDBSS context + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + RxCaptureFcb; + RxCaptureFobx; + + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + PMDL OriginalDataMdl = LowIoContext->ParamsFor.ReadWrite.Buffer; + + PVOID pbUserBuffer = VBoxRxLowIoGetBufferAddress(RxContext); + uint32_t ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount; + RXVBO ByteOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset; + LONGLONG FileSize = 0; + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; + PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = (PMRX_VBOX_NETROOT_EXTENSION)pNetRoot->Context; + BOOLEAN SynchronousIo = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION); +#ifndef VBOX + PDEVICE_OBJECT deviceObject; +#endif + + PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen; + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); + + Log(("VBOXSF: VBoxMRxRead: SynchronousIo = %d\n", SynchronousIo)); + Log(("VBOXSF: VBoxMRxRead: NetRoot is 0x%x, Fcb is 0x%x\n", pNetRoot, capFcb)); + + VBoxRxGetFileSizeWithLock((PFCB)capFcb, &FileSize); + + // + // NB: This should be done by the wrapper ! It does this + // only if READCACHING is enabled on the FCB !! + // +#if (NTDDI_VERSION >= NTDDI_VISTA) /* Correct spelling for Vista 6001 SDK. */ + if (!FlagOn(capFcb->FcbState, FCB_STATE_READCACHING_ENABLED)) +#else + if (!FlagOn(capFcb->FcbState,FCB_STATE_READCACHEING_ENABLED)) +#endif + { + // + // If the read starts beyond End of File, return EOF. + // + + if (ByteOffset >= FileSize) + { + Log(("VBOXSF: VBoxMRxRead: End of File\n", 0 )); + Status = STATUS_END_OF_FILE; + goto Exit; + } + + // + // If the read extends beyond EOF, truncate the read + // + + if (ByteCount > FileSize - ByteOffset) + { + ByteCount = (ULONG)(FileSize - ByteOffset); + } + } + + Log(("VBOXSF: VBoxMRxRead: UserBuffer is 0x%x\n", pbUserBuffer)); + Log(("VBOXSF: VBoxMRxRead: ByteCount is %d, ByteOffset is %x\n", ByteCount, ByteOffset)); + + Assert((OriginalDataMdl != NULL && (RxMdlIsLocked(OriginalDataMdl) || RxMdlSourceIsNonPaged(OriginalDataMdl))) || (OriginalDataMdl == NULL && LowIoContext->ParamsFor.ReadWrite.ByteCount == 0)); + + if (OriginalDataMdl == NULL || LowIoContext->ParamsFor.ReadWrite.ByteCount == 0) + { + AssertFailed(); + return STATUS_INVALID_PARAMETER; + } + + /* @todo async io !!!! */ + SynchronousIo = TRUE; + + if (SynchronousIo) + { + int vboxRC; + + /* Do the actual reading */ +#ifdef VBOX_FAKE_IO_READ_WRITE + Status = STATUS_SUCCESS; + memset(pbUserBuffer, 0, ByteCount); +#else + vboxRC = vboxCallRead(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, ByteOffset, &ByteCount, (uint8_t *)pbUserBuffer, true /* locked */); + AssertRC(vboxRC); + + Status = VBoxErrorToNTStatus(vboxRC); +#endif + if (Status != STATUS_SUCCESS) + ByteCount = 0; /* Nothing read */ + + Log(("VBOXSF: VBoxMRxRead: This I/O is sync!\n")); + + RxContext->InformationToReturn = ByteCount; + + /* Never call RxLowIoCompletion here!! */ + } + else + { + Log(("VBOXSF: VBoxMRxRead: This I/O is async!\n")); + } + + Log(("VBOXSF: VBoxMRxRead: Status = %x Info = %x\n",RxContext->IoStatusBlock.Status,RxContext->IoStatusBlock.Information)); + + Exit: + + return (Status); +} + + +static VOID VBoxMRxReadWorker (VOID *pv) +{ + PRX_CONTEXT RxContext = (PRX_CONTEXT)pv; + + Log(("VBOXSF: VBoxMRxReadWorker: calling the worker\n")); + + RxContext->IoStatusBlock.Status = VBoxMRxReadInternal (RxContext); + + Log(("VBOXSF: VBoxMRxReadWorker: Status %x\n", RxContext->IoStatusBlock.Status)); + + RxLowIoCompletion (RxContext); +} + + +#ifdef VBOX_ASYNC_RW +NTSTATUS +VBoxMRxRead ( + IN PRX_CONTEXT RxContext) +{ + NTSTATUS Status = STATUS_SUCCESS; + + Status = RxDispatchToWorkerThread(VBoxMRxDeviceObject, DelayedWorkQueue, + VBoxMRxReadWorker, + RxContext); + + Log(("VBOXSF: VBoxMRxRead: RxDispatchToWorkerThread: Status %x\n", Status)); + + if (Status == STATUS_SUCCESS) + { + Status = STATUS_PENDING; + } + + return Status; +} +#else +NTSTATUS +VBoxMRxRead ( + IN PRX_CONTEXT RxContext) +{ + RxContext->IoStatusBlock.Status = VBoxMRxReadInternal (RxContext); + return RxContext->IoStatusBlock.Status; +} +#endif /* !VBOX_ASYNC_RW */ diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rename.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rename.c new file mode 100644 index 00000000000..320c88f8b7e --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rename.c @@ -0,0 +1,129 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + rename.c + + Abstract: + + This module implements rename in the null minirdr. + + --*/ + +#include "precomp.h" +#pragma hdrstop + +#ifdef VBOX +NTSTATUS +#endif +VBoxMRxRename (IN PRX_CONTEXT RxContext, IN FILE_INFORMATION_CLASS FileInformationClass, IN PVOID pBuffer, IN ULONG BufferLength) +/*++ + + Routine Description: + + This routine does a rename. since the real NT-->NT path is not implemented at the server end, + we implement just the downlevel path. + + Arguments: + + RxContext - the RDBSS context + FILE_INFO_CLASS - must be rename....shouldn't really pass this + pBuffer - pointer to the new name + bufferlength - and the size + + Return Value: + + NTSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + + RxCaptureFcb; + RxCaptureFobx; + PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen; + PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen, capFcb); + PFILE_RENAME_INFORMATION RenameInformation = (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer; + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; + VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension); + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + int vboxRC; + PSHFLSTRING SrcPath = 0, DestPath = 0; + ULONG ParsedPathSize, flags; + + Assert(FileInformationClass == FileRenameInformation); + + Log(("VBOXSF: VBoxMRxRename: FileName = %.*ls\n", RenameInformation->FileNameLength / sizeof(WCHAR), &RenameInformation->FileName[0])); + + /* Must close the file before renaming it! */ + if (pVBoxFobx->hFile != SHFL_HANDLE_NIL) + { + vboxRC = vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile); + AssertRC(vboxRC); + pVBoxFobx->hFile = SHFL_HANDLE_NIL; + } + + /* Mark it as renamed, so we do nothing during close */ + SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED); + + /* Calculate length required for destination path. + */ + ParsedPathSize = sizeof(*DestPath) + (RenameInformation->FileNameLength + sizeof(WCHAR)); + + Log(("VBOXSF: VBoxMRxRename: ParsedPathSize = %d\n", ParsedPathSize)); + + DestPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize); + + if (NULL == DestPath) + return STATUS_INSUFFICIENT_RESOURCES; + + RtlZeroMemory(DestPath, ParsedPathSize); + ShflStringInitBuffer(DestPath, ParsedPathSize - sizeof(SHFLSTRING)); + + Log(("VBOXSF: VBoxMRxRename: Setting up destination path ...\n")); + DestPath->u16Size = (USHORT)(RenameInformation->FileNameLength + sizeof(WCHAR)); + DestPath->u16Length = DestPath->u16Size - sizeof(WCHAR); /* without terminating null */ + RtlCopyMemory(DestPath->String.ucs2, RenameInformation->FileName, DestPath->u16Length); + Log(("VBOXSF: VBoxMRxRename: Destination path = %.*ls\n", DestPath->u16Length / sizeof(WCHAR), &DestPath->String.ucs2[0])); + + /* Calculate length required for source path + */ + ParsedPathSize = sizeof(*DestPath) + (RemainingName->Length + sizeof(WCHAR)); + Log(("VBOXSF: VBoxMRxRename: ParsedPathSize = %d\n", ParsedPathSize)); + + SrcPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize); + + if (NULL == SrcPath) + return STATUS_INSUFFICIENT_RESOURCES; + + RtlZeroMemory(SrcPath, ParsedPathSize); + ShflStringInitBuffer(SrcPath, ParsedPathSize - sizeof(SHFLSTRING)); + + Log(("VBOXSF: VBoxMRxRename: Setting up source path ...\n")); + SrcPath->u16Size = RemainingName->Length + sizeof(WCHAR); + SrcPath->u16Length = SrcPath->u16Size - sizeof(WCHAR); /* without terminating null */ + RtlCopyMemory(SrcPath->String.ucs2, RemainingName->Buffer, SrcPath->u16Length); + Log(("VBOXSF: VBoxMRxRename: Source path = %.*ls\n", SrcPath->u16Length / sizeof(WCHAR), &SrcPath->String.ucs2[0])); + + /* Call host. */ + flags = (pVBoxFobx->FileStandardInfo.Directory) ? SHFL_RENAME_DIR : SHFL_RENAME_FILE; + if (RenameInformation->ReplaceIfExists) + flags |= SHFL_RENAME_REPLACE_IF_EXISTS; + + Log(("VBOXSF: VBoxMRxRename: Calling vboxCallRename ...\n", SrcPath->u16Length / sizeof(WCHAR), &SrcPath->String.ucs2[0])); + vboxRC = vboxCallRename(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, SrcPath, DestPath, flags); + + vbsfFreeNonPagedMem(SrcPath); + vbsfFreeNonPagedMem(DestPath); + + Status = VBoxErrorToNTStatus(vboxRC); + if (vboxRC != VINF_SUCCESS) + Log(("VBOXSF: VBoxMRxRename: vboxCallRename failed with %d (Status = %x)!\n", vboxRC, Status)); + + Log(("VBOXSF: VBoxMRxRename: Returned 0x%lx\n", Status)); + return (Status); +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/srvcall.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/srvcall.c new file mode 100644 index 00000000000..83a52effd68 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/srvcall.c @@ -0,0 +1,243 @@ +/* + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + srvcall.c + + Abstract: + + This module implements the routines for handling the creation/manipulation of + server entries in the connection engine database. It also contains the routines + for parsing the negotiate response from the server. + + --*/ + +#include "precomp.h" +#pragma hdrstop + +VOID ExecuteCreateSrvCall (PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext) +/*++ + + Routine Description: + + This routine patches the RDBSS created srv call instance with the + information required by the mini redirector. + + Arguments: + + CallBackContext - the call back context in RDBSS for continuation. + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status; + PWCHAR pSrvName = 0; + BOOLEAN Verifier; + + PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = pCallbackContext; + PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(SCCBC->SrvCalldownStructure); + PMRX_SRV_CALL pSrvCall = SrvCalldownStructure->SrvCall; + + Assert(pSrvCall); + Assert(NodeType(pSrvCall) == RDBSS_NTC_SRVCALL); + + /* Validate the server name with the test name of 'vboxsvr'. */ + Log(("VBOXSF: ExecuteCreateSrvCall: Connection Name %.*ls Length: %d, pSrvCall = %p\n", pSrvCall->pSrvCallName->Length / sizeof(WCHAR), pSrvCall->pSrvCallName->Buffer, pSrvCall->pSrvCallName->Length, pSrvCall)); + + if (pSrvCall->pPrincipalName && pSrvCall->pPrincipalName->Length) + Log(("VBOXSF: ExecuteCreateSrvCall: Principal name = %.*ls\n", pSrvCall->pPrincipalName->Length / sizeof(WCHAR), pSrvCall->pPrincipalName->Buffer)); + + if (pSrvCall->pDomainName && pSrvCall->pDomainName->Length) + Log(("VBOXSF: ExecuteCreateSrvCall: Domain name = %.*ls\n", pSrvCall->pDomainName->Length / sizeof(WCHAR), pSrvCall->pDomainName->Buffer)); + + if (pSrvCall->pSrvCallName->Length >= 14) + { + pSrvName = pSrvCall->pSrvCallName->Buffer; + + Verifier = (pSrvName[0] == L'\\'); + Verifier &= (pSrvName[1] == L'V') || (pSrvName[1] == L'v'); + Verifier &= (pSrvName[2] == L'B') || (pSrvName[2] == L'b'); + Verifier &= (pSrvName[3] == L'O') || (pSrvName[3] == L'o'); + Verifier &= (pSrvName[4] == L'X') || (pSrvName[4] == L'x'); + Verifier &= (pSrvName[5] == L'S') || (pSrvName[5] == L's'); + /* Both vboxsvr & vboxsrv are now accepted */ + if ((pSrvName[6] == L'V') || (pSrvName[6] == L'v')) + { + Verifier &= (pSrvName[6] == L'V') || (pSrvName[6] == L'v'); + Verifier &= (pSrvName[7] == L'R') || (pSrvName[7] == L'r'); + } + else + { + Verifier &= (pSrvName[6] == L'R') || (pSrvName[6] == L'r'); + Verifier &= (pSrvName[7] == L'V') || (pSrvName[7] == L'v'); + } + Verifier &= (pSrvName[8] == L'\\') || (pSrvName[8] == 0); + } + else + { + Verifier = FALSE; + } + + if (Verifier) + { + Log(("VBOXSF: ExecuteCreateSrvCall: Verifier succeeded!\n")); + Status = STATUS_SUCCESS; + } + else + { + Log(("VBOXSF: ExecuteCreateSrvCall: Verifier failed!\n")); + Status = STATUS_BAD_NETWORK_PATH; + } + + SCCBC->Status = Status; + SrvCalldownStructure->CallBack(SCCBC); +} + +NTSTATUS VBoxMRxCreateSrvCall (PMRX_SRV_CALL pSrvCall, PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext) +/*++ + + Routine Description: + + This routine patches the RDBSS created srv call instance with the information required + by the mini redirector. + + Arguments: + + RxContext - Supplies the context of the original create/ioctl + + CallBackContext - the call back context in RDBSS for continuation. + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status; + + PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(pCallbackContext->SrvCalldownStructure); + + Assert(pSrvCall); + Assert(NodeType(pSrvCall) == RDBSS_NTC_SRVCALL); + + Log(("VBOXSF: VBoxMRxCreateSrvCall: Called %p.\n", pSrvCall)); + + // + // If this request was made on behalf of the RDBSS, do ExecuteCreatSrvCall + // immediately. If the request was made from somewhere else, create a work item + // and place it on a queue for a worker thread to process later. This distinction + // is made to simplify transport handle management. + // + if (IoGetCurrentProcess() == RxGetRDBSSProcess()) + { + Log(("VBOXSF: VBoxMRxCreateSrvCall: Called in context of RDBSS process\n")); + + // + // Peform the processing immediately because RDBSS is the initiator of this + // request + // + + ExecuteCreateSrvCall(pCallbackContext); + } + else + { + Log(("VBOXSF: VBoxMRxCreateSrvCall: Dispatching to worker thread\n")); + + // + // Dispatch the request to a worker thread because the redirected drive + // buffering sub-system (RDBSS) was not the initiator + // + + Status = RxDispatchToWorkerThread(VBoxMRxDeviceObject, DelayedWorkQueue, (PWORKER_THREAD_ROUTINE)ExecuteCreateSrvCall, /* explicit cast for first parameter type */ + pCallbackContext); + + if (Status == STATUS_SUCCESS) + { + Log(("VBOXSF: VBoxMRxCreateSrvCall: queued!\n")); + } + else + { + pCallbackContext->Status = Status; + SrvCalldownStructure->CallBack(pCallbackContext); + } + } + + // + // The wrapper expects PENDING. + // + return STATUS_PENDING; +} + +NTSTATUS VBoxMRxFinalizeSrvCall (PMRX_SRV_CALL pSrvCall, BOOLEAN Force) +/*++ + + Routine Description: + + This routine destroys a given server call instance + + Arguments: + + pSrvCall - the server call instance to be disconnected. + + Force - TRUE if a disconnection is to be enforced immediately. + + Return Value: + + RXSTATUS - The return status for the operation + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + Log(("VBOXSF: VBoxMRxFinalizeSrvCall called %p, ctx = %p.\n", pSrvCall, pSrvCall->Context)); + pSrvCall->Context = NULL; + + return (Status); +} + +NTSTATUS VBoxMRxSrvCallWinnerNotify (IN PMRX_SRV_CALL pSrvCall, IN BOOLEAN ThisMinirdrIsTheWinner, IN OUT PVOID pSrvCallContext) +/*++ + + Routine Description: + + This routine finalizes the mini rdr context associated with an RDBSS Server call instance + + Arguments: + + pSrvCall - the Server Call + + ThisMinirdrIsTheWinner - TRUE if this mini rdr is the choosen one. + + pSrvCallContext - the server call context created by the mini redirector. + + Return Value: + + RXSTATUS - The return status for the operation + + Notes: + + The two phase construction protocol for Server calls is required because of parallel + initiation of a number of mini redirectors. The RDBSS finalizes the particular mini + redirector to be used in communicating with a given server based on quality of + service criterion. + + --*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + Log(("VBOXSF: VBoxMRxSrvCallWinnerNotify called %p.\n", pSrvCall)); + if (ThisMinirdrIsTheWinner) + { + Log(("VBOXSF: VBoxMRxSrvCallWinnerNotify: VboxSF.sys is the winner!\n")); + } + + pSrvCall->Context = (PVOID)0xDEADBEEF; + + return (Status); +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/transprt.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/transprt.c new file mode 100644 index 00000000000..f2313d84d03 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/transprt.c @@ -0,0 +1,51 @@ +/*++ + + Copyright (c) 1989 - 1999 Microsoft Corporation + + Module Name: + + transport.c + + Abstract: + + This module implements all transport related functions in the SMB connection engine + + --*/ + +#include "precomp.h" +#pragma hdrstop + +NTSTATUS VBoxMRxInitializeTransport () +/*++ + + Routine Description: + + This routine initializes the transport related data structures + + Returns: + + STATUS_SUCCESS if the transport data structures was successfully initialized + + Notes: + + --*/ +{ + Log(("VBOXSF: VBoxMRxInitializeTransport: Called.\n")); + return STATUS_SUCCESS; +} + +NTSTATUS VBoxMRxUninitializeTransport () +/*++ + + Routine Description: + + This routine uninitializes the transport related data structures + + Notes: + + --*/ +{ + Log(("VBOXSF: VBoxMRxUninitializeTransport: Called.\n")); + return STATUS_SUCCESS; +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vboxsf.ini b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vboxsf.ini new file mode 100644 index 00000000000..15db40d1ffe --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vboxsf.ini @@ -0,0 +1,16 @@ +\registry\machine\system\currentcontrolset\services\VBoxSF + Description = VBoxSF + DisplayName = VBoxSF + ErrorControl = REG_DWORD 0x00000001 + Group = Network + ImagePath = System32\DRIVERS\VBoxSF.sys + LastLoadStatus = REG_DWORD 0 + Start = REG_DWORD 0x00000001 + Type = REG_DWORD 0x00000002 + +\registry\machine\system\currentcontrolset\services\VBoxSF\NetworkProvider + DeviceName = \Device\VBoxMiniRdr + Name = VirtualBox Shared Folders + ProviderPath = System32\VBoxMRXNP.dll + + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhdrs.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhdrs.h new file mode 100644 index 00000000000..a889ca9be15 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhdrs.h @@ -0,0 +1,70 @@ +/** @file + * + * VirtualBox Windows Guest Shared Folders + * + * File System Driver main header + * + * Copyright (C) 2006-2010 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +#ifndef __VBOXHDRS__H +#define __VBOXHDRS__H + +#include "VBoxGuestR0LibSharedFolders.h" + +/* + * UNICODE name of the virtual drive device and FSD device. + */ +#define VBOXSF_DEVICE_NAME_U L"VBoxSharedFolders" + +/* + * The path in the ob namespace for a virtual drive device. + * ? is replaced with a drive letter. + */ +#define VBOXSF_DEVICE_NAME_TEMPLATE_U L"\\Device\\" VBOXSF_DEVICE_NAME_U L"?" + +#if 0 /** @todo r=bird: defined in two .c files but with different parameter lists. dunno who uses them. + * Vitali / Sander, please fix when you got time. */ +NTSTATUS vbsfFsdStartPollerThread (void); +void vbsfFsdStopPollerThread (void); +#endif + +NTSTATUS +FatMountVolume ( + IN struct _VOLUME_DEVICE_OBJECT *pVdo +); + +typedef struct _VBSFDIRENT +{ + ULONG64 FileSize; + ULONG64 AllocationSize; + + ULONG64 LastAccessTime; + ULONG64 CreationTime; + ULONG64 LastWriteTime; + + UCHAR Attributes; + +#if 0 + FAT8DOT3 FileName; // offset = 0 + UCHAR Attributes; // offset = 11 + UCHAR NtByte; // offset = 12 + UCHAR CreationMSec; // offset = 13 + FAT_TIME_STAMP CreationTime; // offset = 14 + FAT_DATE LastAccessDate; // offset = 18 + union + { + USHORT ExtendedAttributes; // offset = 20 + USHORT FirstClusterOfFileHi; // offset = 20 + }; + FAT_TIME_STAMP LastWriteTime; // offset = 22 + USHORT FirstClusterOfFile; // offset = 26 + ULONG32 FileSize; // offset = 28 +#endif +} VBSFDIRENT; // sizeof = 32 +typedef VBSFDIRENT *PVBSFDIRENT; + +#endif /* __VBOXHDRS__H */ diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.c new file mode 100644 index 00000000000..f91d56650c5 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.c @@ -0,0 +1,343 @@ +/** @file + * + * VirtualBox Windows Guest Shared Folders + * + * File System Driver system helpers + * + * Copyright (C) 2006-2007 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +#include <ntifs.h> +#include <ntdddisk.h> + +#include "vbsfhdrs.h" +#include "vbsfhlp.h" + +#ifdef DEBUG +static int s_iAllocRefCount = 0; +#endif + +void vbsfHlpSleep (ULONG ulMillies) +{ + KEVENT event; + LARGE_INTEGER dueTime; + + KeInitializeEvent(&event, NotificationEvent, FALSE); + + dueTime.QuadPart = -10000 * (int)ulMillies; + + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &dueTime); +} + +/** + * Convert VBox IRT file attributes to NT file attributes + * + * @returns NT file attributes + * @param fMode IRT file attributes + * + */ +uint32_t VBoxToNTFileAttributes (uint32_t fMode) +{ + uint32_t FileAttributes = 0; + + if (fMode & RTFS_DOS_READONLY) + FileAttributes |= FILE_ATTRIBUTE_READONLY; + if (fMode & RTFS_DOS_HIDDEN) + FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + if (fMode & RTFS_DOS_SYSTEM) + FileAttributes |= FILE_ATTRIBUTE_SYSTEM; + if (fMode & RTFS_DOS_DIRECTORY) + FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + if (fMode & RTFS_DOS_ARCHIVED) + FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; + if (fMode & RTFS_DOS_NT_TEMPORARY) + FileAttributes |= FILE_ATTRIBUTE_TEMPORARY; + if (fMode & RTFS_DOS_NT_SPARSE_FILE) + FileAttributes |= FILE_ATTRIBUTE_SPARSE_FILE; + if (fMode & RTFS_DOS_NT_REPARSE_POINT) + FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT; + if (fMode & RTFS_DOS_NT_COMPRESSED) + FileAttributes |= FILE_ATTRIBUTE_COMPRESSED; + // if (fMode & RTFS_DOS_NT_OFFLINE) + if (fMode & RTFS_DOS_NT_NOT_CONTENT_INDEXED) + FileAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED; + if (fMode & RTFS_DOS_NT_ENCRYPTED) + FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED; + if (fMode & RTFS_DOS_NT_NORMAL) + { + FileAttributes |= FILE_ATTRIBUTE_NORMAL; + } + return FileAttributes; +} + +/** + * Convert VBox IRT file attributes to NT file attributes + * + * @returns NT file attributes + * @param fMode IRT file attributes + * + */ +uint32_t NTToVBoxFileAttributes (uint32_t fMode) +{ + uint32_t FileAttributes = 0; + + if (fMode & FILE_ATTRIBUTE_READONLY) + FileAttributes |= RTFS_DOS_READONLY; + if (fMode & FILE_ATTRIBUTE_HIDDEN) + FileAttributes |= RTFS_DOS_HIDDEN; + if (fMode & FILE_ATTRIBUTE_SYSTEM) + FileAttributes |= RTFS_DOS_SYSTEM; + if (fMode & FILE_ATTRIBUTE_DIRECTORY) + FileAttributes |= RTFS_DOS_DIRECTORY; + if (fMode & FILE_ATTRIBUTE_ARCHIVE) + FileAttributes |= RTFS_DOS_ARCHIVED; + if (fMode & FILE_ATTRIBUTE_TEMPORARY) + FileAttributes |= RTFS_DOS_NT_TEMPORARY; + if (fMode & FILE_ATTRIBUTE_SPARSE_FILE) + FileAttributes |= RTFS_DOS_NT_SPARSE_FILE; + if (fMode & FILE_ATTRIBUTE_REPARSE_POINT) + FileAttributes |= RTFS_DOS_NT_REPARSE_POINT; + if (fMode & FILE_ATTRIBUTE_COMPRESSED) + FileAttributes |= RTFS_DOS_NT_COMPRESSED; + if (fMode & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) + FileAttributes |= RTFS_DOS_NT_NOT_CONTENT_INDEXED; + if (fMode & FILE_ATTRIBUTE_ENCRYPTED) + FileAttributes |= RTFS_DOS_NT_ENCRYPTED; + if (fMode & FILE_ATTRIBUTE_NORMAL) + { + FileAttributes |= RTFS_DOS_NT_NORMAL; + } + return FileAttributes; +} + +NTSTATUS vbsfHlpCreateDriveLetter (WCHAR Letter, UNICODE_STRING *pDeviceName) +{ + UNICODE_STRING driveName; + RtlInitUnicodeString(&driveName,L"\\??\\_:" ); + + /* Replace '_' with actual drive letter */ + driveName.Buffer[driveName.Length/sizeof(WCHAR) - 2] = Letter; + + return IoCreateSymbolicLink (&driveName, pDeviceName); +} + +NTSTATUS vbsfHlpDeleteDriveLetter (WCHAR Letter) +{ + UNICODE_STRING driveName; + RtlInitUnicodeString(&driveName,L"\\??\\_:" ); + + /* Replace '_' with actual drive letter */ + driveName.Buffer[driveName.Length/sizeof(WCHAR) - 2] = Letter; + + return IoDeleteSymbolicLink (&driveName); +} + + /** + * Convert VBox error code to NT status code + * + * @returns NT status code + * @param vboxRC VBox error code + * + */ +NTSTATUS VBoxErrorToNTStatus (int vboxRC) +{ + NTSTATUS Status; + + switch (vboxRC) + { + case VINF_SUCCESS: + Status = STATUS_SUCCESS; + break; + + case VERR_ACCESS_DENIED: + Status = STATUS_ACCESS_DENIED; + break; + + case VERR_NO_MORE_FILES: + Status = STATUS_NO_MORE_FILES; + break; + + case VERR_PATH_NOT_FOUND: + Status = STATUS_OBJECT_PATH_NOT_FOUND; + break; + + case VERR_FILE_NOT_FOUND: + Status = STATUS_OBJECT_NAME_NOT_FOUND; + break; + + case VERR_DIR_NOT_EMPTY: + Status = STATUS_DIRECTORY_NOT_EMPTY; + break; + + case VERR_SHARING_VIOLATION: + Status = STATUS_SHARING_VIOLATION; + break; + + case VERR_FILE_LOCK_VIOLATION: + Status = STATUS_FILE_LOCK_CONFLICT; + break; + + case VERR_FILE_LOCK_FAILED: + Status = STATUS_LOCK_NOT_GRANTED; + break; + + case VINF_BUFFER_OVERFLOW: + Status = STATUS_BUFFER_OVERFLOW; + break; + + case VERR_EOF: + case VINF_EOF: + Status = STATUS_END_OF_FILE; + break; + + case VERR_READ_ERROR: + case VERR_WRITE_ERROR: + case VERR_FILE_IO_ERROR: + Status = STATUS_UNEXPECTED_IO_ERROR; + break; + + case VERR_WRITE_PROTECT: + Status = STATUS_MEDIA_WRITE_PROTECTED; + break; + + case VERR_ALREADY_EXISTS: + Status = STATUS_OBJECT_NAME_COLLISION; + break; + + case VERR_NOT_A_DIRECTORY: + Status = STATUS_NOT_A_DIRECTORY; + break; + + case VERR_SEEK: + Status = STATUS_INVALID_PARAMETER; + break; + + case VERR_INVALID_PARAMETER: + Status = STATUS_INVALID_PARAMETER; + break; + + case VERR_NOT_SUPPORTED: + Status = STATUS_NOT_SUPPORTED; + break; + + default: + /* @todo error handling */ + Status = STATUS_INVALID_PARAMETER; + AssertMsgFailed(("Unexpected vbox error %d\n", vboxRC)); + break; + } + return Status; +} + +PVOID vbsfAllocNonPagedMem (ULONG ulSize) +{ + PVOID pMemory = NULL; + +#ifdef DEBUG + s_iAllocRefCount = s_iAllocRefCount + 1; + Log(("vbsfAllocNonPagedMem: RefCnt after incrementing: %d\n", s_iAllocRefCount)); +#endif + + Assert(ulSize > sizeof(void *)); + + /* Tag is reversed (a.k.a "SHFL") to display correctly in debuggers, so search for "SHFL" */ + pMemory = ExAllocatePoolWithTag(NonPagedPool, ulSize, 'LFHS'); + + if (NULL != pMemory) + { + RtlZeroMemory(pMemory, ulSize); +#ifdef DEBUG + Log(("vbsfAllocNonPagedMem: Allocated %d bytes of memory at %p.\n", ulSize, pMemory)); +#endif + } + else + { +#ifdef DEBUG + Log(("vbsfAllocNonPagedMem: ERROR: Could not allocate %d bytes of memory!\n", ulSize)); +#endif + } + + return pMemory; +} + +void vbsfFreeNonPagedMem (PVOID lpMem) +{ +#ifdef DEBUG + s_iAllocRefCount = s_iAllocRefCount - 1; + Log(("vbsfFreeNonPagedMem: RefCnt after decrementing: %d\n", s_iAllocRefCount)); +#endif + + Assert(lpMem); + + /* MSDN: The ExFreePoolWithTag routine issues a bug check if the specified value for Tag does not match the tag value passed + to the routine that originally allocated the memory block. Otherwise, the behavior of this routine is identical to ExFreePool. */ + ExFreePoolWithTag(lpMem, 'LFHS'); + lpMem = NULL; +} + +winVersion_t vboxQueryWinVersion () +{ + static winVersion_t winVersion = UNKNOWN_WINVERSION; + ULONG majorVersion; + ULONG minorVersion; + ULONG buildNumber; + + if (winVersion != UNKNOWN_WINVERSION) + return winVersion; + + PsGetVersion(&majorVersion, &minorVersion, &buildNumber, NULL); + + Log(("VBoxVideo::vboxQueryWinVersion: running on Windows NT version %d.%d, build %d\n", majorVersion, minorVersion, buildNumber)); + + if (majorVersion >= 5) + { + if (minorVersion >= 1) + { + winVersion = WINXP; + } + else + { + winVersion = WIN2K; + } + } + else if (majorVersion == 4) + { + winVersion = WINNT4; + } + else + { + Log(("VBoxVideo::vboxQueryWinVersion: NT4 required!\n")); + } + return winVersion; +} + +#if 0 //def DEBUG +/** + * Callback for RTLogFormatV which writes to the backdoor. + * See PFNLOGOUTPUT() for details. + */ +static DECLCALLBACK(size_t) rtLogBackdoorOutput(void *pv, const char *pachChars, size_t cbChars) +{ + RTLogWriteUser(pachChars, cbChars); + return cbChars; +} + +int RTLogBackdoorPrintf1(const char *pszFormat, ...) +{ + va_list args; + + LARGE_INTEGER time; + + KeQueryTickCount(&time); + + RTLogBackdoorPrintf("T=%RX64 ", time.QuadPart); + va_start(args, pszFormat); + RTLogFormatV(rtLogBackdoorOutput, NULL, pszFormat, args); + va_end(args); + + return 0; +} +#endif diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.h new file mode 100644 index 00000000000..ee87ff49195 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.h @@ -0,0 +1,61 @@ +/** @file + * + * VirtualBox Windows Guest Shared Folders + * + * File System Driver system helpers + * + * Copyright (C) 2006-2007 Oracle Corporation + * + * Oracle Corporation confidential + * All rights reserved + */ + +#ifndef __VBSFHLP__H +#define __VBSFHLP__H + +#include <ntifs.h> +#include <ntverp.h> + +// Windows version identifier +typedef enum +{ + UNKNOWN_WINVERSION = 0, WINNT4 = 1, WIN2K = 2, WINXP = 3 +} winVersion_t; + +void vbsfHlpSleep (ULONG ulMillies); +NTSTATUS vbsfHlpCreateDriveLetter (WCHAR Letter, UNICODE_STRING *pDeviceName); +NTSTATUS vbsfHlpDeleteDriveLetter (WCHAR Letter); + +/** + * Convert VBox IRT file attributes to NT file attributes + * + * @returns NT file attributes + * @param fMode IRT file attributes + * + */ +uint32_t VBoxToNTFileAttributes (uint32_t fMode); + +/** + * Convert VBox IRT file attributes to NT file attributes + * + * @returns NT file attributes + * @param fMode IRT file attributes + * + */ +uint32_t NTToVBoxFileAttributes (uint32_t fMode); + +/** + * Convert VBox error code to NT status code + * + * @returns NT status code + * @param vboxRC VBox error code + * + */ +NTSTATUS VBoxErrorToNTStatus (int vboxRC); + +PVOID vbsfAllocNonPagedMem (ULONG ulSize); +void vbsfFreeNonPagedMem (PVOID lpMem); + +winVersion_t vboxQueryWinVersion (); + +#endif /* __VBSFHLP__H */ diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.c new file mode 100644 index 00000000000..26424c5caa3 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.c @@ -0,0 +1,138 @@ +/*++ + +Copyright (c) 1996-1998 Microsoft Corporation + +Module Name: + + cldskwmi.c + +Abstract: + + km wmi tracing code. + + Will be shared between our drivers. + + +Environment: + + kernel mode only + +Notes: + + + +Comments: + + This code is a quick hack to enable WMI tracing in cluster drivers. + It should eventually go away. + + WmlTinySystemControl will be replaced with WmilibSystemControl from wmilib.sys . + + WmlTrace or equivalent will be added to the kernel in addition to IoWMIWriteEvent(&TraceBuffer); + +--*/ +#include "precomp.h" +#pragma hdrstop + +//#include <ntos.h> +//#include <ntrtl.h> +//#include <nturtl.h> + + +// #include <wmistr.h> +// #include <evntrace.h> + +// #include "wmlkm.h" + +BOOLEAN +WmlpFindGuid( + __in PVOID GuidList, + __in ULONG GuidCount, + __in LPVOID Guid, + __out PULONG GuidIndex + ) +/*++ + +Routine Description: + + This routine will search the list of guids registered and return + the index for the one that was registered. + +Arguments: + + GuidList is the list of guids to search + + GuidCount is the count of guids in the list + + Guid is the guid being searched for + + *GuidIndex returns the index to the guid + +Return Value: + + TRUE if guid is found else FALSE + +--*/ +{ + + return(FALSE); +} + + +NTSTATUS +WmlTinySystemControl( + __inout PVOID WmiLibInfo, + __in PVOID DeviceObject, + __in PVOID Irp + ) +/*++ + +Routine Description: + + Dispatch routine for IRP_MJ_SYSTEM_CONTROL. This routine will process + all wmi requests received, forwarding them if they are not for this + driver or determining if the guid is valid and if so passing it to + the driver specific function for handing wmi requests. + +Arguments: + + WmiLibInfo has the WMI information control block + + DeviceObject - Supplies a pointer to the device object for this request. + + Irp - Supplies the Irp making the request. + +Return Value: + + status + +--*/ + +{ + return(STATUS_WMI_GUID_NOT_FOUND); +} + +ULONG +WmlTrace( + __in ULONG Type, + __in LPVOID TraceGuid, + __in ULONG64 LoggerHandle, + ... // Pairs: Address, Length + ) +{ + return STATUS_SUCCESS; +} + + +ULONG +WmlPrintf( + __in ULONG Type, + __in LPCGUID TraceGuid, + __in ULONG64 LoggerHandle, + __in PCWSTR FormatString, + ... // printf var args + ) +{ + return STATUS_SUCCESS; +} + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.h new file mode 100644 index 00000000000..2381e642fa1 --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.h @@ -0,0 +1,80 @@ +/*++ + +Copyright (c) 1999 Microsoft Corporation + +Module Name: + + wmlkm.h + +Abstract: + + Kernel mode definitions for an easy wmi tracing. + + +Comments: + + Needs to be moved to wmilib\inc when DCR is approved + +--*/ +#ifndef WMLKM_H +#define WMLKM_H 1 + +#pragma warning(disable: 4201) // error C4201: nonstandard extension used : nameless struct/union +#include <wmistr.h> +#include <evntrace.h> + +#include "wmlmacro.h" +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_TRACE_GUIDS_PER_CONTROL 3 + +typedef struct _WML_CONTROL_GUID_REG { + GUID Guid; + GUID TraceGuids[MAX_TRACE_GUIDS_PER_CONTROL]; + ULONG EnableFlags; + ULONG EnableLevel; + TRACEHANDLE LoggerHandle; +} WML_CONTROL_GUID_REG, *PWML_CONTROL_GUID_REG; + +typedef struct _WML_TINY_INFO { + PWML_CONTROL_GUID_REG ControlGuids; + ULONG GuidCount; + PDEVICE_OBJECT LowerDeviceObject; + PUNICODE_STRING DriverRegPath; +} WML_TINY_INFO, *PWML_TINY_INFO; + + +NTSTATUS +WmlTinySystemControl( + IN OUT PWML_TINY_INFO WmiLibInfo, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +ULONG +WmlTrace( + IN ULONG Type, + IN LPCGUID TraceGuid, + IN TRACEHANDLE LoggerHandle, + ... // Pairs: Address, Length + ); + +ULONG +WmlPrintf( + IN ULONG Type, + IN LPCGUID TraceGuid, + IN TRACEHANDLE LoggerHandle, + IN PCHAR FormatString, + ... // var args + ); + + + +#ifdef __cplusplus +}; +#endif + +#endif // WMLKM_H + diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/write.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/write.c new file mode 100644 index 00000000000..9c79ceda85d --- /dev/null +++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/write.c @@ -0,0 +1,175 @@ +/*++ + +Copyright (c) 1989 - 1999 Microsoft Corporation + +Module Name: + + write.c + +Abstract: + + This module implements the mini redirector call down routines pertaining + to write of file system objects. + +--*/ + +#include "precomp.h" +#include "rdbss_vbox.h" +#pragma hdrstop + + +static NTSTATUS +VBoxMRxWriteInternal ( + IN PRX_CONTEXT RxContext) + +/*++ + +Routine Description: + + This routine opens a file across the network. + +Arguments: + + RxContext - the RDBSS context + +Return Value: + + RXSTATUS - The return status for the operation + +--*/ + +{ + NTSTATUS Status = STATUS_SUCCESS; + RxCaptureFcb; + RxCaptureFobx; + + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + PMDL OriginalDataMdl = LowIoContext->ParamsFor.ReadWrite.Buffer; + + PVOID pbUserBuffer = VBoxRxLowIoGetBufferAddress(RxContext); + uint32_t ByteCount = (LowIoContext->ParamsFor).ReadWrite.ByteCount; + RXVBO ByteOffset = (LowIoContext->ParamsFor).ReadWrite.ByteOffset; + LONGLONG FileSize = 0; + PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot; + VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension); + BOOLEAN SynchronousIo = !BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION); +#ifndef VBOX + PDEVICE_OBJECT deviceObject; +#endif + VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension); + PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); + + Log(("VBOXSF: VBoxMRxWrite: SynchronousIo = %d\n", SynchronousIo)); + Log(("VBOXSF: VBoxMRxWrite: NetRoot is 0x%x Fcb is 0x%x\n", pNetRoot, capFcb)); + + Assert( ( OriginalDataMdl != NULL + && + ( RxMdlIsLocked(OriginalDataMdl) + || RxMdlSourceIsNonPaged(OriginalDataMdl) + ) + ) + || + ( + OriginalDataMdl == NULL + && + LowIoContext->ParamsFor.ReadWrite.ByteCount == 0 + ) + ); + + if ( OriginalDataMdl == NULL + || LowIoContext->ParamsFor.ReadWrite.ByteCount == 0) + { + AssertFailed(); + return STATUS_INVALID_PARAMETER; + } + + // + // Lengths that are not sector aligned will be rounded up to + // the next sector boundary. The rounded up length should be + // < AllocationSize. + // + VBoxRxGetFileSizeWithLock((PFCB)capFcb,&FileSize); + + Log(("VBOXSF: VBoxMRxWrite: UserBuffer is 0x%x\n", pbUserBuffer )); + Log(("VBOXSF: VBoxMRxWrite: ByteCount is %d, ByteOffset is %d\n", ByteCount, ByteOffset )); + + /* @todo async io !!!! */ + SynchronousIo = TRUE; + + if( SynchronousIo ) + { + int vboxRC; + PMDL pMdlBuf = NULL; + +#ifdef VBOX_FAKE_IO_READ_WRITE + Status = STATUS_SUCCESS; +#else + vboxRC = vboxCallWrite(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, ByteOffset, &ByteCount, (uint8_t *)pbUserBuffer, true /* locked */); + AssertRC(vboxRC); + + Status = VBoxErrorToNTStatus(vboxRC); +#endif + if (Status != STATUS_SUCCESS) + ByteCount = 0; /* Nothing written */ + + Log(("VBOXSF: VBoxMRxWrite: This I/O is sync!\n")); + + RxContext->InformationToReturn = ByteCount; + + /* Never call RxLowIoCompletion here!! */ + } + else { + Log(("VBOXSF: VBoxMRxWrite: This I/O is async!\n")); + } + + Log(("VBOXSF: VBoxMRxWrite: Status = %x, Info = %x\n",RxContext->IoStatusBlock.Status,RxContext->IoStatusBlock.Information)); + +#ifndef VBOX +Exit: +#endif + return(Status); +} + +static VOID VBoxMRxWriteWorker (VOID *pv) +{ + PRX_CONTEXT RxContext = (PRX_CONTEXT)pv; + + Log(("VBOXSF: VBoxMRxWriteWorker: calling the worker\n")); + + RxContext->IoStatusBlock.Status = VBoxMRxWriteInternal (RxContext); + + Log(("VBOXSF: VBoxMRxWriteWorker: Status %x\n", RxContext->IoStatusBlock.Status)); + + RxLowIoCompletion (RxContext); +} + + +#ifdef VBOX_ASYNC_RW +NTSTATUS +VBoxMRxWrite ( + IN PRX_CONTEXT RxContext) +{ + NTSTATUS Status = STATUS_SUCCESS; + + Status = RxDispatchToWorkerThread(VBoxMRxDeviceObject, DelayedWorkQueue, + VBoxMRxWriteWorker, + RxContext); + + Log(("VBOXSF: VBoxMRxWrite: RxDispatchToWorkerThread: Status %x\n", Status)); + + if (Status == STATUS_SUCCESS) + { + Status = STATUS_PENDING; + } + + return Status; +} +#else +NTSTATUS +VBoxMRxWrite ( + IN PRX_CONTEXT RxContext) +{ + RxContext->IoStatusBlock.Status = VBoxMRxWriteInternal (RxContext); + return RxContext->IoStatusBlock.Status; +} +#endif /* !VBOX_ASYNC_RW */ |