Compare commits

..

110 Commits
v0.9 ... v0.11

Author SHA1 Message Date
f7adbaba92 dll: FspCallNamedPipeSecurely replaces CallNamedPipeW 2016-05-18 10:05:33 -07:00
fea92c4ae0 doc: add Service Architecture document 2016-05-17 18:59:16 -07:00
1e2f0930a2 inc: winfsp.h: add service related documentation 2016-05-17 16:21:18 -07:00
ab11ff2b39 dll: np: NPEnumResource: minor change 2016-05-17 13:01:20 -07:00
1e1b9cdda3 dll: NPOpenEnum, NPEnumResources, NPCloseEnum: testing 2016-05-17 11:49:31 -07:00
00ee25f904 dll: NPOpenEnum, NPEnumResources, NPCloseEnum: implementation 2016-05-17 00:39:26 -07:00
cf29bd5a58 dll: FspNpAddConnection3, FspNpCancelConnection: improve error handling 2016-05-16 21:35:52 -07:00
597dd43f23 launcher: fix bug in SvcInstanceCreate 2016-05-16 16:34:59 -07:00
1c3fc530f6 dll: np: NPAddConnection3, NPCancelConnection implementation 2016-05-16 15:48:27 -07:00
67c6cd453a dll: FspNpRegister: get NetworkProvider name from version info 2016-05-15 15:14:12 -07:00
7eec1649a4 installer: add requirement for VC++ redistributable to F.Developer feature description 2016-05-15 13:24:17 -07:00
9971472be7 launcher, launchctl: ensure that they build under all platforms/configurations 2016-05-15 11:22:19 -07:00
c1985bef6c installer: update installer to include launcher and launchctl and install launcher as a service 2016-05-15 10:05:39 -07:00
e4e2465bcb memfs: empty Mountpoint ("") now means autodetect (same as no MountPoint) 2016-05-14 23:52:37 -07:00
22d1f86ac1 launcher: AllocConsole if we are running as a service without one (DETACHED_PROCESS) 2016-05-14 23:18:43 -07:00
1a7d3b8f9e launcher: remove JOB_OBJECT_LIMIT_BREAKAWAY_OK, use JobControl=0 registry setting instead 2016-05-14 21:01:29 -07:00
768a393342 launcher, launchctl: add quit command on debug version of launcher 2016-05-14 21:00:02 -07:00
08a02d7b35 launcher:
- STOP_TIMEOUT vs KILL_TIMEOUT
    - JobControl registry value
2016-05-14 19:27:59 -07:00
3035ba2847 launcher: better handling of service instance stopping:
- instances are now launched in a job so that they get killed if the parent process dies
    - instances are killed after a timeout if they do not respond timely to console control events
2016-05-14 18:47:26 -07:00
147c90be9f launcher: minor bug fix 2016-05-13 15:25:31 -07:00
0822458238 launcher: SvcInstanceReplaceArguments 2016-05-13 14:30:54 -07:00
c322a4b14a launcher: testing 2016-05-13 13:13:08 -07:00
0c6300b97c launcher: testing 2016-05-13 12:38:30 -07:00
be952729c9 launcher, launchctl: testing 2016-05-13 12:07:30 -07:00
1802ac8878 launcher, launchctl: testing 2016-05-13 11:10:59 -07:00
5491187e1d launcher, launchctl: command line arguments are now numbered %1 to %9 2016-05-13 10:42:23 -07:00
ec2494433b launcher: fix deadlock when SvcPipeServer stops itself 2016-05-13 10:37:25 -07:00
0756649572 launchctl: fix usage string 2016-05-13 10:24:12 -07:00
8ccd44a1f7 launcher, launchctl: refactoring 2016-05-13 10:00:54 -07:00
2c51251cb7 launcher, launchctl: refactoring 2016-05-13 09:55:27 -07:00
35d2b3f626 launcher, launchctl: refactoring 2016-05-13 09:28:56 -07:00
26a9bb714b launchctl: major refactoring 2016-05-12 22:44:34 -07:00
13f2517a31 launchctl: major refactoring 2016-05-12 22:36:37 -07:00
da85f2aa08 launcher, launchctl: testing 2016-05-12 22:11:28 -07:00
22c324de69 launcher: testing 2016-05-12 17:19:48 -07:00
c42e2a5958 launcher: security model improvements 2016-05-12 15:31:35 -07:00
1c587dbcb7 version.properties: bump version to 0.11 2016-05-12 14:49:10 -07:00
bc2e87763e launcher, launchctl: add version info 2016-05-12 14:48:18 -07:00
724d177d0b launcher: security model improvements 2016-05-12 14:18:08 -07:00
6971f4d6ae launcher: access control 2016-05-12 13:44:07 -07:00
ceef2bf55e launcher: access check on client token 2016-05-11 21:35:12 -07:00
a81a766bbe launcher: named pipe SDDL 2016-05-11 20:37:44 -07:00
da839e39b8 launcher: SvcInstanceCreate improvements 2016-05-11 20:23:00 -07:00
ec21e830f1 launchctl: implementation 2016-05-11 17:40:49 -07:00
9ae28a5529 add launchctl project 2016-05-11 16:02:56 -07:00
1a14971911 launcher: improvements 2016-05-11 15:32:16 -07:00
ab48beb4ba launcher: List, Info command implementation 2016-05-11 15:20:23 -07:00
528cbd3295 launcher: named pipe implementation 2016-05-11 14:46:03 -07:00
c32d05c3b6 launcher: named pipe implementation 2016-05-11 13:31:07 -07:00
e82b06ae49 dll: FspServiceStop: early exit if service is already being stopped 2016-05-11 11:29:36 -07:00
457e151fa5 launcher: SvcInstance implementation 2016-05-10 16:48:21 -07:00
dc4109fc22 dll: refactor library.h into src/shared/minimal.h for reuse 2016-05-09 20:07:35 -07:00
2a69ad6710 add launcher project 2016-05-09 16:20:52 -07:00
d3ff12bf60 dll: FspServiceConsoleModeThread: fix stupid bug with command line argument handling 2016-05-09 14:51:30 -07:00
713ee8a917 memfs: add old memfs-main.c 2016-05-09 14:17:28 -07:00
f4744258a7 dll: FspServiceCtrlHandler: disable Shutdown handling 2016-05-09 13:50:36 -07:00
7e57edf72e dll: FspService: console mode further improvements with respect to console ctrl handling 2016-05-09 13:19:54 -07:00
89e4e8a96c dll: FspService: console mode testing 2016-05-09 12:35:51 -07:00
0c18b82cc2 dll: FspService: console mode improvements 2016-05-08 21:12:34 -07:00
57f9db6cc0 dll: FspService: console mode improvements 2016-05-08 17:57:08 -07:00
6da81be792 dll: FspService: console mode improvements 2016-05-08 17:46:09 -07:00
b77a749f93 dll: FspService: improve console mode handling 2016-05-08 17:23:12 -07:00
bb946d5a3a dll: streamline DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH handling 2016-05-08 16:22:07 -07:00
27a16e5c54 dll: service: testing 2016-05-07 22:37:17 -07:00
789222af68 dll: FspServiceRun 2016-05-07 17:25:49 -07:00
587fee93e9 dll, memfs: rename FspServiceRun to FspServiceLoop 2016-05-07 17:08:03 -07:00
077bbb0d65 memfs: convert to service 2016-05-07 17:00:58 -07:00
3d2a2dd90d dll: service: use FspServiceLog instead of FspEventLog 2016-05-07 14:57:39 -07:00
0b1bba36f8 dll: FspIsInteractive, FspServiceLog, FspServiceLogV 2016-05-07 14:55:19 -07:00
8dd5a03b51 dll: FSP_SERVICE: rename interactive mode to console mode 2016-05-07 13:30:12 -07:00
ac2e9f9882 dll: FSP_SERVICE 2016-05-07 12:56:32 -07:00
1017e7fda7 dll: FSP_SERVICE 2016-05-07 12:55:48 -07:00
125b612c9f winfsp-tests: eventlog-test.c 2016-05-06 15:58:33 -07:00
9addfa5899 dll: FspEventLogRegister, FspEventLogUnregister 2016-05-06 15:05:36 -07:00
12db7cf9dc dll: add eventlog.mc and related files 2016-05-06 13:15:29 -07:00
e53e915a72 dll: service, eventlog 2016-05-06 12:25:47 -07:00
d7a6f33d26 dll: add FSP_SERVICE and EventLog functionality 2016-05-06 11:41:45 -07:00
de973fa5ab dll: FspFileSystemRegister, FspFileSystemUnregister: rename and place in fsctl.c 2016-05-05 11:14:23 -07:00
4a4fba4670 build: bump version to 0.10 2016-05-04 16:32:17 -07:00
e45ac30b65 tools: build.bat: add friendly MSI name when signing (primarily for use in UAC dialog) 2016-05-04 16:25:49 -07:00
cbb7d943bd dll: fsctl: FspFsctlStartService 2016-05-04 16:06:14 -07:00
df5d2d6e87 installer: disallow major upgrades 2016-05-04 15:22:03 -07:00
b1b31b9017 dll: FspFileSystemRegister: fix WinFsp service security descriptor to allow Everyone to start the service 2016-05-04 13:29:34 -07:00
ff0b8bc3fe installer: only install memfs executables when developer build is selected! 2016-05-04 00:34:44 -07:00
a99e8ac9d2 dll: FspFileSystemRegister: handle the case where service already exists better 2016-05-03 22:53:51 -07:00
3f7ebe7996 tools: build.bat: sign MSI 2016-05-03 22:15:58 -07:00
030ef84c2e installer: check if ServiceRunning both on install and uninstall 2016-05-03 21:59:58 -07:00
ba5c670034 tools: build.bat 2016-05-03 15:13:21 -07:00
690e7662d6 dll: FspFileSystemRegister: now will correctly recreate the WinFsp service if it already exists 2016-05-02 21:54:59 -07:00
500db7b1cd installer: CustomActions: ServiceRunning 2016-05-02 20:47:24 -07:00
e43c5091e4 dll: FspFileSystemRegister, FspFileSystemUnregister: fix closing the wrong handle 2016-05-02 12:26:33 -07:00
9ffc3f03ed memfs: comment fix 2016-05-02 11:12:41 -07:00
14366f76c5 installer: simplify FSD/DLL registration by removing regsvr32 custom actions 2016-05-01 20:22:38 -07:00
b089b98afc dll: FspFileSystemRegister, FspFileSystemUnregister 2016-05-01 18:01:49 -07:00
26aadb0b72 installer: use regsvr32 to register FSD/DLL (Wix cannot register file system drivers or network provider DLL's) 2016-04-30 17:33:25 -07:00
9c11ca5bda installer: remember installation directory in registry 2016-04-29 16:33:55 -07:00
8ae2bb3bfc build: update version.properties 2016-04-29 14:22:53 -07:00
b0a2e4ff40 installer: add UI 2016-04-29 11:38:38 -07:00
0c75b58810 versioning: rename shared.properties to version.properties 2016-04-29 00:33:46 -07:00
b12e0aad47 versioning: add version resources to FSD and DLL; consolidate versioning to shared.properties 2016-04-29 00:23:55 -07:00
1264cae110 installer: reorg 2016-04-28 22:19:59 -07:00
5a7c7bb4f2 installer: automatic versioning scheme 2016-04-28 21:51:29 -07:00
acfd02c31d installer: add Package description 2016-04-28 19:22:21 -07:00
efa200aac4 installer: add memfs sample 2016-04-28 17:31:13 -07:00
3a1cba2442 installer: reorg 2016-04-28 17:19:07 -07:00
59698f5517 installer: reorg 2016-04-28 16:39:49 -07:00
1176114528 install: winfsp.wixproj 2016-04-28 15:55:05 -07:00
e0dde7349e sys,dll,tst: ensure that project compiles for x86 2016-04-28 15:02:00 -07:00
1bdfc8a579 install: winfsp.wixproj 2016-04-28 14:47:09 -07:00
2659effafb install: winfsp.wixproj 2016-04-28 13:04:46 -07:00
54 changed files with 5328 additions and 262 deletions

View File

@ -0,0 +1,83 @@
/**
* @file CustomActions.cpp
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <msiquery.h>
#include <wcautil.h>
#include <strutil.h>
UINT __stdcall ServiceRunning(MSIHANDLE MsiHandle)
{
#if 0
WCHAR MessageBuf[64];
wsprintfW(MessageBuf, L"PID=%ld", GetCurrentProcessId());
MessageBoxW(0, MessageBuf, L"" __FUNCTION__ " Break", MB_OK);
#endif
HRESULT hr = S_OK;
UINT err = ERROR_SUCCESS;
PWSTR ServiceName = 0;
SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0;
SERVICE_STATUS ServiceStatus;
int Result = 0;
hr = WcaInitialize(MsiHandle, __FUNCTION__);
ExitOnFailure(hr, "Failed to initialize");
WcaGetProperty(L"" __FUNCTION__, &ServiceName);
ExitOnFailure(hr, "Failed to get ServiceName");
WcaLog(LOGMSG_STANDARD, "Initialized: \"%S\"", ServiceName);
ScmHandle = OpenSCManagerW(0, 0, 0);
ExitOnNullWithLastError(ScmHandle, hr, "Failed to open SCM");
SvcHandle = OpenServiceW(ScmHandle, ServiceName, SERVICE_QUERY_STATUS);
if (0 != SvcHandle && QueryServiceStatus(SvcHandle, &ServiceStatus))
Result = SERVICE_STOPPED != ServiceStatus.dwCurrentState;
WcaSetIntProperty(L"" __FUNCTION__, Result);
LExit:
if (0 != SvcHandle)
CloseServiceHandle(SvcHandle);
if (0 != ScmHandle)
CloseServiceHandle(ScmHandle);
ReleaseStr(ServiceName);
err = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(err);
}
extern "C"
BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH:
WcaGlobalInitialize(Instance);
break;
case DLL_PROCESS_DETACH:
WcaGlobalFinalize();
break;
}
return TRUE;
}

View File

@ -0,0 +1,2 @@
EXPORTS
ServiceRunning

View File

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{95C223E6-B5F1-4FD0-9376-41CDBC824445}</ProjectGuid>
<RootNamespace>CustomActions</RootNamespace>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.25123.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(WIX)sdk\VS2015\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(WIX)sdk\VS2015\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ModuleDefinitionFile>CustomActions.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(WIX)sdk\VS2015\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(WIX)sdk\VS2015\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ModuleDefinitionFile>CustomActions.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="CustomActions.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="CustomActions.def" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CustomActions.cpp">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="CustomActions.def">
<Filter>Source</Filter>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,330 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product
Id="*"
Name="$(var.MyProductName)"
Manufacturer="$(var.MyCompanyName)"
Version="$(var.MyVersion)"
Language="1033"
UpgradeCode="82F812D9-4083-4EF1-8BC8-0F1EDA05B46B">
<Package
Description="$(var.MyProductName) - $(var.MyDescription)"
InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine" />
<MajorUpgrade
Disallow="yes"
AllowDowngrades="no"
AllowSameVersionUpgrades="no"
DisallowUpgradeErrorMessage="An older version of [ProductName] is already installed. You must uninstall it before you can install this version."
DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Media Id="1" Cabinet="WinFsp.cab" EmbedCab="yes" />
<Property Id="P.LauncherName">$(var.MyProductName).Launcher</Property>
<Property Id="P.LauncherRegistryKey">SYSTEM\\CurrentControlSet\\Services\\$(var.MyProductName).Launcher\\Services</Property>
<Property Id="P.RegistryKey">Software\$(var.MyProductName)</Property>
<Property Id="INSTALLDIR">
<RegistrySearch
Id="R.INSTALLDIR"
Root="HKLM"
Key="[P.RegistryKey]"
Name="InstallDir"
Type="raw" />
</Property>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="WinFsp">
<Directory Id="BINDIR" Name="bin" />
<Directory Id="INCDIR" Name="inc" />
<Directory Id="LIBDIR" Name="lib" />
<Directory Id="SMPDIR" Name="samples" />
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="INSTALLDIR">
<Component Id="C.INSTALLDIR">
<RegistryValue
Root="HKLM"
Key="[P.RegistryKey]"
Name="InstallDir"
Type="string"
Value="[INSTALLDIR]" />
</Component>
</DirectoryRef>
<DirectoryRef Id="BINDIR" FileSource="..\build\$(var.Configuration)">
<Component Id="C.winfsp_x64.sys">
<File Name="winfsp-x64.sys" KeyPath="yes" />
</Component>
<Component Id="C.winfsp_x86.sys">
<File Name="winfsp-x86.sys" KeyPath="yes" />
</Component>
<!-- On Win64 register winfsp-x64.dll -->
<Component Id="C.winfsp_x64.dll.selfreg" Guid="F0A67746-1A9C-4976-8EC0-882E9407FA6D">
<File Id="FILE.winfsp_x64.dll.selfreg" Name="winfsp-x64.dll" KeyPath="yes" SelfRegCost="1" />
<Condition>VersionNT64</Condition>
</Component>
<Component Id="C.winfsp_x86.dll" Guid="950492FB-12F7-4E27-9124-8325A2BC9927">
<File Name="winfsp-x86.dll" KeyPath="yes" />
<Condition>VersionNT64</Condition>
</Component>
<!-- On Win32 register winfsp-x86.dll -->
<Component Id="C.winfsp_x64.dll" Guid="4D6E7A8E-0CA6-49BE-B312-1EDADE725756">
<File Name="winfsp-x64.dll" KeyPath="yes" />
<Condition>NOT VersionNT64</Condition>
</Component>
<Component Id="C.winfsp_x86.dll.selfreg" Guid="F0DEF7A6-AF55-419F-A58A-DF4018C6FA73">
<File Id="FILE.winfsp_x86.dll.selfreg" Name="winfsp-x86.dll" KeyPath="yes" SelfRegCost="1" />
<Condition>NOT VersionNT64</Condition>
</Component>
<!-- On Win64 ServiceInstall launcher-x64.exe -->
<Component Id="C.launcher_x64.exe.svcinst">
<File Id="launcher_x64.exe.svcinst" Name="launcher-x64.exe" KeyPath="yes" />
<ServiceInstall
Id="launcher_x64.exe.svcinst"
Name="[P.LauncherName]"
Description="$(var.MyDescription)"
Type="ownProcess"
Start="auto"
ErrorControl="ignore" />
<ServiceControl
Id="launcher_x64.exe.svcinst"
Name="[P.LauncherName]"
Start="install"
Stop="both"
Remove="uninstall" />
<Condition>VersionNT64</Condition>
</Component>
<Component Id="C.launcher_x86.exe">
<File Name="launcher-x86.exe" KeyPath="yes" />
<Condition>VersionNT64</Condition>
</Component>
<!-- On Win32 ServiceInstall launcher-x86.exe -->
<Component Id="C.launcher_x64.exe" Guid="88CDBE92-8B67-485A-838F-FA4AD37F306F">
<File Name="launcher-x64.exe" KeyPath="yes" />
<Condition>NOT VersionNT64</Condition>
</Component>
<Component Id="C.launcher_x86.exe.svcinst" Guid="E995D906-0273-4758-9B26-99A3A8CD143A">
<File Id="launcher_x86.exe.svcinst" Name="launcher-x86.exe" KeyPath="yes" />
<ServiceInstall
Id="launcher_x86.exe.svcinst"
Name="[P.LauncherName]"
Description="$(var.MyDescription)"
Type="ownProcess"
Start="auto"
ErrorControl="ignore" />
<ServiceControl
Id="launcher_x86.exe.svcinst"
Name="[P.LauncherName]"
Start="install"
Stop="both"
Remove="uninstall" />
<Condition>NOT VersionNT64</Condition>
</Component>
<Component Id="C.launchctl_x64.exe" Guid="2753623B-66F1-4514-B9C7-F879178DFF49">
<File Name="launchctl-x64.exe" KeyPath="yes" />
</Component>
<Component Id="C.launchctl_x86.exe" Guid="EBDEC4FB-07BB-47CA-BFFF-EB854CA2D22D">
<File Name="launchctl-x86.exe" KeyPath="yes" />
</Component>
<Component Id="C.memfs_x64.exe">
<File Name="memfs-x64.exe" KeyPath="yes" />
<RegistryKey
Root="HKLM"
Key="[P.LauncherRegistryKey]">
<RegistryKey
Key="memfs64">
<RegistryValue
Type="string"
Name="Executable"
Value="[BINDIR]memfs-x64.exe" />
<RegistryValue
Type="string"
Name="CommandLine"
Value="-u %1 -m %2" />
<RegistryValue
Type="string"
Name="Security"
Value="D:P(A;;RPWPLC;;;WD)" />
<RegistryValue
Type="integer"
Name="JobControl"
Value="1" />
</RegistryKey>
</RegistryKey>
</Component>
<Component Id="C.memfs_x86.exe">
<File Name="memfs-x86.exe" KeyPath="yes" />
<RegistryKey
Root="HKLM"
Key="[P.LauncherRegistryKey]">
<RegistryKey
Key="memfs32">
<RegistryValue
Type="string"
Name="Executable"
Value="[BINDIR]memfs-x86.exe" />
<RegistryValue
Type="string"
Name="CommandLine"
Value="-u %1 -m %2" />
<RegistryValue
Type="string"
Name="Security"
Value="D:P(A;;RPWPLC;;;WD)" />
<RegistryValue
Type="integer"
Name="JobControl"
Value="1" />
</RegistryKey>
</RegistryKey>
</Component>
</DirectoryRef>
<DirectoryRef Id="INCDIR" FileSource="..\..\..\inc">
<Directory Id="INCDIR.winfsp" Name="winfsp">
<Component Id="C.fsctl.h">
<File Name="fsctl.h" KeyPath="yes" />
</Component>
<Component Id="C.winfsp.h">
<File Name="winfsp.h" KeyPath="yes" />
</Component>
</Directory>
</DirectoryRef>
<DirectoryRef Id="LIBDIR" FileSource="..\build\$(var.Configuration)">
<Component Id="C.winfsp_x64.lib">
<File Name="winfsp-x64.lib" KeyPath="yes" />
</Component>
<Component Id="C.winfsp_x86.lib">
<File Name="winfsp-x86.lib" KeyPath="yes" />
</Component>
</DirectoryRef>
<DirectoryRef Id="SMPDIR" FileSource="..\..\..\tst">
<Directory Id="SMPDIR.memfs" Name="memfs">
<Component Id="C.memfs.h">
<File Name="memfs.h" KeyPath="yes" />
</Component>
<Component Id="C.memfs.cpp">
<File Name="memfs.cpp" KeyPath="yes" />
</Component>
<Component Id="C.memfs_main.c">
<File Name="memfs-main.c" KeyPath="yes" />
</Component>
</Directory>
</DirectoryRef>
<ComponentGroup Id="C.WinFsp.bin">
<ComponentRef Id="C.winfsp_x64.sys" />
<ComponentRef Id="C.winfsp_x86.sys" />
<ComponentRef Id="C.winfsp_x64.dll.selfreg" />
<ComponentRef Id="C.winfsp_x86.dll" />
<ComponentRef Id="C.winfsp_x64.dll" />
<ComponentRef Id="C.winfsp_x86.dll.selfreg" />
<ComponentRef Id="C.launcher_x64.exe.svcinst" />
<ComponentRef Id="C.launcher_x86.exe" />
<ComponentRef Id="C.launcher_x64.exe" />
<ComponentRef Id="C.launcher_x86.exe.svcinst" />
<ComponentRef Id="C.launchctl_x64.exe" />
<ComponentRef Id="C.launchctl_x86.exe" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.inc">
<ComponentRef Id="C.fsctl.h" />
<ComponentRef Id="C.winfsp.h" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.lib">
<ComponentRef Id="C.winfsp_x64.lib" />
<ComponentRef Id="C.winfsp_x86.lib" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.smp">
<ComponentRef Id="C.memfs_x64.exe" />
<ComponentRef Id="C.memfs_x86.exe" />
<ComponentRef Id="C.memfs.h" />
<ComponentRef Id="C.memfs.cpp" />
<ComponentRef Id="C.memfs_main.c" />
</ComponentGroup>
<Feature
Id="F.Main"
Level="1"
Title="$(var.MyProductName) $(var.MyVersion)"
Description="$(var.MyDescription)"
Display="expand"
ConfigurableDirectory="INSTALLDIR"
AllowAdvertise="no"
InstallDefault="local"
Absent="disallow">
<ComponentRef Id="C.INSTALLDIR" />
<Feature
Id="F.User"
Level="1"
Title="Core"
Description="The core $(var.MyProductName) files."
AllowAdvertise="no"
InstallDefault="local"
Absent="disallow">
<ComponentGroupRef Id="C.WinFsp.bin" />
</Feature>
<Feature
Id="F.Developer"
Level="1000"
Title="Developer"
Description="Additional files needed for development. Please note that the memfs sample requires the VC++ 2015 redistributable to be installed."
AllowAdvertise="no"
InstallDefault="local"
Absent="allow">
<ComponentGroupRef Id="C.WinFsp.inc" />
<ComponentGroupRef Id="C.WinFsp.lib" />
<ComponentGroupRef Id="C.WinFsp.smp" />
</Feature>
</Feature>
<UI Id="FeatureTree">
<UIRef Id="WixUI_FeatureTree" />
<!-- skip the license agreement dialog; higher Order takes priority (weird) -->
<Publish
Dialog="WelcomeDlg"
Control="Next"
Event="NewDialog"
Value="CustomizeDlg"
Order="10">NOT Installed</Publish>
<Publish
Dialog="CustomizeDlg"
Control="Back"
Event="NewDialog"
Value="WelcomeDlg"
Order="10">NOT Installed</Publish>
</UI>
<Binary Id="CustomActions" SourceFile="..\build\$(var.Configuration)\CustomActions.dll" />
<CustomAction
Id="Params.ServiceRunning"
Property="ServiceRunning"
Value="$(var.MyProductName)" />
<CustomAction
Id="Action.ServiceRunning"
BinaryKey="CustomActions"
DllEntry="ServiceRunning"
Execute="immediate"
Return="ignore" />
<CustomAction
Id="Action.ServiceRunning.Error"
Error="The $(var.MyProductName) service appears to be running. If you just uninstalled $(var.MyProductName) please restart your computer. If you are running a development version of $(var.MyProductName) please remove it before proceeding." />
<InstallExecuteSequence>
<Custom Action="Params.ServiceRunning" Before="Action.ServiceRunning" />
<Custom Action="Action.ServiceRunning" Before="LaunchConditions" />
<Custom Action="Action.ServiceRunning.Error" After="Action.ServiceRunning">
<![CDATA[NOT Installed AND (0 <> ServiceRunning)]]>
</Custom>
<ScheduleReboot After="RemoveFiles">
<![CDATA[(REMOVE ~= "ALL") AND (0 <> ServiceRunning)]]>
</ScheduleReboot>
</InstallExecuteSequence>
</Product>
</Wix>

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\version.properties" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>3.10</ProductVersion>
<ProjectGuid>d53aac39-4c57-4ca5-a4f3-c2b24888c594</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>winfsp-$(MyVersion)</OutputName>
<OutputType>Package</OutputType>
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
<Name>winfsp.msi</Name>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<IntermediateOutputPath>$(SolutionDir)build\$(Name).build\$(Configuration)\$(Platform)\</IntermediateOutputPath>
<DefineConstants>Debug;MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion)</DefineConstants>
<SuppressAllWarnings>False</SuppressAllWarnings>
<Pedantic>True</Pedantic>
<SuppressPdbOutput>True</SuppressPdbOutput>
<SuppressIces>ICE30</SuppressIces>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<IntermediateOutputPath>$(SolutionDir)build\$(Name).build\$(Configuration)\$(Platform)\</IntermediateOutputPath>
<DefineConstants>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion)</DefineConstants>
<SuppressAllWarnings>False</SuppressAllWarnings>
<Pedantic>True</Pedantic>
<SuppressPdbOutput>True</SuppressPdbOutput>
<SuppressIces>ICE30</SuppressIces>
</PropertyGroup>
<ItemGroup>
<Compile Include="Product.wxs" />
</ItemGroup>
<ItemGroup>
<WixExtension Include="WixUIExtension">
<HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
<Name>WixUIExtension</Name>
</WixExtension>
</ItemGroup>
<Import Project="$(WixTargetsPath)" />
<!--
To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Wix.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,194 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\version.properties" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{73EAAEDA-557B-48D5-A137-328934720FB4}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>launchctl</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\launcher\launcher.h" />
<ClInclude Include="..\..\..\src\shared\minimal.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\launcher\launchctl.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\src\launcher\launchctl-version.rc">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\winfsp_dll.vcxproj">
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Include">
<UniqueIdentifier>{e650819b-355e-455c-81c9-10dc7debe109}</UniqueIdentifier>
</Filter>
<Filter Include="Include\shared">
<UniqueIdentifier>{744edf89-567a-40b7-b6f2-ee2bc7b9f0d9}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\shared\minimal.h">
<Filter>Include\shared</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\launcher\launcher.h">
<Filter>Source</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\launcher\launchctl.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\src\launcher\launchctl-version.rc">
<Filter>Source</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,194 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\version.properties" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{A5EFD487-0140-4184-8C54-FFAEC2F85E35}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>launcher</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\launcher\launcher.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\winfsp_dll.vcxproj">
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\launcher\launcher.h" />
<ClInclude Include="..\..\..\src\shared\minimal.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\src\launcher\launcher-version.rc">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
</ResourceCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Include">
<UniqueIdentifier>{11e7c0f2-7782-43ee-84fa-9e56efbe39de}</UniqueIdentifier>
</Filter>
<Filter Include="Include\shared">
<UniqueIdentifier>{d83ea433-d9f7-494c-90b9-3a8997483cd9}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\launcher\launcher.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\shared\minimal.h">
<Filter>Include\shared</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\launcher\launcher.h">
<Filter>Source</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\src\launcher\launcher-version.rc">
<Filter>Source</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -183,6 +183,7 @@
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp" />
<ClCompile Include="..\..\..\tst\winfsp-tests\create-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\dirctl-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\info-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\lock-test.c" />

View File

@ -52,6 +52,9 @@
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MyProductName>WinFsp</MyProductName>
<MyDescription>Windows File System Proxy</MyDescription>
<MyCompanyName>Navimatics Corporation</MyCompanyName>
<MyCopyright>2015-2016 Bill Zissimopoulos</MyCopyright>
<!-- build number: concat 2-digit year with 3-digit day of the year (16-bits until 2066) -->
<MyBuildNumber>$([System.DateTime]::Now.ToString(`yy`))$([System.DateTime]::Now.DayOfYear.ToString(`000`))</MyBuildNumber>
<MyVersion>0.11.$(MyBuildNumber)</MyVersion>
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
</PropertyGroup>
</Project>

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winfsp.dll", "winfsp_dll.vcxproj", "{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}"
ProjectSection(ProjectDependencies) = postProject
@ -23,10 +23,36 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memfs", "testing\memfs.vcxp
{C85C26BA-8C22-4D30-83DA-46C3548E6332} = {C85C26BA-8C22-4D30-83DA-46C3548E6332}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "installer", "installer", "{B464EF06-42AE-4674-81BB-FDDE80204822}"
EndProject
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "winfsp_msi", "installer\winfsp_msi.wixproj", "{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}"
ProjectSection(ProjectDependencies) = postProject
{95C223E6-B5F1-4FD0-9376-41CDBC824445} = {95C223E6-B5F1-4FD0-9376-41CDBC824445}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomActions", "installer\CustomActions\CustomActions.vcxproj", "{95C223E6-B5F1-4FD0-9376-41CDBC824445}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "launcher", "launcher", "{FD28A504-431E-49B9-BB8C-DCA0E7019F66}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launcher", "launcher\launcher.vcxproj", "{A5EFD487-0140-4184-8C54-FFAEC2F85E35}"
ProjectSection(ProjectDependencies) = postProject
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}
{C85C26BA-8C22-4D30-83DA-46C3548E6332} = {C85C26BA-8C22-4D30-83DA-46C3548E6332}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launchctl", "launcher\launchctl.vcxproj", "{73EAAEDA-557B-48D5-A137-328934720FB4}"
ProjectSection(ProjectDependencies) = postProject
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {A5EFD487-0140-4184-8C54-FFAEC2F85E35}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Installer.Debug|x64 = Installer.Debug|x64
Installer.Debug|x86 = Installer.Debug|x86
Installer.Release|x64 = Installer.Release|x64
Installer.Release|x86 = Installer.Release|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
@ -35,6 +61,10 @@ Global
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x64.Build.0 = Debug|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x86.ActiveCfg = Debug|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x86.Build.0 = Debug|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Debug|x64.ActiveCfg = Debug|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Release|x64.ActiveCfg = Release|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Release|x86.ActiveCfg = Release|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x64.ActiveCfg = Release|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x64.Build.0 = Release|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x86.ActiveCfg = Release|Win32
@ -43,6 +73,10 @@ Global
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x64.Build.0 = Debug|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x86.ActiveCfg = Debug|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x86.Build.0 = Debug|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Debug|x64.ActiveCfg = Debug|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Release|x64.ActiveCfg = Release|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Release|x86.ActiveCfg = Release|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x64.ActiveCfg = Release|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x64.Build.0 = Release|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x86.ActiveCfg = Release|Win32
@ -51,6 +85,10 @@ Global
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x64.Build.0 = Debug|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x86.ActiveCfg = Debug|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x86.Build.0 = Debug|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Debug|x64.ActiveCfg = Debug|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Release|x64.ActiveCfg = Release|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Release|x86.ActiveCfg = Release|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x64.ActiveCfg = Release|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x64.Build.0 = Release|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x86.ActiveCfg = Release|Win32
@ -59,10 +97,62 @@ Global
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x64.Build.0 = Debug|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x86.ActiveCfg = Debug|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x86.Build.0 = Debug|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Debug|x64.ActiveCfg = Debug|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Release|x64.ActiveCfg = Release|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Release|x86.ActiveCfg = Release|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x64.ActiveCfg = Release|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x64.Build.0 = Release|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x86.ActiveCfg = Release|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x86.Build.0 = Release|Win32
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Debug|x64.ActiveCfg = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Debug|x86.ActiveCfg = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x64.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x64.Build.0 = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x86.ActiveCfg = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x86.Build.0 = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x64.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x64.Build.0 = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x86.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x86.Build.0 = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Release|x64.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Release|x86.ActiveCfg = Release|x86
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Debug|x64.ActiveCfg = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Debug|x86.ActiveCfg = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x64.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x64.Build.0 = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x86.Build.0 = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x64.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x64.Build.0 = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x86.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x86.Build.0 = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x64.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x86.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.ActiveCfg = Debug|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.Build.0 = Debug|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x86.ActiveCfg = Debug|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x86.Build.0 = Debug|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|x64.ActiveCfg = Debug|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|x64.ActiveCfg = Release|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|x86.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x64.ActiveCfg = Release|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x64.Build.0 = Release|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x86.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x86.Build.0 = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x64.ActiveCfg = Debug|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x64.Build.0 = Debug|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x86.ActiveCfg = Debug|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x86.Build.0 = Debug|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|x64.ActiveCfg = Debug|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|x64.ActiveCfg = Release|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|x86.ActiveCfg = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.ActiveCfg = Release|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.Build.0 = Release|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.ActiveCfg = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -70,5 +160,9 @@ Global
GlobalSection(NestedProjects) = preSolution
{262DF8CC-E7A8-4460-A22C-683CBA322C32} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594} = {B464EF06-42AE-4674-81BB-FDDE80204822}
{95C223E6-B5F1-4FD0-9376-41CDBC824445} = {B464EF06-42AE-4674-81BB-FDDE80204822}
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
{73EAAEDA-557B-48D5-A137-328934720FB4} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
EndGlobalSection
EndGlobal

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="version.properties" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -22,8 +23,10 @@
<ClInclude Include="..\..\inc\winfsp\fsctl.h" />
<ClInclude Include="..\..\inc\winfsp\winfsp.h" />
<ClInclude Include="..\..\src\dll\library.h" />
<ClInclude Include="..\..\src\shared\minimal.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\dll\eventlog.c" />
<ClCompile Include="..\..\src\dll\np.c" />
<ClCompile Include="..\..\src\dll\security.c" />
<ClCompile Include="..\..\src\dll\debug.c" />
@ -33,11 +36,21 @@
<ClCompile Include="..\..\src\dll\fs.c" />
<ClCompile Include="..\..\src\dll\ntstatus.c" />
<ClCompile Include="..\..\src\dll\path.c" />
<ClCompile Include="..\..\src\dll\service.c" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\src\dll\library.def" />
<None Include="..\..\src\dll\ntstatus.i" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\dll\eventlog\eventlog.rc" />
<ResourceCompile Include="..\..\src\dll\version.rc">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
</ResourceCompile>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
@ -136,6 +149,7 @@
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);version.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -160,6 +174,7 @@
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);version.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -187,6 +202,7 @@
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);version.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -214,6 +230,7 @@
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);version.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -12,6 +12,9 @@
<Filter Include="Include\winfsp">
<UniqueIdentifier>{1d6501f4-cebd-4a00-a774-deb782b59fb5}</UniqueIdentifier>
</Filter>
<Filter Include="Include\shared">
<UniqueIdentifier>{c7b83307-0aa0-4593-b2d4-26ff2f1edfc6}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\inc\winfsp\fsctl.h">
@ -23,6 +26,9 @@
<ClInclude Include="..\..\src\dll\library.h">
<Filter>Source</Filter>
</ClInclude>
<ClInclude Include="..\..\src\shared\minimal.h">
<Filter>Include\shared</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\dll\library.c">
@ -52,6 +58,12 @@
<ClCompile Include="..\..\src\dll\np.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\service.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\eventlog.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\src\dll\ntstatus.i">
@ -61,4 +73,12 @@
<Filter>Source</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\dll\version.rc">
<Filter>Source</Filter>
</ResourceCompile>
<ResourceCompile Include="..\..\src\dll\eventlog\eventlog.rc">
<Filter>Source</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="version.properties" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -177,6 +178,14 @@
<ClInclude Include="..\..\inc\winfsp\fsctl.h" />
<ClInclude Include="..\..\src\sys\driver.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\sys\version.rc">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_WIN64;_AMD64_=1;AMD64;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WIN64;_AMD64_=1;AMD64;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
</ResourceCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -101,4 +101,9 @@
<Filter>Include\winfsp</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\sys\version.rc">
<Filter>Source</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -1,9 +1,13 @@
web: web/winfsp-design.html web/winfsp.h.html
web: web/winfsp-design.html web/service-architecture.html web/winfsp.h.html
web/winfsp-design.html:
mkdir -p web
asciidoc -b html4 -a hr= -s -o $@ winfsp-design.adoc
web/service-architecture.html:
mkdir -p web
asciidoc -b html4 -a hr= -s -o $@ service-architecture.adoc
web/winfsp.h.html:
mkdir -p web
prettydoc -H-O -o web ../inc/winfsp/winfsp.h

View File

@ -0,0 +1,47 @@
= WinFsp Service Architecture
This document discusses an architecture for writing user mode file systems as Windows services.
== Overview
There are a variety of reasons that user mode file systems should be written as Windows services. Chief among those are that a Windows service runs independently from user sessions. Therefore a user mode file system can provide its services to all processes in the system rather than those of the current user session. Furthermore a Windows service (usually) runs under an account with elevated privileges, which may be a requirement for some user mode file systems.
The Windows Service Control Manager provides a clean protocol for installing, configuring and controlling services. Unfortunately it also has a major deficiency in that it only allows a single instance of a particular service to be launched. The technique usually employed to work around this deficiency is to create multiple named instances of the same service (e.g. ServiceName #1, ServiceName #2). This technique assumes that there is a finite and well known set of instances, which may not always be the case.
Consider, for example, a network file system NETFS which can be used to provide a network based file system. NETFS connects to a particular server and uses its proprietary protocol to access files on that server, which it then presents to Windows as native files. Clearly there may be a very large number of NETFS servers, which makes the idea of creating separate named service instances for each server unworkable. One alternative for the NETFS developer is to create a service that manages multiple NETFS instances. Another one is to use the WinFsp service architecture described in this document.
== WinFsp Launcher
In order to overcome the issue with launching multiple instances of a particular service, WinFsp provides a generic launcher named WinFsp.Launcher. The WinFsp.Launcher is itself a Windows service that can be used to launch and control other services, provided that they fulfill the following requirements:
* That they are marked as console executables.
* That they can be parameterized using the command line.
* That they respond to the CTRL-BREAK console control event and terminate timely.
Services that wish to be controlled by the WinFsp.Launcher must add themselves under the following registry key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services
For example, the MEMFS sample adds the following registry entries under this key:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services\memfs32]
"Executable"="C:\\Program Files (x86)\\WinFsp\\bin\\memfs-x86.exe"
"CommandLine"="-u %1 -m %2"
"Security"="D:P(A;;RPWPLC;;;WD)"
"JobControl"=dword:00000001
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services\memfs64]
"Executable"="C:\\Program Files (x86)\\WinFsp\\bin\\memfs-x64.exe"
"CommandLine"="-u %1 -m %2"
"Security"="D:P(A;;RPWPLC;;;WD)"
"JobControl"=dword:00000001
When the WinFsp.Launcher starts up it creates a named pipe that applications can use to start, stop, get information about and list service instances. A small command line utility (`launchctl`) can be used to issue those commands. The CallNamedPipeW API can be used as well.
One final note regarding security. Notice the `Security` registry value in the example above. This registry value uses SDDL syntax to instruct WinFsp.Launcher to allow Everyone (`WD`) to start (`RP`), stop (`WP`) and get information (`LC`) about the service instance. If the `Security` registry value is missing the default is to allow only LocalSystem and Administrators to control the service instance.
== WinFsp Network Provider
WinFsp includes a Network Provider that integrates with Windows and can be used to start and stop user mode file systems from the Windows shell. To achieve this the Network Provider (implemented as part of the WinFsp DLL) works closely with the WinFsp.Launcher service.
For example, if a user uses the Windows Explorer to map `\\memfs64\share` to the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to start an instance of the memfs64 service with command line `-u \\memfs64\share -m Z:`. When the user disconnects the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to stop the previously started instance of the memfs64 service.

View File

@ -24,6 +24,7 @@
extern "C" {
#endif
#define FSP_FSCTL_DRIVER_NAME "WinFsp"
#define FSP_FSCTL_DISK_DEVICE_NAME "WinFsp.Disk"
#define FSP_FSCTL_NET_DEVICE_NAME "WinFsp.Net"
@ -311,7 +312,7 @@ typedef struct
UINT64 Hint;
struct
{
UINT64 Information;
UINT32 Information;
UINT32 Status;
} IoStatus;
union

View File

@ -1,12 +1,6 @@
/**
* @file winfsp/winfsp.h
* WinFsp user mode API.
*
* A user mode file system is a program that uses the WinFsp API to expose a file system to
* Windows. The user mode file system must implement the operations in FSP_FILE_SYSTEM_INTERFACE,
* create a file system object using FspFileSystemCreate and start its dispatcher using
* FspFileSystemStartDispatcher. At that point it will start receing file system requests on the
* FSP_FILE_SYSTEM_INTERFACE operations.
* WinFsp User Mode API.
*
* In order to use the WinFsp API the user mode file system must include &lt;winfsp/winfsp.h&gt;
* and link with the winfsp_x64.dll (or winfsp_x86.dll) library.
@ -46,8 +40,14 @@
extern "C" {
#endif
/*
* File System
/**
* @group File System
*
* A user mode file system is a program that uses the WinFsp API to expose a file system to
* Windows. The user mode file system must implement the operations in FSP_FILE_SYSTEM_INTERFACE,
* create a file system object using FspFileSystemCreate and start its dispatcher using
* FspFileSystemStartDispatcher. At that point it will start receing file system requests on the
* FSP_FILE_SYSTEM_INTERFACE operations.
*/
typedef struct _FSP_FILE_SYSTEM FSP_FILE_SYSTEM;
typedef VOID FSP_FILE_SYSTEM_OPERATION_GUARD(FSP_FILE_SYSTEM *,
@ -838,13 +838,206 @@ FSP_API VOID FspPathPrefix(PWSTR Path, PWSTR *PPrefix, PWSTR *PRemain, PWSTR Roo
FSP_API VOID FspPathSuffix(PWSTR Path, PWSTR *PRemain, PWSTR *PSuffix, PWSTR Root);
FSP_API VOID FspPathCombine(PWSTR Prefix, PWSTR Suffix);
/**
* @group Service Framework
*
* User mode file systems typically are run as Windows services. WinFsp provides an API to make
* the creation of Windows services easier. This API is provided for convenience and is not
* necessary to expose a user mode file system to Windows.
*/
typedef struct _FSP_SERVICE FSP_SERVICE;
typedef NTSTATUS FSP_SERVICE_START(FSP_SERVICE *, ULONG, PWSTR *);
typedef NTSTATUS FSP_SERVICE_STOP(FSP_SERVICE *);
typedef NTSTATUS FSP_SERVICE_CONTROL(FSP_SERVICE *, ULONG, ULONG, PVOID);
#pragma warning(push)
#pragma warning(disable:4200) /* zero-sized array in struct/union */
typedef struct _FSP_SERVICE
{
UINT16 Version;
PVOID UserContext;
FSP_SERVICE_START *OnStart;
FSP_SERVICE_STOP *OnStop;
FSP_SERVICE_CONTROL *OnControl;
ULONG AcceptControl;
ULONG ExitCode;
SERVICE_STATUS_HANDLE StatusHandle;
SERVICE_STATUS ServiceStatus;
CRITICAL_SECTION ServiceStatusGuard;
CRITICAL_SECTION ServiceStopGuard;
BOOLEAN AllowConsoleMode;
WCHAR ServiceName[];
} FSP_SERVICE;
#pragma warning(pop)
/**
* Run a service.
*
* This function wraps calls to FspServiceCreate, FspServiceLoop and FspServiceDelete to create,
* run and delete a service. It is intended to be used from a service's main/wmain function.
*
* This function runs a service with console mode allowed.
*
* @param ServiceName
* The name of the service.
* @param OnStart
* Function to call when the service starts.
* @param OnStop
* Function to call when the service stops.
* @param OnControl
* Function to call when the service receives a service control code.
* @return
* Service process exit code.
*/
FSP_API ULONG FspServiceRun(PWSTR ServiceName,
FSP_SERVICE_START *OnStart,
FSP_SERVICE_STOP *OnStop,
FSP_SERVICE_CONTROL *OnControl);
/**
* Create a service object.
*
* @param ServiceName
* The name of the service.
* @param OnStart
* Function to call when the service starts.
* @param OnStop
* Function to call when the service stops.
* @param OnControl
* Function to call when the service receives a service control code.
* @param PService [out]
* Pointer that will receive the service object created on successful return from this
* call.
* @return
* STATUS_SUCCESS on error code.
*/
FSP_API NTSTATUS FspServiceCreate(PWSTR ServiceName,
FSP_SERVICE_START *OnStart,
FSP_SERVICE_STOP *OnStop,
FSP_SERVICE_CONTROL *OnControl,
FSP_SERVICE **PService);
/**
* Delete a service object.
*
* @param Service
* The service object.
*/
FSP_API VOID FspServiceDelete(FSP_SERVICE *Service);
/**
* Allow a service to run in console mode.
*
* A service that is run in console mode runs with a console attached and outside the control of
* the Service Control Manager. This is useful for debugging and testing a service during
* development.
*
* User mode file systems that wish to use the WinFsp Launcher functionality must also use this
* call. The WinFsp Launcher is a Windows service that can be configured to launch and manage
* multiple instances of a user mode file system.
*
* @param Service
* The service object.
*/
FSP_API VOID FspServiceAllowConsoleMode(FSP_SERVICE *Service);
/**
* Configure the control codes that a service accepts.
*
* This API should be used prior to Start operations.
*
* @param Service
* The service object.
* @param Control
* The control codes to accept. Note that the SERVICE_ACCEPT_PAUSE_CONTINUE code is silently
* ignored.
*/
FSP_API VOID FspServiceAcceptControl(FSP_SERVICE *Service, ULONG Control);
/**
* Request additional time from the Service Control Manager.
*
* This API should be used during Start and Stop operations only.
*
* @param Service
* The service object.
* @param Time
* Additional time (in milliseconds).
*/
FSP_API VOID FspServiceRequestTime(FSP_SERVICE *Service, ULONG Time);
/**
* Set the service process exit code.
*
* @param Service
* The service object.
* @param ExitCode
* Service process exit code.
*/
FSP_API VOID FspServiceSetExitCode(FSP_SERVICE *Service, ULONG ExitCode);
/**
* Get the service process exit code.
*
* @param Service
* The service object.
* @return
* Service process exit code.
*/
FSP_API ULONG FspServiceGetExitCode(FSP_SERVICE *Service);
/**
* Run a service main loop.
*
* This function starts and runs a service. It executes the Windows StartServiceCtrlDispatcher API
* to connect the service process to the Service Control Manager. If the Service Control Manager is
* not available (and console mode is allowed) it will enter console mode.
*
* @param Service
* The service object.
* @return
* STATUS_SUCCESS on error code.
*/
FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service);
/**
* Stops a running service.
*
* Stopping a service usually happens when the Service Control Manager instructs the service to
* stop. In some situations (e.g. fatal errors) the service may wish to stop itself. It can do so
* in a clean manner by calling this function.
*
* @param Service
* The service object.
* @return
* STATUS_SUCCESS on error code.
*/
FSP_API VOID FspServiceStop(FSP_SERVICE *Service);
/**
* Determine if the current process is running in user interactive mode.
*
* @return
* TRUE if the process is running in running user interactive mode.
*/
FSP_API BOOLEAN FspServiceIsInteractive(VOID);
/**
* Log a service message.
*
* This function can be used to log an arbitrary message to the Windows Event Log or to the current
* console if running in user interactive mode.
*
* @param Type
* One of EVENTLOG_INFORMATION_TYPE, EVENTLOG_WARNING_TYPE, EVENTLOG_ERROR_TYPE.
* @param Format
* Format specification. This function uses the Windows wsprintf API for formatting. Refer to
* that API's documentation for details on the format specification.
*/
FSP_API VOID FspServiceLog(ULONG Type, PWSTR Format, ...);
FSP_API VOID FspServiceLogV(ULONG Type, PWSTR Format, va_list ap);
/*
* Utility
*/
FSP_API NTSTATUS FspNtStatusFromWin32(DWORD Error);
FSP_API DWORD FspWin32FromNtStatus(NTSTATUS Status);
FSP_API VOID FspEventLog(ULONG Type, PWSTR Format, ...);
FSP_API VOID FspEventLogV(ULONG Type, PWSTR Format, va_list ap);
FSP_API VOID FspDebugLog(const char *format, ...);
FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDescriptor);
FSP_API VOID FspDebugLogFT(const char *format, PFILETIME FileTime);
FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout,
PSID Sid);
#ifdef __cplusplus
}

141
src/dll/eventlog.c Normal file
View File

@ -0,0 +1,141 @@
/**
* @file dll/eventlog.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dll/library.h>
#include <stdarg.h>
#include "eventlog/eventlog.h"
#define FSP_EVENTLOG_NAME LIBRARY_NAME
static HANDLE FspEventLogHandle;
static INIT_ONCE FspEventLogInitOnce = INIT_ONCE_STATIC_INIT;
static BOOL WINAPI FspEventLogRegisterEventSource(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context);
VOID FspEventLogInitialize(BOOLEAN Dynamic)
{
}
VOID FspEventLogFinalize(BOOLEAN Dynamic)
{
/*
* This function is called during DLL_PROCESS_DETACH. We must therefore keep
* finalization tasks to a minimum.
*
* We must deregister our event source (if any). We only do so if the library
* is being explicitly unloaded (rather than the process exiting).
*/
if (Dynamic && 0 != FspEventLogHandle)
DeregisterEventSource(FspEventLogHandle);
}
FSP_API VOID FspEventLog(ULONG Type, PWSTR Format, ...)
{
va_list ap;
va_start(ap, Format);
FspEventLogV(Type, Format, ap);
va_end(ap);
}
FSP_API VOID FspEventLogV(ULONG Type, PWSTR Format, va_list ap)
{
InitOnceExecuteOnce(&FspEventLogInitOnce, FspEventLogRegisterEventSource, 0, 0);
if (0 == FspEventLogHandle)
return;
WCHAR Buf[1024], *Strings[1];
/* wvsprintfW is only safe with a 1024 WCHAR buffer */
DWORD EventId;
wvsprintfW(Buf, Format, ap);
Buf[(sizeof Buf / sizeof Buf[0]) - 1] = L'\0';
Strings[0] = Buf;
switch (Type)
{
default:
case EVENTLOG_INFORMATION_TYPE:
case EVENTLOG_SUCCESS:
EventId = FSP_EVENTLOG_INFORMATION;
break;
case EVENTLOG_WARNING_TYPE:
EventId = FSP_EVENTLOG_WARNING;
break;
case EVENTLOG_ERROR_TYPE:
EventId = FSP_EVENTLOG_ERROR;
break;
}
ReportEventW(FspEventLogHandle, (WORD)Type, 0, EventId, 0, 1, 0, Strings, 0);
}
static BOOL WINAPI FspEventLogRegisterEventSource(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
FspEventLogHandle = RegisterEventSourceW(0, L"" FSP_EVENTLOG_NAME);
return TRUE;
}
NTSTATUS FspEventLogRegister(VOID)
{
extern HINSTANCE DllInstance;
WCHAR Path[MAX_PATH];
DWORD RegResult, DwordValue;
HKEY RegKey;
if (0 == GetModuleFileNameW(DllInstance, Path, MAX_PATH))
return FspNtStatusFromWin32(GetLastError());
RegResult = RegCreateKeyExW(
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\" FSP_EVENTLOG_NAME,
0, 0, 0, KEY_ALL_ACCESS, 0, &RegKey, 0);
if (ERROR_SUCCESS != RegResult)
return FspNtStatusFromWin32(RegResult);
RegResult = RegSetValueExW(RegKey,
L"EventMessageFile", 0, REG_SZ, (PVOID)Path, (lstrlenW(Path) + 1) * sizeof(WCHAR));
if (ERROR_SUCCESS != RegResult)
goto close_and_exit;
DwordValue = EVENTLOG_INFORMATION_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_ERROR_TYPE;
RegResult = RegSetValueExW(RegKey,
L"TypesSupported", 0, REG_DWORD, (PVOID)&DwordValue, sizeof DwordValue);
if (ERROR_SUCCESS != RegResult)
goto close_and_exit;
RegCloseKey(RegKey);
return STATUS_SUCCESS;
close_and_exit:
RegCloseKey(RegKey);
return FspNtStatusFromWin32(RegResult);
}
NTSTATUS FspEventLogUnregister(VOID)
{
DWORD RegResult;
RegResult = RegDeleteTreeW(
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\" FSP_EVENTLOG_NAME);
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
return FspNtStatusFromWin32(RegResult);
return STATUS_SUCCESS;
}

View File

@ -0,0 +1,63 @@
//
// Values are 32 bit values laid out as follows:
//
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +---+-+-+-----------------------+-------------------------------+
// |Sev|C|R| Facility | Code |
// +---+-+-+-----------------------+-------------------------------+
//
// where
//
// Sev - is the severity code
//
// 00 - Success
// 01 - Informational
// 10 - Warning
// 11 - Error
//
// C - is the Customer code flag
//
// R - is a reserved bit
//
// Facility - is the facility code
//
// Code - is the facility's status code
//
//
// Define the facility codes
//
//
// Define the severity codes
//
//
// MessageId: FSP_EVENTLOG_INFORMATION
//
// MessageText:
//
// %1
//
#define FSP_EVENTLOG_INFORMATION 0x60000001L
//
// MessageId: FSP_EVENTLOG_WARNING
//
// MessageText:
//
// %1
//
#define FSP_EVENTLOG_WARNING 0xA0000001L
//
// MessageId: FSP_EVENTLOG_ERROR
//
// MessageText:
//
// %1
//
#define FSP_EVENTLOG_ERROR 0xE0000001L

View File

@ -0,0 +1,20 @@
MessageId=1
Severity=Informational
SymbolicName=FSP_EVENTLOG_INFORMATION
Language=English
%1
.
MessageId=1
Severity=Warning
SymbolicName=FSP_EVENTLOG_WARNING
Language=English
%1
.
MessageId=1
Severity=Error
SymbolicName=FSP_EVENTLOG_ERROR
Language=English
%1
.

View File

@ -0,0 +1,2 @@
LANGUAGE 0x9,0x1
1 11 "eventlog_MSG00001.bin"

Binary file not shown.

View File

@ -0,0 +1,5 @@
@echo off
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat"
mc -b -c eventlog.mc

View File

@ -27,11 +27,11 @@ static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface;
static CRITICAL_SECTION FspFileSystemMountListGuard;
static LIST_ENTRY FspFileSystemMountList = { &FspFileSystemMountList, &FspFileSystemMountList };
VOID FspFileSystemInitialize(VOID)
VOID FspFileSystemInitialize(BOOLEAN Dynamic)
{
/*
* This function is called during DLL_PROCESS_ATTACH. We must therefore keep initialization
* tasks to a minimum.
* This function is called during DLL_PROCESS_ATTACH. We must therefore keep
* initialization tasks to a minimum.
*
* Initialization of synchronization objects is allowed! See:
* https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx
@ -40,16 +40,11 @@ VOID FspFileSystemInitialize(VOID)
InitializeCriticalSection(&FspFileSystemMountListGuard);
}
VOID FspFileSystemFinalize(VOID)
VOID FspFileSystemFinalize(BOOLEAN Dynamic)
{
/*
* This function is called during DLL_PROCESS_DETACH. We must therefore keep finalization
* tasks to a minimum.
*
* Very few things can be safely done during DLL_PROCESS_DETACH. See:
* https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx
* https://blogs.msdn.microsoft.com/oldnewthing/20070503-00/?p=27003/
* https://blogs.msdn.microsoft.com/oldnewthing/20100122-00/?p=15193/
* This function is called during DLL_PROCESS_DETACH. We must therefore keep
* finalization tasks to a minimum.
*
* We enter our FspFileSystemMountListGuard critical section here and then attempt to cleanup
* our mount points using DefineDosDeviceW. On Vista and later orphaned critical sections
@ -60,6 +55,9 @@ VOID FspFileSystemFinalize(VOID)
* out to CSRSS, which is probably not the safest thing to do when in DllMain! There is also
* some evidence that it may attempt to load DLL's under some circumstances, which is a
* definite no-no as we are under the loader lock!
*
* We only delete the criticaly section when being dynamically unloaded. On process exit the
* OS will clean it up for us.
*/
FSP_FILE_SYSTEM *FileSystem;
@ -79,6 +77,9 @@ VOID FspFileSystemFinalize(VOID)
}
LeaveCriticalSection(&FspFileSystemMountListGuard);
if (Dynamic)
DeleteCriticalSection(&FspFileSystemMountListGuard);
}
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,

View File

@ -16,11 +16,14 @@
*/
#include <dll/library.h>
#include <aclapi.h>
#define GLOBALROOT L"\\\\?\\GLOBALROOT"
#define PREFIXW L"" FSP_FSCTL_VOLUME_PARAMS_PREFIX
#define PREFIXW_SIZE (sizeof PREFIXW - sizeof(WCHAR))
static NTSTATUS FspFsctlStartService(VOID);
FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
PWCHAR VolumeNameBuf, SIZE_T VolumeNameSize,
@ -62,6 +65,10 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
}
*DevicePathPtr = L'\0';
Result = FspFsctlStartService();
if (!NT_SUCCESS(Result))
return Result;
VolumeHandle = CreateFileW(DevicePathBuf,
0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (INVALID_HANDLE_VALUE == VolumeHandle)
@ -185,3 +192,320 @@ exit:
return Result;
}
static NTSTATUS FspFsctlStartService(VOID)
{
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME;
SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0;
SERVICE_STATUS ServiceStatus;
DWORD LastError;
NTSTATUS Result;
ScmHandle = OpenSCManagerW(0, 0, 0);
if (0 == ScmHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
SvcHandle = OpenServiceW(ScmHandle, DriverName, SERVICE_QUERY_STATUS | SERVICE_START);
if (0 == SvcHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (!StartServiceW(SvcHandle, 0, 0))
{
LastError = GetLastError();
if (ERROR_SERVICE_ALREADY_RUNNING != LastError)
Result = FspNtStatusFromWin32(LastError);
else
Result = STATUS_SUCCESS;
goto exit;
}
/* Poll until the service is running! Yes, that's the best we can do! */
Result = STATUS_DRIVER_UNABLE_TO_LOAD;
for (DWORD Timeout = 500, N = 20, I = 0; N > I; I++)
/* wait up to 500ms * 20 = 10000ms = 10s */
{
if (!QueryServiceStatus(SvcHandle, &ServiceStatus))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (SERVICE_RUNNING == ServiceStatus.dwCurrentState)
{
Result = STATUS_SUCCESS;
break;
}
Sleep(Timeout);
}
exit:
if (0 != SvcHandle)
CloseServiceHandle(SvcHandle);
if (0 != ScmHandle)
CloseServiceHandle(ScmHandle);
return Result;
}
static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
{
/*
* This function adds an ACE that allows Everyone to start a service.
*/
PSID WorldSid = 0;
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PSECURITY_DESCRIPTOR NewSecurityDescriptor = 0;
EXPLICIT_ACCESSW AccessEntry;
ACCESS_MASK AccessRights;
PACL Dacl;
BOOL DaclPresent, DaclDefaulted;
DWORD Size;
DWORD LastError;
NTSTATUS Result;
/* get the Everyone (World) SID */
Size = SECURITY_MAX_SID_SIZE;
WorldSid = MemAlloc(Size);
if (0 == WorldSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!CreateWellKnownSid(WinWorldSid, 0, WorldSid, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
/* get the service security descriptor DACL */
Size = 0;
if (!QueryServiceObjectSecurity(SvcHandle, DACL_SECURITY_INFORMATION, SecurityDescriptor, Size, &Size))
{
LastError = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
}
SecurityDescriptor = MemAlloc(Size);
if (0 == SecurityDescriptor)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!QueryServiceObjectSecurity(SvcHandle, DACL_SECURITY_INFORMATION, SecurityDescriptor, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
/* extract the DACL */
if (!GetSecurityDescriptorDacl(SecurityDescriptor, &DaclPresent, &Dacl, &DaclDefaulted))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
/* prepare an EXPLICIT_ACCESS for the SERVICE_QUERY_STATUS | SERVICE_START right for Everyone */
AccessEntry.grfAccessPermissions = SERVICE_QUERY_STATUS | SERVICE_START;
AccessEntry.grfAccessMode = GRANT_ACCESS;
AccessEntry.grfInheritance = NO_INHERITANCE;
AccessEntry.Trustee.pMultipleTrustee = 0;
AccessEntry.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
AccessEntry.Trustee.TrusteeForm = TRUSTEE_IS_SID;
AccessEntry.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
AccessEntry.Trustee.ptstrName = WorldSid;
/* get the effective rights for Everyone */
AccessRights = 0;
if (DaclPresent && 0 != Dacl)
{
LastError = GetEffectiveRightsFromAclW(Dacl, &AccessEntry.Trustee, &AccessRights);
if (0 != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
}
/* do we have the required access rights? */
if (AccessEntry.grfAccessPermissions != (AccessRights & AccessEntry.grfAccessPermissions))
{
/* create a new security descriptor with the new access */
LastError = BuildSecurityDescriptorW(0, 0, 1, &AccessEntry, 0, 0, SecurityDescriptor,
&Size, &NewSecurityDescriptor);
if (0 != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
/* set the new service security descriptor DACL */
if (!SetServiceObjectSecurity(SvcHandle, DACL_SECURITY_INFORMATION, NewSecurityDescriptor))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Result = STATUS_SUCCESS;
exit:
LocalFree(NewSecurityDescriptor);
MemFree(SecurityDescriptor);
MemFree(WorldSid);
return Result;
}
NTSTATUS FspFsctlRegister(VOID)
{
extern HINSTANCE DllInstance;
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME;
WCHAR DriverPath[MAX_PATH];
DWORD Size;
SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0;
PVOID VersionInfo = 0;
SERVICE_DESCRIPTION ServiceDescription;
NTSTATUS Result;
if (0 == GetModuleFileNameW(DllInstance, DriverPath, MAX_PATH))
return FspNtStatusFromWin32(GetLastError());
Size = lstrlenW(DriverPath);
if (4 < Size &&
(L'.' == DriverPath[Size - 4]) &&
(L'D' == DriverPath[Size - 3] || L'd' == DriverPath[Size - 3]) &&
(L'L' == DriverPath[Size - 2] || L'l' == DriverPath[Size - 2]) &&
(L'L' == DriverPath[Size - 1] || L'l' == DriverPath[Size - 1]) &&
(L'\0' == DriverPath[Size]))
{
DriverPath[Size - 3] = L's';
DriverPath[Size - 2] = L'y';
DriverPath[Size - 1] = L's';
}
else
/* should not happen! */
return STATUS_NO_SUCH_DEVICE;
ScmHandle = OpenSCManagerW(0, 0, SC_MANAGER_CREATE_SERVICE);
if (0 == ScmHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
SvcHandle = OpenServiceW(ScmHandle, DriverName, SERVICE_CHANGE_CONFIG | READ_CONTROL | WRITE_DAC);
if (0 != SvcHandle)
{
if (!ChangeServiceConfigW(SvcHandle,
SERVICE_FILE_SYSTEM_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, DriverPath,
0, 0, 0, 0, 0, DriverName))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
else
{
SvcHandle = CreateServiceW(ScmHandle, DriverName, DriverName,
SERVICE_CHANGE_CONFIG | READ_CONTROL | WRITE_DAC,
SERVICE_FILE_SYSTEM_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, DriverPath,
0, 0, 0, 0, 0);
if (0 == SvcHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Size = GetFileVersionInfoSizeW(DriverPath, &Size/*dummy*/);
if (0 < Size)
{
VersionInfo = MemAlloc(Size);
if (0 != VersionInfo &&
GetFileVersionInfoW(DriverPath, 0, Size, VersionInfo) &&
VerQueryValueW(VersionInfo, L"\\StringFileInfo\\040904b0\\FileDescription",
&ServiceDescription.lpDescription, &Size))
{
ChangeServiceConfig2W(SvcHandle, SERVICE_CONFIG_DESCRIPTION, &ServiceDescription);
}
}
Result = FspFsctlFixServiceSecurity(SvcHandle);
if (!NT_SUCCESS(Result))
goto exit;
Result = STATUS_SUCCESS;
exit:
MemFree(VersionInfo);
if (0 != SvcHandle)
CloseServiceHandle(SvcHandle);
if (0 != ScmHandle)
CloseServiceHandle(ScmHandle);
return Result;
}
NTSTATUS FspFsctlUnregister(VOID)
{
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME;
SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0;
DWORD LastError;
NTSTATUS Result;
ScmHandle = OpenSCManagerW(0, 0, SC_MANAGER_CREATE_SERVICE);
/*
* The SC_MANAGER_CREATE_SERVICE access right is not strictly needed here,
* but we use it to enforce admin rights.
*/
if (0 == ScmHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
SvcHandle = OpenServiceW(ScmHandle, DriverName, DELETE);
if (0 == SvcHandle)
{
LastError = GetLastError();
if (ERROR_SERVICE_DOES_NOT_EXIST != LastError)
Result = FspNtStatusFromWin32(LastError);
else
Result = STATUS_SUCCESS;
goto exit;
}
if (!DeleteService(SvcHandle))
{
LastError = GetLastError();
if (ERROR_SERVICE_MARKED_FOR_DELETE != LastError)
Result = FspNtStatusFromWin32(LastError);
else
Result = STATUS_SUCCESS;
goto exit;
}
Result = STATUS_SUCCESS;
exit:
if (0 != SvcHandle)
CloseServiceHandle(SvcHandle);
if (0 != ScmHandle)
CloseServiceHandle(ScmHandle);
return Result;
}

View File

@ -304,7 +304,7 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenTargetDirectory(FSP_FILE_SYSTEM *F
UINT32 GrantedAccess;
PVOID FileNode;
FSP_FSCTL_FILE_INFO FileInfo;
UINT_PTR Information;
UINT32 Information;
Result = FspAccessCheck(FileSystem, Request, TRUE, TRUE,
Request->Req.Create.DesiredAccess, &GrantedAccess);

View File

@ -22,6 +22,8 @@ HANDLE ProcessHeap;
BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
{
BOOLEAN Dynamic;
switch (Reason)
{
case DLL_PROCESS_ATTACH:
@ -29,30 +31,68 @@ BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
ProcessHeap = GetProcessHeap();
if (0 == ProcessHeap)
return FALSE;
FspFileSystemInitialize();
/*
* These functions are called during DLL_PROCESS_ATTACH. We must therefore keep
* initialization tasks to a minimum.
*
* See the DLL best practices document:
* https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx
*/
Dynamic = 0 == Reserved;
FspNtStatusInitialize(Dynamic);
FspEventLogInitialize(Dynamic);
FspFileSystemInitialize(Dynamic);
FspServiceInitialize(Dynamic);
break;
case DLL_PROCESS_DETACH:
FspFileSystemFinalize();
/*
* These functions are called during DLL_PROCESS_DETACH. We must therefore keep
* finalization tasks to a minimum.
*
* See the following documents:
* https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx
* https://blogs.msdn.microsoft.com/oldnewthing/20070503-00/?p=27003/
* https://blogs.msdn.microsoft.com/oldnewthing/20100122-00/?p=15193/
*/
Dynamic = 0 == Reserved;
FspServiceFinalize(Dynamic);
FspFileSystemFinalize(Dynamic);
FspEventLogFinalize(Dynamic);
FspNtStatusFinalize(Dynamic);
break;
}
return TRUE;
}
/* see comments in library.h */
#if defined(WINFSP_DLL_NODEFAULTLIB)
/* see comments in shared/minimal.h */
BOOL WINAPI _DllMainCRTStartup(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
{
return DllMain(Instance, Reason, Reserved);
}
#endif
HRESULT WINAPI DllRegisterServer(VOID)
{
NTSTATUS Result;
Result = FspNpRegister();
Result = FspFsctlRegister();
FspDebugLog("FspFsctlRegister = %lx\n", Result);
if (!NT_SUCCESS(Result))
goto exit;
/* ignore errors below; these are non-critical */
Result = FspNpRegister();
FspDebugLog("FspNpRegister = %lx\n", Result);
Result = FspEventLogRegister();
FspDebugLog("FspEventLogRegister = %lx\n", Result);
Result = STATUS_SUCCESS;
exit:
return NT_SUCCESS(Result) ? S_OK : 0x80040201/*SELFREG_E_CLASS*/;
}
@ -60,7 +100,21 @@ HRESULT WINAPI DllUnregisterServer(VOID)
{
NTSTATUS Result;
Result = FspNpUnregister();
Result = FspFsctlUnregister();
FspDebugLog("FspFsctlUnregister = %lx\n", Result);
if (!NT_SUCCESS(Result))
goto exit;
/* ignore errors below; these are non-critical */
Result = FspNpUnregister();
FspDebugLog("FspNpUnregister = %lx\n", Result);
Result = FspEventLogUnregister();
FspDebugLog("FspEventLogUnregister = %lx\n", Result);
Result = STATUS_SUCCESS;
exit:
return NT_SUCCESS(Result) ? S_OK : 0x80040201/*SELFREG_E_CLASS*/;
}

View File

@ -3,3 +3,9 @@ EXPORTS
DllUnregisterServer PRIVATE
NPGetCaps PRIVATE
NPGetConnection PRIVATE
NPAddConnection PRIVATE
NPAddConnection3 PRIVATE
NPCancelConnection PRIVATE
NPOpenEnum PRIVATE
NPEnumResource PRIVATE
NPCloseEnum PRIVATE

View File

@ -19,8 +19,8 @@
#define WINFSP_DLL_LIBRARY_H_INCLUDED
#define WINFSP_DLL_INTERNAL
#define WINFSP_DLL_NODEFAULTLIB
#include <winfsp/winfsp.h>
#include <shared/minimal.h>
#include <strsafe.h>
#define LIBRARY_NAME "WinFsp"
@ -36,77 +36,20 @@
#define DEBUGLOGSD(fmt, SD) ((void)0)
#endif
static inline PVOID MemAlloc(SIZE_T Size)
{
extern HANDLE ProcessHeap;
return HeapAlloc(ProcessHeap, 0, Size);
}
static inline VOID MemFree(PVOID Pointer)
{
extern HANDLE ProcessHeap;
if (0 != Pointer)
HeapFree(ProcessHeap, 0, Pointer);
}
/*
* Define WINFSP_DLL_NODEFAULTLIB to eliminate dependency on the MSVCRT libraries.
*
* For this to work the following project settings must be set:
* - "C/C++ > General > SDL checks" must be empty (not "Yes" or "No").
* - "C/C++ > Code Generation > Basic Runtime Checks" must be set to "Default"
* - "C/C++ > Code Generation > Security Check" must be disabled (/GS-).
* - "Linker > Input > Ignore All Default Libraries" must be "Yes".
*/
#if defined(WINFSP_DLL_NODEFAULTLIB)
#undef RtlFillMemory
#undef RtlMoveMemory
NTSYSAPI VOID NTAPI RtlFillMemory(VOID *Destination, DWORD Length, BYTE Fill);
NTSYSAPI VOID NTAPI RtlMoveMemory(VOID *Destination, CONST VOID *Source, DWORD Length);
#pragma function(memcpy)
#pragma function(memset)
static inline
void *memcpy(void *dst, const void *src, size_t siz)
{
RtlMoveMemory(dst, src, (DWORD)siz);
return dst;
}
static inline
void *memset(void *dst, int val, size_t siz)
{
RtlFillMemory(dst, (DWORD)siz, val);
return dst;
}
#endif
static FORCEINLINE
VOID InsertTailList(PLIST_ENTRY ListHead, PLIST_ENTRY Entry)
{
PLIST_ENTRY Blink;
Blink = ListHead->Blink;
Entry->Flink = ListHead;
Entry->Blink = Blink;
Blink->Flink = Entry;
ListHead->Blink = Entry;
}
static FORCEINLINE
BOOLEAN RemoveEntryList(PLIST_ENTRY Entry)
{
PLIST_ENTRY Blink;
PLIST_ENTRY Flink;
Flink = Entry->Flink;
Blink = Entry->Blink;
Blink->Flink = Flink;
Flink->Blink = Blink;
return Flink == Blink;
}
VOID FspFileSystemInitialize(VOID);
VOID FspFileSystemFinalize(VOID);
VOID FspNtStatusInitialize(BOOLEAN Dynamic);
VOID FspNtStatusFinalize(BOOLEAN Dynamic);
VOID FspEventLogInitialize(BOOLEAN Dynamic);
VOID FspEventLogFinalize(BOOLEAN Dynamic);
VOID FspFileSystemInitialize(BOOLEAN Dynamic);
VOID FspFileSystemFinalize(BOOLEAN Dynamic);
VOID FspServiceInitialize(BOOLEAN Dynamic);
VOID FspServiceFinalize(BOOLEAN Dynamic);
NTSTATUS FspFsctlRegister(VOID);
NTSTATUS FspFsctlUnregister(VOID);
NTSTATUS FspNpRegister(VOID);
NTSTATUS FspNpUnregister(VOID);
NTSTATUS FspEventLogRegister(VOID);
NTSTATUS FspEventLogUnregister(VOID);
#endif

View File

@ -16,12 +16,118 @@
*/
#include <dll/library.h>
#include <launcher/launcher.h>
#include <aclapi.h>
#include <npapi.h>
#define FSP_NP_NAME "WinFsp.Np"
#define FSP_NP_DESC "File System Proxy"
#define FSP_NP_NAME LIBRARY_NAME ".Np"
#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */
FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout,
PSID Sid)
{
NTSTATUS Result;
HANDLE Pipe = INVALID_HANDLE_VALUE;
DWORD PipeMode;
Pipe = CreateFileW(PipeName,
GENERIC_READ | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, 0);
if (INVALID_HANDLE_VALUE == Pipe)
{
if (ERROR_PIPE_BUSY != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
WaitNamedPipeW(PipeName, Timeout);
Pipe = CreateFileW(PipeName,
GENERIC_READ | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, 0);
if (INVALID_HANDLE_VALUE == Pipe)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
if (0 != Sid)
{
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PSID OwnerSid, WellKnownSid = 0;
DWORD SidSize, LastError;
/* if it is a small number treat it like a well known SID */
if (1024 > (INT_PTR)Sid)
{
SidSize = SECURITY_MAX_SID_SIZE;
WellKnownSid = MemAlloc(SidSize);
if (0 == WellKnownSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto sid_exit;
}
if (!CreateWellKnownSid((INT_PTR)Sid, 0, WellKnownSid, &SidSize))
{
Result = FspNtStatusFromWin32(GetLastError());
goto sid_exit;
}
}
LastError = GetSecurityInfo(Pipe, SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION, &OwnerSid, 0, 0, 0, &SecurityDescriptor);
if (0 != LastError)
{
Result = FspNtStatusFromWin32(GetLastError());
goto sid_exit;
}
if (!EqualSid(OwnerSid, WellKnownSid ? WellKnownSid : Sid))
{
Result = STATUS_ACCESS_DENIED;
goto sid_exit;
}
Result = STATUS_SUCCESS;
sid_exit:
MemFree(WellKnownSid);
LocalFree(SecurityDescriptor);
if (!NT_SUCCESS(Result))
goto exit;
}
PipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
if (!SetNamedPipeHandleState(Pipe, &PipeMode, 0, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (!TransactNamedPipe(Pipe, InBuffer, InBufferSize, OutBuffer, OutBufferSize,
PBytesTransferred, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Result = STATUS_SUCCESS;
exit:
if (INVALID_HANDLE_VALUE != Pipe)
CloseHandle(Pipe);
return Result;
}
DWORD APIENTRY NPGetCaps(DWORD Index)
{
switch (Index)
@ -34,14 +140,17 @@ DWORD APIENTRY NPGetCaps(DWORD Index)
return 0;
case WNNC_CONNECTION:
/*
* WNNC_CON_ADDCONECTION
* WNNC_CON_ADDCONNECTION
* WNNC_CON_CANCELCONNECTION
* WNNC_CON_GETCONNECTIONS
* WNNC_CON_ADDCONECTION3
* WNNC_CON_ADDCONNECTION3
* WNNC_CON_GETPERFORMANCE
* WNNC_CON_DEFER
*/
return WNNC_CON_GETCONNECTIONS;
return
WNNC_CON_GETCONNECTIONS |
WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3 |
WNNC_CON_CANCELCONNECTION;
case WNNC_DIALOG:
/*
* WNNC_DLG_DEVICEMODE
@ -59,7 +168,7 @@ DWORD APIENTRY NPGetCaps(DWORD Index)
* WNNC_ENUM_LOCAL
* WNNC_ENUM_CONTEXT
*/
return 0;
return WNNC_ENUM_LOCAL | WNNC_ENUM_CONTEXT;
case WNNC_NET_TYPE:
return FSP_NP_TYPE;
case WNNC_SPEC_VERSION:
@ -76,6 +185,91 @@ DWORD APIENTRY NPGetCaps(DWORD Index)
}
}
static inline BOOLEAN FspNpCheckLocalName(PWSTR LocalName)
{
return 0 != LocalName &&
(
(L'A' <= LocalName[0] && LocalName[0] <= L'Z') ||
(L'a' <= LocalName[0] && LocalName[0] <= L'z')
) &&
L':' == LocalName[1] || L'\0' == LocalName[2];
}
static inline BOOLEAN FspNpCheckRemoteName(PWSTR RemoteName)
{
return 0 != RemoteName && L'\\' == RemoteName[0] && L'\\' == RemoteName[1] &&
sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR) >= lstrlenW(RemoteName);
}
static inline BOOLEAN FspNpParseRemoteName(PWSTR RemoteName,
PWSTR *PClassName, PULONG PClassNameLen,
PWSTR *PInstanceName, PULONG PInstanceNameLen)
{
PWSTR ClassName, InstanceName, P;
ULONG ClassNameLen, InstanceNameLen;
ClassName = RemoteName + 2; /* skip \\ */
for (P = ClassName; *P; P++)
if (L'\\' == *P)
break;
if (ClassName == P || L'\\' != *P)
return FALSE;
ClassNameLen = (ULONG)(P - ClassName);
InstanceName = P + 1;
for (P = InstanceName; *P; P++)
;
for (;;)
{
if (InstanceName == P)
return FALSE;
if (L'\\' != P[-1])
break;
P--;
}
InstanceNameLen = (ULONG)(P - InstanceName);
*PClassName = ClassName; *PClassNameLen = ClassNameLen;
*PInstanceName = InstanceName; *PInstanceNameLen = InstanceNameLen;
return TRUE;
}
static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
{
DWORD NpResult;
NTSTATUS Result;
DWORD BytesTransferred;
Result = FspCallNamedPipeSecurely(L"" LAUNCHER_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize,
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, LAUNCHER_PIPE_OWNER);
if (!NT_SUCCESS(Result))
NpResult = WN_NO_NETWORK;
else if (sizeof(WCHAR) > BytesTransferred)
NpResult = WN_NO_NETWORK;
else if (LauncherSuccess == PipeBuf[0])
NpResult = WN_SUCCESS;
else if (LauncherFailure == PipeBuf[0])
{
NpResult = 0;
for (PWSTR P = PipeBuf + 1, EndP = PipeBuf + BytesTransferred / sizeof(WCHAR); EndP > P; P++)
{
if (L'0' > *P || *P > L'9')
break;
NpResult = 10 * NpResult + (*P - L'0');
}
if (0 == NpResult)
NpResult = WN_NO_NETWORK;
}
else
NpResult = WN_NO_NETWORK;
return NpResult;
}
static NTSTATUS FspNpGetVolumeList(
PWCHAR *PVolumeListBuf, PSIZE_T PVolumeListSize)
{
@ -108,7 +302,37 @@ static NTSTATUS FspNpGetVolumeList(
}
}
DWORD APIENTRY NPGetConnection(LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpnBufferLen)
static WCHAR FspNpGetDriveLetter(PDWORD PLogicalDrives, PWSTR VolumeName)
{
WCHAR VolumeNameBuf[MAX_PATH];
WCHAR LocalNameBuf[3];
WCHAR Drive;
if (0 == *PLogicalDrives)
return 0;
LocalNameBuf[1] = L':';
LocalNameBuf[2] = L'\0';
for (Drive = 'Z'; 'A' <= Drive; Drive--)
if (0 != (*PLogicalDrives & (1 << (Drive - 'A'))))
{
LocalNameBuf[0] = Drive;
if (QueryDosDeviceW(LocalNameBuf, VolumeNameBuf, sizeof VolumeNameBuf / sizeof(WCHAR)))
{
if (0 == lstrcmpW(VolumeNameBuf, VolumeName))
{
*PLogicalDrives &= ~(1 << (Drive - 'A'));
return Drive;
}
}
}
return 0;
}
DWORD APIENTRY NPGetConnection(
LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpnBufferLen)
{
DWORD NpResult;
NTSTATUS Result;
@ -118,15 +342,10 @@ DWORD APIENTRY NPGetConnection(LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD
SIZE_T VolumeListSize, VolumeNameSize;
ULONG Backslashes;
if (0 == lpLocalName ||
!(
(L'A' <= lpLocalName[0] && lpLocalName[0] <= L'Z') ||
(L'a' <= lpLocalName[0] && lpLocalName[0] <= L'z')
) ||
L':' != lpLocalName[1])
if (!FspNpCheckLocalName(lpLocalName))
return WN_BAD_LOCALNAME;
LocalNameBuf[0] = lpLocalName[0];
LocalNameBuf[0] = lpLocalName[0] & ~0x20; /* convert to uppercase */
LocalNameBuf[1] = L':';
LocalNameBuf[2] = L'\0';
@ -189,6 +408,351 @@ DWORD APIENTRY NPGetConnection(LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD
return NpResult;
}
DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName)
{
return NPAddConnection3(0, lpNetResource, lpPassword, lpUserName, 0);
}
DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName, DWORD dwFlags)
{
DWORD NpResult;
DWORD dwType = lpNetResource->dwType;
LPWSTR lpRemoteName = lpNetResource->lpRemoteName;
LPWSTR lpLocalName = lpNetResource->lpLocalName;
WCHAR LocalNameBuf[3];
PWSTR ClassName, InstanceName, RemoteName, P;
ULONG ClassNameLen, InstanceNameLen;
PWSTR PipeBuf = 0;
if (dwType & RESOURCETYPE_PRINT)
return WN_BAD_VALUE;
if (!FspNpCheckRemoteName(lpRemoteName))
return WN_BAD_NETNAME;
if (!FspNpParseRemoteName(lpRemoteName,
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
return WN_BAD_NETNAME;
RemoteName = lpRemoteName + 1;
LocalNameBuf[0] = L'\0';
if (0 != lpLocalName && L'\0' != lpLocalName[0])
{
if (!FspNpCheckLocalName(lpLocalName))
return WN_BAD_LOCALNAME;
LocalNameBuf[0] = lpLocalName[0] & ~0x20; /* convert to uppercase */
LocalNameBuf[1] = L':';
LocalNameBuf[2] = L'\0';
if (GetLogicalDrives() & (1 << (LocalNameBuf[0] - 'A')))
return WN_ALREADY_CONNECTED;
}
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
if (0 == PipeBuf)
return WN_OUT_OF_MEMORY;
P = PipeBuf;
*P++ = LauncherSvcInstanceStart;
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
lstrcpyW(P, RemoteName); P += lstrlenW(RemoteName) + 1;
lstrcpyW(P, LocalNameBuf); P += lstrlenW(LocalNameBuf) + 1;
NpResult = FspNpCallLauncherPipe(
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE);
switch (NpResult)
{
case WN_SUCCESS:
break;
case ERROR_ALREADY_EXISTS:
/*
* The file system is already running! If we are being asked for a drive mapping,
* see if it is the one we already have to decide on the error code to return.
*/
if (L'\0' != LocalNameBuf[0])
{
WCHAR ExpectRemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
WCHAR RemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
DWORD RemoteNameSize;
P = ExpectRemoteNameBuf;
*P++ = L'\\'; *P++ = L'\\';
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\\';
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
RemoteNameSize = sizeof RemoteNameBuf / sizeof(WCHAR);
NpResult = NPGetConnection(LocalNameBuf, RemoteNameBuf, &RemoteNameSize);
if (WN_SUCCESS == NpResult)
NpResult = 0 == lstrcmpW(ExpectRemoteNameBuf, RemoteNameBuf) ? WN_SUCCESS : WN_NO_NETWORK;
else
NpResult = WN_NO_NETWORK;
}
else
/* we are not being asked for a drive mapping, so whatever we have is good! */
NpResult = WN_SUCCESS;
break;
default:
NpResult = WN_NO_NETWORK;
break;
}
MemFree(PipeBuf);
return NpResult;
}
DWORD APIENTRY NPCancelConnection(LPWSTR lpName, BOOL fForce)
{
DWORD NpResult;
WCHAR RemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
DWORD RemoteNameSize;
PWSTR ClassName, InstanceName, RemoteName, P;
ULONG ClassNameLen, InstanceNameLen;
PWSTR PipeBuf = 0;
if (FspNpCheckLocalName(lpName))
{
RemoteNameSize = sizeof RemoteNameBuf / sizeof(WCHAR);
NpResult = NPGetConnection(lpName, RemoteNameBuf, &RemoteNameSize);
if (WN_SUCCESS != NpResult)
return NpResult;
RemoteName = RemoteNameBuf;
}
else if (FspNpCheckRemoteName(lpName))
RemoteName = lpName;
else
return WN_BAD_NETNAME;
if (!FspNpParseRemoteName(RemoteName,
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
return WN_BAD_NETNAME;
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
if (0 == PipeBuf)
return WN_OUT_OF_MEMORY;
P = PipeBuf;
*P++ = LauncherSvcInstanceStop;
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
NpResult = FspNpCallLauncherPipe(
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE);
switch (NpResult)
{
case WN_SUCCESS:
break;
case ERROR_FILE_NOT_FOUND:
NpResult = WN_NOT_CONNECTED;
break;
default:
NpResult = WN_NO_NETWORK;
break;
}
MemFree(PipeBuf);
return NpResult;
}
typedef struct
{
DWORD Signature; /* cheap and cheerful! */
DWORD dwScope;
PWCHAR VolumeListBuf, VolumeListBufEnd, VolumeName;
DWORD LogicalDrives;
} FSP_NP_ENUM;
static inline BOOLEAN FspNpValidateEnum(FSP_NP_ENUM *Enum)
{
#if 0
extern HANDLE ProcessHeap;
return
0 != Enum &&
HeapValidate(ProcessHeap, 0, Enum) &&
'munE' == Enum->Signature;
#else
return
0 != Enum &&
'munE' == Enum->Signature;
#endif
}
DWORD APIENTRY NPOpenEnum(
DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCEW lpNetResource, LPHANDLE lphEnum)
{
NTSTATUS Result;
FSP_NP_ENUM *Enum = 0;
SIZE_T VolumeListSize;
switch (dwScope)
{
case RESOURCE_CONNECTED:
case RESOURCE_CONTEXT:
/* ignore lpNetResource; according to documentation it should be NULL */
break;
default:
return WN_NOT_SUPPORTED;
}
if (dwType & RESOURCETYPE_PRINT)
return WN_BAD_VALUE;
Enum = MemAlloc(sizeof *Enum);
if (0 == Enum)
return WN_OUT_OF_MEMORY;
Result = FspNpGetVolumeList(&Enum->VolumeListBuf, &VolumeListSize);
if (!NT_SUCCESS(Result))
{
MemFree(Enum);
return WN_OUT_OF_MEMORY;
}
Enum->Signature = 'munE';
Enum->dwScope = dwScope;
Enum->VolumeListBufEnd = (PVOID)((PUINT8)Enum->VolumeListBuf + VolumeListSize);
Enum->VolumeName = Enum->VolumeListBuf;
Enum->LogicalDrives = GetLogicalDrives();
*lphEnum = Enum;
return WN_SUCCESS;
}
DWORD APIENTRY NPEnumResource(
HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
{
FSP_NP_ENUM *Enum = hEnum;
DWORD NpResult;
LPNETRESOURCEW Resource; /* grows upwards */
PWCHAR Strings; /* grows downwards */
PWCHAR ProviderName = 0;
DWORD Count;
PWCHAR P, VolumePrefix;
ULONG Backslashes;
WCHAR Drive;
if (!FspNpValidateEnum(Enum))
return WN_BAD_HANDLE;
if (0 == lpcCount || 0 == lpBuffer || 0 == lpBufferSize)
return WN_BAD_VALUE;
Resource = lpBuffer;
Strings = (PVOID)((PUINT8)lpBuffer + (*lpBufferSize & ~1/* WCHAR alignment */));
Count = 0;
for (P = Enum->VolumeName; *lpcCount > Count && Enum->VolumeListBufEnd > P; P++)
{
if (L'\0' == *P)
{
/*
* Extract the VolumePrefix from the VolumeName.
*
* The VolumeName will have the following syntax:
* \Device\Volume{GUID}\Server\Share
*
* We want to extract the \Server\Share part. We will simply count backslashes and
* stop at the third one.
*/
for (Backslashes = 0, VolumePrefix = Enum->VolumeName; VolumePrefix < P; VolumePrefix++)
if (L'\\' == *VolumePrefix)
if (3 == ++Backslashes)
break;
if (3 == Backslashes)
{
Drive = FspNpGetDriveLetter(&Enum->LogicalDrives, Enum->VolumeName);
Strings -= (Drive ? 3 : 0) + 2/* backslash + term-0 */ + lstrlenW(VolumePrefix) +
(0 == ProviderName ? lstrlenW(L"" FSP_NP_NAME) + 1 : 0);
if ((PVOID)(Resource + 1) > (PVOID)Strings)
{
if (0 == Count)
{
*lpBufferSize =
(DWORD)((PUINT8)(Resource + 1) - (PUINT8)lpBuffer) +
(DWORD)((PUINT8)lpBuffer + *lpBufferSize - (PUINT8)Strings);
NpResult = WN_MORE_DATA;
}
else
{
*lpcCount = Count;
NpResult = WN_SUCCESS;
}
goto exit;
}
if (0 == ProviderName)
{
ProviderName = Strings + (Drive ? 3 : 0) + 2/* backslash + term-0 */ + lstrlenW(VolumePrefix);
lstrcpyW(ProviderName, L"" FSP_NP_NAME);
}
if (Drive)
{
Strings[0] = Drive;
Strings[1] = L':';
Strings[2] = L'\0';
Strings[3] = L'\\';
lstrcpyW(Strings + 4, VolumePrefix);
}
else
{
Strings[0] = L'\\';
lstrcpyW(Strings + 1, VolumePrefix);
}
Resource->dwScope = Enum->dwScope;
Resource->dwType = RESOURCETYPE_DISK;
Resource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
Resource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
Resource->lpLocalName = Drive ? Strings : 0;
Resource->lpRemoteName = Drive ? Strings + 3 : Strings;
Resource->lpComment = 0;
Resource->lpProvider = ProviderName;
Resource++;
Count++;
}
Enum->VolumeName = P + 1;
}
}
if (0 == Count)
NpResult = WN_NO_MORE_ENTRIES;
else
{
*lpcCount = Count;
NpResult = WN_SUCCESS;
}
exit:
return NpResult;
}
DWORD APIENTRY NPCloseEnum(HANDLE hEnum)
{
FSP_NP_ENUM *Enum = hEnum;
if (!FspNpValidateEnum(Enum))
return WN_BAD_HANDLE;
MemFree(Enum->VolumeListBuf);
MemFree(Enum);
return WN_SUCCESS;
}
NTSTATUS FspNpRegister(VOID)
{
extern HINSTANCE DllInstance;
@ -221,8 +785,29 @@ NTSTATUS FspNpRegister(VOID)
if (ERROR_SUCCESS != RegResult)
return FspNtStatusFromWin32(RegResult);
RegResult = ERROR_RESOURCE_NAME_NOT_FOUND; /* not a real resource error! */
{
PVOID VersionInfo = 0;
DWORD Size;
PWSTR Description;
Size = GetFileVersionInfoSizeW(ProviderPath, &Size/*dummy*/);
if (0 < Size)
{
VersionInfo = MemAlloc(Size);
if (0 != VersionInfo &&
GetFileVersionInfoW(ProviderPath, 0, Size, VersionInfo) &&
VerQueryValueW(VersionInfo, L"\\StringFileInfo\\040904b0\\FileDescription",
&Description, &Size))
{
Size = Size * 2 + sizeof(WCHAR);
RegResult = RegSetValueExW(RegKey,
L"Name", 0, REG_SZ, (PVOID) L"" FSP_NP_DESC, sizeof L"" FSP_NP_DESC);
L"Name", 0, REG_SZ, (PVOID)Description, Size);
}
MemFree(VersionInfo);
}
}
if (ERROR_SUCCESS != RegResult)
goto close_and_exit;

View File

@ -17,6 +17,29 @@
#include <dll/library.h>
static ULONG (WINAPI *FspRtlNtStatusToDosError)(NTSTATUS Status);
VOID FspNtStatusInitialize(BOOLEAN Dynamic)
{
/*
* This function is called during DLL_PROCESS_ATTACH. We must therefore keep
* initialization tasks to a minimum.
*
* GetModuleHandle/GetProcAddress is allowed (because they are kernel32 API's)! See:
* https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx
*/
HANDLE Handle;
Handle = GetModuleHandleW(L"ntdll.dll");
if (0 != Handle)
FspRtlNtStatusToDosError = (PVOID)GetProcAddress(Handle, "RtlNtStatusToDosError");
}
VOID FspNtStatusFinalize(BOOLEAN Dynamic)
{
}
FSP_API NTSTATUS FspNtStatusFromWin32(DWORD Error)
{
switch (Error)
@ -26,3 +49,11 @@ FSP_API NTSTATUS FspNtStatusFromWin32(DWORD Error)
return STATUS_ACCESS_DENIED;
}
}
FSP_API DWORD FspWin32FromNtStatus(NTSTATUS Status)
{
if (0 == FspRtlNtStatusToDosError)
return ERROR_MR_MID_NOT_FOUND;
return FspRtlNtStatusToDosError(Status);
}

607
src/dll/service.c Normal file
View File

@ -0,0 +1,607 @@
/**
* @file dll/service.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dll/library.h>
enum
{
SetStatus_ServiceType = 0x0001,
SetStatus_CurrentState = 0x0002,
SetStatus_ControlsAccepted = 0x0004,
SetStatus_Win32ExitCode = 0x0008,
SetStatus_ServiceSpecificExitCode = 0x0010,
SetStatus_CheckPoint = 0x0020,
SetStatus_WaitHint = 0x0040,
AddStatus_CheckPoint = 0x0080,
GetStatus_ServiceType = 0x0100,
GetStatus_CurrentState = 0x0200,
GetStatus_ControlsAccepted = 0x0400,
GetStatus_Win32ExitCode = 0x0800,
GetStatus_ServiceSpecificExitCode = 0x1000,
GetStatus_CheckPoint = 0x2000,
GetStatus_WaitHint = 0x4000,
};
static SERVICE_TABLE_ENTRYW *FspServiceTable;
static HANDLE FspServiceConsoleModeEvent;
static UINT32 FspServiceConsoleCtrlHandlerDisabled;
static VOID FspServiceSetStatus(FSP_SERVICE *Service, ULONG Flags, SERVICE_STATUS *ServiceStatus);
static VOID WINAPI FspServiceEntry(DWORD Argc, PWSTR *Argv);
static VOID FspServiceMain(FSP_SERVICE *Service, DWORD Argc, PWSTR *Argv);
static DWORD WINAPI FspServiceCtrlHandler(
DWORD Control, DWORD EventType, PVOID EventData, PVOID Context);
static DWORD WINAPI FspServiceConsoleModeThread(PVOID Context);
static BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
#define FspServiceFromTable() (0 != FspServiceTable ?\
(FSP_SERVICE *)((PUINT8)FspServiceTable[0].lpServiceName - FIELD_OFFSET(FSP_SERVICE, ServiceName)) :\
0)
VOID FspServiceInitialize(BOOLEAN Dynamic)
{
}
VOID FspServiceFinalize(BOOLEAN Dynamic)
{
/*
* This function is called during DLL_PROCESS_DETACH. We must therefore keep
* finalization tasks to a minimum.
*
* We must close our console mode event handle. We only do so when we are
* explicitly unloaded. If the process is exiting the OS will clean up for us.
*/
if (Dynamic && 0 != FspServiceConsoleModeEvent)
CloseHandle(FspServiceConsoleModeEvent);
}
FSP_API ULONG FspServiceRun(PWSTR ServiceName,
FSP_SERVICE_START *OnStart,
FSP_SERVICE_STOP *OnStop,
FSP_SERVICE_CONTROL *OnControl)
{
FSP_SERVICE *Service;
NTSTATUS Result;
ULONG ExitCode;
Result = FspServiceCreate(ServiceName, OnStart, OnStop, OnControl, &Service);
if (!NT_SUCCESS(Result))
{
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"The service %s cannot be created (Status=%lx).", Service->ServiceName, Result);
return FspWin32FromNtStatus(Result);
}
FspServiceAllowConsoleMode(Service);
Result = FspServiceLoop(Service);
ExitCode = FspServiceGetExitCode(Service);
FspServiceDelete(Service);
if (!NT_SUCCESS(Result))
{
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"The service %s has failed to run (Status=%lx).", Service->ServiceName, Result);
return FspWin32FromNtStatus(Result);
}
return ExitCode;
}
FSP_API NTSTATUS FspServiceCreate(PWSTR ServiceName,
FSP_SERVICE_START *OnStart,
FSP_SERVICE_STOP *OnStop,
FSP_SERVICE_CONTROL *OnControl,
FSP_SERVICE **PService)
{
FSP_SERVICE *Service;
DWORD Size;
*PService = 0;
Size = (lstrlenW(ServiceName) + 1) * sizeof(WCHAR);
Service = MemAlloc(sizeof *Service + Size);
if (0 == Service)
return STATUS_INSUFFICIENT_RESOURCES;
memset(Service, 0, sizeof *Service);
memcpy(Service->ServiceName, ServiceName, Size);
Service->OnStart = OnStart;
Service->OnStop = OnStop;
Service->OnControl = OnControl;
Service->AcceptControl = OnStop ? SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN : 0;
InitializeCriticalSection(&Service->ServiceStatusGuard);
InitializeCriticalSection(&Service->ServiceStopGuard);
*PService = Service;
return STATUS_SUCCESS;
}
FSP_API VOID FspServiceDelete(FSP_SERVICE *Service)
{
DeleteCriticalSection(&Service->ServiceStopGuard);
DeleteCriticalSection(&Service->ServiceStatusGuard);
MemFree(Service);
}
static VOID FspServiceSetStatus(FSP_SERVICE *Service, ULONG Flags, SERVICE_STATUS *ServiceStatus)
{
#define XCHG(FIELD)\
if (Flags & SetStatus_##FIELD)\
{\
DWORD Temp = ServiceStatus->dw##FIELD;\
if (Flags & GetStatus_##FIELD)\
ServiceStatus->dw##FIELD = Service->ServiceStatus.dw##FIELD;\
Service->ServiceStatus.dw##FIELD = Temp;\
}
EnterCriticalSection(&Service->ServiceStatusGuard);
//XCHG(ServiceType);
XCHG(CurrentState);
XCHG(ControlsAccepted);
XCHG(Win32ExitCode);
//XCHG(ServiceSpecificExitCode);
if (Flags & AddStatus_CheckPoint)
{
DWORD Temp = ServiceStatus->dwCheckPoint;
if (Flags & GetStatus_CheckPoint)
ServiceStatus->dwCheckPoint = Service->ServiceStatus.dwCheckPoint;
Service->ServiceStatus.dwCheckPoint += Temp;
}
else
XCHG(CheckPoint);
XCHG(WaitHint);
if (0 != Service->StatusHandle)
{
if (!SetServiceStatus(Service->StatusHandle, &Service->ServiceStatus))
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"" __FUNCTION__ ": SetServiceStatus = %ld", GetLastError());
}
else if (0 != FspServiceConsoleModeEvent &&
SERVICE_STOPPED == Service->ServiceStatus.dwCurrentState)
{
SetEvent(FspServiceConsoleModeEvent);
}
LeaveCriticalSection(&Service->ServiceStatusGuard);
#undef XCHG
}
FSP_API VOID FspServiceAllowConsoleMode(FSP_SERVICE *Service)
{
Service->AllowConsoleMode = TRUE;
}
FSP_API VOID FspServiceAcceptControl(FSP_SERVICE *Service, ULONG Control)
{
Service->AcceptControl = Control & ~SERVICE_ACCEPT_PAUSE_CONTINUE;
}
FSP_API VOID FspServiceRequestTime(FSP_SERVICE *Service, ULONG Time)
{
SERVICE_STATUS ServiceStatus;
ServiceStatus.dwCheckPoint = +1;
ServiceStatus.dwWaitHint = Time;
FspServiceSetStatus(Service,
AddStatus_CheckPoint | SetStatus_WaitHint, &ServiceStatus);
}
FSP_API VOID FspServiceSetExitCode(FSP_SERVICE *Service, ULONG ExitCode)
{
Service->ExitCode = ExitCode;
}
FSP_API ULONG FspServiceGetExitCode(FSP_SERVICE *Service)
{
return Service->ServiceStatus.dwWin32ExitCode;
}
FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service)
{
NTSTATUS Result;
SERVICE_TABLE_ENTRYW ServiceTable[2];
Service->ExitCode = NO_ERROR;
Service->ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
Service->ServiceStatus.dwCurrentState = SERVICE_STOPPED;
Service->ServiceStatus.dwControlsAccepted = 0;
Service->ServiceStatus.dwWin32ExitCode = NO_ERROR;
Service->ServiceStatus.dwServiceSpecificExitCode = 0;
Service->ServiceStatus.dwCheckPoint = 0;
Service->ServiceStatus.dwWaitHint = 0;
ServiceTable[0].lpServiceName = Service->ServiceName;
ServiceTable[0].lpServiceProc = FspServiceEntry;
ServiceTable[1].lpServiceName = 0;
ServiceTable[1].lpServiceProc = 0;
FspServiceTable = ServiceTable;
if (!StartServiceCtrlDispatcherW(ServiceTable))
{
HANDLE Thread;
PWSTR *Argv;
DWORD Argc;
DWORD WaitResult;
DWORD LastError;
LastError = GetLastError();
if (!Service->AllowConsoleMode || ERROR_FAILED_SERVICE_CONTROLLER_CONNECT != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
/* ENTER CONSOLE MODE! */
/* create/reset the console mode event and console control handler */
if (0 == FspServiceConsoleModeEvent)
{
FspServiceConsoleModeEvent = CreateEventW(0, TRUE, FALSE, 0);
if (0 == FspServiceConsoleModeEvent)
{
Result = FspNtStatusFromWin32(GetLastError());
goto console_mode_exit;
}
if (!SetConsoleCtrlHandler(FspServiceConsoleCtrlHandler, TRUE))
{
Result = FspNtStatusFromWin32(GetLastError());
goto console_mode_exit;
}
}
else
{
ResetEvent(FspServiceConsoleModeEvent);
FspServiceConsoleCtrlHandlerDisabled = 0;
MemoryBarrier();
}
/* prepare the command line arguments */
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
if (0 == Argv)
{
Result = FspNtStatusFromWin32(GetLastError());
goto console_mode_exit;
}
Argv[0] = Service->ServiceName;
/* create the console mode startup thread (mimic StartServiceCtrlDispatcherW) */
Thread = CreateThread(0, 0, FspServiceConsoleModeThread, Argv/* give ownership */, 0, 0);
if (0 == Thread)
{
LocalFree(Argv);
Result = FspNtStatusFromWin32(GetLastError());
goto console_mode_exit;
}
/* wait for the console mode startup thread to terminate */
WaitResult = WaitForSingleObject(Thread, INFINITE);
CloseHandle(Thread);
if (WAIT_OBJECT_0 != WaitResult)
{
Result = FspNtStatusFromWin32(GetLastError());
goto console_mode_exit;
}
/* wait until signaled by the console control handler */
WaitResult = WaitForSingleObject(FspServiceConsoleModeEvent, INFINITE);
if (WAIT_OBJECT_0 != WaitResult)
{
Result = FspNtStatusFromWin32(GetLastError());
goto console_mode_exit;
}
if (Service->AcceptControl & SERVICE_ACCEPT_STOP)
FspServiceCtrlHandler(SERVICE_CONTROL_STOP, 0, 0, Service);
console_mode_exit:
/*
* Turns out that if we are sleeping/waiting in the FspServiceConsoleCtrlHandler
* we cannot call SetConsoleCtrlHandler, because we will deadlock. So we cannot
* really cleanup our console control handler upon return from this function.
*
* What we do instead is disable our handler by setting a variable.
*/
FspServiceConsoleCtrlHandlerDisabled = 1;
MemoryBarrier();
}
Result = STATUS_SUCCESS;
exit:
FspServiceTable = 0;
return Result;
}
FSP_API VOID FspServiceStop(FSP_SERVICE *Service)
{
SERVICE_STATUS ServiceStatus;
BOOLEAN Stopped;
NTSTATUS Result;
if (!TryEnterCriticalSection(&Service->ServiceStopGuard))
return; /* the service is already being stopped! */
EnterCriticalSection(&Service->ServiceStatusGuard);
Stopped = SERVICE_STOPPED == Service->ServiceStatus.dwCurrentState;
LeaveCriticalSection(&Service->ServiceStatusGuard);
if (Stopped)
goto exit;
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
FspServiceSetStatus(Service,
SetStatus_CurrentState | SetStatus_CheckPoint | SetStatus_WaitHint |
GetStatus_CurrentState | GetStatus_CheckPoint | GetStatus_WaitHint,
&ServiceStatus);
Result = STATUS_SUCCESS;
if (0 != Service->OnStop)
Result = Service->OnStop(Service);
if (NT_SUCCESS(Result))
{
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = Service->ExitCode;
FspServiceSetStatus(Service,
SetStatus_CurrentState | SetStatus_Win32ExitCode, &ServiceStatus);
FspServiceLog(EVENTLOG_INFORMATION_TYPE,
L"The service %s has been stopped.", Service->ServiceName);
}
else
{
/* revert the service status */
FspServiceSetStatus(Service,
SetStatus_CurrentState | SetStatus_CheckPoint | SetStatus_WaitHint,
&ServiceStatus);
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"The service %s has failed to stop (Status=%lx).", Service->ServiceName, Result);
}
exit:
LeaveCriticalSection(&Service->ServiceStopGuard);
}
static VOID WINAPI FspServiceEntry(DWORD Argc, PWSTR *Argv)
{
FSP_SERVICE *Service;
Service = FspServiceFromTable();
if (0 == Service)
{
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"" __FUNCTION__ ": internal error: FspServiceFromTable = 0");
return;
}
Service->StatusHandle = RegisterServiceCtrlHandlerExW(Service->ServiceName,
FspServiceCtrlHandler, Service);
if (0 == Service->StatusHandle)
{
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"" __FUNCTION__ ": RegisterServiceCtrlHandlerW = %ld", GetLastError());
return;
}
FspServiceMain(Service, Argc, Argv);
}
static VOID FspServiceMain(FSP_SERVICE *Service, DWORD Argc, PWSTR *Argv)
{
SERVICE_STATUS ServiceStatus;
NTSTATUS Result;
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwControlsAccepted = 0;
FspServiceSetStatus(Service,
SetStatus_CurrentState | SetStatus_ControlsAccepted, &ServiceStatus);
Result = STATUS_SUCCESS;
if (0 != Service->OnStart)
Result = Service->OnStart(Service, Argc, Argv);
if (NT_SUCCESS(Result))
{
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwControlsAccepted = Service->AcceptControl;
FspServiceSetStatus(Service,
SetStatus_CurrentState | SetStatus_ControlsAccepted, &ServiceStatus);
FspServiceLog(EVENTLOG_INFORMATION_TYPE,
L"The service %s has been started.", Service->ServiceName);
}
else
{
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = FspWin32FromNtStatus(Result);
FspServiceSetStatus(Service,
SetStatus_CurrentState | SetStatus_Win32ExitCode, &ServiceStatus);
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"The service %s has failed to start (Status=%lx).", Service->ServiceName, Result);
}
}
static DWORD WINAPI FspServiceCtrlHandler(
DWORD Control, DWORD EventType, PVOID EventData, PVOID Context)
{
FSP_SERVICE *Service = Context;
NTSTATUS Result;
switch (Control)
{
case SERVICE_CONTROL_SHUTDOWN:
/*
* Shutdown simply falls through to Stop. If specific Shutdown handling is needed
* we need to enable this. We also need to arrange for console mode to have two
* events: one to signal Stop and another to signal Shutdown. We currently use a
* single event for both console mode controls.
*/
#if 0
Result = STATUS_NOT_IMPLEMENTED;
if (0 != Service->OnControl)
Result = Service->OnControl(Service, Control, EventType, EventData);
if (STATUS_NOT_IMPLEMENTED != Result)
return FspWin32FromNtStatus(Result);
/* fall through */
#endif
case SERVICE_CONTROL_STOP:
FspServiceStop(Service);
return NO_ERROR;
case SERVICE_CONTROL_PAUSE:
case SERVICE_CONTROL_CONTINUE:
return ERROR_CALL_NOT_IMPLEMENTED;
case SERVICE_CONTROL_INTERROGATE:
return NO_ERROR;
default:
Result = STATUS_SUCCESS;
if (0 != Service->OnControl)
Result = Service->OnControl(Service, Control, EventType, EventData);
return FspWin32FromNtStatus(Result);
}
}
static DWORD WINAPI FspServiceConsoleModeThread(PVOID Context)
{
FSP_SERVICE *Service;
PWSTR *Argv = Context;
DWORD Argc;
for (Argc = 0; 0 != Argv[Argc]; Argc++)
;
Service = FspServiceFromTable();
if (0 == Service)
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"" __FUNCTION__ ": internal error: FspServiceFromTable = 0");
else
FspServiceMain(Service, Argc, Argv);
LocalFree(Argv);
return 0;
}
static BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType)
{
UINT32 Disabled = FspServiceConsoleCtrlHandlerDisabled;
MemoryBarrier();
if (Disabled)
return FALSE;
switch (CtrlType)
{
default:
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
if (0 != FspServiceConsoleModeEvent)
SetEvent(FspServiceConsoleModeEvent);
return TRUE;
case CTRL_CLOSE_EVENT:
case CTRL_SHUTDOWN_EVENT:
/*
* Returning from these events will kill the process. OTOH if we do not return timely
* the OS will kill us within 5-20 seconds. Our strategy is to wait some time (30 sec)
* to give the process some time to cleanup itself.
*
* We only do so if we have a Close event or we are interactive. If we are running as
* a service the OS will not kill us after delivering a Shutdown (or Logoff) event.
*/
if (0 != FspServiceConsoleModeEvent)
SetEvent(FspServiceConsoleModeEvent);
if (CTRL_CLOSE_EVENT == CtrlType || FspServiceIsInteractive())
Sleep(30000);
return TRUE;
case CTRL_LOGOFF_EVENT:
/* services should ignore this! */
return TRUE;
}
}
FSP_API BOOLEAN FspServiceIsInteractive(VOID)
{
/*
* Modeled after System.Environment.UserInteractive.
* See http://referencesource.microsoft.com/#mscorlib/system/environment.cs,947ad026e7cb830c
*/
static HWINSTA ProcessWindowStation;
static BOOLEAN IsInteractive;
HWINSTA CurrentWindowStation;
USEROBJECTFLAGS Flags;
CurrentWindowStation = GetProcessWindowStation();
if (0 != CurrentWindowStation && ProcessWindowStation != CurrentWindowStation)
{
if (GetUserObjectInformationW(CurrentWindowStation, UOI_FLAGS, &Flags, sizeof Flags, 0))
IsInteractive = 0 != (Flags.dwFlags & WSF_VISIBLE);
ProcessWindowStation = CurrentWindowStation;
}
return IsInteractive;
}
FSP_API VOID FspServiceLog(ULONG Type, PWSTR Format, ...)
{
va_list ap;
va_start(ap, Format);
FspServiceLogV(Type, Format, ap);
va_end(ap);
}
FSP_API VOID FspServiceLogV(ULONG Type, PWSTR Format, va_list ap)
{
if (FspServiceIsInteractive())
{
WCHAR BufW[1024];
/* wvsprintfW is only safe with a 1024 WCHAR buffer */
PSTR BufA;
DWORD Length;
wvsprintfW(BufW, Format, ap);
BufW[(sizeof BufW / sizeof BufW[0]) - 1] = L'\0';
Length = lstrlenW(BufW);
BufA = MemAlloc(Length * 3 + 1/* '\n' */);
if (0 != BufA)
{
Length = WideCharToMultiByte(CP_UTF8, 0, BufW, Length, BufA, Length * 3 + 1/* '\n' */,
0, 0);
if (0 < Length)
{
BufA[Length++] = '\n';
WriteFile(GetStdHandle(STD_ERROR_HANDLE), BufA, Length, &Length, 0);
}
MemFree(BufA);
}
}
else
FspEventLogV(Type, Format, ap);
}

37
src/dll/version.rc Normal file
View File

@ -0,0 +1,37 @@
#include <winver.h>
#define STR(x) STR_(x)
#define STR_(x) #x
VS_VERSION_INFO VERSIONINFO
FILEVERSION MyVersionWithCommas
PRODUCTVERSION MyVersionWithCommas
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0
#endif
FILEOS VOS_NT
FILETYPE VFT_DLL
FILESUBTYPE 0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", STR(MyCompanyName)
VALUE "FileDescription", STR(MyDescription)
VALUE "FileVersion", STR(MyVersion)
VALUE "InternalName", "winfsp.dll"
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "winfsp.dll"
VALUE "ProductName", STR(MyProductName)
VALUE "ProductVersion", STR(MyVersion)
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

View File

@ -0,0 +1,37 @@
#include <winver.h>
#define STR(x) STR_(x)
#define STR_(x) #x
VS_VERSION_INFO VERSIONINFO
FILEVERSION MyVersionWithCommas
PRODUCTVERSION MyVersionWithCommas
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0
#endif
FILEOS VOS_NT
FILETYPE VFT_APP
FILESUBTYPE 0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", STR(MyCompanyName)
VALUE "FileDescription", STR(MyDescription)
VALUE "FileVersion", STR(MyVersion)
VALUE "InternalName", "launchctl.exe"
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "launchctl.exe"
VALUE "ProductName", STR(MyProductName)
VALUE "ProductVersion", STR(MyVersion)
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

291
src/launcher/launchctl.c Normal file
View File

@ -0,0 +1,291 @@
/**
* @file launcher/launchctl.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <launcher/launcher.h>
#define PROGNAME "launchctl"
#define info(format, ...) printlog(GetStdHandle(STD_OUTPUT_HANDLE), format, __VA_ARGS__)
#define warn(format, ...) printlog(GetStdHandle(STD_ERROR_HANDLE), format, __VA_ARGS__)
#define fatal(ExitCode, format, ...) (warn(format, __VA_ARGS__), ExitProcess(ExitCode))
static void vprintlog(HANDLE h, const char *format, va_list ap)
{
char buf[1024];
/* wvsprintf is only safe with a 1024 byte buffer */
size_t len;
DWORD BytesTransferred;
wvsprintfA(buf, format, ap);
buf[sizeof buf - 1] = '\0';
len = lstrlenA(buf);
buf[len++] = '\n';
WriteFile(h, buf, (DWORD)len, &BytesTransferred, 0);
}
static void printlog(HANDLE h, const char *format, ...)
{
va_list ap;
va_start(ap, format);
vprintlog(h, format, ap);
va_end(ap);
}
static void usage(void)
{
fatal(ERROR_INVALID_PARAMETER,
"usage: %s COMMAND ARGS\n"
"\n"
"commands:\n"
" start ClassName InstanceName Args...\n"
" stop ClassName InstanceName\n"
" info ClassName InstanceName\n"
" list\n",
PROGNAME);
}
static int call_pipe_and_report(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
{
NTSTATUS Result;
DWORD LastError, BytesTransferred;
Result = FspCallNamedPipeSecurely(L"" LAUNCHER_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize,
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, LAUNCHER_PIPE_OWNER);
LastError = FspWin32FromNtStatus(Result);
if (0 != LastError)
warn("KO CallNamedPipe = %ld", LastError);
else if (sizeof(WCHAR) > BytesTransferred)
warn("KO launcher: empty buffer");
else if (LauncherSuccess == PipeBuf[0])
{
if (sizeof(WCHAR) == BytesTransferred)
info("OK");
else
{
ULONG Count = 0;
for (PWSTR P = PipeBuf, PipeBufEnd = P + BytesTransferred / sizeof(WCHAR);
PipeBufEnd > P; P++)
if (L'\0' == *P)
{
/* print a newline every 2 nulls; this works for both list and info */
*P = 1 == Count % 2 ? L'\n' : L' ';
Count++;
}
if (BytesTransferred < RecvSize)
PipeBuf[BytesTransferred / sizeof(WCHAR)] = L'\0';
else
PipeBuf[RecvSize / sizeof(WCHAR) - 1] = L'\0';
info("OK\n%S", PipeBuf + 1);
}
}
else if (LauncherFailure == PipeBuf[0])
{
if (BytesTransferred < RecvSize)
PipeBuf[BytesTransferred / sizeof(WCHAR)] = L'\0';
else
PipeBuf[RecvSize / sizeof(WCHAR) - 1] = L'\0';
info("KO launcher: error %S", PipeBuf + 1);
}
else
warn("KO launcher: corrupted buffer", 0);
return LastError;
}
int start(PWSTR PipeBuf, ULONG PipeBufSize,
PWSTR ClassName, PWSTR InstanceName, DWORD Argc, PWSTR *Argv)
{
PWSTR P;
DWORD ClassNameSize, InstanceNameSize, ArgvSize;
ClassNameSize = lstrlenW(ClassName) + 1;
InstanceNameSize = lstrlenW(InstanceName) + 1;
ArgvSize = 0;
for (DWORD Argi = 0; Argc > Argi; Argi++)
ArgvSize += lstrlenW(Argv[Argi]) + 1;
if (PipeBufSize < (1 + ClassNameSize + InstanceNameSize + ArgvSize) * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER;
P = PipeBuf;
*P++ = LauncherSvcInstanceStart;
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
for (DWORD Argi = 0; Argc > Argi; Argi++)
{
ArgvSize = lstrlenW(Argv[Argi]) + 1;
memcpy(P, Argv[Argi], ArgvSize * sizeof(WCHAR)); P += ArgvSize;
}
return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize);
}
int stop(PWSTR PipeBuf, ULONG PipeBufSize,
PWSTR ClassName, PWSTR InstanceName)
{
PWSTR P;
DWORD ClassNameSize, InstanceNameSize;
ClassNameSize = lstrlenW(ClassName) + 1;
InstanceNameSize = lstrlenW(InstanceName) + 1;
if (PipeBufSize < (1 + ClassNameSize + InstanceNameSize) * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER;
P = PipeBuf;
*P++ = LauncherSvcInstanceStop;
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize);
}
int getinfo(PWSTR PipeBuf, ULONG PipeBufSize,
PWSTR ClassName, PWSTR InstanceName)
{
PWSTR P;
DWORD ClassNameSize, InstanceNameSize;
ClassNameSize = lstrlenW(ClassName) + 1;
InstanceNameSize = lstrlenW(InstanceName) + 1;
if (PipeBufSize < (1 + ClassNameSize + InstanceNameSize) * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER;
P = PipeBuf;
*P++ = LauncherSvcInstanceInfo;
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize);
}
int list(PWSTR PipeBuf, ULONG PipeBufSize)
{
PWSTR P;
if (PipeBufSize < 1 * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER;
P = PipeBuf;
*P++ = LauncherSvcInstanceList;
return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize);
}
int quit(PWSTR PipeBuf, ULONG PipeBufSize)
{
/* works only against DEBUG version of launcher */
PWSTR P;
if (PipeBufSize < 1 * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER;
P = PipeBuf;
*P++ = LauncherQuit;
return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize);
}
int wmain(int argc, wchar_t **argv)
{
PWSTR PipeBuf = 0;
/* allocate our PipeBuf early on; freed on process exit by the system */
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
if (0 == PipeBuf)
return ERROR_NO_SYSTEM_RESOURCES;
argc--;
argv++;
if (0 == argc)
usage();
if (0 == lstrcmpW(L"start", argv[0]))
{
if (3 > argc || argc > 12)
usage();
return start(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3);
}
else
if (0 == lstrcmpW(L"stop", argv[0]))
{
if (3 != argc)
usage();
return stop(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2]);
}
else
if (0 == lstrcmpW(L"info", argv[0]))
{
if (3 != argc)
usage();
return getinfo(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2]);
}
else
if (0 == lstrcmpW(L"list", argv[0]))
{
if (1 != argc)
usage();
return list(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE);
}
else
if (0 == lstrcmpW(L"quit", argv[0]))
{
if (1 != argc)
usage();
/* works only against DEBUG version of launcher */
return quit(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE);
}
else
usage();
return 0;
}
void wmainCRTStartup(void)
{
DWORD Argc;
PWSTR *Argv;
extern HANDLE ProcessHeap;
ProcessHeap = GetProcessHeap();
if (0 == ProcessHeap)
ExitProcess(GetLastError());
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
if (0 == Argv)
ExitProcess(GetLastError());
ExitProcess(wmain(Argc, Argv));
}
HANDLE ProcessHeap;

View File

@ -0,0 +1,37 @@
#include <winver.h>
#define STR(x) STR_(x)
#define STR_(x) #x
VS_VERSION_INFO VERSIONINFO
FILEVERSION MyVersionWithCommas
PRODUCTVERSION MyVersionWithCommas
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0
#endif
FILEOS VOS_NT
FILETYPE VFT_APP
FILESUBTYPE 0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", STR(MyCompanyName)
VALUE "FileDescription", STR(MyDescription)
VALUE "FileVersion", STR(MyVersion)
VALUE "InternalName", "launcher.exe"
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "launcher.exe"
VALUE "ProductName", STR(MyProductName)
VALUE "ProductVersion", STR(MyVersion)
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

992
src/launcher/launcher.c Normal file
View File

@ -0,0 +1,992 @@
/**
* @file launcher/launcher.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <launcher/launcher.h>
#include <sddl.h>
#define PROGNAME "WinFsp.Launcher"
#define REGKEY "SYSTEM\\CurrentControlSet\\Services\\" PROGNAME "\\Services"
typedef struct
{
HANDLE Process;
HANDLE ProcessWait;
} KILL_PROCESS_DATA;
static VOID CALLBACK KillProcessWait(PVOID Context, BOOLEAN Timeout);
VOID KillProcess(ULONG ProcessId, HANDLE Process, ULONG Timeout)
{
if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, ProcessId))
{
/*
* If GenerateConsoleCtrlEvent succeeds, but the child process does not exit
* timely we will terminate it with extreme prejudice. This is done by calling
* RegisterWaitForSingleObject with timeout on a duplicated process handle.
*
* If GenerateConsoleCtrlEvent succeeds, but we are not able to successfully call
* RegisterWaitForSingleObject, we do NOT terminate the child process forcibly.
* This is by design as it is not the child process's fault and the child process
* should (we hope in this case) respond to the console control event timely.
*/
KILL_PROCESS_DATA *KillProcessData;
KillProcessData = MemAlloc(sizeof *KillProcessData);
if (0 != KillProcessData)
{
if (DuplicateHandle(GetCurrentProcess(), Process, GetCurrentProcess(), &KillProcessData->Process,
0, FALSE, DUPLICATE_SAME_ACCESS))
{
if (RegisterWaitForSingleObject(&KillProcessData->ProcessWait, KillProcessData->Process,
KillProcessWait, KillProcessData, Timeout, WT_EXECUTEONLYONCE))
KillProcessData = 0;
else
CloseHandle(KillProcessData->Process);
}
MemFree(KillProcessData);
}
}
else
TerminateProcess(Process, 0);
}
static VOID CALLBACK KillProcessWait(PVOID Context, BOOLEAN Timeout)
{
KILL_PROCESS_DATA *KillProcessData = Context;
if (Timeout)
TerminateProcess(KillProcessData->Process, 0);
UnregisterWaitEx(KillProcessData->ProcessWait, 0);
CloseHandle(KillProcessData->Process);
MemFree(KillProcessData);
}
typedef struct
{
PWSTR ClassName;
PWSTR InstanceName;
PWSTR CommandLine;
PSECURITY_DESCRIPTOR SecurityDescriptor;
DWORD ProcessId;
HANDLE Process;
HANDLE ProcessWait;
LIST_ENTRY ListEntry;
WCHAR Buffer[];
} SVC_INSTANCE;
static CRITICAL_SECTION SvcInstanceLock;
static HANDLE SvcInstanceEvent;
static LIST_ENTRY SvcInstanceList = { &SvcInstanceList, &SvcInstanceList };
static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Timeout);
static SVC_INSTANCE *SvcInstanceLookup(PWSTR ClassName, PWSTR InstanceName)
{
SVC_INSTANCE *SvcInstance;
PLIST_ENTRY ListEntry;
for (ListEntry = SvcInstanceList.Flink;
&SvcInstanceList != ListEntry;
ListEntry = ListEntry->Flink)
{
SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry);
if (0 == lstrcmpW(ClassName, SvcInstance->ClassName) &&
0 == lstrcmpW(InstanceName, SvcInstance->InstanceName))
return SvcInstance;
}
return 0;
}
static ULONG SvcInstanceArgumentLength(PWSTR Arg)
{
ULONG Length;
Length = 2; /* for beginning and ending quotes */
for (PWSTR P = Arg; *P; P++)
if (L'"' != *P)
Length++;
return Length;
}
static PWSTR SvcInstanceArgumentCopy(PWSTR Dest, PWSTR Arg)
{
*Dest++ = L'"';
for (PWSTR P = Arg; *P; P++)
if (L'"' != *P)
*Dest++ = *P;
*Dest++ = L'"';
return Dest;
}
static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Argv,
PWSTR *PNewString)
{
PWSTR NewString = 0, P, Q;
PWSTR EmptyArg = L"";
ULONG Length;
*PNewString = 0;
Length = 0;
for (P = String; *P; P++)
{
switch (*P)
{
case L'%':
P++;
if (L'0' <= *P && *P <= '9')
{
if (Argc > (ULONG)(*P - L'0'))
Length += SvcInstanceArgumentLength(Argv[*P - L'0']);
else
Length += SvcInstanceArgumentLength(EmptyArg);
}
else
Length++;
break;
default:
Length++;
break;
}
}
NewString = MemAlloc((Length + 1) * sizeof(WCHAR));
if (0 == NewString)
return STATUS_INSUFFICIENT_RESOURCES;
for (P = String, Q = NewString; *P; P++)
{
switch (*P)
{
case L'%':
P++;
if (L'0' <= *P && *P <= '9')
{
if (Argc > (ULONG)(*P - L'0'))
Q = SvcInstanceArgumentCopy(Q, Argv[*P - L'0']);
else
Q = SvcInstanceArgumentCopy(Q, EmptyArg);
}
else
*Q++ = *P;
break;
default:
*Q++ = *P;
break;
}
}
*Q = L'\0';
*PNewString = NewString;
return STATUS_SUCCESS;
}
static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess,
PSECURITY_DESCRIPTOR SecurityDescriptor)
{
static GENERIC_MAPPING GenericMapping =
{
.GenericRead = STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS |
SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS,
.GenericWrite = STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG,
.GenericExecute = STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP |
SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL,
.GenericAll = SERVICE_ALL_ACCESS,
};
UINT8 PrivilegeSetBuf[sizeof(PRIVILEGE_SET) + 15 * sizeof(LUID_AND_ATTRIBUTES)];
PPRIVILEGE_SET PrivilegeSet = (PVOID)PrivilegeSetBuf;
DWORD PrivilegeSetLength = sizeof PrivilegeSetBuf;
ULONG GrantedAccess;
BOOL AccessStatus;
NTSTATUS Result;
if (AccessCheck(SecurityDescriptor, ClientToken, DesiredAccess,
&GenericMapping, PrivilegeSet, &PrivilegeSetLength, &GrantedAccess, &AccessStatus))
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
else
Result = FspNtStatusFromWin32(GetLastError());
return Result;
}
NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv0, HANDLE Job,
SVC_INSTANCE **PSvcInstance)
{
SVC_INSTANCE *SvcInstance = 0;
HKEY RegKey = 0;
DWORD RegResult, RegSize;
DWORD ClassNameSize, InstanceNameSize;
WCHAR Executable[MAX_PATH], CommandLineBuf[512], SecurityBuf[512];
PWSTR CommandLine, Security;
DWORD JobControl;
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PWSTR Argv[10];
STARTUPINFOW StartupInfo;
PROCESS_INFORMATION ProcessInfo;
NTSTATUS Result;
*PSvcInstance = 0;
lstrcpyW(CommandLineBuf, L"%0 ");
lstrcpyW(SecurityBuf, L"O:SYG:SY");
if (Argc > sizeof Argv / sizeof Argv[0] - 1)
Argc = sizeof Argv / sizeof Argv[0] - 1;
memcpy(Argv + 1, Argv0, Argc * sizeof(PWSTR));
Argv[0] = 0;
Argc++;
memset(&StartupInfo, 0, sizeof StartupInfo);
memset(&ProcessInfo, 0, sizeof ProcessInfo);
EnterCriticalSection(&SvcInstanceLock);
if (0 != SvcInstanceLookup(ClassName, InstanceName))
{
Result = STATUS_OBJECT_NAME_COLLISION;
goto exit;
}
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" REGKEY, 0, KEY_READ, &RegKey);
if (ERROR_SUCCESS != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);
goto exit;
}
RegSize = sizeof Executable;
Executable[0] = L'\0';
RegResult = RegGetValueW(RegKey, ClassName, L"Executable", RRF_RT_REG_SZ, 0,
Executable, &RegSize);
if (ERROR_SUCCESS != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);
goto exit;
}
Argv[0] = Executable;
CommandLine = CommandLineBuf + lstrlenW(CommandLineBuf);
RegSize = (DWORD)(sizeof CommandLineBuf - (CommandLine - CommandLineBuf) * sizeof(WCHAR));
RegResult = RegGetValueW(RegKey, ClassName, L"CommandLine", RRF_RT_REG_SZ, 0,
CommandLine, &RegSize);
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);
goto exit;
}
if (ERROR_FILE_NOT_FOUND == RegResult)
CommandLine[-1] = L'\0';
CommandLine = CommandLineBuf;
Security = SecurityBuf + lstrlenW(SecurityBuf);
RegSize = (DWORD)(sizeof SecurityBuf - (Security - SecurityBuf) * sizeof(WCHAR));
RegResult = RegGetValueW(RegKey, ClassName, L"Security", RRF_RT_REG_SZ, 0,
Security, &RegSize);
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);
goto exit;
}
RegSize = sizeof JobControl;
JobControl = 1; /* default is YES! */
RegResult = RegGetValueW(RegKey, ClassName, L"JobControl", RRF_RT_REG_DWORD, 0,
&JobControl, &RegSize);
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);
goto exit;
}
RegCloseKey(RegKey);
RegKey = 0;
if (L'\0' == Security[0])
lstrcpyW(Security, L"" SVC_INSTANCE_DEFAULT_SDDL);
if (L'D' == Security[0] && L':' == Security[1])
Security = SecurityBuf;
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(Security, SDDL_REVISION_1,
&SecurityDescriptor, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityDescriptor);
Result = SvcInstanceAccessCheck(ClientToken, SERVICE_START, SecurityDescriptor);
if (!NT_SUCCESS(Result))
goto exit;
ClassNameSize = (lstrlenW(ClassName) + 1) * sizeof(WCHAR);
InstanceNameSize = (lstrlenW(InstanceName) + 1) * sizeof(WCHAR);
SvcInstance = MemAlloc(sizeof *SvcInstance + ClassNameSize + InstanceNameSize);
if (0 == SvcInstance)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
memset(SvcInstance, 0, sizeof *SvcInstance);
memcpy(SvcInstance->Buffer, ClassName, ClassNameSize);
memcpy(SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR), InstanceName, InstanceNameSize);
SvcInstance->ClassName = SvcInstance->Buffer;
SvcInstance->InstanceName = SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR);
SvcInstance->SecurityDescriptor = SecurityDescriptor;
Result = SvcInstanceReplaceArguments(CommandLine, Argc, Argv, &SvcInstance->CommandLine);
if (!NT_SUCCESS(Result))
goto exit;
StartupInfo.cb = sizeof StartupInfo;
if (!CreateProcessW(Executable, SvcInstance->CommandLine, 0, 0, FALSE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP, 0, 0, &StartupInfo, &ProcessInfo))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
SvcInstance->ProcessId = ProcessInfo.dwProcessId;
SvcInstance->Process = ProcessInfo.hProcess;
if (!RegisterWaitForSingleObject(&SvcInstance->ProcessWait, SvcInstance->Process,
SvcInstanceTerminated, SvcInstance, INFINITE, WT_EXECUTEONLYONCE))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (0 != Job && JobControl)
{
if (!AssignProcessToJobObject(Job, SvcInstance->Process))
FspServiceLog(EVENTLOG_WARNING_TYPE,
L"Ignorning error: AssignProcessToJobObject = %ld", GetLastError());
}
/*
* ONCE THE PROCESS IS RESUMED NO MORE FAILURES ALLOWED!
*/
ResumeThread(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hThread);
ProcessInfo.hThread = 0;
InsertTailList(&SvcInstanceList, &SvcInstance->ListEntry);
ResetEvent(SvcInstanceEvent);
*PSvcInstance = SvcInstance;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
{
LocalFree(SecurityDescriptor);
if (0 != ProcessInfo.hThread)
CloseHandle(ProcessInfo.hThread);
if (0 != SvcInstance)
{
if (0 != SvcInstance->ProcessWait)
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
if (0 != SvcInstance->Process)
{
TerminateProcess(SvcInstance->Process, 0);
CloseHandle(SvcInstance->Process);
}
MemFree(SvcInstance->CommandLine);
MemFree(SvcInstance);
}
}
if (0 != RegKey)
RegCloseKey(RegKey);
LeaveCriticalSection(&SvcInstanceLock);
return Result;
}
VOID SvcInstanceDelete(SVC_INSTANCE *SvcInstance)
{
EnterCriticalSection(&SvcInstanceLock);
if (RemoveEntryList(&SvcInstance->ListEntry))
SetEvent(SvcInstanceEvent);
LeaveCriticalSection(&SvcInstanceLock);
if (0 != SvcInstance->ProcessWait)
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
if (0 != SvcInstance->Process)
CloseHandle(SvcInstance->Process);
LocalFree(SvcInstance->SecurityDescriptor);
MemFree(SvcInstance->CommandLine);
MemFree(SvcInstance);
}
static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Timeout)
{
SVC_INSTANCE *SvcInstance = Context;
SvcInstanceDelete(SvcInstance);
}
NTSTATUS SvcInstanceStart(HANDLE ClientToken,
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv, HANDLE Job)
{
SVC_INSTANCE *SvcInstance;
return SvcInstanceCreate(ClientToken, ClassName, InstanceName, Argc, Argv, Job, &SvcInstance);
}
NTSTATUS SvcInstanceStop(HANDLE ClientToken,
PWSTR ClassName, PWSTR InstanceName)
{
SVC_INSTANCE *SvcInstance;
NTSTATUS Result;
EnterCriticalSection(&SvcInstanceLock);
SvcInstance = SvcInstanceLookup(ClassName, InstanceName);
if (0 == SvcInstance)
{
Result = STATUS_OBJECT_NAME_NOT_FOUND;
goto exit;
}
Result = SvcInstanceAccessCheck(ClientToken, SERVICE_STOP, SvcInstance->SecurityDescriptor);
if (!NT_SUCCESS(Result))
goto exit;
KillProcess(SvcInstance->ProcessId, SvcInstance->Process, LAUNCHER_KILL_TIMEOUT);
Result = STATUS_SUCCESS;
exit:
LeaveCriticalSection(&SvcInstanceLock);
return Result;
}
NTSTATUS SvcInstanceGetInfo(HANDLE ClientToken,
PWSTR ClassName, PWSTR InstanceName, PWSTR Buffer, PULONG PSize)
{
SVC_INSTANCE *SvcInstance;
PWSTR P = Buffer;
ULONG ClassNameSize, InstanceNameSize, CommandLineSize;
NTSTATUS Result;
EnterCriticalSection(&SvcInstanceLock);
SvcInstance = SvcInstanceLookup(ClassName, InstanceName);
if (0 == SvcInstance)
{
Result = STATUS_OBJECT_NAME_NOT_FOUND;
goto exit;
}
Result = SvcInstanceAccessCheck(ClientToken, SERVICE_QUERY_STATUS, SvcInstance->SecurityDescriptor);
if (!NT_SUCCESS(Result))
goto exit;
ClassNameSize = lstrlenW(SvcInstance->ClassName) + 1;
InstanceNameSize = lstrlenW(SvcInstance->InstanceName) + 1;
CommandLineSize = lstrlenW(SvcInstance->CommandLine) + 1;
if (*PSize < (ClassNameSize + InstanceNameSize + CommandLineSize) * sizeof(WCHAR))
{
Result = STATUS_BUFFER_TOO_SMALL;
goto exit;
}
memcpy(P, SvcInstance->ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, SvcInstance->InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
memcpy(P, SvcInstance->CommandLine, CommandLineSize * sizeof(WCHAR)); P += CommandLineSize;
*PSize = (ULONG)(P - Buffer) * sizeof(WCHAR);
Result = STATUS_SUCCESS;
exit:
LeaveCriticalSection(&SvcInstanceLock);
return Result;
}
NTSTATUS SvcInstanceGetNameList(HANDLE ClientToken,
PWSTR Buffer, PULONG PSize)
{
SVC_INSTANCE *SvcInstance;
PLIST_ENTRY ListEntry;
PWSTR P = Buffer, BufferEnd = P + *PSize / sizeof(WCHAR);
ULONG ClassNameSize, InstanceNameSize;
EnterCriticalSection(&SvcInstanceLock);
for (ListEntry = SvcInstanceList.Flink;
&SvcInstanceList != ListEntry;
ListEntry = ListEntry->Flink)
{
SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry);
ClassNameSize = lstrlenW(SvcInstance->ClassName) + 1;
InstanceNameSize = lstrlenW(SvcInstance->InstanceName) + 1;
if (BufferEnd < P + ClassNameSize + InstanceNameSize)
break;
memcpy(P, SvcInstance->ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, SvcInstance->InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
}
LeaveCriticalSection(&SvcInstanceLock);
*PSize = (ULONG)(P - Buffer) * sizeof(WCHAR);
return STATUS_SUCCESS;
}
NTSTATUS SvcInstanceStopAndWaitAll(VOID)
{
SVC_INSTANCE *SvcInstance;
PLIST_ENTRY ListEntry;
EnterCriticalSection(&SvcInstanceLock);
for (ListEntry = SvcInstanceList.Flink;
&SvcInstanceList != ListEntry;
ListEntry = ListEntry->Flink)
{
SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry);
KillProcess(SvcInstance->ProcessId, SvcInstance->Process, LAUNCHER_KILL_TIMEOUT);
}
LeaveCriticalSection(&SvcInstanceLock);
WaitForSingleObject(SvcInstanceEvent, LAUNCHER_STOP_TIMEOUT);
return STATUS_SUCCESS;
}
static HANDLE SvcJob, SvcThread, SvcEvent;
static DWORD SvcThreadId;
static HANDLE SvcPipe = INVALID_HANDLE_VALUE;
static OVERLAPPED SvcOverlapped;
static DWORD WINAPI SvcPipeServer(PVOID Context);
static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize);
static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
{
SECURITY_ATTRIBUTES SecurityAttributes = { 0 };
/*
* Allocate a console in case we are running as a service without one.
* This will ensure that we can send console control events to service instances.
*/
if (AllocConsole())
ShowWindow(GetConsoleWindow(), SW_HIDE);
InitializeCriticalSection(&SvcInstanceLock);
SecurityAttributes.nLength = sizeof SecurityAttributes;
SecurityAttributes.bInheritHandle = FALSE;
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(L"" LAUNCHER_PIPE_SDDL, SDDL_REVISION_1,
&SecurityAttributes.lpSecurityDescriptor, 0))
goto fail;
FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityAttributes.lpSecurityDescriptor);
SvcInstanceEvent = CreateEventW(0, TRUE, TRUE, 0);
if (0 == SvcInstanceEvent)
goto fail;
SvcJob = CreateJobObjectW(0, 0);
if (0 != SvcJob)
{
JOBOBJECT_EXTENDED_LIMIT_INFORMATION LimitInfo;
memset(&LimitInfo, 0, sizeof LimitInfo);
LimitInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if (!SetInformationJobObject(SvcJob, JobObjectExtendedLimitInformation,
&LimitInfo, sizeof LimitInfo))
{
CloseHandle(SvcJob);
SvcJob = 0;
}
}
SvcEvent = CreateEventW(0, TRUE, FALSE, 0);
if (0 == SvcEvent)
goto fail;
SvcOverlapped.hEvent = CreateEventW(0, TRUE, FALSE, 0);
if (0 == SvcOverlapped.hEvent)
goto fail;
SvcPipe = CreateNamedPipeW(L"" LAUNCHER_PIPE_NAME,
PIPE_ACCESS_DUPLEX |
FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
1, LAUNCHER_PIPE_BUFFER_SIZE, LAUNCHER_PIPE_BUFFER_SIZE, LAUNCHER_PIPE_DEFAULT_TIMEOUT,
&SecurityAttributes);
if (INVALID_HANDLE_VALUE == SvcPipe)
goto fail;
SvcThread = CreateThread(0, 0, SvcPipeServer, Service, 0, &SvcThreadId);
if (0 == SvcThread)
goto fail;
LocalFree(SecurityAttributes.lpSecurityDescriptor);
return STATUS_SUCCESS;
fail:
DWORD LastError = GetLastError();
/*
* The OS will cleanup for us. So there is no need to explicitly release these resources.
*/
#if 0
if (0 != SvcThread)
CloseHandle(SvcThread);
if (INVALID_HANDLE_VALUE != SvcPipe)
CloseHandle(SvcPipe);
if (0 != SvcOverlapped.hEvent)
CloseHandle(SvcOverlapped.hEvent);
if (0 != SvcEvent)
CloseHandle(SvcEvent);
if (0 != SvcJob)
CloseHandle(SvcJob);
if (0 != SvcInstanceEvent)
CloseHandle(SvcInstanceEvent);
LocalFree(SecurityAttributes.lpSecurityDescriptor);
DeleteCriticalSection(&SvcInstanceLock);
#endif
return FspNtStatusFromWin32(LastError);
}
static NTSTATUS SvcStop(FSP_SERVICE *Service)
{
if (GetCurrentThreadId() != SvcThreadId)
{
SetEvent(SvcEvent);
FspServiceRequestTime(Service, LAUNCHER_STOP_TIMEOUT);
WaitForSingleObject(SvcThread, LAUNCHER_STOP_TIMEOUT);
}
/*
* The OS will cleanup for us. So there is no need to explicitly release these resources.
*
* This also protects us from scenarios where not all child processes terminate timely
* and KillProcess decides to terminate them forcibly, thus creating racing conditions
* with SvcInstanceTerminated.
*/
#if 0
if (0 != SvcThread)
CloseHandle(SvcThread);
if (INVALID_HANDLE_VALUE != SvcPipe)
CloseHandle(SvcPipe);
if (0 != SvcOverlapped.hEvent)
CloseHandle(SvcOverlapped.hEvent);
if (0 != SvcEvent)
CloseHandle(SvcEvent);
if (0 != SvcJob)
CloseHandle(SvcJob);
if (0 != SvcInstanceEvent)
CloseHandle(SvcInstanceEvent);
DeleteCriticalSection(&SvcInstanceLock);
#endif
return STATUS_SUCCESS;
}
static inline DWORD SvcPipeWaitResult(BOOL Success, HANDLE StopEvent,
HANDLE Handle, OVERLAPPED *Overlapped, PDWORD PBytesTransferred)
{
HANDLE WaitObjects[2];
DWORD WaitResult;
if (!Success && ERROR_IO_PENDING != GetLastError())
return GetLastError();
WaitObjects[0] = StopEvent;
WaitObjects[1] = Overlapped->hEvent;
WaitResult = WaitForMultipleObjects(2, WaitObjects, FALSE, INFINITE);
if (WAIT_OBJECT_0 == WaitResult)
return -1; /* special: stop thread */
else if (WAIT_OBJECT_0 + 1 == WaitResult)
{
if (!GetOverlappedResult(Handle, Overlapped, PBytesTransferred, TRUE))
return GetLastError();
return 0;
}
else
return GetLastError();
}
static DWORD WINAPI SvcPipeServer(PVOID Context)
{
static PWSTR LoopErrorMessage =
L"Error in service main loop (%s = %ld). Exiting...";
static PWSTR LoopWarningMessage =
L"Error in service main loop (%s = %ld). Continuing...";
FSP_SERVICE *Service = Context;
PWSTR PipeBuf = 0;
HANDLE ClientToken;
DWORD LastError, BytesTransferred;
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
if (0 == PipeBuf)
{
FspServiceSetExitCode(Service, ERROR_NO_SYSTEM_RESOURCES);
goto exit;
}
for (;;)
{
LastError = SvcPipeWaitResult(
ConnectNamedPipe(SvcPipe, &SvcOverlapped),
SvcEvent, SvcPipe, &SvcOverlapped, &BytesTransferred);
if (-1 == LastError)
break;
else if (0 != LastError &&
ERROR_PIPE_CONNECTED != LastError && ERROR_NO_DATA != LastError)
{
FspServiceLog(EVENTLOG_WARNING_TYPE, LoopWarningMessage,
L"ConnectNamedPipe", LastError);
continue;
}
LastError = SvcPipeWaitResult(
ReadFile(SvcPipe, PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, &BytesTransferred, &SvcOverlapped),
SvcEvent, SvcPipe, &SvcOverlapped, &BytesTransferred);
if (-1 == LastError)
break;
else if (0 != LastError || sizeof(WCHAR) > BytesTransferred)
{
DisconnectNamedPipe(SvcPipe);
if (0 != LastError)
FspServiceLog(EVENTLOG_WARNING_TYPE, LoopWarningMessage,
L"ReadFile", LastError);
continue;
}
ClientToken = 0;
if (!ImpersonateNamedPipeClient(SvcPipe) ||
!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &ClientToken) ||
!RevertToSelf())
{
LastError = GetLastError();
if (0 == ClientToken)
{
CloseHandle(ClientToken);
DisconnectNamedPipe(SvcPipe);
FspServiceLog(EVENTLOG_WARNING_TYPE, LoopWarningMessage,
L"ImpersonateNamedPipeClient||OpenThreadToken", LastError);
continue;
}
else
{
CloseHandle(ClientToken);
DisconnectNamedPipe(SvcPipe);
FspServiceLog(EVENTLOG_ERROR_TYPE, LoopErrorMessage,
L"RevertToSelf", LastError);
break;
}
}
SvcPipeTransact(ClientToken, PipeBuf, &BytesTransferred);
CloseHandle(ClientToken);
LastError = SvcPipeWaitResult(
WriteFile(SvcPipe, PipeBuf, BytesTransferred, &BytesTransferred, &SvcOverlapped),
SvcEvent, SvcPipe, &SvcOverlapped, &BytesTransferred);
if (-1 == LastError)
break;
else if (0 != LastError)
{
DisconnectNamedPipe(SvcPipe);
FspServiceLog(EVENTLOG_WARNING_TYPE, LoopWarningMessage,
L"WriteFile", LastError);
continue;
}
DisconnectNamedPipe(SvcPipe);
}
exit:
MemFree(PipeBuf);
SvcInstanceStopAndWaitAll();
FspServiceStop(Service);
return 0;
}
static inline PWSTR SvcPipeTransactGetPart(PWSTR *PP, PWSTR PipeBufEnd)
{
PWSTR PipeBufBeg = *PP, P;
for (P = PipeBufBeg; PipeBufEnd > P && *P; P++)
;
if (PipeBufEnd > P)
{
*PP = P + 1;
return PipeBufBeg;
}
else
{
*PP = P;
return 0;
}
}
static inline VOID SvcPipeTransactResult(NTSTATUS Result, PWSTR PipeBuf, PULONG PSize)
{
if (NT_SUCCESS(Result))
{
*PipeBuf = LauncherSuccess;
*PSize += sizeof(WCHAR);
}
else
*PSize = (wsprintfW(PipeBuf, L"%c%ld", LauncherFailure, FspWin32FromNtStatus(Result)) + 1) *
sizeof(WCHAR);
}
static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
{
if (sizeof(WCHAR) > *PSize)
return;
PWSTR P = PipeBuf, PipeBufEnd = PipeBuf + *PSize / sizeof(WCHAR);
PWSTR ClassName, InstanceName;
ULONG Argc; PWSTR Argv[9];
NTSTATUS Result;
*PSize = 0;
switch (*P++)
{
case LauncherSvcInstanceStart:
ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd);
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
for (Argc = 0; sizeof Argv / sizeof Argv[0] > Argc; Argc++)
if (0 == (Argv[Argc] = SvcPipeTransactGetPart(&P, PipeBufEnd)))
break;
Result = STATUS_INVALID_PARAMETER;
if (0 != ClassName && 0 != InstanceName)
Result = SvcInstanceStart(ClientToken, ClassName, InstanceName, Argc, Argv, SvcJob);
SvcPipeTransactResult(Result, PipeBuf, PSize);
break;
case LauncherSvcInstanceStop:
ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd);
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
Result = STATUS_INVALID_PARAMETER;
if (0 != ClassName && 0 != InstanceName)
Result = SvcInstanceStop(ClientToken, ClassName, InstanceName);
SvcPipeTransactResult(Result, PipeBuf, PSize);
break;
case LauncherSvcInstanceInfo:
ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd);
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
Result = STATUS_INVALID_PARAMETER;
if (0 != ClassName && 0 != InstanceName)
{
*PSize = LAUNCHER_PIPE_BUFFER_SIZE - 1;
Result = SvcInstanceGetInfo(ClientToken, ClassName, InstanceName, PipeBuf + 1, PSize);
}
SvcPipeTransactResult(Result, PipeBuf, PSize);
break;
case LauncherSvcInstanceList:
*PSize = LAUNCHER_PIPE_BUFFER_SIZE - 1;
Result = SvcInstanceGetNameList(ClientToken, PipeBuf + 1, PSize);
SvcPipeTransactResult(Result, PipeBuf, PSize);
break;
#if !defined(NDEBUG)
case LauncherQuit:
SetEvent(SvcEvent);
SvcPipeTransactResult(STATUS_SUCCESS, PipeBuf, PSize);
break;
#endif
default:
SvcPipeTransactResult(STATUS_INVALID_PARAMETER, PipeBuf, PSize);
break;
}
}
int wmain(int argc, wchar_t **argv)
{
return FspServiceRun(L"" PROGNAME, SvcStart, SvcStop, 0);
}
void wmainCRTStartup(void)
{
extern HANDLE ProcessHeap;
ProcessHeap = GetProcessHeap();
if (0 == ProcessHeap)
ExitProcess(GetLastError());
ExitProcess(wmain(0, 0));
}
HANDLE ProcessHeap;

65
src/launcher/launcher.h Normal file
View File

@ -0,0 +1,65 @@
/**
* @file launcher/launcher.h
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#ifndef WINFSP_LAUNCHER_LAUNCHER_H_INCLUDED
#define WINFSP_LAUNCHER_LAUNCHER_H_INCLUDED
#include <winfsp/winfsp.h>
#include <shared/minimal.h>
#define LAUNCHER_STOP_TIMEOUT 5500
#define LAUNCHER_KILL_TIMEOUT 5000
#define LAUNCHER_PIPE_NAME "\\\\.\\pipe\\WinFsp.{14E7137D-22B4-437A-B0C1-D21D1BDF3767}"
#define LAUNCHER_PIPE_BUFFER_SIZE 2048
#define LAUNCHER_PIPE_DEFAULT_TIMEOUT 3000
/*
* The launcher named pipe SDDL gives full access to LocalSystem and Administrators and
* GENERIC_READ and FILE_WRITE_DATA access to Everyone. We are careful not to give the
* FILE_CREATE_PIPE_INSTANCE right to Everyone to disallow the creation of additional
* pipe instances.
*/
#define LAUNCHER_PIPE_SDDL "O:SYG:SYD:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRDCCR;;;WD)"
#define LAUNCHER_PIPE_OWNER ((PSID)WinLocalSystemSid)
/*
* The default service instance SDDL gives full access to LocalSystem and Administrators.
* The only possible service instance rights are as follows:
* RP SERVICE_START
* WP SERVICE_STOP
* LC SERVICE_QUERY_STATUS
*
* To create a service that can be started, stopped or queried by Everyone, you can set
* the following SDDL:
* D:P(A;;RPWPLC;;;WD)
*/
#define SVC_INSTANCE_DEFAULT_SDDL "D:P(A;;RPWPLC;;;SY)(A;;RPWPLC;;;BA)"
enum
{
LauncherSvcInstanceStart = 'S', /* requires: SERVICE_START */
LauncherSvcInstanceStop = 'T', /* requires: SERVICE_STOP */
LauncherSvcInstanceInfo = 'I', /* requires: SERVICE_QUERY_STATUS */
LauncherSvcInstanceList = 'L', /* requires: none*/
LauncherQuit = 'Q', /* DEBUG version only */
LauncherSuccess = '$',
LauncherFailure = '!',
};
#endif

87
src/shared/minimal.h Normal file
View File

@ -0,0 +1,87 @@
/**
* @file shared/minimal.h
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#ifndef WINFSP_SHARED_MINIMAL_H_INCLUDED
#define WINFSP_SHARED_MINIMAL_H_INCLUDED
/*
* Eliminate dependency on the MSVCRT libraries.
*
* For this to work the following project settings must be set:
* - "C/C++ > General > SDL checks" must be empty (not "Yes" or "No").
* - "C/C++ > Code Generation > Basic Runtime Checks" must be set to "Default"
* - "C/C++ > Code Generation > Security Check" must be disabled (/GS-).
* - "Linker > Input > Ignore All Default Libraries" must be "Yes".
*/
#undef RtlFillMemory
#undef RtlMoveMemory
NTSYSAPI VOID NTAPI RtlFillMemory(VOID *Destination, DWORD Length, BYTE Fill);
NTSYSAPI VOID NTAPI RtlMoveMemory(VOID *Destination, CONST VOID *Source, DWORD Length);
#pragma function(memcpy)
#pragma function(memset)
static inline
void *memcpy(void *dst, const void *src, size_t siz)
{
RtlMoveMemory(dst, src, (DWORD)siz);
return dst;
}
static inline
void *memset(void *dst, int val, size_t siz)
{
RtlFillMemory(dst, (DWORD)siz, val);
return dst;
}
static inline PVOID MemAlloc(SIZE_T Size)
{
extern HANDLE ProcessHeap;
return HeapAlloc(ProcessHeap, 0, Size);
}
static inline VOID MemFree(PVOID Pointer)
{
extern HANDLE ProcessHeap;
if (0 != Pointer)
HeapFree(ProcessHeap, 0, Pointer);
}
static FORCEINLINE
VOID InsertTailList(PLIST_ENTRY ListHead, PLIST_ENTRY Entry)
{
PLIST_ENTRY Blink;
Blink = ListHead->Blink;
Entry->Flink = ListHead;
Entry->Blink = Blink;
Blink->Flink = Entry;
ListHead->Blink = Entry;
}
static FORCEINLINE
BOOLEAN RemoveEntryList(PLIST_ENTRY Entry)
{
PLIST_ENTRY Blink;
PLIST_ENTRY Flink;
Flink = Entry->Flink;
Blink = Entry->Blink;
Blink->Flink = Flink;
Flink->Blink = Blink;
return Flink == Blink;
}
#endif

View File

@ -28,7 +28,7 @@
#pragma warning(disable:4100) /* unreferenced formal parameter */
#pragma warning(disable:4200) /* zero-sized array in struct/union */
#define DRIVER_NAME "WinFsp"
#define DRIVER_NAME FSP_FSCTL_DRIVER_NAME
/* IoCreateDeviceSecure default SDDL's */
#define FSP_FSCTL_DEVICE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;WD)"

37
src/sys/version.rc Normal file
View File

@ -0,0 +1,37 @@
#include <winver.h>
#define STR(x) STR_(x)
#define STR_(x) #x
VS_VERSION_INFO VERSIONINFO
FILEVERSION MyVersionWithCommas
PRODUCTVERSION MyVersionWithCommas
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0
#endif
FILEOS VOS_NT
FILETYPE VFT_DRV
FILESUBTYPE VFT2_DRV_SYSTEM
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", STR(MyCompanyName)
VALUE "FileDescription", STR(MyDescription)
VALUE "FileVersion", STR(MyVersion)
VALUE "InternalName", "winfsp.sys"
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "winfsp.sys"
VALUE "ProductName", STR(MyProductName)
VALUE "ProductVersion", STR(MyVersion)
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

View File

@ -693,7 +693,7 @@ NTSTATUS FspVolumeTransact(
if (0 == ProcessIrp)
{
/* either IRP was canceled or a bogus Hint was provided */
DEBUGLOG("BOGUS(Kind=%d, Hint=%p)", Response->Kind, (PVOID)Response->Hint);
DEBUGLOG("BOGUS(Kind=%d, Hint=%p)", Response->Kind, (PVOID)(UINT_PTR)Response->Hint);
Response = NextResponse;
continue;
}

View File

@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFOzCCAyOgAwIBAgIKYSBNtAAAAAAAJzANBgkqhkiG9w0BAQUFADB/MQswCQYD
VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe
MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQDEyBNaWNyb3Nv
ZnQgQ29kZSBWZXJpZmljYXRpb24gUm9vdDAeFw0xMTA0MTUxOTQ1MzNaFw0yMTA0
MTUxOTU1MzNaMGwxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx
GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xKzApBgNVBAMTIkRpZ2lDZXJ0IEhp
Z2ggQXNzdXJhbmNlIEVWIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDGzOVz5vvUu+UtLTKm3+WBP8nNJUm2cSrD1ZQ0Z6IKHLBfaaZAscS3
so/QmKSpQVk609yU1jzbdDikSsxNJYL3SqVTEjju80ltcZF+Y7arpl/DpIT4T2JR
vvjF7Ns4kuMG5QiRDMQoQVX7y1qJFX5x6DW/TXIJPb46OFBbdzEbjbPHJEWap6xt
ABRaBLe6E+tRCphBQSJOZWGHgUFQpnlcid4ZSlfVLuZdHFMsfpjNGgYWpGhz0DQE
E1yhcdNafFXbXmThN4cwVgTlEbQpgBLxeTmIogIRfCdmt4i3ePLKCqg4qwpkwr9m
XZWEwaElHoddGlALIBLMQbtuC1E4uEvLAgMBAAGjgcswgcgwEQYDVR0gBAowCDAG
BgRVHSAAMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSx
PsNpA/i/RwHUmCYaCALvY2QrwzAfBgNVHSMEGDAWgBRi+wohW39DbhHaCVRQa/XS
lnHxnjBVBgNVHR8ETjBMMEqgSKBGhkRodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
cGtpL2NybC9wcm9kdWN0cy9NaWNyb3NvZnRDb2RlVmVyaWZSb290LmNybDANBgkq
hkiG9w0BAQUFAAOCAgEAIIzBWe1vnGstwUo+dR1FTEFQHL2A6tmwkosGKhM/Uxae
VjlqimO2eCR59X24uUehCpbC9su9omafBuGs0nkJDv083KwCDHCvPxvseH7U60sF
YCbZc2GRIe2waGPglxKrb6AS7dmf0tonPLPkVvnR1IEPcb1CfKaJ3M3VvZWiq/GT
EX3orDEpqF1mcEGd/HXJ1bMaOSrQhQVQi6yRysSTy3GlnaSUb1gM+m4gxAgxtYWd
foH50j3KWxiFbAqG7CIJG6V0NE9/KLyVSqsdtpiwXQmkd3Z+76eOXYT2GCTL0W2m
w6GcwhB1gP+dMv3mz0M6gvfOj+FyKptit1/tlRo5XC+UbUi3AV8zL7vcLXM0iQRC
ChyLefmj+hfv+qEaEN/gssGV61wMBZc7NT4YiE3bbL8kiY3Ivdifezk6JKDV39Hz
ShqX9qZveh+wkKmzrAE5kdNht2TxPlc4A6/OetK1kPWu3DmZ1bY8l+2myxbHfWsq
TJCU5kxU/R7NIOzOaJyHWOlhYL7rDsnVGX2f6Xi9DqwhdQePqW7gjGoqa5zj52W8
vC08bdwE3GdFNjKvBIG8qABuYUyVxVzUjo6fL8EydL29EWUDB83vt14CV9qG1Boo
NK+ISbLPpd2CVm9oqhTiWVT+/+ru7+qScCJggeMlI8CfzA9JsjWqWMM6w9kWlBA=
-----END CERTIFICATE-----

29
tools/build.bat Normal file
View File

@ -0,0 +1,29 @@
@echo off
set Configuration=Release
set MsiName="WinFsp - Windows File System Proxy"
set CrossCert="%~dp0DigiCert High Assurance EV Root CA.crt"
set Issuer="DigiCert"
set Subject="Navimatics Corporation"
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat"
if not X%1==X set Configuration=%1
cd %~dp0..\build\VStudio
if exist build\ del /s/q build >nul
devenv winfsp.sln /build "%Configuration%|x64"
devenv winfsp.sln /build "%Configuration%|x86"
for %%f in (build\%Configuration%\winfsp-x64.sys build\%Configuration%\winfsp-x86.sys) do (
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com %%f
signtool sign /as /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 %%f
)
devenv winfsp.sln /build "Installer.%Configuration%|x86"
for %%f in (build\%Configuration%\winfsp-*.msi) do (
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com /d %MsiName% %%f
REM signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 /d %MsiName% %%f
)

192
tst/memfs/memfs-main-old.c Normal file
View File

@ -0,0 +1,192 @@
/**
* @file memfs-main-old.c
*
* This file serves as an example that it is possible to create
* a WinFsp file system without using the FspService framework.
*
* Please note that this file is no longer maintained.
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <winfsp/winfsp.h>
#include "memfs.h"
#define PROGNAME "memfs"
static void vwarn(const char *format, va_list ap)
{
char buf[1024];
/* wvsprintf is only safe with a 1024 byte buffer */
DWORD BytesTransferred;
wvsprintfA(buf, format, ap);
buf[sizeof buf - 1] = '\0';
WriteFile(GetStdHandle(STD_ERROR_HANDLE),
buf, (DWORD)strlen(buf),
&BytesTransferred, 0);
WriteFile(GetStdHandle(STD_ERROR_HANDLE),
"\n", 1,
&BytesTransferred, 0);
}
static void warn(const char *format, ...)
{
va_list ap;
va_start(ap, format);
vwarn(format, ap);
va_end(ap);
}
static void fail(const char *format, ...)
{
va_list ap;
va_start(ap, format);
vwarn(format, ap);
va_end(ap);
exit(1);
}
static void usage(void)
{
static char usage[] = ""
"usage: %s OPTIONS\n"
"\n"
"options:\n"
" -t FileInfoTimeout [millis]\n"
" -n MaxFileNodes\n"
" -s MaxFileSize [bytes]\n"
" -S RootSddl [file rights: FA, etc; NO generic rights: GA, etc.]\n"
" -u \\Server\\Share [UNC prefix (single backslash)]\n"
" -m MountPoint [X:]\n";
warn(usage, PROGNAME);
exit(2);
}
static ULONG argtol(wchar_t **argp, ULONG deflt)
{
if (0 == argp[0])
usage();
wchar_t *endp;
ULONG ul = wcstol(argp[0], &endp, 10);
return L'\0' != argp[0][0] && L'\0' == *endp ? ul : deflt;
}
static wchar_t *argtos(wchar_t **argp)
{
if (0 == argp[0])
usage();
return argp[0];
}
static HANDLE MainEvent;
static BOOL WINAPI ConsoleCtrlHandler(DWORD CtrlType)
{
SetEvent(MainEvent);
return TRUE;
}
int wmain(int argc, wchar_t **argv)
{
wchar_t **argp;
NTSTATUS Result;
MEMFS *Memfs;
ULONG Flags = MemfsDisk;
ULONG FileInfoTimeout = INFINITE;
ULONG MaxFileNodes = 1024;
ULONG MaxFileSize = 16 * 1024 * 1024;
PWSTR MountPoint = 0;
PWSTR VolumePrefix = 0;
PWSTR RootSddl = 0;
for (argp = argv + 1; 0 != argp[0]; argp++)
{
if (L'-' != argp[0][0])
break;
switch (argp[0][1])
{
case L'?':
usage();
break;
case L'm':
MountPoint = argtos(++argp);
break;
case L'n':
MaxFileNodes = argtol(++argp, MaxFileNodes);
break;
case L'S':
RootSddl = argtos(++argp);
break;
case L's':
MaxFileSize = argtol(++argp, MaxFileSize);
break;
case L't':
FileInfoTimeout = argtol(++argp, FileInfoTimeout);
break;
case L'u':
VolumePrefix = argtos(++argp);
Flags = MemfsNet;
break;
default:
usage();
break;
}
}
if (0 != argp[0])
usage();
MainEvent = CreateEvent(0, TRUE, FALSE, 0);
if (0 == MainEvent)
fail("error: cannot create MainEvent");
Result = MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl,
&Memfs);
if (!NT_SUCCESS(Result))
fail("error: cannot create MEMFS");
Result = MemfsStart(Memfs);
if (!NT_SUCCESS(Result))
fail("error: cannot start MEMFS");
Result = FspFileSystemSetMountPoint(MemfsFileSystem(Memfs), MountPoint);
if (!NT_SUCCESS(Result))
fail("error: cannot mount MEMFS");
MountPoint = FspFileSystemMountPoint(MemfsFileSystem(Memfs));
warn("%s -t %ld -n %ld -s %ld%s%S%s%S -m %S",
PROGNAME, FileInfoTimeout, MaxFileNodes, MaxFileSize,
RootSddl ? " -S " : "", RootSddl ? RootSddl : L"",
VolumePrefix ? " -u " : "", VolumePrefix ? VolumePrefix : L"",
MountPoint);
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
if (WAIT_OBJECT_0 != WaitForSingleObject(MainEvent, INFINITE))
fail("error: cannot wait on MainEvent");
FspFileSystemRemoveMountPoint(MemfsFileSystem(Memfs));
MemfsStop(Memfs);
MemfsDelete(Memfs);
/* the OS will handle this! */
// CloseHandle(MainEvent);
// MainEvent = 0;
return 0;
}

View File

@ -20,46 +20,116 @@
#define PROGNAME "memfs"
static void vwarn(const char *format, va_list ap)
#define info(format, ...) FspServiceLog(EVENTLOG_INFORMATION_TYPE, format, __VA_ARGS__)
#define warn(format, ...) FspServiceLog(EVENTLOG_WARNING_TYPE, format, __VA_ARGS__)
#define fail(format, ...) FspServiceLog(EVENTLOG_ERROR_TYPE, format, __VA_ARGS__)
#define argtos(v) if (arge > ++argp) v = *argp; else goto usage
#define argtol(v) if (arge > ++argp) v = wcstol_deflt(*argp, v); else goto usage
static ULONG wcstol_deflt(wchar_t *w, ULONG deflt)
{
char buf[1024];
/* wvsprintf is only safe with a 1024 byte buffer */
DWORD BytesTransferred;
wvsprintfA(buf, format, ap);
buf[sizeof buf - 1] = '\0';
WriteFile(GetStdHandle(STD_ERROR_HANDLE),
buf, (DWORD)strlen(buf),
&BytesTransferred, 0);
WriteFile(GetStdHandle(STD_ERROR_HANDLE),
"\n", 1,
&BytesTransferred, 0);
wchar_t *endp;
ULONG ul = wcstol(w, &endp, 10);
return L'\0' != w[0] && L'\0' == *endp ? ul : deflt;
}
static void warn(const char *format, ...)
NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
{
va_list ap;
wchar_t **argp, **arge;
ULONG Flags = MemfsDisk;
ULONG FileInfoTimeout = INFINITE;
ULONG MaxFileNodes = 1024;
ULONG MaxFileSize = 16 * 1024 * 1024;
PWSTR MountPoint = 0;
PWSTR VolumePrefix = 0;
PWSTR RootSddl = 0;
MEMFS *Memfs = 0;
NTSTATUS Result;
va_start(ap, format);
vwarn(format, ap);
va_end(ap);
for (argp = argv + 1, arge = argv + argc; arge > argp; argp++)
{
if (L'-' != argp[0][0])
break;
switch (argp[0][1])
{
case L'?':
goto usage;
case L'm':
argtos(MountPoint);
break;
case L'n':
argtol(MaxFileNodes);
break;
case L'S':
argtos(RootSddl);
break;
case L's':
argtol(MaxFileSize);
break;
case L't':
argtol(FileInfoTimeout);
break;
case L'u':
argtos(VolumePrefix);
Flags = MemfsNet;
break;
default:
goto usage;
}
}
static void fail(const char *format, ...)
if (arge > argp)
goto usage;
if (MemfsDisk == Flags && 0 == MountPoint)
goto usage;
Result = MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl,
&Memfs);
if (!NT_SUCCESS(Result))
{
va_list ap;
va_start(ap, format);
vwarn(format, ap);
va_end(ap);
exit(1);
fail(L"cannot create MEMFS");
goto exit;
}
static void usage(void)
if (0 != MountPoint && L'\0' != MountPoint[0])
{
static char usage[] = ""
Result = FspFileSystemSetMountPoint(MemfsFileSystem(Memfs),
L'*' == MountPoint[0] && L'\0' == MountPoint[1] ? 0 : MountPoint);
if (!NT_SUCCESS(Result))
{
fail(L"cannot mount MEMFS");
goto exit;
}
}
Result = MemfsStart(Memfs);
if (!NT_SUCCESS(Result))
{
fail(L"cannot start MEMFS");
goto exit;
}
MountPoint = FspFileSystemMountPoint(MemfsFileSystem(Memfs));
info(L"%s -t %ld -n %ld -s %ld%s%s%s%s%s%s",
L"" PROGNAME, FileInfoTimeout, MaxFileNodes, MaxFileSize,
RootSddl ? L" -S " : L"", RootSddl ? RootSddl : L"",
VolumePrefix ? L" -u " : L"", VolumePrefix ? VolumePrefix : L"",
MountPoint ? L" -m " : L"", MountPoint ? MountPoint : L"");
Service->UserContext = Memfs;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result) && 0 != Memfs)
MemfsDelete(Memfs);
return Result;
usage:
static wchar_t usage[] = L""
"usage: %s OPTIONS\n"
"\n"
"options:\n"
@ -68,120 +138,24 @@ static void usage(void)
" -s MaxFileSize [bytes]\n"
" -S RootSddl [file rights: FA, etc; NO generic rights: GA, etc.]\n"
" -u \\Server\\Share [UNC prefix (single backslash)]\n"
" -m MountPoint [X:]\n";
" -m MountPoint [X:|* (required if no UNC prefix)]\n";
warn(usage, PROGNAME);
exit(2);
fail(usage, L"" PROGNAME);
return STATUS_UNSUCCESSFUL;
}
static ULONG argtol(wchar_t **argp, ULONG deflt)
NTSTATUS SvcStop(FSP_SERVICE *Service)
{
if (0 == argp[0])
usage();
MEMFS *Memfs = Service->UserContext;
wchar_t *endp;
ULONG ul = wcstol(argp[0], &endp, 10);
return L'\0' != argp[0][0] && L'\0' == *endp ? ul : deflt;
}
MemfsStop(Memfs);
MemfsDelete(Memfs);
static wchar_t *argtos(wchar_t **argp)
{
if (0 == argp[0])
usage();
return argp[0];
}
static HANDLE MainEvent;
static BOOL WINAPI ConsoleCtrlHandler(DWORD CtrlType)
{
SetEvent(MainEvent);
return TRUE;
return STATUS_SUCCESS;
}
int wmain(int argc, wchar_t **argv)
{
wchar_t **argp;
NTSTATUS Result;
MEMFS *Memfs;
ULONG Flags = MemfsDisk;
ULONG FileInfoTimeout = INFINITE;
ULONG MaxFileNodes = 1024;
ULONG MaxFileSize = 16 * 1024 * 1024;
PWSTR MountPoint = 0;
PWSTR VolumePrefix = 0;
PWSTR RootSddl = 0;
for (argp = argv + 1; 0 != argp[0]; argp++)
{
if (L'-' != argp[0][0])
break;
switch (argp[0][1])
{
case L'?':
usage();
break;
case L'm':
MountPoint = argtos(++argp);
break;
case L'n':
MaxFileNodes = argtol(++argp, MaxFileNodes);
break;
case L'S':
RootSddl = argtos(++argp);
break;
case L's':
MaxFileSize = argtol(++argp, MaxFileSize);
break;
case L't':
FileInfoTimeout = argtol(++argp, FileInfoTimeout);
break;
case L'u':
VolumePrefix = argtos(++argp);
Flags = MemfsNet;
break;
default:
usage();
break;
}
}
if (0 != argp[0])
usage();
MainEvent = CreateEvent(0, TRUE, FALSE, 0);
if (0 == MainEvent)
fail("error: cannot create MainEvent");
Result = MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl,
&Memfs);
if (!NT_SUCCESS(Result))
fail("error: cannot create MEMFS");
Result = MemfsStart(Memfs);
if (!NT_SUCCESS(Result))
fail("error: cannot start MEMFS");
Result = FspFileSystemSetMountPoint(MemfsFileSystem(Memfs), MountPoint);
if (!NT_SUCCESS(Result))
fail("error: cannot mount MEMFS");
MountPoint = FspFileSystemMountPoint(MemfsFileSystem(Memfs));
warn("%s -t %ld -n %ld -s %ld%s%S%s%S -m %S",
PROGNAME, FileInfoTimeout, MaxFileNodes, MaxFileSize,
RootSddl ? " -S " : "", RootSddl ? RootSddl : L"",
VolumePrefix ? " -u " : "", VolumePrefix ? VolumePrefix : L"",
MountPoint);
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
if (WAIT_OBJECT_0 != WaitForSingleObject(MainEvent, INFINITE))
fail("error: cannot wait on MainEvent");
FspFileSystemRemoveMountPoint(MemfsFileSystem(Memfs));
MemfsStop(Memfs);
MemfsDelete(Memfs);
/* the OS will handle this! */
// CloseHandle(MainEvent);
// MainEvent = 0;
return 0;
return FspServiceRun(L"" PROGNAME, SvcStart, SvcStop, 0);
}

View File

@ -1,5 +1,5 @@
/**
* @file memfs.c
* @file memfs.cpp
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
@ -396,7 +396,7 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
FileNode->FileInfo.AllocationSize = AllocationSize;
if (0 != FileNode->FileInfo.AllocationSize)
{
FileNode->FileData = malloc(FileNode->FileInfo.AllocationSize);
FileNode->FileData = malloc((size_t)FileNode->FileInfo.AllocationSize);
if (0 == FileNode->FileData)
{
MemfsFileNodeDelete(FileNode);
@ -507,7 +507,7 @@ static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem,
if (EndOffset > FileNode->FileInfo.FileSize)
EndOffset = FileNode->FileInfo.FileSize;
memcpy(Buffer, (PUINT8)FileNode->FileData + Offset, EndOffset - Offset);
memcpy(Buffer, (PUINT8)FileNode->FileData + Offset, (size_t)(EndOffset - Offset));
*PBytesTransferred = (ULONG)(EndOffset - Offset);
@ -555,7 +555,7 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
SetFileSize(FileSystem, Request, FileNode, EndOffset, FileInfo);
}
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, EndOffset - Offset);
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset));
*PBytesTransferred = (ULONG)(EndOffset - Offset);
*FileInfo = FileNode->FileInfo;
@ -619,7 +619,7 @@ static NTSTATUS SetAllocationSize(FSP_FILE_SYSTEM *FileSystem,
if (AllocationSize > Memfs->MaxFileSize)
return STATUS_DISK_FULL;
FileData = realloc(FileNode->FileData, AllocationSize);
FileData = realloc(FileNode->FileData, (size_t)AllocationSize);
if (0 == FileData)
return STATUS_INSUFFICIENT_RESOURCES;
@ -656,7 +656,7 @@ static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
if (FileNode->FileInfo.FileSize < FileSize)
memset((PUINT8)FileNode->FileData + FileNode->FileInfo.FileSize, 0,
FileSize - FileNode->FileInfo.FileSize);
(size_t)(FileSize - FileNode->FileInfo.FileSize));
FileNode->FileInfo.FileSize = FileSize;
}

View File

@ -0,0 +1,16 @@
#include <winfsp/winfsp.h>
#include <tlib/testsuite.h>
void eventlog_test(void)
{
/* this is not a real test! */
FspEventLog(EVENTLOG_INFORMATION_TYPE, L"EventLog %s message", L"informational");
FspEventLog(EVENTLOG_WARNING_TYPE, L"EventLog %s message", L"warning");
FspEventLog(EVENTLOG_ERROR_TYPE, L"EventLog %s message", L"error");
}
void eventlog_tests(void)
{
TEST_OPT(eventlog_test);
}

View File

@ -6,6 +6,7 @@ int WinFspNetTests = 1;
int main(int argc, char *argv[])
{
TESTSUITE(eventlog_tests);
TESTSUITE(path_tests);
TESTSUITE(mount_tests);
TESTSUITE(timeout_tests);