mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-02 17:02:57 -05:00
Compare commits
336 Commits
Author | SHA1 | Date | |
---|---|---|---|
858df29ba2 | |||
4366866653 | |||
e4b808806c | |||
13cee6e019 | |||
35b9cb15a3 | |||
0d8f0f9ac8 | |||
a4e2ad9dd6 | |||
9b4318c655 | |||
5827b1fa9c | |||
913f7ac9cd | |||
0e2f46dc90 | |||
e7cba96c74 | |||
03db443406 | |||
0b65bc7e01 | |||
12e1caaa98 | |||
7a690a789b | |||
8ca419830c | |||
c310d8ea1b | |||
c3ddf73661 | |||
6b00b8e28a | |||
35c722e91b | |||
ae8802514b | |||
e90aa46a27 | |||
760cd5e46f | |||
b36b6c60e2 | |||
e4984bf675 | |||
0c8bcd5d7d | |||
b5d8cd3ea6 | |||
af5f409233 | |||
cffb066d46 | |||
804434d836 | |||
f7595e40b6 | |||
669dd07ce2 | |||
b6fa54d301 | |||
342e7e39e2 | |||
9dfdd19616 | |||
2c651b1bd8 | |||
41764f7b41 | |||
08e697c52c | |||
66cc043149 | |||
518cd0e8c0 | |||
c0344f53b0 | |||
76445a5403 | |||
0577b8febb | |||
610a7ac2a6 | |||
e33fda4d00 | |||
2151e193dc | |||
ccfaf04f76 | |||
7e8d9fb986 | |||
37b6936ad0 | |||
3683afe203 | |||
a3cfc84007 | |||
ee5c584614 | |||
b8b15e8035 | |||
3db09be764 | |||
f2a0eb544e | |||
8c1c407b34 | |||
8dc4225ea1 | |||
ed0b83c84d | |||
71c68d1e17 | |||
053a5f1e4b | |||
e5d7f4ee9a | |||
d6fb076cad | |||
698b711df4 | |||
842f649f06 | |||
b062df9c42 | |||
f0385e3c7d | |||
10ce221fcc | |||
3f3092bdae | |||
29496a35be | |||
99a1e331b5 | |||
68d79b0c3b | |||
b695ef8ad8 | |||
b8ec5ba019 | |||
958f694b6f | |||
e227ae5751 | |||
007ec8f360 | |||
00976b92b8 | |||
9b56b3a420 | |||
adecc6fb25 | |||
b71d086ea7 | |||
382a6675da | |||
cbf8079324 | |||
1124e24a61 | |||
c6bab18947 | |||
3310a4300e | |||
6347803392 | |||
259bd84cc9 | |||
6bc3ec7c8a | |||
cf66fc3931 | |||
8a5218b273 | |||
e3ffa209eb | |||
a8f0f58d35 | |||
beeae73c79 | |||
2aa683177e | |||
0437218691 | |||
8a37cb9c36 | |||
32912b587f | |||
fb6a139c85 | |||
267ed97d36 | |||
53289f0c74 | |||
a4f687c635 | |||
55336e3dcf | |||
90d868c58f | |||
e0386db270 | |||
3490a379b0 | |||
009728e2b7 | |||
240bdfeb39 | |||
ea8ed690f6 | |||
a94d41c6b4 | |||
662df6544f | |||
15363e0256 | |||
c74f34eaf0 | |||
bc777f2d91 | |||
a9868ba883 | |||
9d42c625cc | |||
afc498ba6e | |||
e222c3ae72 | |||
90039ecd72 | |||
8f0f5b3d9e | |||
0e8d694bdd | |||
b0b15dff05 | |||
0f63dddb32 | |||
20fc185530 | |||
6b99160625 | |||
1a406eb462 | |||
70d5c095ca | |||
396997fb22 | |||
8c8d80add3 | |||
6bef445102 | |||
9edbe7012e | |||
bc5f5c02db | |||
326d6479ad | |||
54d343c4e4 | |||
96e048ec5e | |||
c46d8b2e0a | |||
bcfa4a326b | |||
b451219bfc | |||
3286033191 | |||
1432d711d8 | |||
0d4aa15377 | |||
7fbaa8d37c | |||
229c3f81fa | |||
9ccb394b04 | |||
22da074ff7 | |||
e08b462566 | |||
77e7147893 | |||
7d4fc0f740 | |||
f0751f1fb3 | |||
4e2aaa8a21 | |||
8525c99d7a | |||
9b93c766c3 | |||
7fef1b87f6 | |||
190e2320c0 | |||
6910b67982 | |||
7e1906bad5 | |||
dddb55243b | |||
88b13082cb | |||
6d5abafdaa | |||
3f8e7273c3 | |||
8b8c567cf7 | |||
da95f05b29 | |||
a53e79984a | |||
59a305b333 | |||
3620de44d1 | |||
3f3c02f3ce | |||
4b9945d9bf | |||
19d400d251 | |||
b559c7405f | |||
765bb1e1a3 | |||
300ce8485b | |||
4a4dab14c5 | |||
fd8a3ab786 | |||
b7665478d9 | |||
a938cb4fe6 | |||
d12a256430 | |||
bcbba3e4cf | |||
10c3f6f507 | |||
ead273ae18 | |||
74a943d8d7 | |||
a40e7d8c56 | |||
187311bb5e | |||
e14a26b540 | |||
4850056bf6 | |||
3d3dcbe0c5 | |||
7ea13a967a | |||
c851e9c98e | |||
9e068049b3 | |||
f993cf7251 | |||
e8f35ac314 | |||
4d57a5c10e | |||
7db0f68dd7 | |||
1f22bd3517 | |||
91825106f1 | |||
9bceb577e3 | |||
2155cbadc3 | |||
71867f6779 | |||
214b43398f | |||
aa75d412ac | |||
6be55aa515 | |||
10c997ab6b | |||
1505b1f368 | |||
b004268583 | |||
301e8fed62 | |||
c2e38bcc97 | |||
37b1dc440e | |||
c4b6e9bb47 | |||
55f9053b1b | |||
a53abe8ab6 | |||
5fa7ba3513 | |||
7e2c767997 | |||
d102edf1e9 | |||
0412fac588 | |||
3935372956 | |||
d89baea193 | |||
599430e649 | |||
4f5e00474e | |||
16836c7cfb | |||
ffded63c56 | |||
0dba3ffe55 | |||
122592f332 | |||
c4421bf3aa | |||
222f015273 | |||
153eb42885 | |||
4d1aeeda4c | |||
f2241fcee4 | |||
f7adbaba92 | |||
fea92c4ae0 | |||
1e2f0930a2 | |||
ab11ff2b39 | |||
1e1b9cdda3 | |||
00ee25f904 | |||
cf29bd5a58 | |||
597dd43f23 | |||
1c3fc530f6 | |||
67c6cd453a | |||
7eec1649a4 | |||
9971472be7 | |||
c1985bef6c | |||
e4e2465bcb | |||
22d1f86ac1 | |||
1a7d3b8f9e | |||
768a393342 | |||
08a02d7b35 | |||
3035ba2847 | |||
147c90be9f | |||
0822458238 | |||
c322a4b14a | |||
0c6300b97c | |||
be952729c9 | |||
1802ac8878 | |||
5491187e1d | |||
ec2494433b | |||
0756649572 | |||
8ccd44a1f7 | |||
2c51251cb7 | |||
35d2b3f626 | |||
26a9bb714b | |||
13f2517a31 | |||
da85f2aa08 | |||
22c324de69 | |||
c42e2a5958 | |||
1c587dbcb7 | |||
bc2e87763e | |||
724d177d0b | |||
6971f4d6ae | |||
ceef2bf55e | |||
a81a766bbe | |||
da839e39b8 | |||
ec21e830f1 | |||
9ae28a5529 | |||
1a14971911 | |||
ab48beb4ba | |||
528cbd3295 | |||
c32d05c3b6 | |||
e82b06ae49 | |||
457e151fa5 | |||
dc4109fc22 | |||
2a69ad6710 | |||
d3ff12bf60 | |||
713ee8a917 | |||
f4744258a7 | |||
7e57edf72e | |||
89e4e8a96c | |||
0c18b82cc2 | |||
57f9db6cc0 | |||
6da81be792 | |||
b77a749f93 | |||
bb946d5a3a | |||
27a16e5c54 | |||
789222af68 | |||
587fee93e9 | |||
077bbb0d65 | |||
3d2a2dd90d | |||
0b1bba36f8 | |||
8dd5a03b51 | |||
ac2e9f9882 | |||
1017e7fda7 | |||
125b612c9f | |||
9addfa5899 | |||
12db7cf9dc | |||
e53e915a72 | |||
d7a6f33d26 | |||
de973fa5ab | |||
4a4fba4670 | |||
e45ac30b65 | |||
cbb7d943bd | |||
df5d2d6e87 | |||
b1b31b9017 | |||
ff0b8bc3fe | |||
a99e8ac9d2 | |||
3f7ebe7996 | |||
030ef84c2e | |||
ba5c670034 | |||
690e7662d6 | |||
500db7b1cd | |||
e43c5091e4 | |||
9ffc3f03ed | |||
14366f76c5 | |||
b089b98afc | |||
26aadb0b72 | |||
9c11ca5bda | |||
8ae2bb3bfc | |||
b0a2e4ff40 | |||
0c75b58810 | |||
b12e0aad47 | |||
1264cae110 | |||
5a7c7bb4f2 | |||
acfd02c31d | |||
efa200aac4 | |||
3a1cba2442 | |||
59698f5517 | |||
1176114528 | |||
e0dde7349e | |||
1bdfc8a579 | |||
2659effafb |
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "ext/test"]
|
||||
path = ext/test
|
||||
url = https://bitbucket.org/billziss/secfs.test.git
|
60
README.md
60
README.md
@ -1,5 +1,7 @@
|
||||
# WinFsp - Windows File System Proxy
|
||||
|
||||

|
||||
|
||||
WinFsp is a set of software components for Windows computers that allows the creation of user mode file systems. In this sense it is similar to FUSE (Filesystem in Userspace), which provides the same functionality on UNIX-like computers.
|
||||
|
||||
Some of the benefits and features of using WinFsp are listed below:
|
||||
@ -20,19 +22,55 @@ WinFsp consists of a kernel mode FSD (File System Driver) and a user mode DLL (D
|
||||
|
||||
The project source code is organized as follows:
|
||||
|
||||
* build/VStudio: contains the WinFsp solution and project files.
|
||||
* doc: contains the WinFsp license, contributor agreement and additional documentation. The WinFsp design document can be found here.
|
||||
* ext/tlib: contains a small test library originally from the secfs (Secure Cloud File System) project.
|
||||
* inc/winfsp: contains public include files to be used when developing a user mode file system.
|
||||
* src/dll: contains the source code to the WinFsp DLL.
|
||||
* src/sys: contains the source code to the WinFsp FSD.
|
||||
* tst/memfs: contains the source code to an example file system written in C++ (memfs).
|
||||
* tst/winfsp-tests: contains the WinFsp test suite.
|
||||
* build/VStudio: WinFsp solution and project files.
|
||||
* doc: WinFsp license, contributor agreement and additional documentation. The WinFsp design documents can be found here.
|
||||
* ext/tlib: A small test library originally from the secfs (Secure Cloud File System) project.
|
||||
* ext/test: Submodule pointing to the secfs.test project, which contains a number of tools for testing Windows and POSIX file systems.
|
||||
* inc/winfsp: Public headers for the WinFsp API.
|
||||
* inc/fuse: Public headers for the FUSE compatibility layer.
|
||||
* src/dll: Source code to the WinFsp DLL.
|
||||
* src/dll/fuse: Source code to the FUSE compatibility layer.
|
||||
* src/launcher: Source code to the launcher service and the launchctl utility.
|
||||
* src/sys: Source code to the WinFsp FSD.
|
||||
* opt/cygfuse: Source code for the Cygwin FUSE package.
|
||||
* tst/memfs: Source code to an example file system written in C++ (memfs).
|
||||
* tst/winfsp-tests: WinFsp test suite.
|
||||
|
||||
## Building
|
||||
## Building and Running
|
||||
|
||||
In order to build WinFsp you will need Windows 10 and Visual Studio 2015. You will also need the Windows Driver Kit (WDK) 10.
|
||||
In order to build WinFsp you will need the following:
|
||||
|
||||
* Windows 10
|
||||
* Visual Studio 2015
|
||||
* Windows Driver Kit (WDK) 10
|
||||
* [Wix toolset](http://wixtoolset.org)
|
||||
|
||||
If you build the driver yourself it will not be signed and Windows will refuse to load it unless you enable "testsigning". You can enable "testsigning" using the command `bcdedit.exe -set testsigning`. For more information see this [document](http://www.secfs.net/winfsp/develop/debug/).
|
||||
|
||||
WinFsp is designed to run on Vista and above. It has been tested on the following platforms so far:
|
||||
|
||||
* Windows 7 Enterprise
|
||||
* Windows 8 Pro
|
||||
* Windows 10 Pro
|
||||
* Windows Server 2012
|
||||
|
||||
## How to Help
|
||||
|
||||
I am looking for help in the following areas:
|
||||
|
||||
* If you have a file system that runs on FUSE please consider porting it to WinFsp. WinFsp has a native API, but it also has a FUSE (high-level) API.
|
||||
* If you are working with a language other than C/C++ (e.g. Delphi, C#, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you.
|
||||
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues) ~~[BitBucket repository](https://bitbucket.org/billziss/winfsp/issues?status=new&status=open)~~. Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart. If you decide to tackle any of those please coordinate with me as I am actively working on that issue list.
|
||||
|
||||
In all cases I can provide ideas and/or support.
|
||||
|
||||
## Where to Discuss
|
||||
|
||||
If you wish to discuss WinFsp there are now two options:
|
||||
|
||||
- [WinFsp Google Group](https://groups.google.com/forum/#!forum/winfsp)
|
||||
- [Author's Twitter](https://twitter.com/BZissimopoulos)
|
||||
|
||||
## License
|
||||
|
||||
WinFsp is available under the [AGPLv3](http://www.gnu.org/licenses/agpl-3.0.html) license. If you find the constraints of the AGPLv3 too onerous, a commercial license is also available. Please contact Bill Zissimopoulos <billziss at navimatics.com> for more details.
|
||||
WinFsp is available under the [AGPLv3](http://www.gnu.org/licenses/agpl-3.0.html) license. If you find the constraints of the AGPLv3 too onerous, a commercial license is also available. Please contact Bill Zissimopoulos <billziss at navimatics.com> for more details.
|
||||
|
23
appveyor.yml
Normal file
23
appveyor.yml
Normal file
@ -0,0 +1,23 @@
|
||||
version: '{build}'
|
||||
|
||||
environment:
|
||||
CONFIGURATION: Release
|
||||
|
||||
install:
|
||||
- git submodule update --init --recursive
|
||||
- appveyor AddMessage "Change boot configuration and reboot" -Category Information
|
||||
- verifier /standard /driver winfsp-x64.sys
|
||||
- bcdedit /set testsigning on
|
||||
- ps: Restart-Computer -Force
|
||||
- ps: Start-Sleep -s 10
|
||||
|
||||
build_script:
|
||||
- appveyor AddMessage "Reboot complete" -Category Information
|
||||
- bcdedit | findstr /i "testsigning"
|
||||
- tools\build.bat %CONFIGURATION%
|
||||
|
||||
test_script:
|
||||
- for %%f in ("build\VStudio\build\%CONFIGURATION%\winfsp-*.msi") do start /wait msiexec /i %%f /qn INSTALLLEVEL=1000
|
||||
- tools\nmake-ext-test.bat %CONFIGURATION%
|
||||
- tools\run-tests.bat %CONFIGURATION%
|
||||
- verifier /query
|
BIN
art/winfsp-outln.afdesign
Normal file
BIN
art/winfsp-outln.afdesign
Normal file
Binary file not shown.
BIN
art/winfsp-solid.afdesign
Normal file
BIN
art/winfsp-solid.afdesign
Normal file
Binary file not shown.
BIN
art/winfsp-solid.png
Normal file
BIN
art/winfsp-solid.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
art/wixbanner.pxm
Normal file
BIN
art/wixbanner.pxm
Normal file
Binary file not shown.
BIN
art/wixdialog.pxm
Normal file
BIN
art/wixdialog.pxm
Normal file
Binary file not shown.
83
build/VStudio/installer/CustomActions/CustomActions.cpp
Normal file
83
build/VStudio/installer/CustomActions/CustomActions.cpp
Normal 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;
|
||||
}
|
2
build/VStudio/installer/CustomActions/CustomActions.def
Normal file
2
build/VStudio/installer/CustomActions/CustomActions.def
Normal file
@ -0,0 +1,2 @@
|
||||
EXPORTS
|
||||
ServiceRunning
|
112
build/VStudio/installer/CustomActions/CustomActions.vcxproj
Normal file
112
build/VStudio/installer/CustomActions/CustomActions.vcxproj
Normal 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>
|
@ -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>
|
373
build/VStudio/installer/Product.wxs
Normal file
373
build/VStudio/installer/Product.wxs
Normal file
@ -0,0 +1,373 @@
|
||||
<?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" Guid="{F876F26E-5016-4AC6-93B3-653C0312A6CE}">
|
||||
<RegistryValue
|
||||
Root="HKLM"
|
||||
Key="[P.RegistryKey]"
|
||||
Name="InstallDir"
|
||||
Type="string"
|
||||
Value="[INSTALLDIR]"
|
||||
KeyPath="yes" />
|
||||
</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>
|
||||
<Directory Id="INCDIR.fuse" Name="fuse">
|
||||
<Component Id="C.fuse.h">
|
||||
<File Name="fuse.h" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.fuse_common.h">
|
||||
<File Name="fuse_common.h" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.fuse_opt.h">
|
||||
<File Name="fuse_opt.h" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.winfsp_fuse.h">
|
||||
<File Name="winfsp_fuse.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>
|
||||
|
||||
<!-- On Win64 copy fuse-x64.pc -->
|
||||
<Component Id="C.fuse_x64.pc" Guid="407395D2-D076-411E-B1D0-D97E21E11A3C">
|
||||
<File
|
||||
Id="FILE.fuse_x64.pc"
|
||||
Name="fuse.pc"
|
||||
Source="..\build\$(var.Configuration)\fuse-x64.pc"
|
||||
KeyPath="yes" />
|
||||
<Condition>VersionNT64</Condition>
|
||||
</Component>
|
||||
|
||||
<!-- On Win32 copy fuse-x86.pc -->
|
||||
<Component Id="C.fuse_x86.pc" Guid="0568EBCB-782E-4C17-9B64-BAFCC43F64ED">
|
||||
<File
|
||||
Id="FILE.fuse_x86.pc"
|
||||
Name="fuse.pc"
|
||||
Source="..\build\$(var.Configuration)\fuse-x86.pc"
|
||||
KeyPath="yes" />
|
||||
<Condition>NOT VersionNT64</Condition>
|
||||
</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" />
|
||||
<ComponentRef Id="C.fuse.h" />
|
||||
<ComponentRef Id="C.fuse_common.h" />
|
||||
<ComponentRef Id="C.fuse_opt.h" />
|
||||
<ComponentRef Id="C.winfsp_fuse.h" />
|
||||
</ComponentGroup>
|
||||
<ComponentGroup Id="C.WinFsp.lib">
|
||||
<ComponentRef Id="C.winfsp_x64.lib" />
|
||||
<ComponentRef Id="C.winfsp_x86.lib" />
|
||||
<ComponentRef Id="C.fuse_x64.pc" />
|
||||
<ComponentRef Id="C.fuse_x86.pc" />
|
||||
</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."
|
||||
AllowAdvertise="no"
|
||||
InstallDefault="local"
|
||||
Absent="allow">
|
||||
<ComponentGroupRef Id="C.WinFsp.inc" />
|
||||
<ComponentGroupRef Id="C.WinFsp.lib" />
|
||||
<ComponentGroupRef Id="C.WinFsp.smp" />
|
||||
</Feature>
|
||||
</Feature>
|
||||
|
||||
<WixVariable Id="WixUIBannerBmp" Value="wixbanner.bmp" />
|
||||
<WixVariable Id="WixUIDialogBmp" Value="wixdialog.bmp" />
|
||||
<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>
|
52
build/VStudio/installer/winfsp_msi.wixproj
Normal file
52
build/VStudio/installer/winfsp_msi.wixproj
Normal 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>
|
BIN
build/VStudio/installer/wixbanner.bmp
Normal file
BIN
build/VStudio/installer/wixbanner.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 112 KiB |
BIN
build/VStudio/installer/wixdialog.bmp
Normal file
BIN
build/VStudio/installer/wixdialog.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 601 KiB |
198
build/VStudio/launcher/launchctl.vcxproj
Normal file
198
build/VStudio/launcher/launchctl.vcxproj
Normal file
@ -0,0 +1,198 @@
|
||||
<?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>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</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>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</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>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</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>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</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>
|
33
build/VStudio/launcher/launchctl.vcxproj.filters
Normal file
33
build/VStudio/launcher/launchctl.vcxproj.filters
Normal 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>
|
202
build/VStudio/launcher/launcher.vcxproj
Normal file
202
build/VStudio/launcher/launcher.vcxproj
Normal file
@ -0,0 +1,202 @@
|
||||
<?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>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
|
||||
</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>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
|
||||
</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>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
|
||||
</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>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
|
||||
</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>
|
33
build/VStudio/launcher/launcher.vcxproj.filters
Normal file
33
build/VStudio/launcher/launcher.vcxproj.filters
Normal 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>
|
@ -103,7 +103,7 @@
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@ -119,7 +119,7 @@
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@ -137,7 +137,7 @@
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@ -157,7 +157,7 @@
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -102,7 +102,7 @@
|
||||
<PreprocessorDefinitions>__func__=__FUNCTION__;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\src;..\..\..\inc;..\..\..\ext</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@ -119,7 +119,7 @@
|
||||
<PreprocessorDefinitions>__func__=__FUNCTION__;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\src;..\..\..\inc;..\..\..\ext</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@ -138,7 +138,7 @@
|
||||
<PreprocessorDefinitions>__func__=__FUNCTION__;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\src;..\..\..\inc;..\..\..\ext</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@ -159,7 +159,7 @@
|
||||
<PreprocessorDefinitions>__func__=__FUNCTION__;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\src;..\..\..\inc;..\..\..\ext</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@ -183,12 +183,15 @@
|
||||
<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\fuse-opt-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\info-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\lock-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\memfs-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\mount-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\path-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\posix-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\rdwr-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\security-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />
|
||||
|
@ -52,6 +52,15 @@
|
||||
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\posix-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
||||
|
18
build/VStudio/version.properties
Normal file
18
build/VStudio/version.properties
Normal file
@ -0,0 +1,18 @@
|
||||
<?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.15.$(MyBuildNumber)</MyVersion>
|
||||
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>NTDDI_VERSION=0x06000000;_WIN32_WINNT=0x0600</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
</Project>
|
@ -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
|
||||
|
@ -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>
|
||||
@ -19,12 +20,24 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\inc\fuse\fuse.h" />
|
||||
<ClInclude Include="..\..\inc\fuse\fuse_common.h" />
|
||||
<ClInclude Include="..\..\inc\fuse\fuse_opt.h" />
|
||||
<ClInclude Include="..\..\inc\fuse\winfsp_fuse.h" />
|
||||
<ClInclude Include="..\..\inc\winfsp\fsctl.h" />
|
||||
<ClInclude Include="..\..\inc\winfsp\winfsp.h" />
|
||||
<ClInclude Include="..\..\src\dll\fuse\library.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\fuse\fuse.c" />
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c" />
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_main.c" />
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_opt.c" />
|
||||
<ClCompile Include="..\..\src\dll\np.c" />
|
||||
<ClCompile Include="..\..\src\dll\posix.c" />
|
||||
<ClCompile Include="..\..\src\dll\security.c" />
|
||||
<ClCompile Include="..\..\src\dll\debug.c" />
|
||||
<ClCompile Include="..\..\src\dll\fsctl.c" />
|
||||
@ -33,10 +46,43 @@
|
||||
<ClCompile Include="..\..\src\dll\fs.c" />
|
||||
<ClCompile Include="..\..\src\dll\ntstatus.c" />
|
||||
<ClCompile Include="..\..\src\dll\path.c" />
|
||||
<ClCompile Include="..\..\src\dll\service.c" />
|
||||
<ClCompile Include="..\..\src\dll\util.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc">
|
||||
<FileType>Document</FileType>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">echo arch=$(PlatformTarget) >$(OutDir)fuse-$(PlatformTarget).pc
|
||||
copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(PlatformTarget).pc >nul</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Writing fuse-$(PlatformTarget).pc</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)fuse-$(PlatformTarget).pc</Outputs>
|
||||
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkObjects>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo arch=$(PlatformTarget) >$(OutDir)fuse-$(PlatformTarget).pc
|
||||
copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(PlatformTarget).pc >nul</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Writing fuse-$(PlatformTarget).pc</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)fuse-$(PlatformTarget).pc</Outputs>
|
||||
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkObjects>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">echo arch=$(PlatformTarget) >$(OutDir)fuse-$(PlatformTarget).pc
|
||||
copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(PlatformTarget).pc >nul</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Writing fuse-$(PlatformTarget).pc</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)fuse-$(PlatformTarget).pc</Outputs>
|
||||
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkObjects>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">echo arch=$(PlatformTarget) >$(OutDir)fuse-$(PlatformTarget).pc
|
||||
copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(PlatformTarget).pc >nul</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Writing fuse-$(PlatformTarget).pc</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)fuse-$(PlatformTarget).pc</Outputs>
|
||||
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkObjects>
|
||||
</CustomBuild>
|
||||
<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>
|
||||
@ -124,7 +170,7 @@
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
</ClCompile>
|
||||
@ -134,8 +180,9 @@
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);credui.lib;version.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@ -148,7 +195,7 @@
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
</ClCompile>
|
||||
@ -160,6 +207,7 @@
|
||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);credui.lib;version.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@ -174,7 +222,7 @@
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -185,8 +233,9 @@
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);credui.lib;version.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@ -201,7 +250,7 @@
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -214,6 +263,7 @@
|
||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);credui.lib;version.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
@ -12,6 +12,15 @@
|
||||
<Filter Include="Include\winfsp">
|
||||
<UniqueIdentifier>{1d6501f4-cebd-4a00-a774-deb782b59fb5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Include\shared">
|
||||
<UniqueIdentifier>{c7b83307-0aa0-4593-b2d4-26ff2f1edfc6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Include\fuse">
|
||||
<UniqueIdentifier>{0e7ab1b1-bfca-4439-accb-45a909be9cad}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source\fuse">
|
||||
<UniqueIdentifier>{518cce17-85cd-489c-b4be-920a84c1d73c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\inc\winfsp\fsctl.h">
|
||||
@ -23,6 +32,24 @@
|
||||
<ClInclude Include="..\..\src\dll\library.h">
|
||||
<Filter>Source</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\shared\minimal.h">
|
||||
<Filter>Include\shared</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\fuse\fuse.h">
|
||||
<Filter>Include\fuse</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\fuse\fuse_common.h">
|
||||
<Filter>Include\fuse</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\fuse\fuse_opt.h">
|
||||
<Filter>Include\fuse</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\fuse\winfsp_fuse.h">
|
||||
<Filter>Include\fuse</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\dll\fuse\library.h">
|
||||
<Filter>Source\fuse</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\dll\library.c">
|
||||
@ -52,13 +79,45 @@
|
||||
<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>
|
||||
<ClCompile Include="..\..\src\dll\util.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse.c">
|
||||
<Filter>Source\fuse</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_opt.c">
|
||||
<Filter>Source\fuse</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_main.c">
|
||||
<Filter>Source\fuse</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\dll\posix.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c">
|
||||
<Filter>Source\fuse</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\src\dll\ntstatus.i">
|
||||
<Filter>Source</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\dll\library.def">
|
||||
<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>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -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>
|
||||
@ -33,6 +34,7 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<TargetVersion>Windows10</TargetVersion>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
|
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
||||
<ConfigurationType>Driver</ConfigurationType>
|
||||
<DriverType>WDM</DriverType>
|
||||
@ -40,6 +42,7 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<TargetVersion>Windows10</TargetVersion>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
|
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
||||
<ConfigurationType>Driver</ConfigurationType>
|
||||
<DriverType>WDM</DriverType>
|
||||
@ -47,6 +50,7 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<TargetVersion>Windows10</TargetVersion>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
|
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
||||
<ConfigurationType>Driver</ConfigurationType>
|
||||
<DriverType>WDM</DriverType>
|
||||
@ -54,6 +58,7 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<TargetVersion>Windows10</TargetVersion>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
|
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
||||
<ConfigurationType>Driver</ConfigurationType>
|
||||
<DriverType>WDM</DriverType>
|
||||
@ -177,6 +182,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>
|
||||
|
@ -101,4 +101,9 @@
|
||||
<Filter>Include\winfsp</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\..\src\sys\version.rc">
|
||||
<Filter>Source</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
32
doc/Changelog.adoc
Normal file
32
doc/Changelog.adoc
Normal file
@ -0,0 +1,32 @@
|
||||
= Changelog
|
||||
|
||||
|
||||
v0.15::
|
||||
|
||||
This is a minor release that brings support for Windows 7 and 32-bit OS'es.
|
||||
|
||||
- Fixes a number of issues for Windows 7. Windows 7 is now officially supported.
|
||||
- Fixes a number of issues with the 32-bit FSD and user mode components. 32-bit versions of Windows are now officially supported.
|
||||
|
||||
|
||||
v0.14::
|
||||
|
||||
This release includes support for file systems protected by credentials.
|
||||
|
||||
- WinFsp now supports file systems that require username/password to be unlocked (e.g. sshfs/secfs). Such file systems must add a DWORD registry value with name "Credentials" and value 1 under their WinFsp.Launcher service entry. The WinFsp network provider will then prompt for credentials using the `CredUIPromptForWindowsCredentials` API. Credentials can optionally be saved with the Windows Credential Manager.
|
||||
- WinFsp-FUSE now uses the S-1-0-65534 <--> 65534 mapping for unmapped SID/UID's. The Anonymous SID mapping from the previous release had security issues.
|
||||
|
||||
|
||||
v0.13::
|
||||
|
||||
This release includes a Cygwin package, an API change and some other minor changes:
|
||||
|
||||
- New Cygwin package includes `cygfuse-2.8.dll` and `libfuse-2.8.dll.a` for easy use in the Cygwin environment. This is currently offered as a separate download.
|
||||
- Minor but breaking API change: `SetFileSize`/`SetAllocationSize` have been consolidated. Please refer to the documentation for a description of the changes.
|
||||
- File system drive symbolic links (`DefineDosDeviceW`) now automatically cleaned up even if user mode file system crashes or is terminated forcefully.
|
||||
- WinFsp-FUSE now maps unmapped UID's to the Anonymous SID (S-1-5-7). See: https://cygwin.com/ml/cygwin/2016-06/msg00359.html
|
||||
|
||||
|
||||
v0.12::
|
||||
|
||||
Prior changes are not recorded in this Changelog.
|
14
doc/Makefile
14
doc/Makefile
@ -1,9 +1,21 @@
|
||||
web: web/winfsp-design.html web/winfsp.h.html
|
||||
web: \
|
||||
web/winfsp-design.html \
|
||||
web/service-architecture.html \
|
||||
web/sshfs-port-case-study.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/sshfs-port-case-study.html:
|
||||
mkdir -p web
|
||||
asciidoc -b html4 -a hr= -s -o $@ sshfs-port-case-study.adoc
|
||||
|
||||
web/winfsp.h.html:
|
||||
mkdir -p web
|
||||
prettydoc -H-O -o web ../inc/winfsp/winfsp.h
|
||||
|
47
doc/service-architecture.adoc
Normal file
47
doc/service-architecture.adoc
Normal 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.
|
217
doc/sshfs-port-case-study.adoc
Normal file
217
doc/sshfs-port-case-study.adoc
Normal file
@ -0,0 +1,217 @@
|
||||
= SSHFS Port Case Study
|
||||
|
||||
This document is a case study in porting SSHFS to Windows and WinFsp. At the time of this writing WinFsp has a native API, but no FUSE compatible API. The main purpose of this case study is to develop a FUSE compatible API for WinFsp.
|
||||
|
||||
== Step 1: Gather Information about SSHFS
|
||||
|
||||
The SSHFS project is one of the early FUSE projects. The project was originally written by Miklos Szeredi who is also the author of FUSE. SSHFS provides a file system interface on top of SFTP (Secure File Transfer Protocol).
|
||||
|
||||
The project's website is at https://github.com/libfuse/sshfs. A quick perusal of the source code shows that this is a POSIX program, the file `configure.ac` further shows that it depends on GLib and FUSE.
|
||||
|
||||
Luckily Cygwin on Windows provides a POSIX interface and it also includes GLib and pkg-config. We are missing FUSE of course. Let's try it anyway:
|
||||
|
||||
----
|
||||
billziss@windows:~/Projects/ext$ git clone https://github.com/libfuse/sshfs.git
|
||||
Cloning into 'sshfs'...
|
||||
[snip]
|
||||
billziss@windows:~/Projects/ext$ cd sshfs/
|
||||
billziss@windows:~/Projects/ext/sshfs [master]$ autoreconf -i
|
||||
[snip]
|
||||
billziss@windows:~/Projects/ext/sshfs [master]$ ./configure
|
||||
[snip]
|
||||
configure: error: Package requirements (fuse >= 2.3 glib-2.0 gthread-2.0) were not met:
|
||||
|
||||
No package 'fuse' found
|
||||
----
|
||||
|
||||
As expected we get an error because there is no package named FUSE. So let's create one.
|
||||
|
||||
== Step 2: Create a FUSE Compatible Package
|
||||
|
||||
After a few days of development there exists now an initial FUSE implementation within WinFsp. Most of the FUSE API's from the header files `fuse.h`, `fuse_common.h` and `fuse_opt.h` have been implemented. However none of the `fuse_operations` currently work as the necessary work to translate WinFsp requests to FUSE requests has not happened yet.
|
||||
|
||||
=== Challenges
|
||||
|
||||
- The FUSE API is old and somewhat hairy. There are multiple versions of it and choosing the right one was not easy. In the end version 2.8 of the API was chosen for implementation.
|
||||
|
||||
- The FUSE API uses a number of OS specific types (notably `struct stat`). Sometimes these types have multiple definitions even within the same OS (e.g. `struct stat` and `struct stat64`). For this reason it was decided to define our own `fuse_*` types (e.g. `struct fuse_stat`) instead of relying on the ones that come with MSVC. Care was taken to ensure that these types remain compatible with Cygwin as it is one of our primary target environments.
|
||||
|
||||
- The WinFsp DLL does *not* use the MSVCRT and uses its own memory allocator (`HeapAlloc`, `HeapFree`). Even if it used the MSVCRT `malloc`, it does not have access to the Cygwin `malloc`. The FUSE API has a few cases where users are expected to use `free` to deallocate memory (e.g. `fuse_opt_add_opt`). But which `free` is that for a Cygwin program? The Cygwin `free`, the MSVCRT `free` or our own `MemFree`?
|
||||
+
|
||||
To solve this problem we use the following pattern: every FUSE API is implemented as a `static inline` function that calls a WinFsp-FUSE API and passes it an extra argument that describes the environment:
|
||||
+
|
||||
----
|
||||
static inline int fuse_opt_add_opt(char **opts, const char *opt)
|
||||
{
|
||||
return fsp_fuse_opt_add_opt(fsp_fuse_env(), opts, opt);
|
||||
}
|
||||
----
|
||||
+
|
||||
The `fsp_fuse_env` function is another `static inline` function that simply "captures" the current environment (things like the environment's `malloc` and `free`).
|
||||
+
|
||||
----
|
||||
...
|
||||
#elif defined(__CYGWIN__)
|
||||
...
|
||||
#define FSP_FUSE_ENV_INIT \
|
||||
{ \
|
||||
'C', \
|
||||
malloc, free, \
|
||||
fsp_fuse_daemonize, \
|
||||
fsp_fuse_set_signal_handlers, \
|
||||
fsp_fuse_remove_signal_handlers,\
|
||||
}
|
||||
...
|
||||
#else
|
||||
...
|
||||
|
||||
static inline struct fsp_fuse_env *fsp_fuse_env(void)
|
||||
{
|
||||
static struct fsp_fuse_env env = FSP_FUSE_ENV_INIT;
|
||||
return &env;
|
||||
}
|
||||
----
|
||||
|
||||
- The implementation of `fuse_opt` proved an unexpected challenge. The function `fuse_opt_parse` is very flexible, but it also has a lot of quirks. It took a lot of trial and error to arrive at a clean reimplementation.
|
||||
|
||||
=== Things that worked rather nicely
|
||||
|
||||
- The pattern `fuse_new` / `fuse_loop` / `fuse_destroy` fits nicely to the WinFsp service model: `FspServiceCreate` / `FspServiceLoop` / `FspServiceDelete`. This means that every (high-level) FUSE file system can rather easily be converted into a Windows service if desired.
|
||||
|
||||
=== Integrating with Cygwin
|
||||
|
||||
It remains to show how to use the WinFsp-FUSE implementation from Cygwin and SSHFS. SSHFS uses `pkg-config` for its build configuration. `Pkg-config` requires a `fuse.pc` file:
|
||||
|
||||
----
|
||||
arch=x64
|
||||
prefix=${pcfiledir}/..
|
||||
incdir=${prefix}/inc/fuse
|
||||
implib=${prefix}/bin/winfsp-${arch}.dll
|
||||
|
||||
Name: fuse
|
||||
Description: WinFsp FUSE compatible API
|
||||
Version: 2.8
|
||||
URL: http://www.secfs.net/winfsp/
|
||||
Libs: "${implib}"
|
||||
Cflags: -I"${incdir}"
|
||||
----
|
||||
|
||||
The WinFsp installer has been modified to place this file within its installation directory. It remains to point `pkg-config` to the appropriate location (using `PKG_CONFIG_PATH`) and the SSHFS configuration process can now find the FUSE package.
|
||||
|
||||
=== SSHFS-Win
|
||||
|
||||
The sshfs-win open-source project (work in progress) can be found here: https://bitbucket.org/billziss/sshfs-win
|
||||
|
||||
== Step 3: Mapping Windows to POSIX
|
||||
|
||||
It would seem that we are now ready to start implementing the `fuse_operations`. However there is another matter that we need to attend to first and that is mapping the Windows file system view of the world to the POSIX one and vice-versa.
|
||||
|
||||
=== Mapping Paths
|
||||
|
||||
The Windows and POSIX file systems both use paths to address files. The path conventions are different, so we need a technique to convert between the two. This goes beyond a simple translation of the backslash character (`\`) to slash (`/`), because several characters are reserved and cannot be used in a Windows file path, but are legal when used in a POSIX path.
|
||||
|
||||
The reserved Windows characters are:
|
||||
|
||||
----
|
||||
< > : " / \ | ? *
|
||||
any character between 0 and 31
|
||||
----
|
||||
|
||||
POSIX only has two reserved characters: slash (`/`) and `NUL`.
|
||||
|
||||
So how do we map between the two? Luckily this problem has been solved before by "Services for Macintosh" (SFM), "Services for UNIX" (SFU) and Gygwin. The solution involves the use of the Unicode "private use area". When mapping a POSIX path to Windows, if we encounter any of the Windows reserved characters we simply map it to the Unicode range U+F000 - U+F0FF. The reverse mapping from Windows to POSIX is obvious.
|
||||
|
||||
=== Mapping Security
|
||||
|
||||
Mapping Windows security to POSIX (and vice-versa) is a much more interesting (and difficult) problem. We have the following requirements:
|
||||
|
||||
- We need a method to map a Windows SID (Security Identifier) to a POSIX uid/gid.
|
||||
- We need a method to map a Windows ACL (Access Control List) to a POSIX permission set.
|
||||
- We want any mapping method we come up with to be bijective (to the extent that it is possible).
|
||||
|
||||
Luckily "Services for UNIX" (and Cygwin) come to the rescue again. The following Cygwin document describes in great detail a method to map a Windows SID to a POSIX uid/gid that is compatible with SFU: https://cygwin.com/cygwin-ug-net/ntsec.html. A different document from SFU describes how to map a Windows ACL to POSIX permissions: https://technet.microsoft.com/en-us/library/bb463216.aspx.
|
||||
|
||||
The mappings provided are not perfect, but they come pretty close. They are also proven as they have been used in SFU and Cygwin for years.
|
||||
|
||||
=== WinFsp Implementation
|
||||
|
||||
A WinFsp implementation of the above mappings can be found in the file `src/dll/posix.c`.
|
||||
|
||||
== Step 4: Implementing FUSE Core
|
||||
|
||||
We are now finally ready to implement the `fuse_operations`. This actually proves to be a straightforward mapping of the WinFSP `FSP_FILE_SYSTEM_INTERACE` to `fuse_operations`:
|
||||
|
||||
GetVolumeInfo:: Mapped to `statfs`. Volume labels are not supported by FUSE (see below).
|
||||
|
||||
SetVolumeLabel:: No equivalent on FUSE, so simply return `STATUS_INVALID_PARAMETER`. One thought is to map this call into a `setxattr("sys.VolumeLabel")` (or similar) call on the root directory (`/`).
|
||||
|
||||
GetSecurityByName:: Mapped to `fgetattr`/`getattr`. The returned `stat` information is translated into a Windows security descriptor using `FspPosixMapPermissionsToSecurityDescriptor`.
|
||||
|
||||
Create:: This is used to create a new file or directory. If a file is created this is mapped to `create` or `mknod`;`open`. If a directory is created this is mapped to `mkdir`;`opendir` calls (the reason is that on Windows a directory remains open after being created). In some circumstances a `chown` may be issued as well. After the file or directory has been created a `fgetattr`/`getattr` is issued to get `stat` information to return to the FSD.
|
||||
|
||||
Open:: This is used to open a new file or directory. First a `fgetattr`/`getattr` is issued. If the file is not a directory it is followed by `open`. If the file is a directory it is followed by `opendir`.
|
||||
|
||||
Overwrite:: This is used to overwrite a file when one of the `FILE_OVERWRITE`, `FILE_SUPERSEDE` or `FILE_OVERWRITE_IF` flags has been set. Mapped to `ftruncate`/`truncate`.
|
||||
|
||||
Cleanup:: Mapped to `unlink` when deleting a file and `rmdir` when deleting a directory.
|
||||
|
||||
Close:: Mapped to `flush`;`release` when closing a file and `releasedir` when closing a directory.
|
||||
|
||||
Read:: Mapped to `read`.
|
||||
|
||||
Write:: Mapped to `fgetattr`/`getattr` and `write`.
|
||||
|
||||
Flush:: Mapped to `fsync` or `fsyncdir`.
|
||||
|
||||
GetFileInfo:: Mapped to `fgetattr`/`getattr`.
|
||||
|
||||
SetBasicInfo:: Mapped to `utimens`/`utime`.
|
||||
|
||||
SetAllocationSize:: Mapped to `fgetattr`/`getattr` followed by `ftruncate`/`truncate`. Note that this call and `SetFileSize` may be consolidated soon in the WinFsp API.
|
||||
|
||||
SetFileSize:: Mapped to `fgetattr`/`getattr` followed by `ftruncate`/`truncate`. Note that this call and `SetAllocationSize` may be consolidated soon in the WinFsp API.
|
||||
|
||||
CanDelete:: For directories only: mapped to a `getdir`/`readdir` call to determine if they are empty and can therefore be deleted.
|
||||
|
||||
Rename:: Mapped to `fgetattr`/`getattr` on the destination file name and `rename`.
|
||||
|
||||
GetSecurity:: Mapped to `fgetattr`/`getattr`. The returned `stat` information is translated into a Windows security descriptor using `FspPosixMapPermissionsToSecurityDescriptor`.
|
||||
|
||||
SetSecurity:: Mapped to `fgetattr`/`getattr` followed by `chmod` and/or `chown`.
|
||||
|
||||
ReadDirectory:: Mapped to `getdir`/`readdir`. Note that because of how the Windows directory enumeration API's work there is a further `fgetattr`/`getattr` per file returned!
|
||||
|
||||
=== Some Additional Challenges
|
||||
|
||||
Let us now discuss a couple of final challenges in getting a proper FUSE port working under Cygwin: the implementation of `fuse_set_signal_handlers`/`fuse_remove_signal_handlers` and `fuse_daemonize`.
|
||||
|
||||
Let us start with `fuse_set_signal_handlers`/`fuse_remove_signal_handlers`. Cygwin supports POSIX signals and we can simply set up signal handlers similar to what libfuse does. However this simple approach does not work within WinFsp, because it uses native API's that Cygwin cannot interrupt with its signal mechanism. For example, the `fuse_loop` FUSE call eventually results in a `WaitForSingleObject` API call that Cygwin cannot interrupt. Even trying with an alertable `WaitForSingleObjectEx` did not work as unfortunately Cygwin does not issue a `QueueUserAPC` when issuing a signal. So we need an alternative mechanism to support signals.
|
||||
|
||||
The alternative is to use `sigwait` in a separate thread. `Fsp_fuse_signal_handler` is a WinFsp API that knows how to interrupt that `WaitForSingleObject` (actually it just signals the waited event).
|
||||
|
||||
----
|
||||
static inline void *fsp_fuse_signal_thread(void *psigmask)
|
||||
{
|
||||
int sig;
|
||||
|
||||
if (0 == sigwait(psigmask, &sig))
|
||||
fsp_fuse_signal_handler(sig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
----
|
||||
|
||||
Let us now move to `fuse_daemonize`. This FUSE call allows a FUSE file system to become a (UNIX) daemon. This is achieved by using the POSIX fork call, which unfortunately has many limitations in Cygwin. One such limitation (and the one that bit us in WinFsp) is that it does not know how to clone Windows heaps (`HeapAlloc`/`HeapFree`).
|
||||
|
||||
Recall that WinFsp uses its own memory allocator (just a thin wrapper around `HeapAlloc`/`HeapFree`). This means that any allocations made prior to the fork() call are doomed after a fork(); with good luck the pointers will point to invalid memory and one will get an Access Violation; with bad luck the pointers will point to valid memory that contains bad data and the program may stumble for a while, just enough to hide the actual cause of the problem.
|
||||
|
||||
Luckily there is a rather straightforward work-around: "do not allocate any non-Cygwin resources prior to fork". This is actually possible within WinFsp, because we are already capturing the Cygwin environment and its `malloc`/`free` (see `fsp_fuse_env` in "Step 2"). It is also possible, because the typical FUSE program structure looks like this:
|
||||
|
||||
----
|
||||
fuse_new
|
||||
fuse_daemonize // do not allocate any non-Cygwin resources prior to this
|
||||
fuse_loop/fuse_loop_mt // safe to allocate non-Cygwin resources
|
||||
fuse_destroy
|
||||
----
|
||||
|
||||
With this change `fuse_daemonize` works and allows me to declare the Cygwin portion of the SSHFS port complete!
|
1
ext/test
Submodule
1
ext/test
Submodule
Submodule ext/test added at a651263c4c
220
inc/fuse/fuse.h
Normal file
220
inc/fuse/fuse.h
Normal file
@ -0,0 +1,220 @@
|
||||
/**
|
||||
* @file fuse/fuse.h
|
||||
* WinFsp FUSE compatible API.
|
||||
*
|
||||
* This file is derived from libfuse/include/fuse.h:
|
||||
* FUSE: Filesystem in Userspace
|
||||
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
*
|
||||
* @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 FUSE_H_
|
||||
#define FUSE_H_
|
||||
|
||||
#include "fuse_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct fuse;
|
||||
|
||||
typedef int (*fuse_fill_dir_t)(void *buf, const char *name,
|
||||
const struct fuse_stat *stbuf, fuse_off_t off);
|
||||
typedef struct fuse_dirhandle *fuse_dirh_t;
|
||||
typedef int (*fuse_dirfil_t)(fuse_dirh_t h, const char *name,
|
||||
int type, fuse_ino_t ino);
|
||||
|
||||
struct fuse_operations
|
||||
{
|
||||
int (*getattr)(const char *path, struct fuse_stat *stbuf);
|
||||
int (*getdir)(const char *path, fuse_dirh_t h, fuse_dirfil_t filler);
|
||||
int (*readlink)(const char *path, char *buf, size_t size);
|
||||
int (*mknod)(const char *path, fuse_mode_t mode, fuse_dev_t dev);
|
||||
int (*mkdir)(const char *path, fuse_mode_t mode);
|
||||
int (*unlink)(const char *path);
|
||||
int (*rmdir)(const char *path);
|
||||
int (*symlink)(const char *dstpath, const char *srcpath);
|
||||
int (*rename)(const char *oldpath, const char *newpath);
|
||||
int (*link)(const char *srcpath, const char *dstpath);
|
||||
int (*chmod)(const char *path, fuse_mode_t mode);
|
||||
int (*chown)(const char *path, fuse_uid_t uid, fuse_gid_t gid);
|
||||
int (*truncate)(const char *path, fuse_off_t size);
|
||||
int (*utime)(const char *path, struct fuse_utimbuf *timbuf);
|
||||
int (*open)(const char *path, struct fuse_file_info *fi);
|
||||
int (*read)(const char *path, char *buf, size_t size, fuse_off_t off,
|
||||
struct fuse_file_info *fi);
|
||||
int (*write)(const char *path, const char *buf, size_t size, fuse_off_t off,
|
||||
struct fuse_file_info *fi);
|
||||
int (*statfs)(const char *path, struct fuse_statvfs *stbuf);
|
||||
int (*flush)(const char *path, struct fuse_file_info *fi);
|
||||
int (*release)(const char *path, struct fuse_file_info *fi);
|
||||
int (*fsync)(const char *path, int datasync, struct fuse_file_info *fi);
|
||||
int (*setxattr)(const char *path, const char *name, const char *value, size_t size,
|
||||
int flags);
|
||||
int (*getxattr)(const char *path, const char *name, char *value, size_t size);
|
||||
int (*listxattr)(const char *path, char *namebuf, size_t size);
|
||||
int (*removexattr)(const char *path, const char *name);
|
||||
int (*opendir)(const char *path, struct fuse_file_info *fi);
|
||||
int (*readdir)(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
|
||||
struct fuse_file_info *fi);
|
||||
int (*releasedir)(const char *path, struct fuse_file_info *fi);
|
||||
int (*fsyncdir)(const char *path, int datasync, struct fuse_file_info *fi);
|
||||
void *(*init)(struct fuse_conn_info *conn);
|
||||
void (*destroy)(void *data);
|
||||
int (*access)(const char *path, int mask);
|
||||
int (*create)(const char *path, fuse_mode_t mode, struct fuse_file_info *fi);
|
||||
int (*ftruncate)(const char *path, fuse_off_t off, struct fuse_file_info *fi);
|
||||
int (*fgetattr)(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi);
|
||||
int (*lock)(const char *path, struct fuse_file_info *fi, int cmd, struct fuse_flock *lock);
|
||||
int (*utimens)(const char *path, const struct fuse_timespec tv[2]);
|
||||
int (*bmap)(const char *path, size_t blocksize, uint64_t *idx);
|
||||
unsigned int flag_nullpath_ok:1;
|
||||
unsigned int flag_reserved:31;
|
||||
int (*ioctl)(const char *path, int cmd, void *arg, struct fuse_file_info *fi,
|
||||
unsigned int flags, void *data);
|
||||
int (*poll)(const char *path, struct fuse_file_info *fi,
|
||||
struct fuse_pollhandle *ph, unsigned *reventsp);
|
||||
};
|
||||
|
||||
struct fuse_context
|
||||
{
|
||||
struct fuse *fuse;
|
||||
fuse_uid_t uid;
|
||||
fuse_gid_t gid;
|
||||
fuse_pid_t pid;
|
||||
void *private_data;
|
||||
fuse_mode_t umask;
|
||||
};
|
||||
|
||||
#define fuse_main(argc, argv, ops, data)\
|
||||
fuse_main_real(argc, argv, ops, sizeof *(ops), data)
|
||||
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_main_real)(struct fsp_fuse_env *env,
|
||||
int argc, char *argv[],
|
||||
const struct fuse_operations *ops, size_t opsize, void *data);
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_is_lib_option)(struct fsp_fuse_env *env,
|
||||
const char *opt);
|
||||
FSP_FUSE_API struct fuse *FSP_FUSE_API_NAME(fsp_fuse_new)(struct fsp_fuse_env *env,
|
||||
struct fuse_chan *ch, struct fuse_args *args,
|
||||
const struct fuse_operations *ops, size_t opsize, void *data);
|
||||
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_destroy)(struct fsp_fuse_env *env,
|
||||
struct fuse *f);
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_loop)(struct fsp_fuse_env *env,
|
||||
struct fuse *f);
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_loop_mt)(struct fsp_fuse_env *env,
|
||||
struct fuse *f);
|
||||
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_exit)(struct fsp_fuse_env *env,
|
||||
struct fuse *f);
|
||||
FSP_FUSE_API struct fuse_context *FSP_FUSE_API_NAME(fsp_fuse_get_context)(struct fsp_fuse_env *env);
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_main_real(int argc, char *argv[],
|
||||
const struct fuse_operations *ops, size_t opsize, void *data),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_main_real)
|
||||
(fsp_fuse_env(), argc, argv, ops, opsize, data);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_is_lib_option(const char *opt),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_is_lib_option)
|
||||
(fsp_fuse_env(), opt);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
|
||||
const struct fuse_operations *ops, size_t opsize, void *data),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_new)
|
||||
(fsp_fuse_env(), ch, args, ops, opsize, data);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
void fuse_destroy(struct fuse *f),
|
||||
{
|
||||
FSP_FUSE_API_CALL(fsp_fuse_destroy)
|
||||
(fsp_fuse_env(), f);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_loop(struct fuse *f),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_loop)
|
||||
(fsp_fuse_env(), f);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_loop_mt(struct fuse *f),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_loop_mt)
|
||||
(fsp_fuse_env(), f);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
void fuse_exit(struct fuse *f),
|
||||
{
|
||||
FSP_FUSE_API_CALL(fsp_fuse_exit)
|
||||
(fsp_fuse_env(), f);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
struct fuse_context *fuse_get_context(void),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_get_context)
|
||||
(fsp_fuse_env());
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_getgroups(int size, fuse_gid_t list[]),
|
||||
{
|
||||
(void)size;
|
||||
(void)list;
|
||||
return -ENOSYS;
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_interrupted(void),
|
||||
{
|
||||
return 0;
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_invalidate(struct fuse *f, const char *path),
|
||||
{
|
||||
(void)f;
|
||||
(void)path;
|
||||
return -EINVAL;
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_notify_poll(struct fuse_pollhandle *ph),
|
||||
{
|
||||
(void)ph;
|
||||
return 0;
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
struct fuse_session *fuse_get_session(struct fuse *f),
|
||||
{
|
||||
return (struct fuse_session *)f;
|
||||
})
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
149
inc/fuse/fuse_common.h
Normal file
149
inc/fuse/fuse_common.h
Normal file
@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @file fuse/fuse_common.h
|
||||
* WinFsp FUSE compatible API.
|
||||
*
|
||||
* This file is derived from libfuse/include/fuse_common.h:
|
||||
* FUSE: Filesystem in Userspace
|
||||
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
*
|
||||
* @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 FUSE_COMMON_H_
|
||||
#define FUSE_COMMON_H_
|
||||
|
||||
#include "winfsp_fuse.h"
|
||||
#include "fuse_opt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define FUSE_MAJOR_VERSION 2
|
||||
#define FUSE_MINOR_VERSION 8
|
||||
#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min))
|
||||
#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
|
||||
|
||||
#define FUSE_CAP_ASYNC_READ (1 << 0)
|
||||
#define FUSE_CAP_POSIX_LOCKS (1 << 1)
|
||||
#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3)
|
||||
#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
|
||||
#define FUSE_CAP_BIG_WRITES (1 << 5)
|
||||
#define FUSE_CAP_DONT_MASK (1 << 6)
|
||||
|
||||
#define FUSE_IOCTL_COMPAT (1 << 0)
|
||||
#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
|
||||
#define FUSE_IOCTL_RETRY (1 << 2)
|
||||
#define FUSE_IOCTL_MAX_IOV 256
|
||||
|
||||
struct fuse_file_info
|
||||
{
|
||||
int flags;
|
||||
unsigned int fh_old;
|
||||
int writepage;
|
||||
unsigned int direct_io:1;
|
||||
unsigned int keep_cache:1;
|
||||
unsigned int flush:1;
|
||||
unsigned int nonseekable:1;
|
||||
unsigned int padding:28;
|
||||
uint64_t fh;
|
||||
uint64_t lock_owner;
|
||||
};
|
||||
|
||||
struct fuse_conn_info
|
||||
{
|
||||
unsigned proto_major;
|
||||
unsigned proto_minor;
|
||||
unsigned async_read;
|
||||
unsigned max_write;
|
||||
unsigned max_readahead;
|
||||
unsigned capable;
|
||||
unsigned want;
|
||||
unsigned reserved[25];
|
||||
};
|
||||
|
||||
struct fuse_session;
|
||||
struct fuse_chan;
|
||||
struct fuse_pollhandle;
|
||||
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_version)(struct fsp_fuse_env *env);
|
||||
FSP_FUSE_API struct fuse_chan *FSP_FUSE_API_NAME(fsp_fuse_mount)(struct fsp_fuse_env *env,
|
||||
const char *mountpoint, struct fuse_args *args);
|
||||
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_unmount)(struct fsp_fuse_env *env,
|
||||
const char *mountpoint, struct fuse_chan *ch);
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_parse_cmdline)(struct fsp_fuse_env *env,
|
||||
struct fuse_args *args,
|
||||
char **mountpoint, int *multithreaded, int *foreground);
|
||||
FSP_FUSE_API int32_t FSP_FUSE_API_NAME(fsp_fuse_ntstatus_from_errno)(struct fsp_fuse_env *env,
|
||||
int err);
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_version(void),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_version)
|
||||
(fsp_fuse_env());
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_mount)
|
||||
(fsp_fuse_env(), mountpoint, args);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch),
|
||||
{
|
||||
FSP_FUSE_API_CALL(fsp_fuse_unmount)
|
||||
(fsp_fuse_env(), mountpoint, ch);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_parse_cmdline(struct fuse_args *args,
|
||||
char **mountpoint, int *multithreaded, int *foreground),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_parse_cmdline)
|
||||
(fsp_fuse_env(), args, mountpoint, multithreaded, foreground);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
void fuse_pollhandle_destroy(struct fuse_pollhandle *ph),
|
||||
{
|
||||
(void)ph;
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_daemonize(int foreground),
|
||||
{
|
||||
return fsp_fuse_daemonize(foreground);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_set_signal_handlers(struct fuse_session *se),
|
||||
{
|
||||
return fsp_fuse_set_signal_handlers(se);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
void fuse_remove_signal_handlers(struct fuse_session *se),
|
||||
{
|
||||
(void)se;
|
||||
fsp_fuse_set_signal_handlers(0);
|
||||
})
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
129
inc/fuse/fuse_opt.h
Normal file
129
inc/fuse/fuse_opt.h
Normal file
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @file fuse/fuse_opt.h
|
||||
* WinFsp FUSE compatible API.
|
||||
*
|
||||
* This file is derived from libfuse/include/fuse_opt.h:
|
||||
* FUSE: Filesystem in Userspace
|
||||
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
*
|
||||
* @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 FUSE_OPT_H_
|
||||
#define FUSE_OPT_H_
|
||||
|
||||
#include "winfsp_fuse.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define FUSE_OPT_KEY(templ, key) { templ, -1, key }
|
||||
#define FUSE_OPT_END { NULL, 0, 0 }
|
||||
|
||||
#define FUSE_OPT_KEY_OPT -1
|
||||
#define FUSE_OPT_KEY_NONOPT -2
|
||||
#define FUSE_OPT_KEY_KEEP -3
|
||||
#define FUSE_OPT_KEY_DISCARD -4
|
||||
|
||||
#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 }
|
||||
|
||||
struct fuse_opt
|
||||
{
|
||||
const char *templ;
|
||||
unsigned int offset;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct fuse_args
|
||||
{
|
||||
int argc;
|
||||
char **argv;
|
||||
int allocated;
|
||||
};
|
||||
|
||||
typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
|
||||
struct fuse_args *outargs);
|
||||
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_parse)(struct fsp_fuse_env *env,
|
||||
struct fuse_args *args, void *data,
|
||||
const struct fuse_opt opts[], fuse_opt_proc_t proc);
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_add_arg)(struct fsp_fuse_env *env,
|
||||
struct fuse_args *args, const char *arg);
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_insert_arg)(struct fsp_fuse_env *env,
|
||||
struct fuse_args *args, int pos, const char *arg);
|
||||
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_opt_free_args)(struct fsp_fuse_env *env,
|
||||
struct fuse_args *args);
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_add_opt)(struct fsp_fuse_env *env,
|
||||
char **opts, const char *opt);
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_add_opt_escaped)(struct fsp_fuse_env *env,
|
||||
char **opts, const char *opt);
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_match)(struct fsp_fuse_env *env,
|
||||
const struct fuse_opt opts[], const char *opt);
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_opt_parse(struct fuse_args *args, void *data,
|
||||
const struct fuse_opt opts[], fuse_opt_proc_t proc),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_opt_parse)
|
||||
(fsp_fuse_env(), args, data, opts, proc);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_opt_add_arg(struct fuse_args *args, const char *arg),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_opt_add_arg)
|
||||
(fsp_fuse_env(), args, arg);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_opt_insert_arg)
|
||||
(fsp_fuse_env(), args, pos, arg);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
void fuse_opt_free_args(struct fuse_args *args),
|
||||
{
|
||||
FSP_FUSE_API_CALL(fsp_fuse_opt_free_args)
|
||||
(fsp_fuse_env(), args);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_opt_add_opt(char **opts, const char *opt),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_opt_add_opt)
|
||||
(fsp_fuse_env(), opts, opt);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_opt_add_opt_escaped(char **opts, const char *opt),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_opt_add_opt_escaped)
|
||||
(fsp_fuse_env(), opts, opt);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_opt_match(const struct fuse_opt opts[], const char *opt),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_opt_match)
|
||||
(fsp_fuse_env(), opts, opt);
|
||||
})
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
364
inc/fuse/winfsp_fuse.h
Normal file
364
inc/fuse/winfsp_fuse.h
Normal file
@ -0,0 +1,364 @@
|
||||
/**
|
||||
* @file fuse/winfsp_fuse.h
|
||||
* WinFsp FUSE compatible API.
|
||||
*
|
||||
* @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 FUSE_WINFSP_FUSE_H_INCLUDED
|
||||
#define FUSE_WINFSP_FUSE_H_INCLUDED
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#if !defined(WINFSP_DLL_INTERNAL)
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !defined(FSP_FUSE_API)
|
||||
#if defined(WINFSP_DLL_INTERNAL)
|
||||
#define FSP_FUSE_API __declspec(dllexport)
|
||||
#else
|
||||
#define FSP_FUSE_API __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(FSP_FUSE_API_NAME)
|
||||
#define FSP_FUSE_API_NAME(n) (n)
|
||||
#endif
|
||||
|
||||
#if !defined(FSP_FUSE_API_CALL)
|
||||
#define FSP_FUSE_API_CALL(n) (n)
|
||||
#endif
|
||||
|
||||
#if !defined(FSP_FUSE_SYM)
|
||||
#if !defined(CYGFUSE)
|
||||
#define FSP_FUSE_SYM(proto, ...) static inline proto { __VA_ARGS__ }
|
||||
#else
|
||||
#define FSP_FUSE_SYM(proto, ...) proto;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FUSE uses a number of types (notably: struct stat) that are OS specific.
|
||||
* Furthermore there are sometimes multiple definitions of the same type even
|
||||
* within the same OS. This is certainly true on Windows, where these types
|
||||
* are not even native.
|
||||
*
|
||||
* For this reason we will define our own fuse_* types which represent the
|
||||
* types as the WinFsp DLL expects to see them. We will define these types
|
||||
* to be compatible with the equivalent Cygwin types as we want WinFsp-FUSE
|
||||
* to be usable from Cygwin.
|
||||
*/
|
||||
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
|
||||
typedef uint32_t fuse_uid_t;
|
||||
typedef uint32_t fuse_gid_t;
|
||||
typedef int32_t fuse_pid_t;
|
||||
|
||||
typedef uint32_t fuse_dev_t;
|
||||
typedef uint64_t fuse_ino_t;
|
||||
typedef uint32_t fuse_mode_t;
|
||||
typedef uint16_t fuse_nlink_t;
|
||||
typedef int64_t fuse_off_t;
|
||||
|
||||
#if defined(_WIN64)
|
||||
typedef uint64_t fuse_fsblkcnt_t;
|
||||
typedef uint64_t fuse_fsfilcnt_t;
|
||||
#else
|
||||
typedef uint32_t fuse_fsblkcnt_t;
|
||||
typedef uint32_t fuse_fsfilcnt_t;
|
||||
#endif
|
||||
typedef int32_t fuse_blksize_t;
|
||||
typedef int64_t fuse_blkcnt_t;
|
||||
|
||||
#if defined(_WIN64)
|
||||
struct fuse_utimbuf
|
||||
{
|
||||
int64_t actime;
|
||||
int64_t modtime;
|
||||
};
|
||||
struct fuse_timespec
|
||||
{
|
||||
int64_t tv_sec;
|
||||
int64_t tv_nsec;
|
||||
};
|
||||
#else
|
||||
struct fuse_utimbuf
|
||||
{
|
||||
int32_t actime;
|
||||
int32_t modtime;
|
||||
};
|
||||
struct fuse_timespec
|
||||
{
|
||||
int32_t tv_sec;
|
||||
int32_t tv_nsec;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct fuse_stat
|
||||
{
|
||||
fuse_dev_t st_dev;
|
||||
fuse_ino_t st_ino;
|
||||
fuse_mode_t st_mode;
|
||||
fuse_nlink_t st_nlink;
|
||||
fuse_uid_t st_uid;
|
||||
fuse_gid_t st_gid;
|
||||
fuse_dev_t st_rdev;
|
||||
fuse_off_t st_size;
|
||||
struct fuse_timespec st_atim;
|
||||
struct fuse_timespec st_mtim;
|
||||
struct fuse_timespec st_ctim;
|
||||
fuse_blksize_t st_blksize;
|
||||
fuse_blkcnt_t st_blocks;
|
||||
struct fuse_timespec st_birthtim;
|
||||
};
|
||||
|
||||
#if defined(_WIN64)
|
||||
struct fuse_statvfs
|
||||
{
|
||||
uint64_t f_bsize;
|
||||
uint64_t f_frsize;
|
||||
fuse_fsblkcnt_t f_blocks;
|
||||
fuse_fsblkcnt_t f_bfree;
|
||||
fuse_fsblkcnt_t f_bavail;
|
||||
fuse_fsfilcnt_t f_files;
|
||||
fuse_fsfilcnt_t f_ffree;
|
||||
fuse_fsfilcnt_t f_favail;
|
||||
uint64_t f_fsid;
|
||||
uint64_t f_flag;
|
||||
uint64_t f_namemax;
|
||||
};
|
||||
#else
|
||||
struct fuse_statvfs
|
||||
{
|
||||
uint32_t f_bsize;
|
||||
uint32_t f_frsize;
|
||||
fuse_fsblkcnt_t f_blocks;
|
||||
fuse_fsblkcnt_t f_bfree;
|
||||
fuse_fsblkcnt_t f_bavail;
|
||||
fuse_fsfilcnt_t f_files;
|
||||
fuse_fsfilcnt_t f_ffree;
|
||||
fuse_fsfilcnt_t f_favail;
|
||||
uint32_t f_fsid;
|
||||
uint32_t f_flag;
|
||||
uint32_t f_namemax;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct fuse_flock
|
||||
{
|
||||
int16_t l_type;
|
||||
int16_t l_whence;
|
||||
fuse_off_t l_start;
|
||||
fuse_off_t l_len;
|
||||
fuse_pid_t l_pid;
|
||||
};
|
||||
|
||||
#if defined(WINFSP_DLL_INTERNAL)
|
||||
#define FSP_FUSE_ENV_INIT \
|
||||
{ \
|
||||
'W', \
|
||||
MemAlloc, MemFree, \
|
||||
fsp_fuse_daemonize, \
|
||||
fsp_fuse_set_signal_handlers, \
|
||||
}
|
||||
#else
|
||||
#define FSP_FUSE_ENV_INIT \
|
||||
{ \
|
||||
'W', \
|
||||
malloc, free, \
|
||||
fsp_fuse_daemonize, \
|
||||
fsp_fuse_set_signal_handlers, \
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__CYGWIN__)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/types.h>
|
||||
#include <utime.h>
|
||||
|
||||
#define fuse_uid_t uid_t
|
||||
#define fuse_gid_t gid_t
|
||||
#define fuse_pid_t pid_t
|
||||
|
||||
#define fuse_dev_t dev_t
|
||||
#define fuse_ino_t ino_t
|
||||
#define fuse_mode_t mode_t
|
||||
#define fuse_nlink_t nlink_t
|
||||
#define fuse_off_t off_t
|
||||
|
||||
#define fuse_fsblkcnt_t fsblkcnt_t
|
||||
#define fuse_fsfilcnt_t fsfilcnt_t
|
||||
#define fuse_blksize_t blksize_t
|
||||
#define fuse_blkcnt_t blkcnt_t
|
||||
|
||||
#define fuse_utimbuf utimbuf
|
||||
#define fuse_timespec timespec
|
||||
|
||||
#define fuse_stat stat
|
||||
#define fuse_statvfs statvfs
|
||||
#define fuse_flock flock
|
||||
|
||||
#define FSP_FUSE_ENV_INIT \
|
||||
{ \
|
||||
'C', \
|
||||
malloc, free, \
|
||||
fsp_fuse_daemonize, \
|
||||
fsp_fuse_set_signal_handlers, \
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that long is 8 bytes long in Cygwin64 and 4 bytes long in Win64.
|
||||
* For this reason we avoid using long anywhere in these headers.
|
||||
*/
|
||||
|
||||
#else
|
||||
#error unsupported environment
|
||||
#endif
|
||||
|
||||
struct fsp_fuse_env
|
||||
{
|
||||
unsigned environment;
|
||||
void *(*memalloc)(size_t);
|
||||
void (*memfree)(void *);
|
||||
int (*daemonize)(int);
|
||||
int (*set_signal_handlers)(void *);
|
||||
void (*reserved[4])();
|
||||
};
|
||||
|
||||
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_signal_handler)(int sig);
|
||||
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
|
||||
static inline int fsp_fuse_daemonize(int foreground)
|
||||
{
|
||||
(void)foreground;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int fsp_fuse_set_signal_handlers(void *se)
|
||||
{
|
||||
(void)se;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(__CYGWIN__)
|
||||
|
||||
static inline int fsp_fuse_daemonize(int foreground)
|
||||
{
|
||||
int daemon(int nochdir, int noclose);
|
||||
int chdir(const char *path);
|
||||
|
||||
if (!foreground)
|
||||
{
|
||||
if (-1 == daemon(0, 0))
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
chdir("/");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void *fsp_fuse_signal_thread(void *psigmask)
|
||||
{
|
||||
int sig;
|
||||
|
||||
if (0 == sigwait((sigset_t *)psigmask, &sig))
|
||||
FSP_FUSE_API_CALL(fsp_fuse_signal_handler)(sig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int fsp_fuse_set_signal_handlers(void *se)
|
||||
{
|
||||
#define FSP_FUSE_SET_SIGNAL_HANDLER(sig, newha)\
|
||||
if (-1 != sigaction((sig), 0, &oldsa) &&\
|
||||
oldsa.sa_handler == (se ? SIG_DFL : (newha)))\
|
||||
{\
|
||||
newsa.sa_handler = se ? (newha) : SIG_DFL;\
|
||||
sigaction((sig), &newsa, 0);\
|
||||
}
|
||||
#define FSP_FUSE_SIGADDSET(sig)\
|
||||
if (-1 != sigaction((sig), 0, &oldsa) &&\
|
||||
oldsa.sa_handler == SIG_DFL)\
|
||||
sigaddset(&sigmask, (sig));
|
||||
|
||||
static sigset_t sigmask;
|
||||
static pthread_t sigthr;
|
||||
struct sigaction oldsa, newsa = { 0 };
|
||||
|
||||
if (0 != se)
|
||||
{
|
||||
if (0 == sigthr)
|
||||
{
|
||||
FSP_FUSE_SET_SIGNAL_HANDLER(SIGPIPE, SIG_IGN);
|
||||
|
||||
sigemptyset(&sigmask);
|
||||
FSP_FUSE_SIGADDSET(SIGHUP);
|
||||
FSP_FUSE_SIGADDSET(SIGINT);
|
||||
FSP_FUSE_SIGADDSET(SIGTERM);
|
||||
if (0 != pthread_sigmask(SIG_BLOCK, &sigmask, 0))
|
||||
return -1;
|
||||
|
||||
if (0 != pthread_create(&sigthr, 0, fsp_fuse_signal_thread, &sigmask))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 != sigthr)
|
||||
{
|
||||
pthread_cancel(sigthr);
|
||||
pthread_join(sigthr, 0);
|
||||
sigthr = 0;
|
||||
|
||||
if (0 != pthread_sigmask(SIG_UNBLOCK, &sigmask, 0))
|
||||
return -1;
|
||||
sigemptyset(&sigmask);
|
||||
|
||||
FSP_FUSE_SET_SIGNAL_HANDLER(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
#undef FSP_FUSE_SIGADDSET
|
||||
#undef FSP_FUSE_SET_SIGNAL_HANDLER
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static inline struct fsp_fuse_env *fsp_fuse_env(void)
|
||||
{
|
||||
static struct fsp_fuse_env env = FSP_FUSE_ENV_INIT;
|
||||
return &env;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -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"
|
||||
|
||||
@ -257,7 +258,7 @@ typedef struct
|
||||
struct
|
||||
{
|
||||
FSP_FSCTL_TRANSACT_BUF NewFileName;
|
||||
UINT32 ReplaceIfExists:1;
|
||||
UINT64 AccessToken; /* request access token (HANDLE) */
|
||||
} Rename;
|
||||
} Info;
|
||||
} SetInformation;
|
||||
@ -311,7 +312,7 @@ typedef struct
|
||||
UINT64 Hint;
|
||||
struct
|
||||
{
|
||||
UINT64 Information;
|
||||
UINT32 Information;
|
||||
UINT32 Status;
|
||||
} IoStatus;
|
||||
union
|
||||
@ -421,6 +422,7 @@ FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle,
|
||||
FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle);
|
||||
FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath,
|
||||
PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize);
|
||||
FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -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 <winfsp/winfsp.h>
|
||||
* and link with the winfsp_x64.dll (or winfsp_x86.dll) library.
|
||||
@ -46,11 +40,17 @@
|
||||
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 *,
|
||||
typedef NTSTATUS FSP_FILE_SYSTEM_OPERATION_GUARD(FSP_FILE_SYSTEM *,
|
||||
FSP_FSCTL_TRANSACT_REQ *, FSP_FSCTL_TRANSACT_RSP *);
|
||||
typedef NTSTATUS FSP_FILE_SYSTEM_OPERATION(FSP_FILE_SYSTEM *,
|
||||
FSP_FSCTL_TRANSACT_REQ *, FSP_FSCTL_TRANSACT_RSP *);
|
||||
@ -402,41 +402,35 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
||||
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
|
||||
FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
/**
|
||||
* Set file allocation size.
|
||||
* Set file/allocation size.
|
||||
*
|
||||
* This function is used to change a file's sizes. Windows file systems maintain two kinds
|
||||
* of sizes: the file size is where the End Of File (EOF) is, and the allocation size is the
|
||||
* actual size that a file takes up on the "disk".
|
||||
*
|
||||
* The rules regarding file/allocation size are:
|
||||
* <ul>
|
||||
* <li>Allocation size must always be aligned to the allocation unit boundary. The allocation
|
||||
* unit is the product <code>(UINT64)SectorSize * (UINT64)SectorsPerAllocationUnit</code> from
|
||||
* the FSP_FSCTL_VOLUME_PARAMS structure. The FSD will always send properly aligned allocation
|
||||
* sizes when setting the allocation size.</li>
|
||||
* <li>Allocation size is always greater or equal to the file size.</li>
|
||||
* <li>A file size of more than the current allocation size will also extend the allocation
|
||||
* size to the next allocation unit boundary.</li>
|
||||
* <li>An allocation size of less than the current file size should also truncate the current
|
||||
* file size.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param FileSystem
|
||||
* The file system on which this request is posted.
|
||||
* @param Request
|
||||
* The request posted by the kernel mode FSD.
|
||||
* @param FileNode
|
||||
* The file node of the file to set the allocation size for.
|
||||
* @param AllocationSize
|
||||
* Allocation size to apply to the file. Allocation size is always greater than file size.
|
||||
* An allocation size of less than the current file size should also truncate the current
|
||||
* file size.
|
||||
* @param FileInfo [out]
|
||||
* Pointer to a structure that will receive the file information on successful return
|
||||
* from this call. This information includes file attributes, file times, etc.
|
||||
* @return
|
||||
* STATUS_SUCCESS on error code.
|
||||
*/
|
||||
NTSTATUS (*SetAllocationSize)(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||
PVOID FileNode, UINT64 AllocationSize,
|
||||
FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
/**
|
||||
* Set file size.
|
||||
*
|
||||
* @param FileSystem
|
||||
* The file system on which this request is posted.
|
||||
* @param Request
|
||||
* The request posted by the kernel mode FSD.
|
||||
* @param FileNode
|
||||
* The file node of the file to set the size for.
|
||||
* @param FileSize
|
||||
* FileSize size to apply to the file. Allocation size is always greater than file size.
|
||||
* A file size of more than the current allocation size will also extend the allocation
|
||||
* size to the next allocation unit boundary.
|
||||
* The file node of the file to set the file/allocation size for.
|
||||
* @param NewSize
|
||||
* New file/allocation size to apply to the file.
|
||||
* @param SetAllocationSize
|
||||
* If TRUE, then the allocation size is being set. if FALSE, then the file size is being set.
|
||||
* @param FileInfo [out]
|
||||
* Pointer to a structure that will receive the file information on successful return
|
||||
* from this call. This information includes file attributes, file times, etc.
|
||||
@ -445,7 +439,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
||||
*/
|
||||
NTSTATUS (*SetFileSize)(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||
PVOID FileNode, UINT64 FileSize,
|
||||
PVOID FileNode, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
||||
FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
/**
|
||||
* Determine whether a file or directory can be deleted.
|
||||
@ -454,6 +448,12 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
||||
* not need to perform access checks, but may performs tasks such as check for empty
|
||||
* directories, etc.
|
||||
*
|
||||
* This function should <b>NEVER</b> delete the file or directory in question. Deletion should
|
||||
* happen during Cleanup with Delete==TRUE.
|
||||
*
|
||||
* This function gets called when Win32 API's such as DeleteFile or RemoveDirectory are used.
|
||||
* It does not get called when a file or directory is opened with FILE_DELETE_ON_CLOSE.
|
||||
*
|
||||
* @param FileSystem
|
||||
* The file system on which this request is posted.
|
||||
* @param Request
|
||||
@ -576,7 +576,26 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
||||
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
||||
PWSTR Pattern,
|
||||
PULONG PBytesTransferred);
|
||||
|
||||
/*
|
||||
* This ensures that this interface will always contain 64 function pointers.
|
||||
* Please update when changing the interface as it is important for future compatibility.
|
||||
*/
|
||||
NTSTATUS (*Reserved[45])();
|
||||
} FSP_FILE_SYSTEM_INTERFACE;
|
||||
#if defined(WINFSP_DLL_INTERNAL)
|
||||
/*
|
||||
* Static_assert is a C++11 feature, but seems to work with C on MSVC 2015.
|
||||
* Use it to verify that FSP_FILE_SYSTEM_INTERFACE has the right size.
|
||||
*/
|
||||
static_assert(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
|
||||
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
|
||||
#endif
|
||||
typedef enum
|
||||
{
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0,
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE,
|
||||
} FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY;
|
||||
typedef struct _FSP_FILE_SYSTEM
|
||||
{
|
||||
UINT16 Version;
|
||||
@ -590,7 +609,10 @@ typedef struct _FSP_FILE_SYSTEM
|
||||
ULONG DispatcherThreadCount;
|
||||
NTSTATUS DispatcherResult;
|
||||
PWSTR MountPoint;
|
||||
LIST_ENTRY MountEntry;
|
||||
HANDLE MountHandle;
|
||||
UINT32 DebugLog;
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
|
||||
SRWLOCK OpGuardLock;
|
||||
} FSP_FILE_SYSTEM;
|
||||
/**
|
||||
* Create a file system object.
|
||||
@ -693,18 +715,22 @@ PWSTR FspFileSystemMountPoint(FSP_FILE_SYSTEM *FileSystem)
|
||||
return FileSystem->MountPoint;
|
||||
}
|
||||
static inline
|
||||
VOID FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
NTSTATUS FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
if (0 != FileSystem->EnterOperation)
|
||||
FileSystem->EnterOperation(FileSystem, Request, Response);
|
||||
if (0 == FileSystem->EnterOperation)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
return FileSystem->EnterOperation(FileSystem, Request, Response);
|
||||
}
|
||||
static inline
|
||||
VOID FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
NTSTATUS FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
if (0 != FileSystem->LeaveOperation)
|
||||
FileSystem->LeaveOperation(FileSystem, Request, Response);
|
||||
if (0 == FileSystem->LeaveOperation)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
return FileSystem->LeaveOperation(FileSystem, Request, Response);
|
||||
}
|
||||
static inline
|
||||
VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
|
||||
@ -715,6 +741,12 @@ VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
|
||||
FileSystem->LeaveOperation = LeaveOperation;
|
||||
}
|
||||
static inline
|
||||
VOID FspFileSystemSetOperationGuardStrategy(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy)
|
||||
{
|
||||
FileSystem->OpGuardStrategy = GuardStrategy;
|
||||
}
|
||||
static inline
|
||||
VOID FspFileSystemSetOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
ULONG Index,
|
||||
FSP_FILE_SYSTEM_OPERATION *Operation)
|
||||
@ -737,10 +769,20 @@ VOID FspFileSystemSetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
|
||||
return;
|
||||
InterlockedCompareExchange(&FileSystem->DispatcherResult, DispatcherResult, 0);
|
||||
}
|
||||
static inline
|
||||
VOID FspFileSystemSetDebugLog(FSP_FILE_SYSTEM *FileSystem,
|
||||
UINT32 DebugLog)
|
||||
{
|
||||
FileSystem->DebugLog = DebugLog;
|
||||
}
|
||||
|
||||
/*
|
||||
* Operations
|
||||
*/
|
||||
FSP_API NTSTATUS FspFileSystemOpEnter(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
FSP_API NTSTATUS FspFileSystemOpLeave(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
FSP_API NTSTATUS FspFileSystemOpCreate(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
FSP_API NTSTATUS FspFileSystemOpOverwrite(FSP_FILE_SYSTEM *FileSystem,
|
||||
@ -831,6 +873,22 @@ NTSTATUS FspAccessCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||
0);
|
||||
}
|
||||
|
||||
/*
|
||||
* POSIX Interop
|
||||
*/
|
||||
FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid);
|
||||
FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid);
|
||||
FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)());
|
||||
FSP_API NTSTATUS FspPosixMapPermissionsToSecurityDescriptor(
|
||||
UINT32 Uid, UINT32 Gid, UINT32 Mode,
|
||||
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
|
||||
FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode);
|
||||
FSP_API NTSTATUS FspPosixMapWindowsToPosixPath(PWSTR WindowsPath, char **PPosixPath);
|
||||
FSP_API NTSTATUS FspPosixMapPosixToWindowsPath(const char *PosixPath, PWSTR *PWindowsPath);
|
||||
FSP_API VOID FspPosixDeletePath(void *Path);
|
||||
|
||||
/*
|
||||
* Path Handling
|
||||
*/
|
||||
@ -838,13 +896,217 @@ 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 FspServiceRunEx(PWSTR ServiceName,
|
||||
FSP_SERVICE_START *OnStart,
|
||||
FSP_SERVICE_STOP *OnStop,
|
||||
FSP_SERVICE_CONTROL *OnControl,
|
||||
PVOID UserContext);
|
||||
static inline
|
||||
ULONG FspServiceRun(PWSTR ServiceName,
|
||||
FSP_SERVICE_START *OnStart,
|
||||
FSP_SERVICE_STOP *OnStop,
|
||||
FSP_SERVICE_CONTROL *OnControl)
|
||||
{
|
||||
return FspServiceRunEx(ServiceName, OnStart, OnStop, OnControl, 0);
|
||||
}
|
||||
/**
|
||||
* 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 VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request);
|
||||
FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
|
||||
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
|
||||
PULONG PBytesTransferred, ULONG Timeout,
|
||||
PSID Sid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
20
opt/cygfuse/Makefile
Normal file
20
opt/cygfuse/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
Version = $(shell sed -n '/^VERSION=/s/VERSION=\(.*\)/\1/p' fuse.cygport)
|
||||
#Debug = -g
|
||||
|
||||
cygfuse-$(Version).dll libfuse-$(Version).dll.a fuse.pc: cygfuse.c fuse.pc.in
|
||||
gcc $(Debug) -shared -o cygfuse-$(Version).dll -Wl,--out-implib=libfuse-$(Version).dll.a -I../../inc/fuse cygfuse.c
|
||||
[ -n "$(Debug)" ] || strip cygfuse-$(Version).dll
|
||||
sed "s/@Version@/$(Version)/g" fuse.pc.in > fuse.pc
|
||||
|
||||
cygfuse-test.exe: cygfuse-test.c cygfuse-$(Version).dll libfuse-$(Version).dll.a
|
||||
gcc $(Debug) -o cygfuse-test.exe -I../../inc/fuse -DCYGFUSE cygfuse-test.c -L$(PWD) -lfuse-$(Version)
|
||||
|
||||
cygport:
|
||||
git clean -dfx
|
||||
(\
|
||||
cd `git rev-parse --show-toplevel` &&\
|
||||
Stash=`git stash create` &&\
|
||||
git archive --prefix=winfsp-work/ --format=tar.gz $${Stash:-HEAD}\
|
||||
> opt/cygfuse/winfsp-work.tar.gz\
|
||||
)
|
||||
CYGPORT_SRC_URI=winfsp-work.tar.gz CYGPORT_SRC_DIR=winfsp-work cygport fuse.cygport download prep compile install package
|
6
opt/cygfuse/cygfuse-test.c
Normal file
6
opt/cygfuse/cygfuse-test.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <fuse.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
return !(FUSE_VERSION == fuse_version());
|
||||
}
|
146
opt/cygfuse/cygfuse.c
Normal file
146
opt/cygfuse/cygfuse.c
Normal file
@ -0,0 +1,146 @@
|
||||
/**
|
||||
* @file cygfuse/cygfuse.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 <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/cygwin.h>
|
||||
|
||||
static void *cygfuse_init_winfsp();
|
||||
static void *cygfuse_init_fail();
|
||||
|
||||
static pthread_mutex_t cygfuse_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static void *cygfuse_handle = 0;
|
||||
|
||||
static inline void cygfuse_init(int force)
|
||||
{
|
||||
pthread_mutex_lock(&cygfuse_mutex);
|
||||
if (force || 0 == cygfuse_handle)
|
||||
cygfuse_handle = cygfuse_init_winfsp();
|
||||
pthread_mutex_unlock(&cygfuse_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unfortunately Cygwin fork is very fragile and cannot even correctly
|
||||
* handle dlopen'ed DLL's if they are native (rather than Cygwin ones).
|
||||
*
|
||||
* So we have this very nasty hack where we reset the dlopen'ed handle
|
||||
* immediately after daemonization. This will force cygfuse_init() to
|
||||
* reload the WinFsp DLL and reset all API pointers in the daemonized
|
||||
* process.
|
||||
*/
|
||||
static inline int cygfuse_daemon(int nochdir, int noclose)
|
||||
{
|
||||
if (-1 == daemon(nochdir, noclose))
|
||||
return -1;
|
||||
|
||||
/* force reload of WinFsp DLL to workaround fork() problems */
|
||||
cygfuse_init(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define daemon cygfuse_daemon
|
||||
|
||||
#define FSP_FUSE_API static
|
||||
#define FSP_FUSE_API_NAME(api) (* pfn_ ## api)
|
||||
#define FSP_FUSE_API_CALL(api) (cygfuse_init(0), pfn_ ## api)
|
||||
#define FSP_FUSE_SYM(proto, ...) __attribute__ ((visibility("default"))) proto { __VA_ARGS__ }
|
||||
#include <fuse_common.h>
|
||||
#include <fuse.h>
|
||||
#include <fuse_opt.h>
|
||||
|
||||
#if defined(__LP64__)
|
||||
#define CYGFUSE_WINFSP_NAME "winfsp-x64.dll"
|
||||
#else
|
||||
#define CYGFUSE_WINFSP_NAME "winfsp-x86.dll"
|
||||
#endif
|
||||
#define CYGFUSE_WINFSP_PATH "bin\\" CYGFUSE_WINFSP_NAME
|
||||
#define CYGFUSE_GET_API(h, n) \
|
||||
if (0 == (*(void **)&(pfn_ ## n) = dlsym(h, #n)))\
|
||||
return cygfuse_init_fail();
|
||||
|
||||
static void *cygfuse_init_winfsp()
|
||||
{
|
||||
void *h;
|
||||
|
||||
h = dlopen(CYGFUSE_WINFSP_NAME, RTLD_NOW);
|
||||
if (0 == h)
|
||||
{
|
||||
char winpath[260], *psxpath;
|
||||
int regfd, bytes;
|
||||
|
||||
regfd = open("/proc/registry32/HKEY_LOCAL_MACHINE/Software/WinFsp/InstallDir", O_RDONLY);
|
||||
if (-1 == regfd)
|
||||
return cygfuse_init_fail();
|
||||
|
||||
bytes = read(regfd, winpath, sizeof winpath - sizeof CYGFUSE_WINFSP_PATH);
|
||||
close(regfd);
|
||||
if (-1 == bytes || 0 == bytes)
|
||||
return cygfuse_init_fail();
|
||||
|
||||
if ('\0' == winpath[bytes - 1])
|
||||
bytes--;
|
||||
memcpy(winpath + bytes, CYGFUSE_WINFSP_PATH, sizeof CYGFUSE_WINFSP_PATH);
|
||||
|
||||
psxpath = (char *)cygwin_create_path(CCP_WIN_A_TO_POSIX | CCP_PROC_CYGDRIVE, winpath);
|
||||
if (0 == psxpath)
|
||||
return cygfuse_init_fail();
|
||||
|
||||
h = dlopen(psxpath, RTLD_NOW);
|
||||
free(psxpath);
|
||||
if (0 == h)
|
||||
return cygfuse_init_fail();
|
||||
}
|
||||
|
||||
/* winfsp_fuse.h */
|
||||
CYGFUSE_GET_API(h, fsp_fuse_signal_handler);
|
||||
|
||||
/* fuse_common.h */
|
||||
CYGFUSE_GET_API(h, fsp_fuse_version);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_mount);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_unmount);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_parse_cmdline);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_ntstatus_from_errno);
|
||||
|
||||
/* fuse.h */
|
||||
CYGFUSE_GET_API(h, fsp_fuse_main_real);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_is_lib_option);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_new);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_destroy);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_loop);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_loop_mt);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_exit);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_get_context);
|
||||
|
||||
/* fuse_opt.h */
|
||||
CYGFUSE_GET_API(h, fsp_fuse_opt_parse);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_opt_add_arg);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_opt_insert_arg);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_opt_free_args);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_opt_add_opt);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_opt_add_opt_escaped);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_opt_match);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static void *cygfuse_init_fail()
|
||||
{
|
||||
abort();
|
||||
return 0;
|
||||
}
|
35
opt/cygfuse/fuse.cygport
Normal file
35
opt/cygfuse/fuse.cygport
Normal file
@ -0,0 +1,35 @@
|
||||
NAME="fuse"
|
||||
VERSION=2.8
|
||||
RELEASE=3
|
||||
CATEGORY="Utils"
|
||||
SUMMARY="WinFsp-FUSE compatibility layer"
|
||||
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."
|
||||
HOMEPAGE="http://www.secfs.net/winfsp/"
|
||||
|
||||
SRC_URI=${CYGPORT_SRC_URI:-"https://github.com/billziss-gh/winfsp/archive/master.tar.gz"}
|
||||
SRC_DIR=${CYGPORT_SRC_DIR:-winfsp-master}
|
||||
|
||||
src_compile()
|
||||
{
|
||||
lndirs
|
||||
cd ${B}/opt/cygfuse
|
||||
make
|
||||
}
|
||||
|
||||
src_install()
|
||||
{
|
||||
cd ${B}/inc/fuse
|
||||
includeinto fuse
|
||||
doinclude fuse.h
|
||||
doinclude fuse_common.h
|
||||
doinclude fuse_opt.h
|
||||
doinclude winfsp_fuse.h
|
||||
|
||||
cd ${B}/opt/cygfuse
|
||||
dobin cygfuse-${VERSION}.dll
|
||||
dolib libfuse-${VERSION}.dll.a
|
||||
dosym libfuse-${VERSION}.dll.a /usr/lib/libfuse.dll.a
|
||||
dopkgconfig fuse.pc
|
||||
}
|
||||
|
||||
RESTRICT="strip postinst-doc"
|
9
opt/cygfuse/fuse.pc.in
Normal file
9
opt/cygfuse/fuse.pc.in
Normal file
@ -0,0 +1,9 @@
|
||||
prefix=/usr
|
||||
incdir=${prefix}/include/fuse
|
||||
|
||||
Name: fuse
|
||||
Description: WinFsp FUSE compatible API
|
||||
Version: @Version@
|
||||
URL: http://www.secfs.net/winfsp/
|
||||
Libs: -lfuse-@Version@
|
||||
Cflags: -I"${incdir}" -DCYGFUSE
|
587
src/dll/debug.c
587
src/dll/debug.c
@ -37,7 +37,8 @@ FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDesc
|
||||
|
||||
if (0 == SecurityDescriptor)
|
||||
FspDebugLog(format, "null security descriptor");
|
||||
else if (ConvertSecurityDescriptorToStringSecurityDescriptorA(SecurityDescriptor, SDDL_REVISION_1,
|
||||
else if (ConvertSecurityDescriptorToStringSecurityDescriptorA(SecurityDescriptor,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0))
|
||||
@ -65,3 +66,587 @@ FSP_API VOID FspDebugLogFT(const char *format, PFILETIME FileTime)
|
||||
else
|
||||
FspDebugLog(format, "invalid file time");
|
||||
}
|
||||
|
||||
#define MAKE_UINT32_PAIR(v) \
|
||||
((PLARGE_INTEGER)&(v))->HighPart, ((PLARGE_INTEGER)&(v))->LowPart
|
||||
|
||||
static const char *FspDebugLogDispositionString(UINT32 CreateOptions)
|
||||
{
|
||||
switch ((CreateOptions >> 24) & 0xff)
|
||||
{
|
||||
case FILE_CREATE:
|
||||
return "FILE_CREATE";
|
||||
case FILE_OPEN:
|
||||
return "FILE_OPEN";
|
||||
case FILE_OPEN_IF:
|
||||
return "FILE_OPEN_IF";
|
||||
case FILE_OVERWRITE:
|
||||
return "FILE_OVERWRITE";
|
||||
case FILE_SUPERSEDE:
|
||||
return "FILE_SUPERSEDE";
|
||||
case FILE_OVERWRITE_IF:
|
||||
return "FILE_OVERWRITE_IF";
|
||||
default:
|
||||
return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *FspDebugLogUserContextString(UINT64 UserContext, UINT64 UserContext2, char *Buf)
|
||||
{
|
||||
wsprintfA(Buf, 0 == UserContext2 ? "%p" : "%p:%p", UserContext, UserContext2);
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogFileTimeString(UINT64 FileTime, char *Buf)
|
||||
{
|
||||
SYSTEMTIME SystemTime;
|
||||
|
||||
if (0 == FileTime)
|
||||
lstrcpyA(Buf, "0");
|
||||
else if (FileTimeToSystemTime((PFILETIME)&FileTime, &SystemTime))
|
||||
{
|
||||
wsprintfA(Buf, "%04hu-%02hu-%02huT%02hu:%02hu:%02hu.%03huZ",
|
||||
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay,
|
||||
SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond,
|
||||
SystemTime.wMilliseconds);
|
||||
}
|
||||
else
|
||||
lstrcpyA(Buf, "INVALID");
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogFileInfoString(FSP_FSCTL_FILE_INFO *FileInfo, char *Buf)
|
||||
{
|
||||
char CreationTimeBuf[32], LastAccessTimeBuf[32], LastWriteTimeBuf[32], ChangeTimeBuf[32];
|
||||
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"FileAttributes=%lx, "
|
||||
"ReparseTag=%lx, "
|
||||
"AllocationSize=%lx:%lx, "
|
||||
"FileSize=%lx:%lx, "
|
||||
"CreationTime=%s, "
|
||||
"LastAccessTime=%s, "
|
||||
"LastWriteTime=%s, "
|
||||
"ChangeTime=%s, "
|
||||
"IndexNumber=%lx:%lx"
|
||||
"}",
|
||||
FileInfo->FileAttributes,
|
||||
FileInfo->ReparseTag,
|
||||
MAKE_UINT32_PAIR(FileInfo->AllocationSize),
|
||||
MAKE_UINT32_PAIR(FileInfo->FileSize),
|
||||
FspDebugLogFileTimeString(FileInfo->CreationTime, CreationTimeBuf),
|
||||
FspDebugLogFileTimeString(FileInfo->LastAccessTime, LastAccessTimeBuf),
|
||||
FspDebugLogFileTimeString(FileInfo->LastWriteTime, LastWriteTimeBuf),
|
||||
FspDebugLogFileTimeString(FileInfo->ChangeTime, ChangeTimeBuf),
|
||||
MAKE_UINT32_PAIR(FileInfo->IndexNumber));
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogVolumeInfoString(FSP_FSCTL_VOLUME_INFO *VolumeInfo, char *Buf)
|
||||
{
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"TotalSize=%lx:%lx, "
|
||||
"FreeSize=%lx:%lx, "
|
||||
"VolumeLabel=\"%.32S\""
|
||||
"}",
|
||||
MAKE_UINT32_PAIR(VolumeInfo->TotalSize),
|
||||
MAKE_UINT32_PAIR(VolumeInfo->FreeSize),
|
||||
&VolumeInfo->VolumeLabel);
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static VOID FspDebugLogRequestVoid(FSP_FSCTL_TRANSACT_REQ *Request, const char *Name)
|
||||
{
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint, Name);
|
||||
}
|
||||
|
||||
static VOID FspDebugLogResponseStatus(FSP_FSCTL_TRANSACT_RSP *Response, const char *Name)
|
||||
{
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<%s IoStatus=%lx[%ld]\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint, Name,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information);
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
{
|
||||
char UserContextBuf[40];
|
||||
char CreationTimeBuf[32], LastAccessTimeBuf[32], LastWriteTimeBuf[32];
|
||||
char *Sddl = 0;
|
||||
|
||||
switch (Request->Kind)
|
||||
{
|
||||
case FspFsctlTransactReservedKind:
|
||||
FspDebugLogRequestVoid(Request, "RESERVED");
|
||||
break;
|
||||
case FspFsctlTransactCreateKind:
|
||||
if (0 != Request->Req.Create.SecurityDescriptor.Offset)
|
||||
ConvertSecurityDescriptorToStringSecurityDescriptorA(
|
||||
Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c] \"%S\", "
|
||||
"%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, "
|
||||
"AllocationSize=%lx:%lx, AccessToken=%p, DesiredAccess=%lx, ShareAccess=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->Req.Create.UserMode ? 'U' : 'K',
|
||||
Request->Req.Create.HasTraversePrivilege ? 'T' : '-',
|
||||
Request->Req.Create.OpenTargetDirectory ? 'D' : '-',
|
||||
Request->Req.Create.CaseSensitive ? 'C' : '-',
|
||||
(PWSTR)Request->Buffer,
|
||||
FspDebugLogDispositionString(Request->Req.Create.CreateOptions),
|
||||
Request->Req.Create.CreateOptions & 0xffffff,
|
||||
Request->Req.Create.FileAttributes,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "",
|
||||
MAKE_UINT32_PAIR(Request->Req.Create.AllocationSize),
|
||||
(PVOID)Request->Req.Create.AccessToken,
|
||||
Request->Req.Create.DesiredAccess,
|
||||
Request->Req.Create.ShareAccess);
|
||||
LocalFree(Sddl);
|
||||
break;
|
||||
case FspFsctlTransactOverwriteKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Overwrite%s %s%S%s%s, "
|
||||
"FileAttributes=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->Req.Overwrite.Supersede ? " [Supersede]" : "",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Overwrite.UserContext, Request->Req.Overwrite.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.Overwrite.FileAttributes);
|
||||
break;
|
||||
case FspFsctlTransactCleanupKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Cleanup%s %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->Req.Cleanup.Delete ? " [Delete]" : "",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Cleanup.UserContext, Request->Req.Cleanup.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactCloseKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Close %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Close.UserContext, Request->Req.Close.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactReadKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Read %s%S%s%s, "
|
||||
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Read.UserContext, Request->Req.Read.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.Read.Address,
|
||||
MAKE_UINT32_PAIR(Request->Req.Read.Offset),
|
||||
Request->Req.Read.Length,
|
||||
Request->Req.Read.Key);
|
||||
break;
|
||||
case FspFsctlTransactWriteKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Write%s %s%S%s%s, "
|
||||
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->Req.Write.ConstrainedIo ? " [C]" : "",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Write.UserContext, Request->Req.Write.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.Write.Address,
|
||||
MAKE_UINT32_PAIR(Request->Req.Write.Offset),
|
||||
Request->Req.Write.Length,
|
||||
Request->Req.Write.Key);
|
||||
break;
|
||||
case FspFsctlTransactQueryInformationKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QueryInformation %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.QueryInformation.UserContext, Request->Req.QueryInformation.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactSetInformationKind:
|
||||
switch (Request->Req.SetInformation.FileInformationClass)
|
||||
{
|
||||
case 4/*FileBasicInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Basic] %s%S%s%s, "
|
||||
"FileAttributes=%lx, CreationTime=%s, LastAccessTime=%s, LastWriteTime=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.SetInformation.Info.Basic.FileAttributes,
|
||||
FspDebugLogFileTimeString(Request->Req.SetInformation.Info.Basic.CreationTime,
|
||||
CreationTimeBuf),
|
||||
FspDebugLogFileTimeString(Request->Req.SetInformation.Info.Basic.LastAccessTime,
|
||||
LastAccessTimeBuf),
|
||||
FspDebugLogFileTimeString(Request->Req.SetInformation.Info.Basic.LastWriteTime,
|
||||
LastWriteTimeBuf));
|
||||
break;
|
||||
case 19/*FileAllocationInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Allocation] %s%S%s%s, "
|
||||
"AllocationSize=%lx:%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
MAKE_UINT32_PAIR(Request->Req.SetInformation.Info.Allocation.AllocationSize));
|
||||
break;
|
||||
case 20/*FileEndOfFileInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [EndOfFile] %s%S%s%s, "
|
||||
"FileSize = %lx:%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
MAKE_UINT32_PAIR(Request->Req.SetInformation.Info.EndOfFile.FileSize));
|
||||
break;
|
||||
case 13/*FileDispositionInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Disposition] %s%S%s%s, "
|
||||
"%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.SetInformation.Info.Disposition.Delete ? "Delete" : "Undelete");
|
||||
break;
|
||||
case 10/*FileRenameInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Rename] %s%S%s%s, "
|
||||
"NewFileName=\"%S\", AccessToken=%p\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
|
||||
(PVOID)Request->Req.SetInformation.Info.Rename.AccessToken);
|
||||
break;
|
||||
default:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [INVALID] %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf));
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactQueryEaKind:
|
||||
FspDebugLogRequestVoid(Request, "QUERYEA");
|
||||
break;
|
||||
case FspFsctlTransactSetEaKind:
|
||||
FspDebugLogRequestVoid(Request, "SETEA");
|
||||
break;
|
||||
case FspFsctlTransactFlushBuffersKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FlushBuffers %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.FlushBuffers.UserContext, Request->Req.FlushBuffers.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactQueryVolumeInformationKind:
|
||||
FspDebugLogRequestVoid(Request, "QueryVolumeInformation");
|
||||
break;
|
||||
case FspFsctlTransactSetVolumeInformationKind:
|
||||
switch (Request->Req.SetVolumeInformation.FsInformationClass)
|
||||
{
|
||||
case 2/*FileFsLabelInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [FsLabel] "
|
||||
"Label=\"%S\"\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
(PWSTR)Request->Buffer);
|
||||
break;
|
||||
default:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [INVALID]\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactQueryDirectoryKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QueryDirectory %s%S%s%s, "
|
||||
"Address=%p, Offset=%lx:%lx, Length=%ld, Pattern=%s%S%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.QueryDirectory.UserContext, Request->Req.QueryDirectory.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.QueryDirectory.Address,
|
||||
MAKE_UINT32_PAIR(Request->Req.QueryDirectory.Offset),
|
||||
Request->Req.QueryDirectory.Length,
|
||||
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "",
|
||||
Request->Req.QueryDirectory.Pattern.Size ?
|
||||
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : L"NULL",
|
||||
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "");
|
||||
break;
|
||||
case FspFsctlTransactFileSystemControlKind:
|
||||
FspDebugLogRequestVoid(Request, "FILESYSTEMCONTROL");
|
||||
break;
|
||||
case FspFsctlTransactDeviceControlKind:
|
||||
FspDebugLogRequestVoid(Request, "DEVICECONTROL");
|
||||
break;
|
||||
case FspFsctlTransactShutdownKind:
|
||||
FspDebugLogRequestVoid(Request, "SHUTDOWN");
|
||||
break;
|
||||
case FspFsctlTransactLockControlKind:
|
||||
FspDebugLogRequestVoid(Request, "LOCKCONTROL");
|
||||
break;
|
||||
case FspFsctlTransactQuerySecurityKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QuerySecurity %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.QuerySecurity.UserContext, Request->Req.QuerySecurity.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactSetSecurityKind:
|
||||
if (0 != Request->Req.SetSecurity.SecurityDescriptor.Size)
|
||||
ConvertSecurityDescriptorToStringSecurityDescriptorA(
|
||||
Request->Buffer + Request->Req.SetSecurity.SecurityDescriptor.Offset,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetSecurity %s%S%s%s, "
|
||||
"SecurityInformation=%lx, AccessToken=%p, Security=%s%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetSecurity.UserContext, Request->Req.SetSecurity.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.SetSecurity.SecurityInformation,
|
||||
(PVOID)Request->Req.SetSecurity.AccessToken,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "");
|
||||
LocalFree(Sddl);
|
||||
break;
|
||||
default:
|
||||
FspDebugLogRequestVoid(Request, "INVALID");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
if (STATUS_PENDING == Response->IoStatus.Status)
|
||||
return;
|
||||
|
||||
char UserContextBuf[40];
|
||||
char InfoBuf[256];
|
||||
char *Sddl = 0;
|
||||
|
||||
switch (Response->Kind)
|
||||
{
|
||||
case FspFsctlTransactReservedKind:
|
||||
FspDebugLogResponseStatus(Response, "RESERVED");
|
||||
break;
|
||||
case FspFsctlTransactCreateKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "Create");
|
||||
else if (STATUS_REPARSE == Response->IoStatus.Status)
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||
"Reparse.FileName=\"%S\"\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
(PWSTR)(Response->Buffer + Response->Rsp.Create.Reparse.FileName.Offset));
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||
"UserContext=%s, GrantedAccess=%lx, FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogUserContextString(
|
||||
Response->Rsp.Create.Opened.UserContext, Response->Rsp.Create.Opened.UserContext2,
|
||||
UserContextBuf),
|
||||
Response->Rsp.Create.Opened.GrantedAccess,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.Create.Opened.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactOverwriteKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "Overwrite");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Overwrite IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.Overwrite.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactCleanupKind:
|
||||
FspDebugLogResponseStatus(Response, "Cleanup");
|
||||
break;
|
||||
case FspFsctlTransactCloseKind:
|
||||
FspDebugLogResponseStatus(Response, "Close");
|
||||
break;
|
||||
case FspFsctlTransactReadKind:
|
||||
FspDebugLogResponseStatus(Response, "Read");
|
||||
break;
|
||||
case FspFsctlTransactWriteKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "Write");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Write IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.Write.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactQueryInformationKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "QueryInformation");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<QueryInformation IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.QueryInformation.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactSetInformationKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "SetInformation");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<SetInformation IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.SetInformation.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactQueryEaKind:
|
||||
FspDebugLogResponseStatus(Response, "QUERYEA");
|
||||
break;
|
||||
case FspFsctlTransactSetEaKind:
|
||||
FspDebugLogResponseStatus(Response, "SETEA");
|
||||
break;
|
||||
case FspFsctlTransactFlushBuffersKind:
|
||||
FspDebugLogResponseStatus(Response, "FlushBuffers");
|
||||
break;
|
||||
case FspFsctlTransactQueryVolumeInformationKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "QueryVolumeInformation");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<QueryVolumeInformation IoStatus=%lx[%ld] "
|
||||
"VolumeInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogVolumeInfoString(&Response->Rsp.QueryVolumeInformation.VolumeInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactSetVolumeInformationKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "SetVolumeInformation");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<SetVolumeInformation IoStatus=%lx[%ld] "
|
||||
"VolumeInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogVolumeInfoString(&Response->Rsp.SetVolumeInformation.VolumeInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactQueryDirectoryKind:
|
||||
FspDebugLogResponseStatus(Response, "QueryDirectory");
|
||||
break;
|
||||
case FspFsctlTransactFileSystemControlKind:
|
||||
FspDebugLogResponseStatus(Response, "FILESYSTEMCONTROL");
|
||||
break;
|
||||
case FspFsctlTransactDeviceControlKind:
|
||||
FspDebugLogResponseStatus(Response, "DEVICECONTROL");
|
||||
break;
|
||||
case FspFsctlTransactShutdownKind:
|
||||
FspDebugLogResponseStatus(Response, "SHUTDOWN");
|
||||
break;
|
||||
case FspFsctlTransactLockControlKind:
|
||||
FspDebugLogResponseStatus(Response, "LOCKCONTROL");
|
||||
break;
|
||||
case FspFsctlTransactQuerySecurityKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "QuerySecurity");
|
||||
else
|
||||
{
|
||||
if (0 != Response->Rsp.QuerySecurity.SecurityDescriptor.Size)
|
||||
ConvertSecurityDescriptorToStringSecurityDescriptorA(
|
||||
Response->Buffer + Response->Rsp.QuerySecurity.SecurityDescriptor.Offset,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<QuerySecurity IoStatus=%lx[%ld] "
|
||||
"Security=%s%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "");
|
||||
LocalFree(Sddl);
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactSetSecurityKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "SetSecurity");
|
||||
else
|
||||
{
|
||||
if (0 != Response->Rsp.SetSecurity.SecurityDescriptor.Size)
|
||||
ConvertSecurityDescriptorToStringSecurityDescriptorA(
|
||||
Response->Buffer + Response->Rsp.SetSecurity.SecurityDescriptor.Offset,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<SetSecurity IoStatus=%lx[%ld] "
|
||||
"Security=%s%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "");
|
||||
LocalFree(Sddl);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FspDebugLogResponseStatus(Response, "INVALID");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
139
src/dll/eventlog.c
Normal file
139
src/dll/eventlog.c
Normal file
@ -0,0 +1,139 @@
|
||||
/**
|
||||
* @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 INIT_ONCE FspEventLogInitOnce = INIT_ONCE_STATIC_INIT;
|
||||
static HANDLE FspEventLogHandle;
|
||||
|
||||
static BOOL WINAPI FspEventLogInitialize(
|
||||
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
||||
{
|
||||
FspEventLogHandle = RegisterEventSourceW(0, L"" FSP_EVENTLOG_NAME);
|
||||
if (0 == FspEventLogHandle)
|
||||
FspEventLogHandle = RegisterEventSourceW(0, FspDiagIdent());
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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, FspEventLogInitialize, 0, 0);
|
||||
if (0 == FspEventLogHandle)
|
||||
return;
|
||||
|
||||
WCHAR Buf[1024], *Strings[2];
|
||||
/* wvsprintfW is only safe with a 1024 WCHAR buffer */
|
||||
DWORD EventId;
|
||||
|
||||
Strings[0] = FspDiagIdent();
|
||||
|
||||
wvsprintfW(Buf, Format, ap);
|
||||
Buf[(sizeof Buf / sizeof Buf[0]) - 1] = L'\0';
|
||||
Strings[1] = 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, 2, 0, Strings, 0);
|
||||
}
|
||||
|
||||
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\\Application\\" 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\\Application\\" FSP_EVENTLOG_NAME);
|
||||
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
|
||||
return FspNtStatusFromWin32(RegResult);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
63
src/dll/eventlog/eventlog.h
Normal file
63
src/dll/eventlog/eventlog.h
Normal 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: %2
|
||||
//
|
||||
#define FSP_EVENTLOG_INFORMATION 0x60000001L
|
||||
|
||||
//
|
||||
// MessageId: FSP_EVENTLOG_WARNING
|
||||
//
|
||||
// MessageText:
|
||||
//
|
||||
// %1: %2
|
||||
//
|
||||
#define FSP_EVENTLOG_WARNING 0xA0000001L
|
||||
|
||||
//
|
||||
// MessageId: FSP_EVENTLOG_ERROR
|
||||
//
|
||||
// MessageText:
|
||||
//
|
||||
// %1: %2
|
||||
//
|
||||
#define FSP_EVENTLOG_ERROR 0xE0000001L
|
||||
|
20
src/dll/eventlog/eventlog.mc
Normal file
20
src/dll/eventlog/eventlog.mc
Normal file
@ -0,0 +1,20 @@
|
||||
MessageId=1
|
||||
Severity=Informational
|
||||
SymbolicName=FSP_EVENTLOG_INFORMATION
|
||||
Language=English
|
||||
%1: %2
|
||||
.
|
||||
|
||||
MessageId=1
|
||||
Severity=Warning
|
||||
SymbolicName=FSP_EVENTLOG_WARNING
|
||||
Language=English
|
||||
%1: %2
|
||||
.
|
||||
|
||||
MessageId=1
|
||||
Severity=Error
|
||||
SymbolicName=FSP_EVENTLOG_ERROR
|
||||
Language=English
|
||||
%1: %2
|
||||
.
|
2
src/dll/eventlog/eventlog.rc
Normal file
2
src/dll/eventlog/eventlog.rc
Normal file
@ -0,0 +1,2 @@
|
||||
LANGUAGE 0x9,0x1
|
||||
1 11 "eventlog_MSG00001.bin"
|
BIN
src/dll/eventlog/eventlog_MSG00001.bin
Normal file
BIN
src/dll/eventlog/eventlog_MSG00001.bin
Normal file
Binary file not shown.
5
src/dll/eventlog/runmc.bat
Normal file
5
src/dll/eventlog/runmc.bat
Normal file
@ -0,0 +1,5 @@
|
||||
@echo off
|
||||
|
||||
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat"
|
||||
|
||||
mc -b -c eventlog.mc
|
161
src/dll/fs.c
161
src/dll/fs.c
@ -24,61 +24,35 @@ enum
|
||||
|
||||
static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface;
|
||||
|
||||
static CRITICAL_SECTION FspFileSystemMountListGuard;
|
||||
static LIST_ENTRY FspFileSystemMountList = { &FspFileSystemMountList, &FspFileSystemMountList };
|
||||
static INIT_ONCE FspFileSystemInitOnce = INIT_ONCE_STATIC_INIT;
|
||||
static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
|
||||
PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
|
||||
static NTSTATUS (NTAPI *FspNtMakeTemporaryObject)(
|
||||
HANDLE Handle);
|
||||
static NTSTATUS (NTAPI *FspNtClose)(
|
||||
HANDLE Handle);
|
||||
|
||||
VOID FspFileSystemInitialize(VOID)
|
||||
static BOOL WINAPI FspFileSystemInitialize(
|
||||
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
||||
{
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
HANDLE Handle;
|
||||
|
||||
InitializeCriticalSection(&FspFileSystemMountListGuard);
|
||||
}
|
||||
|
||||
VOID FspFileSystemFinalize(VOID)
|
||||
{
|
||||
/*
|
||||
* 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/
|
||||
*
|
||||
* We enter our FspFileSystemMountListGuard critical section here and then attempt to cleanup
|
||||
* our mount points using DefineDosDeviceW. On Vista and later orphaned critical sections
|
||||
* become "electrified", so our process will be forcefully terminated if one of its threads
|
||||
* was already modifying the list when the ExitProcess happened. This is a good thing!
|
||||
*
|
||||
* The use of DefineDosDeviceW is rather suspect and probably unsafe. DefineDosDeviceW reaches
|
||||
* 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!
|
||||
*/
|
||||
|
||||
FSP_FILE_SYSTEM *FileSystem;
|
||||
PLIST_ENTRY MountEntry;
|
||||
|
||||
EnterCriticalSection(&FspFileSystemMountListGuard);
|
||||
|
||||
for (MountEntry = FspFileSystemMountList.Flink;
|
||||
&FspFileSystemMountList != MountEntry;
|
||||
MountEntry = MountEntry->Flink)
|
||||
Handle = GetModuleHandleW(L"ntdll.dll");
|
||||
if (0 != Handle)
|
||||
{
|
||||
FileSystem = CONTAINING_RECORD(MountEntry, FSP_FILE_SYSTEM, MountEntry);
|
||||
FspNtOpenSymbolicLinkObject = (PVOID)GetProcAddress(Handle, "NtOpenSymbolicLinkObject");
|
||||
FspNtMakeTemporaryObject = (PVOID)GetProcAddress(Handle, "NtMakeTemporaryObject");
|
||||
FspNtClose = (PVOID)GetProcAddress(Handle, "NtClose");
|
||||
|
||||
DefineDosDeviceW(
|
||||
DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
|
||||
FileSystem->MountPoint, FileSystem->VolumeName);
|
||||
if (0 == FspNtOpenSymbolicLinkObject || 0 == FspNtMakeTemporaryObject || 0 == FspNtClose)
|
||||
{
|
||||
FspNtOpenSymbolicLinkObject = 0;
|
||||
FspNtMakeTemporaryObject = 0;
|
||||
FspNtClose = 0;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&FspFileSystemMountListGuard);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
||||
@ -94,6 +68,8 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
||||
if (0 == Interface)
|
||||
Interface = &FspFileSystemNullInterface;
|
||||
|
||||
InitOnceExecuteOnce(&FspFileSystemInitOnce, FspFileSystemInitialize, 0, 0);
|
||||
|
||||
FileSystem = MemAlloc(sizeof *FileSystem);
|
||||
if (0 == FileSystem)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
@ -122,9 +98,13 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
||||
FileSystem->Operations[FspFsctlTransactQueryDirectoryKind] = FspFileSystemOpQueryDirectory;
|
||||
FileSystem->Operations[FspFsctlTransactQuerySecurityKind] = FspFileSystemOpQuerySecurity;
|
||||
FileSystem->Operations[FspFsctlTransactSetSecurityKind] = FspFileSystemOpSetSecurity;
|
||||
// !!!: ...
|
||||
FileSystem->Interface = Interface;
|
||||
|
||||
FileSystem->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE;
|
||||
InitializeSRWLock(&FileSystem->OpGuardLock);
|
||||
FileSystem->EnterOperation = FspFileSystemOpEnter;
|
||||
FileSystem->LeaveOperation = FspFileSystemOpLeave;
|
||||
|
||||
*PFileSystem = FileSystem;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
@ -143,6 +123,7 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
NTSTATUS Result;
|
||||
HANDLE MountHandle = 0;
|
||||
|
||||
if (0 == MountPoint)
|
||||
{
|
||||
@ -195,13 +176,41 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
|
||||
}
|
||||
|
||||
exit:
|
||||
if (NT_SUCCESS(Result) && 0 != FspNtOpenSymbolicLinkObject)
|
||||
{
|
||||
WCHAR SymlinkBuf[6];
|
||||
UNICODE_STRING Symlink;
|
||||
OBJECT_ATTRIBUTES Obja;
|
||||
|
||||
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
|
||||
SymlinkBuf[4] = MountPoint[0];
|
||||
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
|
||||
Symlink.Buffer = SymlinkBuf;
|
||||
|
||||
memset(&Obja, 0, sizeof Obja);
|
||||
Obja.Length = sizeof Obja;
|
||||
Obja.ObjectName = &Symlink;
|
||||
Obja.Attributes = OBJ_CASE_INSENSITIVE;
|
||||
|
||||
Result = FspNtOpenSymbolicLinkObject(&MountHandle, DELETE, &Obja);
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
Result = FspNtMakeTemporaryObject(MountHandle);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspNtClose(MountHandle);
|
||||
MountHandle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* this path always considered successful regardless if we made symlink temporary */
|
||||
Result = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
FileSystem->MountPoint = MountPoint;
|
||||
|
||||
EnterCriticalSection(&FspFileSystemMountListGuard);
|
||||
InsertTailList(&FspFileSystemMountList, &FileSystem->MountEntry);
|
||||
LeaveCriticalSection(&FspFileSystemMountListGuard);
|
||||
FileSystem->MountHandle = MountHandle;
|
||||
}
|
||||
else
|
||||
MemFree(MountPoint);
|
||||
@ -214,15 +223,16 @@ FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
|
||||
if (0 == FileSystem->MountPoint)
|
||||
return;
|
||||
|
||||
EnterCriticalSection(&FspFileSystemMountListGuard);
|
||||
RemoveEntryList(&FileSystem->MountEntry);
|
||||
LeaveCriticalSection(&FspFileSystemMountListGuard);
|
||||
|
||||
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
|
||||
FileSystem->MountPoint, FileSystem->VolumeName);
|
||||
|
||||
MemFree(FileSystem->MountPoint);
|
||||
FileSystem->MountPoint = 0;
|
||||
|
||||
if (0 != FileSystem->MountHandle)
|
||||
{
|
||||
FspNtClose(FileSystem->MountHandle);
|
||||
FileSystem->MountHandle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
|
||||
@ -266,24 +276,37 @@ static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
|
||||
if (0 == RequestSize)
|
||||
continue;
|
||||
|
||||
#if 0
|
||||
FspDebugLog("FspFileSystemDispatcherThread: TID=%ld, Request={Kind=%d, Hint=%p}\n",
|
||||
GetCurrentThreadId(), Request->Kind, (PVOID)Request->Hint);
|
||||
#endif
|
||||
if (FileSystem->DebugLog)
|
||||
{
|
||||
if (FspFsctlTransactKindCount <= Request->Kind ||
|
||||
(FileSystem->DebugLog & (1 << Request->Kind)))
|
||||
FspDebugLogRequest(Request);
|
||||
}
|
||||
|
||||
Response->Size = sizeof *Response;
|
||||
Response->Kind = Request->Kind;
|
||||
Response->Hint = Request->Hint;
|
||||
if (FspFsctlTransactKindCount > Request->Kind && 0 != FileSystem->Operations[Request->Kind])
|
||||
{
|
||||
FspFileSystemEnterOperation(FileSystem, Request, Response);
|
||||
Response->IoStatus.Status =
|
||||
FileSystem->Operations[Request->Kind](FileSystem, Request, Response);
|
||||
FspFileSystemLeaveOperation(FileSystem, Request, Response);
|
||||
FspFileSystemEnterOperation(FileSystem, Request, Response);
|
||||
if (NT_SUCCESS(Response->IoStatus.Status))
|
||||
{
|
||||
Response->IoStatus.Status =
|
||||
FileSystem->Operations[Request->Kind](FileSystem, Request, Response);
|
||||
FspFileSystemLeaveOperation(FileSystem, Request, Response);
|
||||
}
|
||||
}
|
||||
else
|
||||
Response->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
if (FileSystem->DebugLog)
|
||||
{
|
||||
if (FspFsctlTransactKindCount <= Response->Kind ||
|
||||
(FileSystem->DebugLog & (1 << Response->Kind)))
|
||||
FspDebugLogResponse(Response);
|
||||
}
|
||||
|
||||
ResponseSize = FSP_FSCTL_DEFAULT_ALIGN_UP(Response->Size);
|
||||
if (FSP_FSCTL_TRANSACT_RSP_SIZEMAX < ResponseSize/* should NOT happen */)
|
||||
{
|
||||
@ -356,6 +379,7 @@ FSP_API VOID FspFileSystemStopDispatcher(FSP_FILE_SYSTEM *FileSystem)
|
||||
|
||||
WaitForSingleObject(FileSystem->DispatcherThread, INFINITE);
|
||||
CloseHandle(FileSystem->DispatcherThread);
|
||||
FileSystem->DispatcherThread = 0;
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
|
||||
@ -363,6 +387,13 @@ FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
|
||||
{
|
||||
NTSTATUS Result;
|
||||
|
||||
if (FileSystem->DebugLog)
|
||||
{
|
||||
if (FspFsctlTransactKindCount <= Response->Kind ||
|
||||
(FileSystem->DebugLog & (1 << Response->Kind)))
|
||||
FspDebugLogResponse(Response);
|
||||
}
|
||||
|
||||
Result = FspFsctlTransact(FileSystem->VolumeHandle,
|
||||
Response, Response->Size, 0, 0, FALSE);
|
||||
if (!NT_SUCCESS(Result))
|
||||
|
349
src/dll/fsctl.c
349
src/dll/fsctl.c
@ -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)
|
||||
@ -125,7 +132,9 @@ exit:
|
||||
|
||||
FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle)
|
||||
{
|
||||
if (!DeviceIoControl(VolumeHandle, FSP_FSCTL_STOP, 0, 0, 0, 0, 0, 0))
|
||||
DWORD Bytes;
|
||||
|
||||
if (!DeviceIoControl(VolumeHandle, FSP_FSCTL_STOP, 0, 0, 0, 0, &Bytes, 0))
|
||||
return FspNtStatusFromWin32(GetLastError());
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
@ -185,3 +194,341 @@ exit:
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath)
|
||||
{
|
||||
NTSTATUS Result;
|
||||
SIZE_T VolumeListSize;
|
||||
|
||||
Result = FspFsctlStartService();
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
VolumeListSize = 0;
|
||||
Result = FspFsctlGetVolumeList(DevicePath, 0, &VolumeListSize);
|
||||
if (!NT_SUCCESS(Result) && STATUS_BUFFER_TOO_SMALL != Result)
|
||||
return Result;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
LastError = GetLastError();
|
||||
if (ERROR_SERVICE_DOES_NOT_EXIST != LastError)
|
||||
Result = FspNtStatusFromWin32(LastError);
|
||||
else
|
||||
Result = STATUS_NO_SUCH_DEVICE;
|
||||
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;
|
||||
}
|
||||
|
208
src/dll/fsop.c
208
src/dll/fsop.c
@ -17,6 +17,96 @@
|
||||
|
||||
#include <dll/library.h>
|
||||
|
||||
/*
|
||||
* The FspFileSystemOpEnter/FspFileSystemOpLeave functions guard against
|
||||
* concurrent accesses. Two concurrency models are provided:
|
||||
*
|
||||
* 1. A fine-grained concurrency model where file system NAMESPACE accesses
|
||||
* are guarded using an exclusive-shared (read-write) lock. File I/O is not
|
||||
* guarded and concurrent reads/writes/etc. are possible. [Note that the FSD
|
||||
* will still apply an exclusive-shared lock PER INDIVIDUAL FILE, but it will
|
||||
* not limit I/O operations for different files.]
|
||||
*
|
||||
* The fine-grained concurrency model applies the exclusive-shared lock as
|
||||
* follows:
|
||||
* - EXCL: SetVolumeLabel, Create, Cleanup(Delete), SetInformation(Rename)
|
||||
* - SHRD: GetVolumeInfo, Open, SetInformation(Disposition), ReadDirectory
|
||||
* - NONE: all other operations
|
||||
*
|
||||
* 2. A coarse-grained concurrency model where all file system accesses are
|
||||
* guarded by a mutually exclusive lock.
|
||||
*/
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemOpEnter(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
switch (FileSystem->OpGuardStrategy)
|
||||
{
|
||||
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
|
||||
if ((FspFsctlTransactCreateKind == Request->Kind &&
|
||||
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
|
||||
(FspFsctlTransactCleanupKind == Request->Kind &&
|
||||
Request->Req.Cleanup.Delete) ||
|
||||
(FspFsctlTransactSetInformationKind == Request->Kind &&
|
||||
10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass) ||
|
||||
FspFsctlTransactSetVolumeInformationKind == Request->Kind)
|
||||
{
|
||||
AcquireSRWLockExclusive(&FileSystem->OpGuardLock);
|
||||
}
|
||||
else
|
||||
if (FspFsctlTransactCreateKind == Request->Kind ||
|
||||
(FspFsctlTransactSetInformationKind == Request->Kind &&
|
||||
13/*FileDispositionInformation*/ == Request->Req.SetInformation.FileInformationClass) ||
|
||||
FspFsctlTransactQueryDirectoryKind == Request->Kind ||
|
||||
FspFsctlTransactQueryVolumeInformationKind == Request->Kind)
|
||||
{
|
||||
AcquireSRWLockShared(&FileSystem->OpGuardLock);
|
||||
}
|
||||
break;
|
||||
|
||||
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE:
|
||||
AcquireSRWLockExclusive(&FileSystem->OpGuardLock);
|
||||
break;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemOpLeave(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
switch (FileSystem->OpGuardStrategy)
|
||||
{
|
||||
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
|
||||
if ((FspFsctlTransactCreateKind == Request->Kind &&
|
||||
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
|
||||
(FspFsctlTransactCleanupKind == Request->Kind &&
|
||||
Request->Req.Cleanup.Delete) ||
|
||||
(FspFsctlTransactSetInformationKind == Request->Kind &&
|
||||
10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass) ||
|
||||
FspFsctlTransactSetVolumeInformationKind == Request->Kind)
|
||||
{
|
||||
ReleaseSRWLockExclusive(&FileSystem->OpGuardLock);
|
||||
}
|
||||
else
|
||||
if (FspFsctlTransactCreateKind == Request->Kind ||
|
||||
(FspFsctlTransactSetInformationKind == Request->Kind &&
|
||||
13/*FileDispositionInformation*/ == Request->Req.SetInformation.FileInformationClass) ||
|
||||
FspFsctlTransactQueryDirectoryKind == Request->Kind ||
|
||||
FspFsctlTransactQueryVolumeInformationKind == Request->Kind)
|
||||
{
|
||||
ReleaseSRWLockShared(&FileSystem->OpGuardLock);
|
||||
}
|
||||
break;
|
||||
|
||||
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE:
|
||||
ReleaseSRWLockExclusive(&FileSystem->OpGuardLock);
|
||||
break;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static inline
|
||||
NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||
@ -25,6 +115,15 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||
{
|
||||
NTSTATUS Result;
|
||||
|
||||
/*
|
||||
* CreateCheck consists of checking the parent directory for the
|
||||
* FILE_ADD_SUBDIRECTORY or FILE_ADD_FILE rights (depending on whether
|
||||
* we are creating a file or directory).
|
||||
*
|
||||
* If the access check succeeds and MAXIMUM_ALLOWED has been requested
|
||||
* then we go ahead and grant all access to the creator.
|
||||
*/
|
||||
|
||||
Result = FspAccessCheckEx(FileSystem, Request, TRUE, AllowTraverseCheck,
|
||||
(Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) ?
|
||||
FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE,
|
||||
@ -45,6 +144,16 @@ NTSTATUS FspFileSystemOpenCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||
{
|
||||
NTSTATUS Result;
|
||||
|
||||
/*
|
||||
* OpenCheck consists of checking the file for the desired access,
|
||||
* unless FILE_DELETE_ON_CLOSE is requested in which case we also
|
||||
* check for DELETE access.
|
||||
*
|
||||
* If the access check succeeds and MAXIMUM_ALLOWED was not requested
|
||||
* then we reset the DELETE access based on whether it was actually
|
||||
* requested in DesiredAccess.
|
||||
*/
|
||||
|
||||
Result = FspAccessCheck(FileSystem, Request, FALSE, AllowTraverseCheck,
|
||||
Request->Req.Create.DesiredAccess |
|
||||
((Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE) ? DELETE : 0),
|
||||
@ -66,6 +175,17 @@ NTSTATUS FspFileSystemOverwriteCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||
NTSTATUS Result;
|
||||
BOOLEAN Supersede = FILE_SUPERSEDE == ((Request->Req.Create.CreateOptions >> 24) & 0xff);
|
||||
|
||||
/*
|
||||
* OverwriteCheck consists of checking the file for the desired access,
|
||||
* unless FILE_DELETE_ON_CLOSE is requested in which case we also
|
||||
* check for DELETE access. Furthermore we grant DELETE or FILE_WRITE_DATA
|
||||
* access based on whether this is a Supersede or Overwrite operation.
|
||||
*
|
||||
* If the access check succeeds and MAXIMUM_ALLOWED was not requested
|
||||
* then we reset the DELETE and FILE_WRITE_DATA accesses based on whether
|
||||
* they were actually requested in DesiredAccess.
|
||||
*/
|
||||
|
||||
Result = FspAccessCheck(FileSystem, Request, FALSE, AllowTraverseCheck,
|
||||
Request->Req.Create.DesiredAccess |
|
||||
(Supersede ? DELETE : FILE_WRITE_DATA) |
|
||||
@ -81,6 +201,56 @@ NTSTATUS FspFileSystemOverwriteCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||
return Result;
|
||||
}
|
||||
|
||||
static inline
|
||||
NTSTATUS FspFileSystemRenameCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
{
|
||||
NTSTATUS Result;
|
||||
FSP_FSCTL_TRANSACT_REQ *CreateRequest = 0;
|
||||
UINT32 GrantedAccess;
|
||||
|
||||
/*
|
||||
* RenameCheck consists of checking the new file name for DELETE access.
|
||||
*
|
||||
* The following assumptions are being made here for a file that is going
|
||||
* to be replaced:
|
||||
* - The new file is in the same directory as the old one. In that case
|
||||
* there is no need for traverse access checks as they have been already
|
||||
* performed (if necessary) when opening the file under the existing file
|
||||
* name.
|
||||
* - The new file is in a different directory than the old one. In that case
|
||||
* NTOS called us with SL_OPEN_TARGET_DIRECTORY and we performed any
|
||||
* necessary traverse access checks at that time.
|
||||
*
|
||||
* FspAccessCheckEx only works on Create requests, so we have to build
|
||||
* a fake one just for that purpose. Sigh!
|
||||
*/
|
||||
|
||||
CreateRequest = MemAlloc(sizeof *CreateRequest +
|
||||
Request->Req.SetInformation.Info.Rename.NewFileName.Size);
|
||||
if (0 == CreateRequest)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
memset(CreateRequest, 0, sizeof *CreateRequest);
|
||||
CreateRequest->Size = sizeof CreateRequest +
|
||||
Request->Req.SetInformation.Info.Rename.NewFileName.Size;
|
||||
CreateRequest->Kind = FspFsctlTransactCreateKind;
|
||||
CreateRequest->Req.Create.CreateOptions = FILE_DELETE_ON_CLOSE; /* force read-only check! */
|
||||
CreateRequest->Req.Create.AccessToken = Request->Req.SetInformation.Info.Rename.AccessToken;
|
||||
CreateRequest->Req.Create.UserMode = TRUE;
|
||||
CreateRequest->FileName.Offset = 0;
|
||||
CreateRequest->FileName.Size = Request->Req.SetInformation.Info.Rename.NewFileName.Size;
|
||||
memcpy(CreateRequest->Buffer,
|
||||
Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset,
|
||||
Request->Req.SetInformation.Info.Rename.NewFileName.Size);
|
||||
|
||||
Result = FspAccessCheck(FileSystem, CreateRequest, FALSE, FALSE, DELETE, &GrantedAccess);
|
||||
|
||||
MemFree(CreateRequest);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFileSystemOpCreate_FileCreate(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
@ -304,7 +474,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);
|
||||
@ -520,32 +690,17 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
|
||||
&FileInfo);
|
||||
break;
|
||||
case 19/*FileAllocationInformation*/:
|
||||
if (0 != FileSystem->Interface->SetAllocationSize)
|
||||
Result = FileSystem->Interface->SetAllocationSize(FileSystem, Request,
|
||||
if (0 != FileSystem->Interface->SetFileSize)
|
||||
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
|
||||
(PVOID)Request->Req.SetInformation.UserContext,
|
||||
Request->Req.SetInformation.Info.Allocation.AllocationSize,
|
||||
Request->Req.SetInformation.Info.Allocation.AllocationSize, TRUE,
|
||||
&FileInfo);
|
||||
else
|
||||
if (0 != FileSystem->Interface->GetFileInfo &&
|
||||
0 != FileSystem->Interface->SetFileSize)
|
||||
{
|
||||
Result = FileSystem->Interface->GetFileInfo(FileSystem, Request,
|
||||
(PVOID)Request->Req.SetInformation.UserContext, &FileInfo);
|
||||
if (NT_SUCCESS(Result) &&
|
||||
Request->Req.SetInformation.Info.Allocation.AllocationSize < FileInfo.FileSize)
|
||||
{
|
||||
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
|
||||
(PVOID)Request->Req.SetInformation.UserContext,
|
||||
Request->Req.SetInformation.Info.Allocation.AllocationSize,
|
||||
&FileInfo);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 20/*FileEndOfFileInformation*/:
|
||||
if (0 != FileSystem->Interface->SetFileSize)
|
||||
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
|
||||
(PVOID)Request->Req.SetInformation.UserContext,
|
||||
Request->Req.SetInformation.Info.EndOfFile.FileSize,
|
||||
Request->Req.SetInformation.Info.EndOfFile.FileSize, FALSE,
|
||||
&FileInfo);
|
||||
break;
|
||||
case 13/*FileDispositionInformation*/:
|
||||
@ -569,11 +724,21 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
|
||||
break;
|
||||
case 10/*FileRenameInformation*/:
|
||||
if (0 != FileSystem->Interface->Rename)
|
||||
{
|
||||
if (0 != Request->Req.SetInformation.Info.Rename.AccessToken)
|
||||
{
|
||||
Result = FspFileSystemRenameCheck(FileSystem, Request);
|
||||
if (!NT_SUCCESS(Result) &&
|
||||
STATUS_OBJECT_PATH_NOT_FOUND != Result &&
|
||||
STATUS_OBJECT_NAME_NOT_FOUND != Result)
|
||||
break;
|
||||
}
|
||||
Result = FileSystem->Interface->Rename(FileSystem, Request,
|
||||
(PVOID)Request->Req.SetInformation.UserContext,
|
||||
(PWSTR)Request->Buffer,
|
||||
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
|
||||
Request->Req.SetInformation.Info.Rename.ReplaceIfExists);
|
||||
0 != Request->Req.SetInformation.Info.Rename.AccessToken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -617,6 +782,7 @@ FSP_API NTSTATUS FspFileSystemOpSetVolumeInformation(FSP_FILE_SYSTEM *FileSystem
|
||||
Result = FileSystem->Interface->SetVolumeLabel(FileSystem, Request,
|
||||
(PWSTR)Request->Buffer,
|
||||
&VolumeInfo);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Result))
|
||||
|
115
src/dll/fuse/errno.i
Normal file
115
src/dll/fuse/errno.i
Normal file
@ -0,0 +1,115 @@
|
||||
#if FSP_FUSE_ERRNO == 87 /* Windows */
|
||||
|
||||
case 0: return STATUS_SUCCESS;
|
||||
case 1: return STATUS_ACCESS_DENIED;
|
||||
case 2: return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
case 3: return STATUS_PROCEDURE_NOT_FOUND;
|
||||
case 4: return STATUS_CANCELLED;
|
||||
case 5: return STATUS_IO_DEVICE_ERROR;
|
||||
case 6: return STATUS_FILE_INVALID;
|
||||
case 7: return STATUS_INSUFFICIENT_RESOURCES;
|
||||
case 8: return STATUS_INVALID_IMAGE_FORMAT;
|
||||
case 9: return STATUS_INVALID_HANDLE;
|
||||
case 12: return STATUS_INSUFFICIENT_RESOURCES;
|
||||
case 13: return STATUS_ACCESS_DENIED;
|
||||
case 14: return STATUS_ACCESS_VIOLATION;
|
||||
case 16: return STATUS_DEVICE_BUSY;
|
||||
case 17: return STATUS_OBJECT_NAME_COLLISION;
|
||||
case 18: return STATUS_NOT_SAME_DEVICE;
|
||||
case 19: return STATUS_NO_SUCH_DEVICE;
|
||||
case 20: return STATUS_NOT_A_DIRECTORY;
|
||||
case 21: return STATUS_FILE_IS_A_DIRECTORY;
|
||||
case 22: return STATUS_INVALID_PARAMETER;
|
||||
case 23: return STATUS_TOO_MANY_OPENED_FILES;
|
||||
case 24: return STATUS_TOO_MANY_OPENED_FILES;
|
||||
case 27: return STATUS_DISK_FULL;
|
||||
case 28: return STATUS_DISK_FULL;
|
||||
case 29: return STATUS_INVALID_PARAMETER;
|
||||
case 30: return STATUS_MEDIA_WRITE_PROTECTED;
|
||||
case 31: return STATUS_TOO_MANY_LINKS;
|
||||
case 32: return STATUS_PIPE_BROKEN;
|
||||
case 33: return STATUS_INVALID_PARAMETER;
|
||||
case 34: return STATUS_INVALID_PARAMETER;
|
||||
case 36: return STATUS_POSSIBLE_DEADLOCK;
|
||||
case 38: return STATUS_NAME_TOO_LONG;
|
||||
case 39: return STATUS_LOCK_NOT_GRANTED;
|
||||
case 40: return STATUS_INVALID_DEVICE_REQUEST;
|
||||
case 41: return STATUS_DIRECTORY_NOT_EMPTY;
|
||||
case 42: return STATUS_INVALID_PARAMETER;
|
||||
case 100: return STATUS_ADDRESS_ALREADY_ASSOCIATED;
|
||||
case 103: return STATUS_CONNECTION_ACTIVE;
|
||||
case 105: return STATUS_CANCELLED;
|
||||
case 106: return STATUS_CONNECTION_ABORTED;
|
||||
case 107: return STATUS_CONNECTION_REFUSED;
|
||||
case 108: return STATUS_CONNECTION_RESET;
|
||||
case 110: return STATUS_HOST_UNREACHABLE;
|
||||
case 113: return STATUS_CONNECTION_ACTIVE;
|
||||
case 114: return STATUS_REPARSE_POINT_NOT_RESOLVED;
|
||||
case 116: return STATUS_HOST_DOWN;
|
||||
case 117: return STATUS_CONNECTION_RESET;
|
||||
case 118: return STATUS_NETWORK_UNREACHABLE;
|
||||
case 119: return STATUS_INSUFFICIENT_RESOURCES;
|
||||
case 120: return STATUS_END_OF_FILE;
|
||||
case 121: return STATUS_CONNECTION_INVALID;
|
||||
case 126: return STATUS_CONNECTION_INVALID;
|
||||
case 128: return STATUS_INVALID_HANDLE;
|
||||
case 138: return STATUS_TRANSACTION_TIMED_OUT;
|
||||
|
||||
#elif FSP_FUSE_ERRNO == 67 /* Cygwin */
|
||||
|
||||
case 0: return STATUS_SUCCESS;
|
||||
case 1: return STATUS_ACCESS_DENIED;
|
||||
case 2: return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
case 3: return STATUS_PROCEDURE_NOT_FOUND;
|
||||
case 4: return STATUS_CANCELLED;
|
||||
case 5: return STATUS_IO_DEVICE_ERROR;
|
||||
case 6: return STATUS_FILE_INVALID;
|
||||
case 7: return STATUS_INSUFFICIENT_RESOURCES;
|
||||
case 8: return STATUS_INVALID_IMAGE_FORMAT;
|
||||
case 9: return STATUS_INVALID_HANDLE;
|
||||
case 12: return STATUS_INSUFFICIENT_RESOURCES;
|
||||
case 13: return STATUS_ACCESS_DENIED;
|
||||
case 14: return STATUS_ACCESS_VIOLATION;
|
||||
case 16: return STATUS_DEVICE_BUSY;
|
||||
case 17: return STATUS_OBJECT_NAME_COLLISION;
|
||||
case 18: return STATUS_NOT_SAME_DEVICE;
|
||||
case 19: return STATUS_NO_SUCH_DEVICE;
|
||||
case 20: return STATUS_NOT_A_DIRECTORY;
|
||||
case 21: return STATUS_FILE_IS_A_DIRECTORY;
|
||||
case 22: return STATUS_INVALID_PARAMETER;
|
||||
case 23: return STATUS_TOO_MANY_OPENED_FILES;
|
||||
case 24: return STATUS_TOO_MANY_OPENED_FILES;
|
||||
case 27: return STATUS_DISK_FULL;
|
||||
case 28: return STATUS_DISK_FULL;
|
||||
case 29: return STATUS_INVALID_PARAMETER;
|
||||
case 30: return STATUS_MEDIA_WRITE_PROTECTED;
|
||||
case 31: return STATUS_TOO_MANY_LINKS;
|
||||
case 32: return STATUS_PIPE_BROKEN;
|
||||
case 33: return STATUS_INVALID_PARAMETER;
|
||||
case 34: return STATUS_INVALID_PARAMETER;
|
||||
case 45: return STATUS_POSSIBLE_DEADLOCK;
|
||||
case 91: return STATUS_NAME_TOO_LONG;
|
||||
case 46: return STATUS_LOCK_NOT_GRANTED;
|
||||
case 88: return STATUS_INVALID_DEVICE_REQUEST;
|
||||
case 90: return STATUS_DIRECTORY_NOT_EMPTY;
|
||||
case 138: return STATUS_INVALID_PARAMETER;
|
||||
case 112: return STATUS_ADDRESS_ALREADY_ASSOCIATED;
|
||||
case 120: return STATUS_CONNECTION_ACTIVE;
|
||||
case 140: return STATUS_CANCELLED;
|
||||
case 113: return STATUS_CONNECTION_ABORTED;
|
||||
case 111: return STATUS_CONNECTION_REFUSED;
|
||||
case 104: return STATUS_CONNECTION_RESET;
|
||||
case 118: return STATUS_HOST_UNREACHABLE;
|
||||
case 127: return STATUS_CONNECTION_ACTIVE;
|
||||
case 92: return STATUS_REPARSE_POINT_NOT_RESOLVED;
|
||||
case 115: return STATUS_HOST_DOWN;
|
||||
case 126: return STATUS_CONNECTION_RESET;
|
||||
case 114: return STATUS_NETWORK_UNREACHABLE;
|
||||
case 105: return STATUS_INSUFFICIENT_RESOURCES;
|
||||
case 61: return STATUS_END_OF_FILE;
|
||||
case 67: return STATUS_CONNECTION_INVALID;
|
||||
case 128: return STATUS_CONNECTION_INVALID;
|
||||
case 108: return STATUS_INVALID_HANDLE;
|
||||
case 116: return STATUS_TRANSACTION_TIMED_OUT;
|
||||
|
||||
#endif
|
657
src/dll/fuse/fuse.c
Normal file
657
src/dll/fuse/fuse.c
Normal file
@ -0,0 +1,657 @@
|
||||
/**
|
||||
* @file dll/fuse/fuse.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/fuse/library.h>
|
||||
|
||||
#define FSP_FUSE_SECTORSIZE_MIN 512
|
||||
#define FSP_FUSE_SECTORSIZE_MAX 4096
|
||||
|
||||
struct fuse_chan
|
||||
{
|
||||
PWSTR MountPoint;
|
||||
UINT8 Buffer[];
|
||||
};
|
||||
|
||||
#define FSP_FUSE_CORE_OPT(n, f, v) { n, offsetof(struct fsp_fuse_core_opt_data, f), v }
|
||||
|
||||
struct fsp_fuse_core_opt_data
|
||||
{
|
||||
struct fsp_fuse_env *env;
|
||||
int help, debug;
|
||||
int hard_remove,
|
||||
use_ino, readdir_ino,
|
||||
set_umask, umask,
|
||||
set_uid, uid,
|
||||
set_gid, gid,
|
||||
set_attr_timeout, attr_timeout;
|
||||
int set_FileInfoTimeout;
|
||||
int CaseInsensitiveSearch, ReparsePoints,
|
||||
NamedStreams, ReadOnlyVolume;
|
||||
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
||||
};
|
||||
|
||||
static struct fuse_opt fsp_fuse_core_opts[] =
|
||||
{
|
||||
FUSE_OPT_KEY("-h", 'h'),
|
||||
FUSE_OPT_KEY("--help", 'h'),
|
||||
FUSE_OPT_KEY("-V", 'V'),
|
||||
FUSE_OPT_KEY("--version", 'V'),
|
||||
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
|
||||
FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
|
||||
FSP_FUSE_CORE_OPT("-d", debug, 1),
|
||||
FSP_FUSE_CORE_OPT("debug", debug, 1),
|
||||
|
||||
FSP_FUSE_CORE_OPT("hard_remove", hard_remove, 1),
|
||||
FSP_FUSE_CORE_OPT("use_ino", use_ino, 1),
|
||||
FSP_FUSE_CORE_OPT("readdir_ino", readdir_ino, 1),
|
||||
FUSE_OPT_KEY("direct_io", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("kernel_cache", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("auto_cache", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("noauto_cache", FUSE_OPT_KEY_DISCARD),
|
||||
FSP_FUSE_CORE_OPT("umask=", set_umask, 1),
|
||||
FSP_FUSE_CORE_OPT("umask=%o", umask, 0),
|
||||
FSP_FUSE_CORE_OPT("uid=", set_uid, 1),
|
||||
FSP_FUSE_CORE_OPT("uid=%d", uid, 0),
|
||||
FSP_FUSE_CORE_OPT("gid=", set_gid, 1),
|
||||
FSP_FUSE_CORE_OPT("gid=%d", gid, 0),
|
||||
FUSE_OPT_KEY("entry_timeout", FUSE_OPT_KEY_DISCARD),
|
||||
FSP_FUSE_CORE_OPT("attr_timeout=", set_attr_timeout, 1),
|
||||
FSP_FUSE_CORE_OPT("attr_timeout=%d", attr_timeout, 0),
|
||||
FUSE_OPT_KEY("ac_attr_timeout", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("negative_timeout", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("noforget", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("intr", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("intr_signal=", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("modules=", FUSE_OPT_KEY_DISCARD),
|
||||
|
||||
FSP_FUSE_CORE_OPT("SectorSize=%hu", VolumeParams.SectorSize, 4096),
|
||||
FSP_FUSE_CORE_OPT("SectorsPerAllocationUnit=%hu", VolumeParams.SectorsPerAllocationUnit, 1),
|
||||
FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
|
||||
FSP_FUSE_CORE_OPT("VolumeCreationTime=%lli", VolumeParams.VolumeCreationTime, 0),
|
||||
FSP_FUSE_CORE_OPT("VolumeSerialNumber=%lx", VolumeParams.VolumeSerialNumber, 0),
|
||||
FSP_FUSE_CORE_OPT("TransactTimeout=%u", VolumeParams.TransactTimeout, 0),
|
||||
FSP_FUSE_CORE_OPT("IrpTimeout=%u", VolumeParams.IrpTimeout, 0),
|
||||
FSP_FUSE_CORE_OPT("IrpCapacity=%u", VolumeParams.IrpCapacity, 0),
|
||||
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
|
||||
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
|
||||
FSP_FUSE_CORE_OPT("CaseInsensitiveSearch", CaseInsensitiveSearch, 1),
|
||||
FSP_FUSE_CORE_OPT("ReparsePoints", ReparsePoints, 1),
|
||||
FSP_FUSE_CORE_OPT("NamedStreams", NamedStreams, 1),
|
||||
FUSE_OPT_KEY("HardLinks", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("ExtendedAttributes", FUSE_OPT_KEY_DISCARD),
|
||||
FSP_FUSE_CORE_OPT("ReadOnlyVolume", ReadOnlyVolume, 1),
|
||||
FUSE_OPT_KEY("--UNC=", 'U'),
|
||||
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
|
||||
|
||||
FUSE_OPT_END,
|
||||
};
|
||||
|
||||
static INIT_ONCE fsp_fuse_initonce = INIT_ONCE_STATIC_INIT;
|
||||
static DWORD fsp_fuse_tlskey = TLS_OUT_OF_INDEXES;
|
||||
|
||||
struct fsp_fuse_obj_hdr
|
||||
{
|
||||
void (*dtor)(void *);
|
||||
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ObjectBuf[];
|
||||
};
|
||||
|
||||
static inline void *fsp_fuse_obj_alloc(struct fsp_fuse_env *env, size_t size)
|
||||
{
|
||||
struct fsp_fuse_obj_hdr *hdr;
|
||||
|
||||
hdr = env->memalloc(sizeof(struct fsp_fuse_obj_hdr) + size);
|
||||
if (0 == hdr)
|
||||
return 0;
|
||||
|
||||
hdr->dtor = env->memfree;
|
||||
memset(hdr->ObjectBuf, 0, size);
|
||||
return hdr->ObjectBuf;
|
||||
}
|
||||
|
||||
static inline void fsp_fuse_obj_free(void *obj)
|
||||
{
|
||||
struct fsp_fuse_obj_hdr *hdr = (PVOID)((PUINT8)obj - sizeof(struct fsp_fuse_obj_hdr));
|
||||
|
||||
hdr->dtor(hdr);
|
||||
}
|
||||
|
||||
static BOOL WINAPI fsp_fuse_initialize(
|
||||
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
||||
{
|
||||
fsp_fuse_tlskey = TlsAlloc();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID fsp_fuse_finalize(BOOLEAN Dynamic)
|
||||
{
|
||||
/*
|
||||
* This function is called during DLL_PROCESS_DETACH. We must therefore keep
|
||||
* finalization tasks to a minimum.
|
||||
*
|
||||
* We must free our TLS key (if any). We only do so if the library
|
||||
* is being explicitly unloaded (rather than the process exiting).
|
||||
*/
|
||||
|
||||
if (Dynamic && TLS_OUT_OF_INDEXES != fsp_fuse_tlskey)
|
||||
{
|
||||
/* !!!:
|
||||
* We should also free all thread local contexts, which means putting them in a list,
|
||||
* protected with a critical section, etc. Arghhh!
|
||||
*
|
||||
* I am too lazy and I am not going to do that, unless people start using this
|
||||
* DLL dynamically (LoadLibrary/FreeLibrary).
|
||||
*/
|
||||
TlsFree(fsp_fuse_tlskey);
|
||||
}
|
||||
}
|
||||
|
||||
VOID fsp_fuse_finalize_thread(VOID)
|
||||
{
|
||||
struct fuse_context *context;
|
||||
|
||||
if (TLS_OUT_OF_INDEXES != fsp_fuse_tlskey)
|
||||
{
|
||||
context = TlsGetValue(fsp_fuse_tlskey);
|
||||
if (0 != context)
|
||||
{
|
||||
fsp_fuse_obj_free(FSP_FUSE_HDR_FROM_CONTEXT(context));
|
||||
TlsSetValue(fsp_fuse_tlskey, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_version(struct fsp_fuse_env *env)
|
||||
{
|
||||
return FUSE_VERSION;
|
||||
}
|
||||
|
||||
FSP_FUSE_API struct fuse_chan *fsp_fuse_mount(struct fsp_fuse_env *env,
|
||||
const char *mountpoint, struct fuse_args *args)
|
||||
{
|
||||
struct fuse_chan *ch = 0;
|
||||
int Size;
|
||||
|
||||
if (0 == mountpoint)
|
||||
mountpoint = "";
|
||||
|
||||
Size = MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, 0, 0);
|
||||
if (0 == Size)
|
||||
goto fail;
|
||||
|
||||
ch = fsp_fuse_obj_alloc(env, sizeof *ch + Size * sizeof(WCHAR));
|
||||
if (0 == ch)
|
||||
goto fail;
|
||||
|
||||
ch->MountPoint = (PVOID)ch->Buffer;
|
||||
Size = MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, ch->MountPoint, Size);
|
||||
if (0 == Size)
|
||||
goto fail;
|
||||
|
||||
return ch;
|
||||
|
||||
fail:
|
||||
fsp_fuse_obj_free(ch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FSP_FUSE_API void fsp_fuse_unmount(struct fsp_fuse_env *env,
|
||||
const char *mountpoint, struct fuse_chan *ch)
|
||||
{
|
||||
fsp_fuse_obj_free(ch);
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_is_lib_option(struct fsp_fuse_env *env,
|
||||
const char *opt)
|
||||
{
|
||||
return fsp_fuse_opt_match(env, fsp_fuse_core_opts, opt);
|
||||
}
|
||||
|
||||
static void fsp_fuse_cleanup(struct fuse *f);
|
||||
|
||||
static NTSTATUS fsp_fuse_preflight(struct fuse *f)
|
||||
{
|
||||
NTSTATUS Result;
|
||||
|
||||
Result = FspFsctlPreflight(f->VolumeParams.Prefix[0] ?
|
||||
L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
if (L'\0' != f->MountPoint)
|
||||
{
|
||||
if ((
|
||||
(L'A' <= f->MountPoint[0] && f->MountPoint[0] <= L'Z') ||
|
||||
(L'a' <= f->MountPoint[0] && f->MountPoint[0] <= L'z')
|
||||
) &&
|
||||
L':' == f->MountPoint[1] || L'\0' == f->MountPoint[2])
|
||||
{
|
||||
if (GetLogicalDrives() & (1 << ((f->MountPoint[0] & ~0x20) - 'a')))
|
||||
return STATUS_OBJECT_NAME_COLLISION;
|
||||
}
|
||||
else
|
||||
if (L'*' == f->MountPoint[0] && L'\0' == f->MountPoint[1])
|
||||
;
|
||||
else
|
||||
return STATUS_OBJECT_NAME_INVALID;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
{
|
||||
struct fuse *f = Service->UserContext;
|
||||
struct fuse_context *context;
|
||||
struct fuse_conn_info conn;
|
||||
NTSTATUS Result;
|
||||
|
||||
f->Service = Service;
|
||||
|
||||
context = fsp_fuse_get_context(f->env);
|
||||
if (0 == context)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto fail;
|
||||
}
|
||||
context->fuse = f;
|
||||
context->private_data = f->data;
|
||||
context->uid = -1;
|
||||
context->gid = -1;
|
||||
|
||||
memset(&conn, 0, sizeof conn);
|
||||
conn.proto_major = 7; /* pretend that we are FUSE kernel protocol 7.12 */
|
||||
conn.proto_minor = 12; /* which was current at the time of FUSE 2.8 */
|
||||
conn.async_read = 1;
|
||||
conn.max_write = UINT_MAX;
|
||||
conn.capable =
|
||||
FUSE_CAP_ASYNC_READ |
|
||||
//FUSE_CAP_POSIX_LOCKS | /* WinFsp handles locking in the FSD currently */
|
||||
//FUSE_CAP_ATOMIC_O_TRUNC | /* due to Windows/WinFsp design, no support */
|
||||
//FUSE_CAP_EXPORT_SUPPORT | /* not needed in Windows/WinFsp */
|
||||
FUSE_CAP_BIG_WRITES |
|
||||
FUSE_CAP_DONT_MASK;
|
||||
if (0 != f->ops.init)
|
||||
context->private_data = f->data = f->ops.init(&conn);
|
||||
f->fsinit = TRUE;
|
||||
if (0 != f->ops.statfs)
|
||||
{
|
||||
struct fuse_statvfs stbuf;
|
||||
int err;
|
||||
|
||||
memset(&stbuf, 0, sizeof stbuf);
|
||||
err = f->ops.statfs("/", &stbuf);
|
||||
if (0 != err)
|
||||
{
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (stbuf.f_frsize > FSP_FUSE_SECTORSIZE_MAX)
|
||||
stbuf.f_frsize = FSP_FUSE_SECTORSIZE_MAX;
|
||||
if (0 == f->VolumeParams.SectorSize)
|
||||
f->VolumeParams.SectorSize = (UINT16)stbuf.f_frsize;
|
||||
if (0 == f->VolumeParams.MaxComponentLength)
|
||||
f->VolumeParams.MaxComponentLength = (UINT16)stbuf.f_namemax;
|
||||
}
|
||||
if (0 != f->ops.getattr)
|
||||
{
|
||||
struct fuse_stat stbuf;
|
||||
int err;
|
||||
|
||||
memset(&stbuf, 0, sizeof stbuf);
|
||||
err = f->ops.getattr("/", (void *)&stbuf);
|
||||
if (0 != err)
|
||||
{
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (0 == f->VolumeParams.VolumeCreationTime)
|
||||
{
|
||||
if (0 != stbuf.st_birthtim.tv_sec)
|
||||
f->VolumeParams.VolumeCreationTime =
|
||||
Int32x32To64(stbuf.st_birthtim.tv_sec, 10000000) + 116444736000000000 +
|
||||
stbuf.st_birthtim.tv_nsec / 100;
|
||||
else
|
||||
if (0 != stbuf.st_ctim.tv_sec)
|
||||
f->VolumeParams.VolumeCreationTime =
|
||||
Int32x32To64(stbuf.st_ctim.tv_sec, 10000000) + 116444736000000000 +
|
||||
stbuf.st_ctim.tv_nsec / 100;
|
||||
}
|
||||
}
|
||||
|
||||
/* the FSD does not currently limit these VolumeParams fields; do so here! */
|
||||
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN)
|
||||
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MIN;
|
||||
if (f->VolumeParams.SectorSize > FSP_FUSE_SECTORSIZE_MAX)
|
||||
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MAX;
|
||||
if (f->VolumeParams.SectorsPerAllocationUnit == 0)
|
||||
f->VolumeParams.SectorsPerAllocationUnit = 1;
|
||||
if (f->VolumeParams.MaxComponentLength > 255)
|
||||
f->VolumeParams.MaxComponentLength = 255;
|
||||
|
||||
if (0 == f->VolumeParams.VolumeCreationTime)
|
||||
{
|
||||
FILETIME FileTime;
|
||||
GetSystemTimeAsFileTime(&FileTime);
|
||||
f->VolumeParams.VolumeCreationTime = *(PUINT64)&FileTime;
|
||||
}
|
||||
if (0 == f->VolumeParams.VolumeSerialNumber)
|
||||
f->VolumeParams.VolumeSerialNumber =
|
||||
((PLARGE_INTEGER)&f->VolumeParams.VolumeCreationTime)->HighPart ^
|
||||
((PLARGE_INTEGER)&f->VolumeParams.VolumeCreationTime)->LowPart;
|
||||
|
||||
Result = FspFileSystemCreate(
|
||||
f->VolumeParams.Prefix[0] ?
|
||||
L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME,
|
||||
&f->VolumeParams, &fsp_fuse_intf,
|
||||
&f->FileSystem);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE,
|
||||
L"Cannot create " FSP_FUSE_LIBRARY_NAME " file system.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
f->FileSystem->UserContext = f;
|
||||
FspFileSystemSetOperationGuard(f->FileSystem, fsp_fuse_op_enter, fsp_fuse_op_leave);
|
||||
FspFileSystemSetOperationGuardStrategy(f->FileSystem, f->OpGuardStrategy);
|
||||
FspFileSystemSetDebugLog(f->FileSystem, f->DebugLog);
|
||||
|
||||
if (L'\0' != f->MountPoint)
|
||||
{
|
||||
Result = FspFileSystemSetMountPoint(f->FileSystem,
|
||||
L'*' == f->MountPoint[0] && L'\0' == f->MountPoint[1] ? 0 : f->MountPoint);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE,
|
||||
L"Cannot set " FSP_FUSE_LIBRARY_NAME " file system mount point.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
Result = FspFileSystemStartDispatcher(f->FileSystem, 0);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE,
|
||||
L"Cannot start " FSP_FUSE_LIBRARY_NAME " file system dispatcher.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
fsp_fuse_cleanup(f);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_svcstop(FSP_SERVICE *Service)
|
||||
{
|
||||
struct fuse *f = Service->UserContext;
|
||||
|
||||
FspFileSystemStopDispatcher(f->FileSystem);
|
||||
|
||||
fsp_fuse_cleanup(f);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void fsp_fuse_cleanup(struct fuse *f)
|
||||
{
|
||||
if (0 != f->FileSystem)
|
||||
{
|
||||
FspFileSystemDelete(f->FileSystem);
|
||||
f->FileSystem = 0;
|
||||
}
|
||||
|
||||
if (f->fsinit)
|
||||
{
|
||||
if (f->ops.destroy)
|
||||
f->ops.destroy(f->data);
|
||||
f->fsinit = FALSE;
|
||||
}
|
||||
|
||||
f->Service = 0;
|
||||
}
|
||||
|
||||
static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
struct fsp_fuse_core_opt_data *opt_data = opt_data0;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
default:
|
||||
return 1;
|
||||
case 'h':
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
|
||||
FSP_FUSE_LIBRARY_NAME " options:\n"
|
||||
" -o SectorSize=N sector size for Windows (512-4096, deflt: 512)\n"
|
||||
" -o SectorsPerAllocationUnit=N allocation unit size (deflt: 1*SectorSize)\n"
|
||||
" -o MaxComponentLength=N max file name component length (deflt: 255)\n"
|
||||
" -o VolumeCreationTime=T volume creation time (FILETIME hex format)\n"
|
||||
" -o VolumeSerialNumber=N 32-bit wide\n"
|
||||
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n"
|
||||
" -o CaseInsensitiveSearch file system supports case-insensitive file names\n"
|
||||
//" -o ReparsePoints file system supports reparse points\n"
|
||||
//" -o NamedStreams file system supports named streams\n"
|
||||
//" -o ReadOnlyVolume file system is read only\n"
|
||||
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n");
|
||||
opt_data->help = 1;
|
||||
return 1;
|
||||
case 'V':
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
|
||||
FSP_FUSE_LIBRARY_NAME " version %d.%d",
|
||||
FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION);
|
||||
opt_data->help = 1;
|
||||
return 1;
|
||||
case 'U':
|
||||
if ('U' == arg[2])
|
||||
arg += sizeof "--UNC=" - 1;
|
||||
else if ('V' == arg[2])
|
||||
arg += sizeof "--VolumePrefix=" - 1;
|
||||
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
|
||||
opt_data->VolumeParams.Prefix, sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR)))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
||||
struct fuse_chan *ch, struct fuse_args *args,
|
||||
const struct fuse_operations *ops, size_t opsize, void *data)
|
||||
{
|
||||
struct fuse *f = 0;
|
||||
struct fsp_fuse_core_opt_data opt_data;
|
||||
ULONG Size;
|
||||
PWSTR ErrorMessage = L".";
|
||||
NTSTATUS Result;
|
||||
|
||||
if (opsize > sizeof(struct fuse_operations))
|
||||
opsize = sizeof(struct fuse_operations);
|
||||
|
||||
memset(&opt_data, 0, sizeof opt_data);
|
||||
opt_data.env = env;
|
||||
|
||||
if (-1 == fsp_fuse_opt_parse(env, args, &opt_data, fsp_fuse_core_opts, fsp_fuse_core_opt_proc))
|
||||
return 0;
|
||||
if (opt_data.help)
|
||||
return 0;
|
||||
|
||||
if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout)
|
||||
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
|
||||
opt_data.VolumeParams.CaseSensitiveSearch = !opt_data.CaseInsensitiveSearch;
|
||||
opt_data.VolumeParams.PersistentAcls = TRUE;
|
||||
opt_data.VolumeParams.ReparsePoints = !!opt_data.ReparsePoints;
|
||||
opt_data.VolumeParams.NamedStreams = !!opt_data.NamedStreams;
|
||||
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
|
||||
|
||||
f = fsp_fuse_obj_alloc(env, sizeof *f);
|
||||
if (0 == f)
|
||||
goto fail;
|
||||
|
||||
f->env = env;
|
||||
f->set_umask = opt_data.set_umask; f->umask = opt_data.umask;
|
||||
f->set_uid = opt_data.set_uid; f->uid = opt_data.uid;
|
||||
f->set_gid = opt_data.set_gid; f->gid = opt_data.gid;
|
||||
memcpy(&f->ops, ops, opsize);
|
||||
f->data = data;
|
||||
f->DebugLog = opt_data.debug ? -1 : 0;
|
||||
memcpy(&f->VolumeParams, &opt_data.VolumeParams, sizeof opt_data.VolumeParams);
|
||||
|
||||
Size = (lstrlenW(ch->MountPoint) + 1) * sizeof(WCHAR);
|
||||
f->MountPoint = fsp_fuse_obj_alloc(env, Size);
|
||||
if (0 == f->MountPoint)
|
||||
goto fail;
|
||||
memcpy(f->MountPoint, ch->MountPoint, Size);
|
||||
|
||||
Result = fsp_fuse_preflight(f);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
switch (Result)
|
||||
{
|
||||
case STATUS_ACCESS_DENIED:
|
||||
ErrorMessage = L": access denied.";
|
||||
break;
|
||||
|
||||
case STATUS_NO_SUCH_DEVICE:
|
||||
ErrorMessage = L": FSD not found.";
|
||||
break;
|
||||
|
||||
case STATUS_OBJECT_NAME_INVALID:
|
||||
ErrorMessage = L": invalid mount point.";
|
||||
break;
|
||||
|
||||
case STATUS_OBJECT_NAME_COLLISION:
|
||||
ErrorMessage = L": mount point in use.";
|
||||
break;
|
||||
|
||||
default:
|
||||
ErrorMessage = L": unspecified error.";
|
||||
break;
|
||||
}
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return f;
|
||||
|
||||
fail:
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE,
|
||||
L"Cannot create " FSP_FUSE_LIBRARY_NAME " file system%s",
|
||||
ErrorMessage);
|
||||
|
||||
if (0 != f)
|
||||
fsp_fuse_destroy(env, f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FSP_FUSE_API void fsp_fuse_destroy(struct fsp_fuse_env *env,
|
||||
struct fuse *f)
|
||||
{
|
||||
fsp_fuse_cleanup(f);
|
||||
|
||||
fsp_fuse_obj_free(f->MountPoint);
|
||||
|
||||
fsp_fuse_obj_free(f);
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_loop(struct fsp_fuse_env *env,
|
||||
struct fuse *f)
|
||||
{
|
||||
f->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE;
|
||||
return 0 == FspServiceRunEx(FspDiagIdent(), fsp_fuse_svcstart, fsp_fuse_svcstop, 0, f) ?
|
||||
0 : -1;
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_loop_mt(struct fsp_fuse_env *env,
|
||||
struct fuse *f)
|
||||
{
|
||||
f->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE;
|
||||
return 0 == FspServiceRunEx(FspDiagIdent(), fsp_fuse_svcstart, fsp_fuse_svcstop, 0, f) ?
|
||||
0 : -1;
|
||||
}
|
||||
|
||||
FSP_FUSE_API void fsp_fuse_exit(struct fsp_fuse_env *env,
|
||||
struct fuse *f)
|
||||
{
|
||||
if (0 != f->Service)
|
||||
FspServiceStop(f->Service);
|
||||
}
|
||||
|
||||
FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env)
|
||||
{
|
||||
struct fuse_context *context;
|
||||
|
||||
InitOnceExecuteOnce(&fsp_fuse_initonce, fsp_fuse_initialize, 0, 0);
|
||||
if (TLS_OUT_OF_INDEXES == fsp_fuse_tlskey)
|
||||
return 0;
|
||||
|
||||
context = TlsGetValue(fsp_fuse_tlskey);
|
||||
if (0 == context)
|
||||
{
|
||||
struct fsp_fuse_context_header *contexthdr;
|
||||
|
||||
contexthdr = fsp_fuse_obj_alloc(env,
|
||||
sizeof(struct fsp_fuse_context_header) + sizeof(struct fuse_context));
|
||||
if (0 == contexthdr)
|
||||
return 0;
|
||||
|
||||
context = FSP_FUSE_CONTEXT_FROM_HDR(contexthdr);
|
||||
context->pid = -1;
|
||||
|
||||
TlsSetValue(fsp_fuse_tlskey, context);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
FSP_FUSE_API int32_t fsp_fuse_ntstatus_from_errno(struct fsp_fuse_env *env,
|
||||
int err)
|
||||
{
|
||||
if (0 > err)
|
||||
err = -err;
|
||||
|
||||
if ('C' == env->environment)
|
||||
switch (err)
|
||||
{
|
||||
#undef FSP_FUSE_ERRNO
|
||||
#define FSP_FUSE_ERRNO 67
|
||||
#include "errno.i"
|
||||
default:
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
else
|
||||
switch (err)
|
||||
{
|
||||
#undef FSP_FUSE_ERRNO
|
||||
#define FSP_FUSE_ERRNO 87
|
||||
#include "errno.i"
|
||||
default:
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cygwin signal support */
|
||||
|
||||
FSP_FUSE_API void fsp_fuse_signal_handler(int sig)
|
||||
{
|
||||
FspServiceConsoleCtrlHandler(CTRL_BREAK_EVENT);
|
||||
}
|
10
src/dll/fuse/fuse.pc
Normal file
10
src/dll/fuse/fuse.pc
Normal file
@ -0,0 +1,10 @@
|
||||
prefix=${pcfiledir}/..
|
||||
incdir=${prefix}/inc/fuse
|
||||
implib=${prefix}/bin/winfsp-${arch}.dll
|
||||
|
||||
Name: fuse
|
||||
Description: WinFsp FUSE compatible API
|
||||
Version: 2.8
|
||||
URL: http://www.secfs.net/winfsp/
|
||||
Libs: "${implib}"
|
||||
Cflags: -I"${incdir}"
|
1446
src/dll/fuse/fuse_intf.c
Normal file
1446
src/dll/fuse/fuse_intf.c
Normal file
File diff suppressed because it is too large
Load Diff
179
src/dll/fuse/fuse_main.c
Normal file
179
src/dll/fuse/fuse_main.c
Normal file
@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @file dll/fuse/fuse_main.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/fuse/library.h>
|
||||
|
||||
#define FSP_FUSE_MAIN_OPT(n, f, v) { n, offsetof(struct fsp_fuse_main_opt_data, f), v }
|
||||
|
||||
struct fsp_fuse_main_opt_data
|
||||
{
|
||||
struct fsp_fuse_env *env;
|
||||
char *mountpoint;
|
||||
int singlethread;
|
||||
int foreground;
|
||||
};
|
||||
|
||||
static struct fuse_opt fsp_fuse_main_opts[] =
|
||||
{
|
||||
FUSE_OPT_KEY("-h", 'h'),
|
||||
FUSE_OPT_KEY("--help", 'h'),
|
||||
FUSE_OPT_KEY("-ho", 'H'),
|
||||
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
|
||||
FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
|
||||
FSP_FUSE_MAIN_OPT("-d", foreground, 1),
|
||||
FSP_FUSE_MAIN_OPT("debug", foreground, 1),
|
||||
|
||||
FSP_FUSE_MAIN_OPT("-f", foreground, 1),
|
||||
FSP_FUSE_MAIN_OPT("-s", singlethread, 1),
|
||||
|
||||
FUSE_OPT_END,
|
||||
};
|
||||
|
||||
static int fsp_fuse_main_opt_proc(void *opt_data0, const char *arg, int key,
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
static PWSTR HeaderHelp = L""
|
||||
"\n"
|
||||
" -o opt,[opt...] mount options\n"
|
||||
" -h --help print help\n"
|
||||
" -V --version print version\n";
|
||||
static PWSTR MainHelp = L""
|
||||
"FUSE options:\n"
|
||||
" -d -o debug enable debug output (implies -f)\n"
|
||||
" -f foreground operation\n"
|
||||
" -s disable multi-threaded operation\n";
|
||||
struct fsp_fuse_main_opt_data *opt_data = opt_data0;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
default:
|
||||
return 1;
|
||||
case 'h':
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
|
||||
"usage: %s mountpoint [options]\n"
|
||||
"%s"
|
||||
"\n"
|
||||
"%s",
|
||||
FspDiagIdent(), HeaderHelp, MainHelp);
|
||||
return 1;
|
||||
case 'H':
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
|
||||
"%s",
|
||||
MainHelp);
|
||||
fsp_fuse_opt_add_arg(opt_data->env, outargs, "-h");
|
||||
return 0;
|
||||
case FUSE_OPT_KEY_NONOPT:
|
||||
if (0 == opt_data->mountpoint)
|
||||
{
|
||||
size_t size = lstrlenA(arg) + 1;
|
||||
opt_data->mountpoint = opt_data->env->memalloc(size);
|
||||
if (0 == opt_data->mountpoint)
|
||||
return -1;
|
||||
memcpy(opt_data->mountpoint, arg, size);
|
||||
}
|
||||
else
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE,
|
||||
L"Invalid argument \"%S\"", arg);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_parse_cmdline(struct fsp_fuse_env *env,
|
||||
struct fuse_args *args,
|
||||
char **mountpoint, int *multithreaded, int *foreground)
|
||||
{
|
||||
struct fsp_fuse_main_opt_data opt_data;
|
||||
|
||||
memset(&opt_data, 0, sizeof opt_data);
|
||||
opt_data.env = env;
|
||||
|
||||
if (-1 == fsp_fuse_opt_parse(env, args, &opt_data, fsp_fuse_main_opts, fsp_fuse_main_opt_proc))
|
||||
return -1;
|
||||
|
||||
if (0 != mountpoint)
|
||||
*mountpoint = opt_data.mountpoint;
|
||||
else
|
||||
env->memfree(mountpoint);
|
||||
|
||||
if (0 != multithreaded)
|
||||
*multithreaded = !opt_data.singlethread;
|
||||
|
||||
if (0 != foreground)
|
||||
*foreground = opt_data.foreground;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_main_real(struct fsp_fuse_env *env,
|
||||
int argc, char *argv[],
|
||||
const struct fuse_operations *ops, size_t opsize, void *data)
|
||||
{
|
||||
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||||
char *mountpoint = 0;
|
||||
int multithreaded = 0;
|
||||
int foreground = 0;
|
||||
struct fuse_chan *ch = 0;
|
||||
struct fuse *f = 0;
|
||||
int signal_handlers = 0;
|
||||
int result;
|
||||
|
||||
result = fsp_fuse_parse_cmdline(env, &args, &mountpoint, &multithreaded, &foreground);
|
||||
if (-1 == result)
|
||||
goto exit;
|
||||
|
||||
ch = fsp_fuse_mount(env, mountpoint, &args);
|
||||
if (0 == ch)
|
||||
{
|
||||
result = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
f = fsp_fuse_new(env, ch, &args, ops, opsize, data);
|
||||
if (0 == f)
|
||||
{
|
||||
result = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
result = env->daemonize(foreground);
|
||||
if (-1 == result)
|
||||
goto exit;
|
||||
|
||||
result = env->set_signal_handlers(f);
|
||||
if (-1 == result)
|
||||
goto exit;
|
||||
signal_handlers = 1;
|
||||
|
||||
result = multithreaded ? fsp_fuse_loop_mt(env, f) : fsp_fuse_loop(env, f);
|
||||
|
||||
exit:
|
||||
if (signal_handlers)
|
||||
env->set_signal_handlers(0);
|
||||
|
||||
if (0 != f)
|
||||
fsp_fuse_destroy(env, f);
|
||||
|
||||
if (0 != ch)
|
||||
fsp_fuse_unmount(env, mountpoint, ch);
|
||||
|
||||
env->memfree(mountpoint);
|
||||
|
||||
fsp_fuse_opt_free_args(env, &args);
|
||||
|
||||
/* main() style return: 0 success, 1 error */
|
||||
return !!result;
|
||||
}
|
622
src/dll/fuse/fuse_opt.c
Normal file
622
src/dll/fuse/fuse_opt.c
Normal file
@ -0,0 +1,622 @@
|
||||
/**
|
||||
* @file dll/fuse/fuse_opt.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/fuse/library.h>
|
||||
|
||||
/*
|
||||
* Define the following symbol to support escaped commas (',') during fuse_opt_parse.
|
||||
*/
|
||||
#define FSP_FUSE_OPT_PARSE_ESCAPED_COMMAS
|
||||
|
||||
#define fsp_fuse_opt_match_none ((const char *)0) /* no option match */
|
||||
#define fsp_fuse_opt_match_exact ((const char *)1) /* exact option match */
|
||||
#define fsp_fuse_opt_match_next ((const char *)2) /* option match, value is next arg */
|
||||
|
||||
static long long strtoint(const char *p, int base, int is_signed)
|
||||
{
|
||||
long long v;
|
||||
int maxdig, maxalp, sign = +1;
|
||||
|
||||
if (is_signed)
|
||||
{
|
||||
if ('+' == *p)
|
||||
p++;
|
||||
else if ('-' == *p)
|
||||
p++, sign = -1;
|
||||
}
|
||||
|
||||
if (0 == base)
|
||||
{
|
||||
if ('0' == *p)
|
||||
{
|
||||
p++;
|
||||
if ('x' == *p || 'X' == *p)
|
||||
{
|
||||
p++;
|
||||
base = 16;
|
||||
}
|
||||
else
|
||||
base = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
base = 10;
|
||||
}
|
||||
}
|
||||
|
||||
maxdig = 10 < base ? '9' : (base - 1) + '0';
|
||||
maxalp = 10 < base ? (base - 1 - 10) + 'a' : 0;
|
||||
|
||||
for (v = 0; *p; p++)
|
||||
{
|
||||
int c = *p;
|
||||
|
||||
if ('0' <= c && c <= maxdig)
|
||||
v = base * v + (c - '0');
|
||||
else
|
||||
{
|
||||
c |= 0x20;
|
||||
if ('a' <= c && c <= maxalp)
|
||||
v = base * v + (c - 'a') + 10;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sign * v;
|
||||
}
|
||||
|
||||
static void fsp_fuse_opt_match_templ(
|
||||
const char *templ, const char **pspec,
|
||||
const char **parg)
|
||||
{
|
||||
const char *p, *q;
|
||||
|
||||
*pspec = 0;
|
||||
|
||||
for (p = templ, q = *parg;; p++, q++)
|
||||
if ('\0' == *q)
|
||||
{
|
||||
if ('\0' == *p)
|
||||
*parg = fsp_fuse_opt_match_exact;
|
||||
else if (' ' == *p)
|
||||
*pspec = p + 1, *parg = fsp_fuse_opt_match_next;
|
||||
else
|
||||
*parg = fsp_fuse_opt_match_none;
|
||||
break;
|
||||
}
|
||||
else if ('=' == *p)
|
||||
{
|
||||
if (*q == *p)
|
||||
{
|
||||
p++, q++;
|
||||
if ('%' == *p || '\0' == *p)
|
||||
*pspec = p, *parg = q;
|
||||
else
|
||||
*parg = 0 == lstrcmpA(q, p) ?
|
||||
fsp_fuse_opt_match_exact : fsp_fuse_opt_match_none;
|
||||
}
|
||||
else
|
||||
*parg = fsp_fuse_opt_match_none;
|
||||
break;
|
||||
}
|
||||
else if (' ' == *p)
|
||||
{
|
||||
*pspec = p + 1, *parg = q;
|
||||
break;
|
||||
}
|
||||
else if (*q != *p)
|
||||
{
|
||||
*parg = fsp_fuse_opt_match_none;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct fuse_opt *fsp_fuse_opt_find(
|
||||
const struct fuse_opt opts[], const char **pspec,
|
||||
const char **parg)
|
||||
{
|
||||
const struct fuse_opt *opt;
|
||||
const char *arg;
|
||||
|
||||
for (opt = opts; 0 != opt->templ; opt++)
|
||||
{
|
||||
arg = *parg;
|
||||
fsp_fuse_opt_match_templ(opt->templ, pspec, &arg);
|
||||
if (fsp_fuse_opt_match_none != arg)
|
||||
{
|
||||
*parg = arg;
|
||||
return opt;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsp_fuse_opt_call_proc(struct fsp_fuse_env *env,
|
||||
void *data, fuse_opt_proc_t proc,
|
||||
const char *arg, const char *argl,
|
||||
int key, int is_opt,
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
int result, len0, len1;
|
||||
char *fullarg = 0;
|
||||
|
||||
if (FUSE_OPT_KEY_DISCARD == key)
|
||||
return 0;
|
||||
|
||||
len0 = lstrlenA(arg);
|
||||
|
||||
if (0 != argl && !(arg <= argl && argl < arg + len0))
|
||||
{
|
||||
len1 = lstrlenA(argl);
|
||||
|
||||
fullarg = env->memalloc(len0 + len1 + 1);
|
||||
if (0 == fullarg)
|
||||
return -1;
|
||||
|
||||
memcpy(fullarg, arg, len0);
|
||||
memcpy(fullarg + len0, argl, len1);
|
||||
fullarg[len0 + len1] = '\0';
|
||||
|
||||
arg = fullarg;
|
||||
}
|
||||
|
||||
if (FUSE_OPT_KEY_KEEP != key && 0 != proc)
|
||||
{
|
||||
result = proc(data, arg, key, outargs);
|
||||
if (-1 == result || 0 == result)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (is_opt)
|
||||
{
|
||||
if (!(3 <= outargs->argc &&
|
||||
'-' == outargs->argv[1][0] && 'o' == outargs->argv[1][1] &&
|
||||
'\0' == outargs->argv[1][2]))
|
||||
{
|
||||
result = fsp_fuse_opt_insert_arg(env, outargs, 1, "-o");
|
||||
if (-1 == result)
|
||||
goto exit;
|
||||
result = fsp_fuse_opt_insert_arg(env, outargs, 2, "");
|
||||
if (-1 == result)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#if defined(FSP_FUSE_OPT_PARSE_ESCAPED_COMMAS)
|
||||
result = fsp_fuse_opt_add_opt_escaped(env, &outargs->argv[2], arg);
|
||||
#else
|
||||
result = fsp_fuse_opt_add_opt(env, &outargs->argv[2], arg);
|
||||
#endif
|
||||
if (-1 == result)
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = fsp_fuse_opt_add_arg(env, outargs, arg);
|
||||
if (-1 == result)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (0 != fullarg)
|
||||
env->memfree(fullarg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsp_fuse_opt_process_arg(struct fsp_fuse_env *env,
|
||||
void *data, const struct fuse_opt *opt, fuse_opt_proc_t proc,
|
||||
const char *spec,
|
||||
const char *arg, const char *argl,
|
||||
int is_opt,
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
#define VAR(data, opt, type) *(type *)((char *)(data) + (opt)->offset)
|
||||
|
||||
if (-1L == opt->offset)
|
||||
return fsp_fuse_opt_call_proc(env,
|
||||
data, proc, arg, argl, opt->value, is_opt, outargs);
|
||||
else
|
||||
{
|
||||
int h, j, l, t, z;
|
||||
long long llv;
|
||||
char *s;
|
||||
int len;
|
||||
|
||||
if (0 == spec || '\0' == spec[0])
|
||||
{
|
||||
VAR(data, opt, int) = opt->value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ('%' != spec[0])
|
||||
return -1; /* bad option template */
|
||||
|
||||
h = j = l = t = z = 0;
|
||||
for (spec++; *spec; spec++)
|
||||
switch (*spec)
|
||||
{
|
||||
default:
|
||||
case 0: case 1: case 2: case 3: case 4:
|
||||
case 5: case 6: case 7: case 8: case 9:
|
||||
case 'm':
|
||||
break;
|
||||
case 'h':
|
||||
h++;
|
||||
break;
|
||||
case 'j':
|
||||
j++;
|
||||
break;
|
||||
case 'l':
|
||||
l++;
|
||||
break;
|
||||
case 'L': case 'q':
|
||||
l += 2;
|
||||
break;
|
||||
case 't':
|
||||
t++;
|
||||
break;
|
||||
case 'z':
|
||||
z++;
|
||||
break;
|
||||
case 'd':
|
||||
llv = strtoint(argl, 10, 1);
|
||||
goto ivar;
|
||||
case 'i':
|
||||
llv = strtoint(argl, 0, 1);
|
||||
goto ivar;
|
||||
case 'o':
|
||||
llv = strtoint(argl, 8, 0);
|
||||
goto ivar;
|
||||
case 'u':
|
||||
llv = strtoint(argl, 10, 0);
|
||||
goto ivar;
|
||||
case 'x': case 'X':
|
||||
llv = strtoint(argl, 16, 0);
|
||||
ivar:
|
||||
if (z)
|
||||
VAR(data, opt, size_t) = (size_t)llv;
|
||||
else if (t)
|
||||
VAR(data, opt, ptrdiff_t) = (ptrdiff_t)llv;
|
||||
else if (j)
|
||||
VAR(data, opt, intmax_t) = (intmax_t)llv;
|
||||
else if (1 == h)
|
||||
VAR(data, opt, short) = (short)llv;
|
||||
else if (2 <= h)
|
||||
VAR(data, opt, char) = (char)llv;
|
||||
else if (1 == l)
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
/* long is 8 bytes long in Cygwin64 and 4 bytes long in Win64 */
|
||||
if ('C' == env->environment)
|
||||
VAR(data, opt, long long) = (long long)llv;
|
||||
else
|
||||
VAR(data, opt, long) = (long)llv;
|
||||
#else
|
||||
VAR(data, opt, long) = (long)llv;
|
||||
#endif
|
||||
}
|
||||
else if (2 <= l)
|
||||
VAR(data, opt, long long) = (long long)llv;
|
||||
else
|
||||
VAR(data, opt, int) = (int)llv;
|
||||
return 0;
|
||||
case 's': case 'c':
|
||||
len = lstrlenA(argl);
|
||||
s = env->memalloc(len + 1);
|
||||
if (0 == s)
|
||||
return -1;
|
||||
memcpy(s, argl, len);
|
||||
s[len] = '\0';
|
||||
VAR(data, opt, const char *) = (const char *)s;
|
||||
return 0;
|
||||
case 'a': case 'e': case 'E': case 'f': case 'g':
|
||||
return -1; /* no float support */
|
||||
}
|
||||
|
||||
return -1; /* bad option template */
|
||||
}
|
||||
|
||||
#undef VAR
|
||||
}
|
||||
|
||||
static int fsp_fuse_opt_parse_arg(struct fsp_fuse_env *env,
|
||||
void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc,
|
||||
const char *arg, const char *nextarg, int *pconsumed_nextarg,
|
||||
int is_opt,
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
const struct fuse_opt *opt;
|
||||
const char *spec, *argl;
|
||||
int processed = 0;
|
||||
|
||||
argl = arg;
|
||||
opt = opts;
|
||||
while (0 != (opt = fsp_fuse_opt_find(opt, &spec, &argl)))
|
||||
{
|
||||
if (fsp_fuse_opt_match_exact == argl)
|
||||
argl = arg;
|
||||
else if (fsp_fuse_opt_match_next == argl)
|
||||
{
|
||||
if (0 == nextarg)
|
||||
return -1; /* missing argument for option */
|
||||
argl = nextarg;
|
||||
*pconsumed_nextarg = 1;
|
||||
}
|
||||
|
||||
if (-1 == fsp_fuse_opt_process_arg(env,
|
||||
data, opt, proc, spec, arg, argl, is_opt, outargs))
|
||||
return -1;
|
||||
processed++;
|
||||
|
||||
argl = arg;
|
||||
opt++;
|
||||
}
|
||||
|
||||
if (0 != processed)
|
||||
return 0;
|
||||
|
||||
return fsp_fuse_opt_call_proc(env,
|
||||
data, proc, arg, arg, FUSE_OPT_KEY_OPT, is_opt, outargs);
|
||||
}
|
||||
|
||||
static int fsp_fuse_opt_proc0(void *data, const char *arg, int key,
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_opt_parse(struct fsp_fuse_env *env,
|
||||
struct fuse_args *args,
|
||||
void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
|
||||
{
|
||||
static struct fuse_args args0 = FUSE_ARGS_INIT(0, 0);
|
||||
static struct fuse_opt opts0[1] = { FUSE_OPT_END };
|
||||
struct fuse_args outargs = FUSE_ARGS_INIT(0, 0);
|
||||
const char *arg;
|
||||
char *argcopy, *argend;
|
||||
int dashdash = 0, consumed_nextarg;
|
||||
|
||||
if (0 == args)
|
||||
args = &args0;
|
||||
if (0 == opts)
|
||||
opts = opts0;
|
||||
if (0 == proc)
|
||||
proc = fsp_fuse_opt_proc0;
|
||||
|
||||
if (-1 == fsp_fuse_opt_add_arg(env, &outargs, args->argv[0]))
|
||||
return -1;
|
||||
|
||||
for (int argi = 1; args->argc > argi; argi++)
|
||||
{
|
||||
arg = args->argv[argi];
|
||||
if ('-' == arg[0] && !dashdash)
|
||||
{
|
||||
switch (arg[1])
|
||||
{
|
||||
case 'o':
|
||||
if ('\0' == arg[2])
|
||||
{
|
||||
if (args->argc <= argi + 1)
|
||||
goto fail; /* missing argument for option "-o" */
|
||||
arg = args->argv[++argi];
|
||||
}
|
||||
else
|
||||
arg += 2;
|
||||
argcopy = env->memalloc(lstrlenA(arg) + 1);
|
||||
if (0 == argcopy)
|
||||
goto fail;
|
||||
argend = argcopy;
|
||||
for (;;)
|
||||
{
|
||||
#if defined(FSP_FUSE_OPT_PARSE_ESCAPED_COMMAS)
|
||||
if ('\\' == *arg)
|
||||
{
|
||||
arg++;
|
||||
*argend++ = *arg++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if ('\0' == *arg || ',' == *arg)
|
||||
{
|
||||
*argend = '\0';
|
||||
if (-1 == fsp_fuse_opt_parse_arg(env,
|
||||
data, opts, proc, argcopy, 0, 0, 1, &outargs))
|
||||
{
|
||||
env->memfree(argcopy);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ('\0' == *arg)
|
||||
break;
|
||||
|
||||
arg++;
|
||||
argend = argcopy;
|
||||
}
|
||||
else
|
||||
*argend++ = *arg++;
|
||||
}
|
||||
env->memfree(argcopy);
|
||||
break;
|
||||
case '-':
|
||||
if ('\0' == arg[2])
|
||||
{
|
||||
if (-1 == fsp_fuse_opt_add_arg(env, &outargs, arg))
|
||||
return -1;
|
||||
dashdash = 1;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
consumed_nextarg = 0;
|
||||
if (-1 == fsp_fuse_opt_parse_arg(env,
|
||||
data, opts, proc, arg, args->argv[argi + 1], &consumed_nextarg, 0, &outargs))
|
||||
goto fail;
|
||||
if (consumed_nextarg)
|
||||
argi++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (-1 == fsp_fuse_opt_call_proc(env,
|
||||
data, proc, arg, arg, FUSE_OPT_KEY_NONOPT, 0, &outargs))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* if "--" is the last argument, remove it (fuse_opt compatibility) */
|
||||
if (0 < outargs.argc &&
|
||||
'-' == outargs.argv[outargs.argc - 1][0] &&
|
||||
'-' == outargs.argv[outargs.argc - 1][1] &&
|
||||
'\0' == outargs.argv[outargs.argc - 1][2])
|
||||
{
|
||||
env->memfree(outargs.argv[--outargs.argc]);
|
||||
outargs.argv[outargs.argc] = 0;
|
||||
}
|
||||
|
||||
fsp_fuse_opt_free_args(env, args);
|
||||
memcpy(args, &outargs, sizeof outargs);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
fsp_fuse_opt_free_args(env, &outargs);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_opt_add_arg(struct fsp_fuse_env *env,
|
||||
struct fuse_args *args, const char *arg)
|
||||
{
|
||||
return fsp_fuse_opt_insert_arg(env, args, args->argc, arg);
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_opt_insert_arg(struct fsp_fuse_env *env,
|
||||
struct fuse_args *args, int pos, const char *arg)
|
||||
{
|
||||
char **argv;
|
||||
int argsize;
|
||||
|
||||
if (0 == args)
|
||||
return -1;
|
||||
if (0 != args->argv && !args->allocated)
|
||||
return -1;
|
||||
if (0 > pos || pos > args->argc)
|
||||
return -1;
|
||||
|
||||
argv = env->memalloc((args->argc + 2) * sizeof(char *));
|
||||
if (0 == argv)
|
||||
return -1;
|
||||
argsize = lstrlenA(arg) + 1;
|
||||
argv[pos] = env->memalloc(argsize);
|
||||
if (0 == argv[pos])
|
||||
{
|
||||
env->memfree(argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(argv[pos], arg, argsize);
|
||||
memcpy(argv, args->argv, sizeof(char *) * pos);
|
||||
memcpy(argv + pos + 1, args->argv + pos, sizeof(char *) * (args->argc - pos));
|
||||
|
||||
env->memfree(args->argv);
|
||||
|
||||
args->argc++;
|
||||
args->argv = argv;
|
||||
argv[args->argc] = 0;
|
||||
args->allocated = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FSP_FUSE_API void fsp_fuse_opt_free_args(struct fsp_fuse_env *env,
|
||||
struct fuse_args *args)
|
||||
{
|
||||
if (0 == args)
|
||||
return;
|
||||
|
||||
if (args->allocated && 0 != args->argv)
|
||||
{
|
||||
for (int argi = 0; args->argc > argi; argi++)
|
||||
env->memfree(args->argv[argi]);
|
||||
|
||||
env->memfree(args->argv);
|
||||
}
|
||||
|
||||
args->argc = 0;
|
||||
args->argv = 0;
|
||||
args->allocated = 0;
|
||||
}
|
||||
|
||||
static int fsp_fuse_opt_add_opt_internal(struct fsp_fuse_env *env,
|
||||
char **opts, const char *opt, int escaped)
|
||||
{
|
||||
size_t optsize, optlen;
|
||||
char *newopts;
|
||||
const char *p;
|
||||
|
||||
optsize = 0 != *opts && '\0' != (*opts)[0] ? lstrlenA(*opts) + 1 : 0;
|
||||
for (p = opt, optlen = 0; *p; p++, optlen++)
|
||||
if (escaped && (',' == *p || '\\' == *p))
|
||||
optlen++;
|
||||
|
||||
newopts = env->memalloc(optsize + optlen + 1);
|
||||
if (0 == newopts)
|
||||
return -1;
|
||||
|
||||
if (0 != optsize)
|
||||
{
|
||||
memcpy(newopts, *opts, optsize - 1);
|
||||
newopts[optsize - 1] = ',';
|
||||
}
|
||||
|
||||
env->memfree(*opts);
|
||||
*opts = newopts;
|
||||
newopts += optsize;
|
||||
|
||||
for (p = opt; *p; p++, newopts++)
|
||||
{
|
||||
if (escaped && (',' == *p || '\\' == *p))
|
||||
*newopts++ = '\\';
|
||||
*newopts = *p;
|
||||
}
|
||||
*newopts = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_opt_add_opt(struct fsp_fuse_env *env,
|
||||
char **opts, const char *opt)
|
||||
{
|
||||
return fsp_fuse_opt_add_opt_internal(env, opts, opt, 0);
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_opt_add_opt_escaped(struct fsp_fuse_env *env,
|
||||
char **opts, const char *opt)
|
||||
{
|
||||
return fsp_fuse_opt_add_opt_internal(env, opts, opt, 1);
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_opt_match(struct fsp_fuse_env *env,
|
||||
const struct fuse_opt opts[], const char *arg)
|
||||
{
|
||||
if (0 == opts)
|
||||
return 0;
|
||||
|
||||
const char *spec;
|
||||
return !!fsp_fuse_opt_find(opts, &spec, &arg);
|
||||
}
|
92
src/dll/fuse/library.h
Normal file
92
src/dll/fuse/library.h
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @file dll/fuse/library.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_DLL_FUSE_LIBRARY_H_INCLUDED
|
||||
#define WINFSP_DLL_FUSE_LIBRARY_H_INCLUDED
|
||||
|
||||
#include <dll/library.h>
|
||||
#include <fuse/fuse.h>
|
||||
#include <fuse/fuse_opt.h>
|
||||
|
||||
#define FSP_FUSE_LIBRARY_NAME LIBRARY_NAME "-FUSE"
|
||||
|
||||
#define FSP_FUSE_HDR_FROM_CONTEXT(c) \
|
||||
(struct fsp_fuse_context_header *)((PUINT8)(c) - sizeof(struct fsp_fuse_context_header))
|
||||
#define FSP_FUSE_CONTEXT_FROM_HDR(h) \
|
||||
(struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header))
|
||||
|
||||
struct fuse
|
||||
{
|
||||
struct fsp_fuse_env *env;
|
||||
int set_umask, umask;
|
||||
int set_uid, uid;
|
||||
int set_gid, gid;
|
||||
struct fuse_operations ops;
|
||||
void *data;
|
||||
UINT32 DebugLog;
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
|
||||
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
||||
PWSTR MountPoint;
|
||||
FSP_FILE_SYSTEM *FileSystem;
|
||||
BOOLEAN fsinit;
|
||||
FSP_SERVICE *Service; /* weak */
|
||||
};
|
||||
|
||||
struct fsp_fuse_context_header
|
||||
{
|
||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||
FSP_FSCTL_TRANSACT_RSP *Response;
|
||||
char *PosixPath;
|
||||
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ContextBuf[];
|
||||
};
|
||||
|
||||
struct fsp_fuse_file_desc
|
||||
{
|
||||
char *PosixPath;
|
||||
BOOLEAN IsDirectory;
|
||||
int OpenFlags;
|
||||
UINT64 FileHandle;
|
||||
PVOID DirBuffer;
|
||||
ULONG DirBufferSize;
|
||||
};
|
||||
|
||||
struct fuse_dirhandle
|
||||
{
|
||||
PVOID Buffer;
|
||||
ULONG Length;
|
||||
ULONG BytesTransferred;
|
||||
BOOLEAN NonZeroOffset;
|
||||
BOOLEAN DotFiles, HasChild;
|
||||
};
|
||||
|
||||
struct fsp_fuse_dirinfo
|
||||
{
|
||||
UINT16 Size;
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
BOOLEAN FileInfoValid;
|
||||
UINT64 NextOffset;
|
||||
char PosixNameBuf[]; /* includes term-0 (unlike FSP_FSCTL_DIR_INFO) */
|
||||
};
|
||||
|
||||
NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
|
||||
extern FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf;
|
||||
|
||||
#endif
|
@ -18,41 +18,68 @@
|
||||
#include <dll/library.h>
|
||||
|
||||
HINSTANCE DllInstance;
|
||||
HANDLE ProcessHeap;
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
|
||||
{
|
||||
BOOLEAN Dynamic;
|
||||
|
||||
switch (Reason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DllInstance = Instance;
|
||||
ProcessHeap = GetProcessHeap();
|
||||
if (0 == ProcessHeap)
|
||||
return FALSE;
|
||||
FspFileSystemInitialize();
|
||||
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;
|
||||
fsp_fuse_finalize(Dynamic);
|
||||
FspServiceFinalize(Dynamic);
|
||||
FspEventLogFinalize(Dynamic);
|
||||
FspPosixFinalize(Dynamic);
|
||||
break;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
fsp_fuse_finalize_thread();
|
||||
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 +87,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*/;
|
||||
}
|
||||
|
@ -3,3 +3,9 @@ EXPORTS
|
||||
DllUnregisterServer PRIVATE
|
||||
NPGetCaps PRIVATE
|
||||
NPGetConnection PRIVATE
|
||||
NPAddConnection PRIVATE
|
||||
NPAddConnection3 PRIVATE
|
||||
NPCancelConnection PRIVATE
|
||||
NPOpenEnum PRIVATE
|
||||
NPEnumResource PRIVATE
|
||||
NPCloseEnum PRIVATE
|
||||
|
@ -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,21 @@
|
||||
#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 FspPosixFinalize(BOOLEAN Dynamic);
|
||||
VOID FspEventLogFinalize(BOOLEAN Dynamic);
|
||||
VOID FspServiceFinalize(BOOLEAN Dynamic);
|
||||
VOID fsp_fuse_finalize(BOOLEAN Dynamic);
|
||||
VOID fsp_fuse_finalize_thread(VOID);
|
||||
|
||||
NTSTATUS FspFsctlRegister(VOID);
|
||||
NTSTATUS FspFsctlUnregister(VOID);
|
||||
NTSTATUS FspNpRegister(VOID);
|
||||
NTSTATUS FspNpUnregister(VOID);
|
||||
NTSTATUS FspEventLogRegister(VOID);
|
||||
NTSTATUS FspEventLogUnregister(VOID);
|
||||
|
||||
PWSTR FspDiagIdent(VOID);
|
||||
|
||||
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
|
||||
|
||||
#endif
|
||||
|
824
src/dll/np.c
824
src/dll/np.c
@ -16,12 +16,31 @@
|
||||
*/
|
||||
|
||||
#include <dll/library.h>
|
||||
#include <launcher/launcher.h>
|
||||
#include <npapi.h>
|
||||
#include <wincred.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 */
|
||||
|
||||
/*
|
||||
* Define the following macro to use CredUIPromptForWindowsCredentials.
|
||||
* Otherwise CredUIPromptForCredentials will be used.
|
||||
*/
|
||||
#define FSP_NP_CREDUI_PROMPT_NEW
|
||||
|
||||
/*
|
||||
* Define the following macro to include support for the credential manager.
|
||||
*/
|
||||
#define FSP_NP_CREDENTIAL_MANAGER
|
||||
|
||||
enum
|
||||
{
|
||||
FSP_NP_CREDENTIALS_NONE = 0,
|
||||
FSP_NP_CREDENTIALS_PASSWORD = 1,
|
||||
FSP_NP_CREDENTIALS_USERPASS = 3,
|
||||
};
|
||||
|
||||
DWORD APIENTRY NPGetCaps(DWORD Index)
|
||||
{
|
||||
switch (Index)
|
||||
@ -34,14 +53,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 +81,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 +98,115 @@ 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;
|
||||
|
||||
if (!FspNpCheckRemoteName(RemoteName))
|
||||
return FALSE;
|
||||
|
||||
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 BOOLEAN FspNpParseUserName(PWSTR RemoteName,
|
||||
PWSTR UserName, ULONG UserNameSize/* in chars */)
|
||||
{
|
||||
PWSTR ClassName, InstanceName, P;
|
||||
ULONG ClassNameLen, InstanceNameLen;
|
||||
|
||||
if (FspNpParseRemoteName(RemoteName,
|
||||
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
|
||||
{
|
||||
for (P = InstanceName; *P; P++)
|
||||
if ('@' == *P && (ULONG)(P - InstanceName) < UserNameSize)
|
||||
{
|
||||
memcpy(UserName, InstanceName, (P - InstanceName) * sizeof(WCHAR));
|
||||
UserName[P - InstanceName] = L'\0';
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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 +239,175 @@ 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;
|
||||
}
|
||||
|
||||
static DWORD FspNpGetCredentialsKind(PWSTR RemoteName, PDWORD PCredentialsKind)
|
||||
{
|
||||
HKEY RegKey = 0;
|
||||
DWORD NpResult, RegSize;
|
||||
DWORD Credentials;
|
||||
PWSTR ClassName, InstanceName;
|
||||
ULONG ClassNameLen, InstanceNameLen;
|
||||
WCHAR ClassNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
|
||||
|
||||
*PCredentialsKind = FSP_NP_CREDENTIALS_NONE;
|
||||
|
||||
if (!FspNpParseRemoteName(RemoteName,
|
||||
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
|
||||
return WN_BAD_NETNAME;
|
||||
|
||||
if (ClassNameLen > sizeof ClassNameBuf / sizeof ClassNameBuf[0] - 1)
|
||||
ClassNameLen = sizeof ClassNameBuf / sizeof ClassNameBuf[0] - 1;
|
||||
memcpy(ClassNameBuf, ClassName, ClassNameLen * sizeof(WCHAR));
|
||||
ClassNameBuf[ClassNameLen] = '\0';
|
||||
|
||||
NpResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY, 0, KEY_READ, &RegKey);
|
||||
if (ERROR_SUCCESS != NpResult)
|
||||
goto exit;
|
||||
|
||||
RegSize = sizeof Credentials;
|
||||
Credentials = 0; /* default is NO credentials */
|
||||
NpResult = RegGetValueW(RegKey, ClassNameBuf, L"Credentials", RRF_RT_REG_DWORD, 0,
|
||||
&Credentials, &RegSize);
|
||||
if (ERROR_SUCCESS != NpResult && ERROR_FILE_NOT_FOUND != NpResult)
|
||||
goto exit;
|
||||
|
||||
switch (Credentials)
|
||||
{
|
||||
case FSP_NP_CREDENTIALS_NONE:
|
||||
case FSP_NP_CREDENTIALS_PASSWORD:
|
||||
case FSP_NP_CREDENTIALS_USERPASS:
|
||||
*PCredentialsKind = Credentials;
|
||||
break;
|
||||
}
|
||||
|
||||
NpResult = ERROR_SUCCESS;
|
||||
|
||||
exit:
|
||||
if (0 != RegKey)
|
||||
RegCloseKey(RegKey);
|
||||
|
||||
return NpResult;
|
||||
}
|
||||
|
||||
static DWORD FspNpGetCredentials(
|
||||
HWND hwndOwner, PWSTR Caption, DWORD PrevNpResult,
|
||||
DWORD CredentialsKind,
|
||||
PBOOL PSave,
|
||||
PWSTR UserName, ULONG UserNameSize/* in chars */,
|
||||
PWSTR Password, ULONG PasswordSize/* in chars */)
|
||||
{
|
||||
DWORD NpResult;
|
||||
CREDUI_INFOW UiInfo;
|
||||
|
||||
memset(&UiInfo, 0, sizeof UiInfo);
|
||||
UiInfo.cbSize = sizeof UiInfo;
|
||||
UiInfo.hwndParent = hwndOwner;
|
||||
UiInfo.pszCaptionText = Caption;
|
||||
UiInfo.pszMessageText = L"Enter credentials to unlock this file system.";
|
||||
|
||||
#if !defined(FSP_NP_CREDUI_PROMPT_NEW)
|
||||
NpResult = CredUIPromptForCredentialsW(&UiInfo, L"NONE", 0, 0,
|
||||
UserName, UserNameSize,
|
||||
Password, PasswordSize,
|
||||
PSave,
|
||||
CREDUI_FLAGS_GENERIC_CREDENTIALS |
|
||||
CREDUI_FLAGS_DO_NOT_PERSIST |
|
||||
CREDUI_FLAGS_ALWAYS_SHOW_UI |
|
||||
(0 != PrevNpResult ? CREDUI_FLAGS_INCORRECT_PASSWORD : 0) |
|
||||
(0 != PSave ? CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX : 0) |
|
||||
(FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind ? 0/*CREDUI_FLAGS_KEEP_USERNAME*/ : 0));
|
||||
#else
|
||||
WCHAR Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1];
|
||||
ULONG AuthPackage = 0;
|
||||
PVOID InAuthBuf = 0, OutAuthBuf = 0;
|
||||
ULONG InAuthSize, OutAuthSize, DomainSize;
|
||||
|
||||
InAuthSize = 0;
|
||||
if (!CredPackAuthenticationBufferW(
|
||||
CRED_PACK_GENERIC_CREDENTIALS, UserName, Password, 0, &InAuthSize) &&
|
||||
ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
||||
{
|
||||
NpResult = GetLastError();
|
||||
goto exit;
|
||||
}
|
||||
|
||||
InAuthBuf = MemAlloc(InAuthSize);
|
||||
if (0 == InAuthBuf)
|
||||
{
|
||||
NpResult = ERROR_NO_SYSTEM_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!CredPackAuthenticationBufferW(
|
||||
CRED_PACK_GENERIC_CREDENTIALS, UserName, Password, InAuthBuf, &InAuthSize))
|
||||
{
|
||||
NpResult = GetLastError();
|
||||
goto exit;
|
||||
}
|
||||
|
||||
NpResult = CredUIPromptForWindowsCredentialsW(&UiInfo, PrevNpResult,
|
||||
&AuthPackage, InAuthBuf, InAuthSize, &OutAuthBuf, &OutAuthSize, PSave,
|
||||
CREDUIWIN_GENERIC | (0 != PSave ? CREDUIWIN_CHECKBOX : 0));
|
||||
if (ERROR_SUCCESS != NpResult)
|
||||
goto exit;
|
||||
|
||||
DomainSize = sizeof Domain / sizeof Domain[0];
|
||||
if (!CredUnPackAuthenticationBufferW(0, OutAuthBuf, OutAuthSize,
|
||||
UserName, &UserNameSize, Domain, &DomainSize, Password, &PasswordSize))
|
||||
{
|
||||
NpResult = GetLastError();
|
||||
goto exit;
|
||||
}
|
||||
|
||||
NpResult = ERROR_SUCCESS;
|
||||
|
||||
exit:
|
||||
if (0 != OutAuthBuf)
|
||||
{
|
||||
SecureZeroMemory(OutAuthBuf, OutAuthSize);
|
||||
CoTaskMemFree(OutAuthBuf);
|
||||
}
|
||||
|
||||
if (0 != InAuthBuf)
|
||||
{
|
||||
SecureZeroMemory(InAuthBuf, InAuthSize);
|
||||
MemFree(InAuthBuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NpResult;
|
||||
}
|
||||
|
||||
DWORD APIENTRY NPGetConnection(
|
||||
LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpnBufferLen)
|
||||
{
|
||||
DWORD NpResult;
|
||||
NTSTATUS Result;
|
||||
@ -118,15 +417,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 +483,479 @@ DWORD APIENTRY NPGetConnection(LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD
|
||||
return NpResult;
|
||||
}
|
||||
|
||||
DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName)
|
||||
{
|
||||
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;
|
||||
DWORD CredentialsKind;
|
||||
PWSTR PipeBuf = 0;
|
||||
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
||||
PCREDENTIALW Credential = 0;
|
||||
#endif
|
||||
|
||||
if (dwType & RESOURCETYPE_PRINT)
|
||||
return WN_BAD_VALUE;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
FspNpGetCredentialsKind(lpRemoteName, &CredentialsKind);
|
||||
|
||||
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
||||
/* if we need credentials and none were passed check with the credential manager */
|
||||
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind && 0 == lpPassword &&
|
||||
CredReadW(lpRemoteName, CRED_TYPE_GENERIC, 0, &Credential))
|
||||
{
|
||||
if (sizeof(WCHAR) <= Credential->CredentialBlobSize &&
|
||||
L'\0' == ((PWSTR)(Credential->CredentialBlob))
|
||||
[(Credential->CredentialBlobSize / sizeof(WCHAR)) - 1])
|
||||
{
|
||||
lpUserName = Credential->UserName;
|
||||
lpPassword = (PVOID)Credential->CredentialBlob;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* if we need credentials and we don't have any return ACCESS DENIED */
|
||||
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind)
|
||||
{
|
||||
int Length;
|
||||
if (0 == lpPassword ||
|
||||
(0 == (Length = lstrlenW(lpPassword))) || CREDUI_MAX_PASSWORD_LENGTH < Length)
|
||||
{
|
||||
NpResult = WN_ACCESS_DENIED;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
|
||||
{
|
||||
int Length;
|
||||
if (0 == lpUserName ||
|
||||
(0 == (Length = lstrlenW(lpUserName))) || CREDUI_MAX_USERNAME_LENGTH < Length)
|
||||
{
|
||||
NpResult = WN_ACCESS_DENIED;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
|
||||
if (0 == PipeBuf)
|
||||
{
|
||||
NpResult = WN_OUT_OF_MEMORY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* we do not explicitly check, but assumption is it all fits in LAUNCHER_PIPE_BUFFER_SIZE */
|
||||
P = PipeBuf;
|
||||
*P++ = FSP_NP_CREDENTIALS_NONE != CredentialsKind ?
|
||||
LauncherSvcInstanceStartWithSecret : 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;
|
||||
if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
|
||||
{
|
||||
lstrcpyW(P, lpUserName); P += lstrlenW(lpUserName) + 1;
|
||||
}
|
||||
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind)
|
||||
{
|
||||
lstrcpyW(P, lpPassword); P += lstrlenW(lpPassword) + 1;
|
||||
}
|
||||
|
||||
NpResult = FspNpCallLauncherPipe(
|
||||
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE);
|
||||
switch (NpResult)
|
||||
{
|
||||
case WN_SUCCESS:
|
||||
case WN_ACCESS_DENIED:
|
||||
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;
|
||||
}
|
||||
|
||||
exit:
|
||||
MemFree(PipeBuf);
|
||||
|
||||
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
||||
if (0 != Credential)
|
||||
CredFree(Credential);
|
||||
#endif
|
||||
|
||||
return NpResult;
|
||||
}
|
||||
|
||||
DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
|
||||
LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName, DWORD dwFlags)
|
||||
{
|
||||
DWORD NpResult;
|
||||
PWSTR RemoteName = lpNetResource->lpRemoteName;
|
||||
DWORD CredentialsKind;
|
||||
WCHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1], Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
|
||||
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
||||
BOOL Save = TRUE;
|
||||
#endif
|
||||
|
||||
//dwFlags |= CONNECT_INTERACTIVE | CONNECT_PROMPT; /* TESTING ONLY! */
|
||||
|
||||
/* CONNECT_PROMPT is only valid if CONNECT_INTERACTIVE is also set */
|
||||
if (CONNECT_PROMPT == (dwFlags & (CONNECT_INTERACTIVE | CONNECT_PROMPT)))
|
||||
return WN_BAD_VALUE;
|
||||
|
||||
/* if not CONNECT_PROMPT go ahead and attempt to NPAddConnection once */
|
||||
if (0 == (dwFlags & CONNECT_PROMPT))
|
||||
{
|
||||
NpResult = NPAddConnection(lpNetResource, lpPassword, lpUserName);
|
||||
if (WN_ACCESS_DENIED != NpResult || 0 == (dwFlags & CONNECT_INTERACTIVE))
|
||||
return NpResult;
|
||||
}
|
||||
|
||||
FspNpGetCredentialsKind(RemoteName, &CredentialsKind);
|
||||
if (FSP_NP_CREDENTIALS_NONE == CredentialsKind)
|
||||
return WN_CANCEL;
|
||||
|
||||
/* if CONNECT_INTERACTIVE keep asking the user for valid credentials or cancel */
|
||||
NpResult = WN_SUCCESS;
|
||||
lstrcpyW(UserName, L"UNSPECIFIED");
|
||||
Password[0] = L'\0';
|
||||
if (FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind)
|
||||
FspNpParseUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]);
|
||||
do
|
||||
{
|
||||
NpResult = FspNpGetCredentials(
|
||||
hwndOwner, RemoteName, NpResult,
|
||||
CredentialsKind,
|
||||
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
||||
&Save,
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
UserName, sizeof UserName / sizeof UserName[0],
|
||||
Password, sizeof Password / sizeof Password[0]);
|
||||
if (WN_SUCCESS != NpResult)
|
||||
break;
|
||||
|
||||
NpResult = NPAddConnection(lpNetResource, Password, UserName);
|
||||
} while (WN_ACCESS_DENIED == NpResult);
|
||||
|
||||
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
||||
if (WN_SUCCESS == NpResult && Save)
|
||||
{
|
||||
CREDENTIALW Credential;
|
||||
|
||||
memset(&Credential, 0, sizeof Credential);
|
||||
Credential.Type = CRED_TYPE_GENERIC;
|
||||
Credential.Persist = CRED_PERSIST_LOCAL_MACHINE;
|
||||
Credential.TargetName = RemoteName;
|
||||
Credential.UserName = UserName;
|
||||
Credential.CredentialBlobSize = (lstrlenW(Password) + 1) * sizeof(WCHAR);
|
||||
Credential.CredentialBlob = (PVOID)Password;
|
||||
|
||||
CredWriteW(&Credential, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
SecureZeroMemory(Password, sizeof Password);
|
||||
|
||||
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
|
||||
return
|
||||
0 != Enum &&
|
||||
HeapValidate(GetProcessHeap(), 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 +988,29 @@ NTSTATUS FspNpRegister(VOID)
|
||||
if (ERROR_SUCCESS != RegResult)
|
||||
return FspNtStatusFromWin32(RegResult);
|
||||
|
||||
RegResult = RegSetValueExW(RegKey,
|
||||
L"Name", 0, REG_SZ, (PVOID) L"" FSP_NP_DESC, sizeof L"" FSP_NP_DESC);
|
||||
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)Description, Size);
|
||||
}
|
||||
|
||||
MemFree(VersionInfo);
|
||||
}
|
||||
}
|
||||
if (ERROR_SUCCESS != RegResult)
|
||||
goto close_and_exit;
|
||||
|
||||
@ -253,7 +1041,7 @@ NTSTATUS FspNpRegister(VOID)
|
||||
{
|
||||
if (L',' == *P || '\0' == *P)
|
||||
{
|
||||
if (CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
|
||||
if (CSTR_EQUAL == CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE,
|
||||
Part, (int)(P - Part),
|
||||
L"" FSP_NP_NAME, (int)(sizeof L"" FSP_NP_NAME - sizeof(WCHAR)) / sizeof(WCHAR)))
|
||||
{
|
||||
@ -316,7 +1104,7 @@ NTSTATUS FspNpUnregister(VOID)
|
||||
{
|
||||
if (L',' == *P || '\0' == *P)
|
||||
{
|
||||
if (CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
|
||||
if (CSTR_EQUAL == CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE,
|
||||
Part, (int)(P - Part),
|
||||
L"" FSP_NP_NAME, (int)(sizeof L"" FSP_NP_NAME - sizeof(WCHAR)) / sizeof(WCHAR)))
|
||||
{
|
||||
|
@ -17,12 +17,37 @@
|
||||
|
||||
#include <dll/library.h>
|
||||
|
||||
static INIT_ONCE FspNtStatusInitOnce = INIT_ONCE_STATIC_INIT;
|
||||
static ULONG (WINAPI *FspRtlNtStatusToDosError)(NTSTATUS Status);
|
||||
|
||||
static BOOL WINAPI FspNtStatusInitialize(
|
||||
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
||||
{
|
||||
HANDLE Handle;
|
||||
|
||||
Handle = GetModuleHandleW(L"ntdll.dll");
|
||||
if (0 != Handle)
|
||||
FspRtlNtStatusToDosError = (PVOID)GetProcAddress(Handle, "RtlNtStatusToDosError");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspNtStatusFromWin32(DWORD Error)
|
||||
{
|
||||
switch (Error)
|
||||
{
|
||||
#include "ntstatus.i"
|
||||
default:
|
||||
return STATUS_ACCESS_DENIED;
|
||||
/* use FACILITY_NTWIN32 if able, else STATUS_ACCESS_DENIED */
|
||||
return 0xffff >= Error ? (0x80070000 | Error) : STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
FSP_API DWORD FspWin32FromNtStatus(NTSTATUS Status)
|
||||
{
|
||||
InitOnceExecuteOnce(&FspNtStatusInitOnce, FspNtStatusInitialize, 0, 0);
|
||||
if (0 == FspRtlNtStatusToDosError)
|
||||
return ERROR_MR_MID_NOT_FOUND;
|
||||
|
||||
return FspRtlNtStatusToDosError(Status);
|
||||
}
|
||||
|
917
src/dll/posix.c
Normal file
917
src/dll/posix.c
Normal file
@ -0,0 +1,917 @@
|
||||
/**
|
||||
* @file dll/posix.c
|
||||
* POSIX Interop.
|
||||
*
|
||||
* This file provides routines for Windows/POSIX interoperability. It is based
|
||||
* on "Services for UNIX" and Cygwin. See the following documents:
|
||||
*
|
||||
* [PERMS]
|
||||
* https://technet.microsoft.com/en-us/library/bb463216.aspx
|
||||
* [WKSID]
|
||||
* https://support.microsoft.com/en-us/kb/243330
|
||||
* [IDMAP]
|
||||
* https://cygwin.com/cygwin-ug-net/ntsec.html
|
||||
* [SNAME]
|
||||
* https://www.cygwin.com/cygwin-ug-net/using-specialnames.html
|
||||
*
|
||||
* @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 <aclapi.h>
|
||||
#define _NTDEF_
|
||||
#include <ntsecapi.h>
|
||||
|
||||
static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...);
|
||||
|
||||
static INIT_ONCE FspPosixInitOnce = INIT_ONCE_STATIC_INIT;
|
||||
union
|
||||
{
|
||||
SID V;
|
||||
UINT8 B[sizeof(SID) - sizeof(DWORD) + (1 * sizeof(DWORD))];
|
||||
} FspUnmappedSidBuf =
|
||||
{
|
||||
/* S-1-0-65534 */
|
||||
.V.Revision = SID_REVISION,
|
||||
.V.SubAuthorityCount = 1,
|
||||
.V.IdentifierAuthority.Value[5] = 0,
|
||||
.V.SubAuthority[0] = 65534,
|
||||
};
|
||||
static PISID FspAccountDomainSid, FspPrimaryDomainSid;
|
||||
|
||||
#define FspUnmappedSid (&FspUnmappedSidBuf.V)
|
||||
#define FspUnmappedUid (65534)
|
||||
|
||||
static BOOL WINAPI FspPosixInitialize(
|
||||
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
||||
{
|
||||
static LSA_OBJECT_ATTRIBUTES Obja;
|
||||
LSA_HANDLE PolicyHandle = 0;
|
||||
PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = 0;
|
||||
PPOLICY_DNS_DOMAIN_INFO PrimaryDomainInfo = 0;
|
||||
BYTE Count;
|
||||
ULONG Size;
|
||||
NTSTATUS Result;
|
||||
|
||||
Result = LsaOpenPolicy(0, &Obja, POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
Result = LsaQueryInformationPolicy(PolicyHandle, PolicyAccountDomainInformation,
|
||||
&AccountDomainInfo);
|
||||
if (NT_SUCCESS(Result) && 0 != AccountDomainInfo && 0 != AccountDomainInfo->DomainSid)
|
||||
{
|
||||
Count = *GetSidSubAuthorityCount(AccountDomainInfo->DomainSid);
|
||||
Size = sizeof(SID) - sizeof(DWORD) + (Count * sizeof(DWORD));
|
||||
FspAccountDomainSid = MemAlloc(Size);
|
||||
if (0 != FspAccountDomainSid)
|
||||
memcpy(FspAccountDomainSid, AccountDomainInfo->DomainSid, Size);
|
||||
}
|
||||
|
||||
Result = LsaQueryInformationPolicy(PolicyHandle, PolicyDnsDomainInformation,
|
||||
&PrimaryDomainInfo);
|
||||
if (NT_SUCCESS(Result) && 0 != PrimaryDomainInfo && 0 != PrimaryDomainInfo->Sid)
|
||||
{
|
||||
Count = *GetSidSubAuthorityCount(PrimaryDomainInfo->Sid);
|
||||
Size = sizeof(SID) - sizeof(DWORD) + (Count * sizeof(DWORD));
|
||||
FspPrimaryDomainSid = MemAlloc(Size);
|
||||
if (0 != FspPrimaryDomainSid)
|
||||
memcpy(FspPrimaryDomainSid, PrimaryDomainInfo->Sid, Size);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (0 != PrimaryDomainInfo)
|
||||
LsaFreeMemory(PrimaryDomainInfo);
|
||||
|
||||
if (0 != AccountDomainInfo)
|
||||
LsaFreeMemory(AccountDomainInfo);
|
||||
|
||||
if (0 != PolicyHandle)
|
||||
LsaClose(PolicyHandle);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID FspPosixFinalize(BOOLEAN Dynamic)
|
||||
{
|
||||
/*
|
||||
* This function is called during DLL_PROCESS_DETACH. We must therefore keep
|
||||
* finalization tasks to a minimum.
|
||||
*/
|
||||
|
||||
if (Dynamic)
|
||||
{
|
||||
MemFree(FspAccountDomainSid);
|
||||
MemFree(FspPrimaryDomainSid);
|
||||
}
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
|
||||
{
|
||||
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
|
||||
|
||||
*PSid = 0;
|
||||
|
||||
/*
|
||||
* UID namespace partitioning (from [IDMAP] rules):
|
||||
*
|
||||
* 0x000000 + RID S-1-5-RID,S-1-5-32-RID
|
||||
* 0x000ffe OtherSession
|
||||
* 0x000fff CurrentSession
|
||||
* 0x001000 * X + RID S-1-5-X-RID ([WKSID]: X=1-15,17-21,32,64,80,83)
|
||||
* 0x010000 + 0x100 * X + Y S-1-X-Y ([WKSID]: X=1,2,3,4,5,9,16)
|
||||
* 0x030000 + RID S-1-5-21-X-Y-Z-RID
|
||||
* 0x060000 + RID S-1-16-RID
|
||||
* 0x100000 + RID S-1-5-21-X-Y-Z-RID
|
||||
*/
|
||||
|
||||
/* [IDMAP]
|
||||
* Well-known SIDs in the NT_AUTHORITY domain of the S-1-5-RID type,
|
||||
* or aliases of the S-1-5-32-RID type are mapped to the uid/gid value RID.
|
||||
* Examples:
|
||||
* "SYSTEM" S-1-5-18 <=> uid/gid: 18
|
||||
* "Users" S-1-5-32-545 <=> uid/gid: 545
|
||||
*/
|
||||
if (0x200 > Uid || 1000 == Uid)
|
||||
*PSid = FspPosixCreateSid(5, 1, Uid);
|
||||
else if (1000 > Uid)
|
||||
*PSid = FspPosixCreateSid(5, 2, 32, Uid);
|
||||
|
||||
/* [IDMAP]
|
||||
* Logon SIDs: The LogonSid of the current user's session is converted
|
||||
* to the fixed uid 0xfff == 4095 and named "CurrentSession". Any other
|
||||
* LogonSid is converted to the fixed uid 0xffe == 4094 and named
|
||||
* "OtherSession".
|
||||
*/
|
||||
else if (0xfff == Uid || 0xffe == Uid)
|
||||
{
|
||||
/*
|
||||
* Actually we do not support Logon SID's for translation.
|
||||
* We need an access token to find its Logon SID and we do not have one.
|
||||
*/
|
||||
}
|
||||
|
||||
/* [IDMAP]
|
||||
* Accounts from the local machine's user DB (SAM):
|
||||
* S-1-5-21-X-Y-Z-RID <=> uid/gid: 0x30000 + RID
|
||||
*
|
||||
* Accounts from the machine's primary domain:
|
||||
* S-1-5-21-X-Y-Z-RID <=> uid/gid: 0x100000 + RID
|
||||
*
|
||||
* Accounts from a trusted domain of the machine's primary domain:
|
||||
* S-1-5-21-X-Y-Z-RID <=> uid/gid: trustPosixOffset(domain) + RID
|
||||
*/
|
||||
else if (0x30000 <= Uid && Uid < 0x40000)
|
||||
{
|
||||
if (0 != FspAccountDomainSid &&
|
||||
5 == FspAccountDomainSid->IdentifierAuthority.Value[5] &&
|
||||
4 == FspAccountDomainSid->SubAuthorityCount)
|
||||
{
|
||||
*PSid = FspPosixCreateSid(5, 5,
|
||||
21,
|
||||
FspAccountDomainSid->SubAuthority[1],
|
||||
FspAccountDomainSid->SubAuthority[2],
|
||||
FspAccountDomainSid->SubAuthority[3],
|
||||
Uid - 0x30000);
|
||||
}
|
||||
}
|
||||
else if (0x100000 <= Uid && Uid < 0x200000)
|
||||
{
|
||||
if (0 != FspPrimaryDomainSid &&
|
||||
5 == FspPrimaryDomainSid->IdentifierAuthority.Value[5] &&
|
||||
4 == FspPrimaryDomainSid->SubAuthorityCount)
|
||||
{
|
||||
*PSid = FspPosixCreateSid(5, 5,
|
||||
21,
|
||||
FspPrimaryDomainSid->SubAuthority[1],
|
||||
FspPrimaryDomainSid->SubAuthority[2],
|
||||
FspPrimaryDomainSid->SubAuthority[3],
|
||||
Uid - 0x100000);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* I am sorry, I am not going to bother with all that trustPosixOffset stuff.
|
||||
* But if you need it, I accept patches :)
|
||||
*/
|
||||
|
||||
/* [IDMAP]
|
||||
* Mandatory Labels:
|
||||
* S-1-16-RID <=> uid/gid: 0x60000 + RID
|
||||
*/
|
||||
else if (0x60000 <= Uid && Uid < 0x70000)
|
||||
*PSid = FspPosixCreateSid(16, 1, Uid - 0x60000);
|
||||
|
||||
/* [IDMAP]
|
||||
* Other well-known SIDs:
|
||||
* S-1-X-Y <=> uid/gid: 0x10000 + 0x100 * X + Y
|
||||
*/
|
||||
else if (0x10000 <= Uid && Uid < 0x11000)
|
||||
*PSid = FspPosixCreateSid((Uid - 0x10000) >> 8, 1, (Uid - 0x10000) & 0xff);
|
||||
|
||||
/* [IDMAP]
|
||||
* Other well-known SIDs in the NT_AUTHORITY domain (S-1-5-X-RID):
|
||||
* S-1-5-X-RID <=> uid/gid: 0x1000 * X + RID
|
||||
*/
|
||||
else if (FspUnmappedUid != Uid && 0x1000 <= Uid && Uid < 0x100000)
|
||||
*PSid = FspPosixCreateSid(5, 2, Uid >> 12, Uid & 0xfff);
|
||||
|
||||
if (0 == *PSid)
|
||||
*PSid = FspUnmappedSid;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
|
||||
{
|
||||
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
|
||||
|
||||
BYTE Authority;
|
||||
BYTE Count;
|
||||
UINT32 SubAuthority0, Rid;
|
||||
|
||||
*PUid = -1;
|
||||
|
||||
if (!IsValidSid(Sid) || 0 == (Count = *GetSidSubAuthorityCount(Sid)))
|
||||
return STATUS_INVALID_SID;
|
||||
|
||||
Authority = GetSidIdentifierAuthority(Sid)->Value[5];
|
||||
SubAuthority0 = 2 <= Count ? *GetSidSubAuthority(Sid, 0) : 0;
|
||||
Rid = *GetSidSubAuthority(Sid, Count - 1);
|
||||
|
||||
if (5 == Authority)
|
||||
{
|
||||
/* [IDMAP]
|
||||
* Well-known SIDs in the NT_AUTHORITY domain of the S-1-5-RID type,
|
||||
* or aliases of the S-1-5-32-RID type are mapped to the uid/gid value RID.
|
||||
* Examples:
|
||||
* "SYSTEM" S-1-5-18 <=> uid/gid: 18
|
||||
* "Users" S-1-5-32-545 <=> uid/gid: 545
|
||||
*/
|
||||
if (1 == Count)
|
||||
*PUid = Rid;
|
||||
else if (2 == Count && 32 == SubAuthority0)
|
||||
*PUid = Rid;
|
||||
|
||||
/* [IDMAP]
|
||||
* Logon SIDs: The LogonSid of the current user's session is converted
|
||||
* to the fixed uid 0xfff == 4095 and named "CurrentSession". Any other
|
||||
* LogonSid is converted to the fixed uid 0xffe == 4094 and named
|
||||
* "OtherSession".
|
||||
*/
|
||||
else if (2 <= Count && 5 == SubAuthority0)
|
||||
{
|
||||
/*
|
||||
* Actually we do not support Logon SID's for translation.
|
||||
* We need an access token to find its Logon SID and we do not have one.
|
||||
*/
|
||||
}
|
||||
|
||||
/* [IDMAP]
|
||||
* Accounts from the local machine's user DB (SAM):
|
||||
* S-1-5-21-X-Y-Z-RID <=> uid/gid: 0x30000 + RID
|
||||
*
|
||||
* Accounts from the machine's primary domain:
|
||||
* S-1-5-21-X-Y-Z-RID <=> uid/gid: 0x100000 + RID
|
||||
*
|
||||
* Accounts from a trusted domain of the machine's primary domain:
|
||||
* S-1-5-21-X-Y-Z-RID <=> uid/gid: trustPosixOffset(domain) + RID
|
||||
*/
|
||||
else if (5 <= Count && 21 == SubAuthority0)
|
||||
{
|
||||
/*
|
||||
* The order is important! A server that is also a domain controller
|
||||
* has PrimaryDomainSid == AccountDomainSid.
|
||||
*/
|
||||
|
||||
BOOL EqualDomains = FALSE;
|
||||
if (0 != FspPrimaryDomainSid &&
|
||||
EqualDomainSid(FspPrimaryDomainSid, Sid, &EqualDomains) && EqualDomains)
|
||||
*PUid = 0x100000 + Rid;
|
||||
else if (0 != FspAccountDomainSid &&
|
||||
EqualDomainSid(FspAccountDomainSid, Sid, &EqualDomains) && EqualDomains)
|
||||
*PUid = 0x30000 + Rid;
|
||||
|
||||
/*
|
||||
* I am sorry, I am not going to bother with all that trustPosixOffset stuff.
|
||||
* But if you need it, I accept patches :)
|
||||
*/
|
||||
}
|
||||
|
||||
/* [IDMAP]
|
||||
* Other well-known SIDs in the NT_AUTHORITY domain (S-1-5-X-RID):
|
||||
* S-1-5-X-RID <=> uid/gid: 0x1000 * X + RID
|
||||
*/
|
||||
else if (2 == Count)
|
||||
{
|
||||
*PUid = 0x1000 * SubAuthority0 + Rid;
|
||||
}
|
||||
}
|
||||
else if (16 == Authority)
|
||||
{
|
||||
/* [IDMAP]
|
||||
* Mandatory Labels:
|
||||
* S-1-16-RID <=> uid/gid: 0x60000 + RID
|
||||
*/
|
||||
*PUid = 0x60000 + Rid;
|
||||
}
|
||||
else if (
|
||||
FspUnmappedSid->IdentifierAuthority.Value[5] != Authority ||
|
||||
FspUnmappedSid->SubAuthority[0] != Rid)
|
||||
{
|
||||
/* [IDMAP]
|
||||
* Other well-known SIDs:
|
||||
* S-1-X-Y <=> uid/gid: 0x10000 + 0x100 * X + Y
|
||||
*/
|
||||
*PUid = 0x10000 + 0x100 * Authority + Rid;
|
||||
}
|
||||
|
||||
if (-1 == *PUid)
|
||||
*PUid = FspUnmappedUid;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...)
|
||||
{
|
||||
PISID Sid;
|
||||
SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
|
||||
va_list ap;
|
||||
|
||||
Sid = MemAlloc(sizeof(SID) - sizeof(DWORD) + (Count * sizeof(DWORD)));
|
||||
if (0 == Sid)
|
||||
return 0;
|
||||
|
||||
memset(&IdentifierAuthority, 0, sizeof IdentifierAuthority);
|
||||
IdentifierAuthority.Value[5] = Authority;
|
||||
|
||||
InitializeSid(Sid, &IdentifierAuthority, (BYTE)Count);
|
||||
va_start(ap, Count);
|
||||
for (ULONG Index = 0; Count > Index; Index++)
|
||||
Sid->SubAuthority[Index] = va_arg(ap, DWORD);
|
||||
va_end(ap);
|
||||
|
||||
return Sid;
|
||||
}
|
||||
|
||||
FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)())
|
||||
{
|
||||
if (FspUnmappedSid == Sid)
|
||||
;
|
||||
else if ((NTSTATUS (*)())FspPosixMapUidToSid == CreateFunc)
|
||||
MemFree(Sid);
|
||||
}
|
||||
|
||||
/* [PERMS]
|
||||
* By default, all access-allowed ACEs will contain the following Windows access rights.
|
||||
*/
|
||||
#define FspPosixDefaultPerm \
|
||||
(SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA)
|
||||
/* [PERMS]
|
||||
* There are some additional Windows access rights that are always set in the
|
||||
* access-allowed ACE for the file's owner.
|
||||
*/
|
||||
#define FspPosixOwnerDefaultPerm \
|
||||
(FspPosixDefaultPerm | DELETE | WRITE_DAC | WRITE_OWNER | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||
|
||||
static inline ACCESS_MASK FspPosixMapPermissionToAccessMask(UINT32 Mode, UINT32 Perm)
|
||||
{
|
||||
/*
|
||||
* We use only the 0040000 (directory) and 0001000 (sticky) bits from Mode.
|
||||
* If this is a directory and it does not have the sticky bit set (and the
|
||||
* write permission is enabled) we add FILE_DELETE_CHILD access.
|
||||
*
|
||||
* When calling this function for computing the Owner access mask, we always
|
||||
* pass Mode & ~0001000 to remove the sticky bit and thus add FILE_DELETE_CHILD
|
||||
* access if it is a directory. For Group and World permissions we do not
|
||||
* remove the sticky bit as we do not want FILE_DELETE_CHILD access in these
|
||||
* cases.
|
||||
*/
|
||||
|
||||
ACCESS_MASK DeleteChild = 0040000 == (Mode & 0041000) ? FILE_DELETE_CHILD : 0;
|
||||
|
||||
/* [PERMS]
|
||||
* Additionally, if the UNIX read permission bit is set, then the Windows
|
||||
* File_Read access right is added to the ACE. When enabled on directories,
|
||||
* this allows them to be searched. When enabled on files, it allows the data
|
||||
* to be viewed. If the UNIX execute permission bit is set, then the Windows
|
||||
* File_Execute access right is added to the ACE. On directories this enables
|
||||
* the directory to be traversed. On files it allows the file to be executed.
|
||||
*
|
||||
* If the UNIX write permission bit is set then the following Windows access
|
||||
* rights are added: Write_Data, Write_Attributes, Append_Data, Delete_Child.
|
||||
*
|
||||
* Notice how Windows has four separate access rights to UNIX's single "write"
|
||||
* permission. In UNIX, the write permission bit on a directory permits both
|
||||
* the creation and removal of new files or sub-directories in the directory.
|
||||
* On Windows, the Write_Data access right controls the creation of new
|
||||
* sub-files and the Delete_Child access right controls the deletion. The
|
||||
* Delete_Child access right is not always present in all ACEs. In the case
|
||||
* where the UNIX sticky-bit is enabled, the Delete_Child bit will be set only
|
||||
* in the file owner ACE and no other ACEs. This will permit only the directory
|
||||
* owner to remove any files or sub-directories from this directory regardless
|
||||
* of the ownership on these sub-files. Other users will be allowed to delete
|
||||
* files or sub-directories only if they are granted the Delete access right
|
||||
* in an ACE of the file or sub-directory itself.
|
||||
*/
|
||||
|
||||
return
|
||||
((Perm & 4) ? FILE_READ_DATA : 0) |
|
||||
((Perm & 2) ? FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | FILE_APPEND_DATA | DeleteChild : 0) |
|
||||
((Perm & 1) ? FILE_EXECUTE : 0);
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspPosixMapPermissionsToSecurityDescriptor(
|
||||
UINT32 Uid, UINT32 Gid, UINT32 Mode,
|
||||
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
|
||||
{
|
||||
PSID OwnerSid = 0, GroupSid = 0, WorldSid = 0;
|
||||
UINT32 OwnerPerm, OwnerDeny, GroupPerm, GroupDeny, WorldPerm;
|
||||
PACL Acl = 0;
|
||||
SECURITY_DESCRIPTOR SecurityDescriptor;
|
||||
PSECURITY_DESCRIPTOR RelativeSecurityDescriptor = 0;
|
||||
ULONG Size;
|
||||
NTSTATUS Result;
|
||||
|
||||
*PSecurityDescriptor = 0;
|
||||
|
||||
Result = FspPosixMapUidToSid(Uid, &OwnerSid);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
Result = FspPosixMapUidToSid(Gid, &GroupSid);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
Result = FspPosixMapUidToSid(0x10100, &WorldSid);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
OwnerPerm = (Mode & 0700) >> 6;
|
||||
GroupPerm = (Mode & 0070) >> 3;
|
||||
WorldPerm = (Mode & 0007);
|
||||
|
||||
/* [PERMS]
|
||||
* What about the case where both owner and group are the same SID and
|
||||
* a chmod(1) request is made where the owner and the group permission
|
||||
* bits are different?. In this case, the most restrictive permissions
|
||||
* are chosen and assigned to both ACEs.
|
||||
*/
|
||||
if (EqualSid(OwnerSid, GroupSid))
|
||||
OwnerPerm = GroupPerm = OwnerPerm & GroupPerm;
|
||||
|
||||
/* [PERMS]
|
||||
* There are situations where one or two access-denied ACEs must be added
|
||||
* to the DACL. If you recall, the UNIX file access algorithm makes a
|
||||
* distinction between owner, group and other such that each is unique
|
||||
* and the ID used in an access request can only match one of them.
|
||||
* However, the Windows file access algorithm makes no such distinction
|
||||
* while scanning the DACL. If the ID in the request is granted permission
|
||||
* in any of the access-allowed ACEs then the request is permitted. This
|
||||
* is a problem when the owner permissions are specified to be more
|
||||
* restrictive than say the group or the other permissions (eg. when a
|
||||
* "chmod 577 foobar" is executed) So, to support UNIX semantics we must
|
||||
* examine the permissions granted to Everyone and if they are more
|
||||
* permissive than those in the group permissions then a special
|
||||
* access-denied ACE must be created for the group. And similarly, if
|
||||
* either the group or other permissions are more permissive than the
|
||||
* owner permissions, then an access-denied ACE must be created for the owner.
|
||||
*/
|
||||
OwnerDeny = (OwnerPerm ^ GroupPerm) & GroupPerm;
|
||||
OwnerDeny |= (OwnerPerm ^ WorldPerm) & WorldPerm;
|
||||
GroupDeny = (GroupPerm ^ WorldPerm) & WorldPerm;
|
||||
|
||||
Size = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) * 3 +
|
||||
sizeof(ACCESS_DENIED_ACE) * (!!OwnerDeny + !!GroupDeny);
|
||||
Size += GetLengthSid(OwnerSid) - sizeof(DWORD);
|
||||
Size += GetLengthSid(GroupSid) - sizeof(DWORD);
|
||||
Size += GetLengthSid(WorldSid) - sizeof(DWORD);
|
||||
if (OwnerDeny)
|
||||
Size += GetLengthSid(OwnerSid) - sizeof(DWORD);
|
||||
if (GroupDeny)
|
||||
Size += GetLengthSid(GroupSid) - sizeof(DWORD);
|
||||
Size += sizeof(DWORD) - 1;
|
||||
Size &= ~(sizeof(DWORD) - 1);
|
||||
|
||||
Acl = MemAlloc(Size);
|
||||
if (0 == Acl)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!InitializeAcl(Acl, Size, ACL_REVISION))
|
||||
goto lasterror;
|
||||
|
||||
if (!AddAccessAllowedAce(Acl, ACL_REVISION,
|
||||
FspPosixOwnerDefaultPerm | FspPosixMapPermissionToAccessMask(Mode & ~001000, OwnerPerm),
|
||||
OwnerSid))
|
||||
goto lasterror;
|
||||
if (OwnerDeny)
|
||||
{
|
||||
if (!AddAccessDeniedAce(Acl, ACL_REVISION,
|
||||
~FILE_WRITE_ATTRIBUTES & FspPosixMapPermissionToAccessMask(Mode & ~001000, OwnerDeny),
|
||||
OwnerSid))
|
||||
goto lasterror;
|
||||
}
|
||||
|
||||
if (!AddAccessAllowedAce(Acl, ACL_REVISION,
|
||||
FspPosixDefaultPerm | FspPosixMapPermissionToAccessMask(Mode, GroupPerm),
|
||||
GroupSid))
|
||||
goto lasterror;
|
||||
if (GroupDeny)
|
||||
{
|
||||
if (!AddAccessDeniedAce(Acl, ACL_REVISION,
|
||||
FspPosixMapPermissionToAccessMask(Mode, GroupDeny),
|
||||
GroupSid))
|
||||
goto lasterror;
|
||||
}
|
||||
|
||||
if (!AddAccessAllowedAce(Acl, ACL_REVISION,
|
||||
FspPosixDefaultPerm | FspPosixMapPermissionToAccessMask(Mode, WorldPerm),
|
||||
WorldSid))
|
||||
goto lasterror;
|
||||
|
||||
if (!InitializeSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
|
||||
goto lasterror;
|
||||
|
||||
if (!SetSecurityDescriptorControl(&SecurityDescriptor, SE_DACL_PROTECTED, SE_DACL_PROTECTED))
|
||||
goto lasterror;
|
||||
if (!SetSecurityDescriptorOwner(&SecurityDescriptor, OwnerSid, FALSE))
|
||||
goto lasterror;
|
||||
if (!SetSecurityDescriptorGroup(&SecurityDescriptor, GroupSid, FALSE))
|
||||
goto lasterror;
|
||||
if (!SetSecurityDescriptorDacl(&SecurityDescriptor, TRUE, Acl, FALSE))
|
||||
goto lasterror;
|
||||
|
||||
Size = 0;
|
||||
if (!MakeSelfRelativeSD(&SecurityDescriptor, 0, &Size) &&
|
||||
ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
||||
goto lasterror;
|
||||
|
||||
RelativeSecurityDescriptor = MemAlloc(Size);
|
||||
if (0 == RelativeSecurityDescriptor)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!MakeSelfRelativeSD(&SecurityDescriptor, RelativeSecurityDescriptor, &Size))
|
||||
goto lasterror;
|
||||
|
||||
*PSecurityDescriptor = RelativeSecurityDescriptor;
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
if (!NT_SUCCESS(Result))
|
||||
MemFree(RelativeSecurityDescriptor);
|
||||
|
||||
MemFree(Acl);
|
||||
|
||||
if (0 != WorldSid)
|
||||
FspDeleteSid(WorldSid, FspPosixMapUidToSid);
|
||||
|
||||
if (0 != GroupSid)
|
||||
FspDeleteSid(GroupSid, FspPosixMapUidToSid);
|
||||
|
||||
if (0 != OwnerSid)
|
||||
FspDeleteSid(OwnerSid, FspPosixMapUidToSid);
|
||||
|
||||
return Result;
|
||||
|
||||
lasterror:
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static inline UINT32 FspPosixMapAccessMaskToPermission(ACCESS_MASK AccessMask)
|
||||
{
|
||||
/* [PERMS]
|
||||
* Once all the granted Windows access right bits have been collected,
|
||||
* then the UNIX permission bits are assembled. For each class, if the
|
||||
* Read_Data bit is granted, then the corresponding "r" permission bit
|
||||
* is set. If both the Write_Data and Append_Data access rights are
|
||||
* granted then the "w" permission bit is set. And finally, if the
|
||||
* Execute access right is granted, then the "x" permission bit is set.
|
||||
*/
|
||||
|
||||
return
|
||||
((AccessMask & FILE_READ_DATA) ? 4 : 0) |
|
||||
((FILE_WRITE_DATA | FILE_APPEND_DATA) ==
|
||||
(AccessMask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? 2 : 0) |
|
||||
((AccessMask & FILE_EXECUTE) ? 1 : 0);
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode)
|
||||
{
|
||||
PSID OwnerSid = 0, GroupSid = 0, WorldSid = 0, AuthUsersSid = 0;
|
||||
BOOL Defaulted, DaclPresent;
|
||||
PACL Acl = 0;
|
||||
ACL_SIZE_INFORMATION AclSizeInfo;
|
||||
PACE_HEADER Ace;
|
||||
PSID AceSid;
|
||||
DWORD AceAccessMask;
|
||||
DWORD OwnerAllow, OwnerDeny, GroupAllow, GroupDeny, WorldAllow, WorldDeny;
|
||||
UINT32 Uid, Gid, Mode;
|
||||
NTSTATUS Result;
|
||||
|
||||
*PUid = 0;
|
||||
*PGid = 0;
|
||||
*PMode = 0;
|
||||
|
||||
if (!GetSecurityDescriptorOwner(SecurityDescriptor, &OwnerSid, &Defaulted))
|
||||
goto lasterror;
|
||||
if (!GetSecurityDescriptorGroup(SecurityDescriptor, &GroupSid, &Defaulted))
|
||||
goto lasterror;
|
||||
if (!GetSecurityDescriptorDacl(SecurityDescriptor, &DaclPresent, &Acl, &Defaulted))
|
||||
goto lasterror;
|
||||
|
||||
Result = FspPosixMapSidToUid(OwnerSid, &Uid);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
Result = FspPosixMapSidToUid(GroupSid, &Gid);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
if (0 != Acl)
|
||||
{
|
||||
Result = FspPosixMapUidToSid(0x10100, &WorldSid);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
Result = FspPosixMapUidToSid(11, &AuthUsersSid);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
OwnerAllow = OwnerDeny = GroupAllow = GroupDeny = WorldAllow = WorldDeny = 0;
|
||||
|
||||
if (!GetAclInformation(Acl, &AclSizeInfo, sizeof AclSizeInfo, AclSizeInformation))
|
||||
goto lasterror;
|
||||
|
||||
/* [PERMS]
|
||||
* For each of the ACEs in the file's DACL
|
||||
*/
|
||||
for (ULONG Index = 0; AclSizeInfo.AceCount > Index; Index++)
|
||||
{
|
||||
if (!GetAce(Acl, Index, &Ace))
|
||||
goto lasterror;
|
||||
|
||||
/* [PERMS]
|
||||
* Ignore the ACE if it is not an access-denied or access-allowed type.
|
||||
*/
|
||||
if (ACCESS_ALLOWED_ACE_TYPE == Ace->AceType)
|
||||
{
|
||||
AceSid = &((PACCESS_ALLOWED_ACE)Ace)->SidStart;
|
||||
AceAccessMask = ((PACCESS_ALLOWED_ACE)Ace)->Mask;
|
||||
}
|
||||
else if (ACCESS_DENIED_ACE_TYPE == Ace->AceType)
|
||||
{
|
||||
AceSid = &((PACCESS_DENIED_ACE)Ace)->SidStart;
|
||||
AceAccessMask = ((PACCESS_DENIED_ACE)Ace)->Mask;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
/* [PERMS]
|
||||
* If the ACE contains the Authenticated Users SID or the World SID then
|
||||
* add the allowed or denied access right bits into the "owner", "group"
|
||||
* and "other" collections.
|
||||
*/
|
||||
if (EqualSid(WorldSid, AceSid) || EqualSid(AuthUsersSid, AceSid))
|
||||
{
|
||||
/* [PERMS]
|
||||
* If this is an access-denied ACE, then add each access right to the set
|
||||
* of denied rights in each collection but only if the access right is not
|
||||
* already present in the set of granted rights in that collection. Similarly
|
||||
* If this is an access-allowed ACE, then add each access right to the set
|
||||
* of granted rights in each collection but only if the access right is not
|
||||
* already present in the set of denied rights in that collection.
|
||||
*/
|
||||
if (ACCESS_ALLOWED_ACE_TYPE == Ace->AceType)
|
||||
{
|
||||
WorldAllow |= AceAccessMask & ~WorldDeny;
|
||||
GroupAllow |= AceAccessMask & ~GroupDeny;
|
||||
OwnerAllow |= AceAccessMask & ~OwnerDeny;
|
||||
}
|
||||
else //if (ACCESS_DENIED_ACE_TYPE == Ace->AceType)
|
||||
{
|
||||
WorldDeny |= AceAccessMask & ~WorldAllow;
|
||||
GroupDeny |= AceAccessMask & ~GroupAllow;
|
||||
OwnerDeny |= AceAccessMask & ~OwnerAllow;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* [PERMS]
|
||||
* Note that if the file owner and file group SIDs are the same,
|
||||
* then the access rights are saved in both the "owner" and "group"
|
||||
* collections.
|
||||
*/
|
||||
|
||||
/* [PERMS]
|
||||
* If the ACE contains the file's group SID, then save the access rights
|
||||
* in the "group" collection as appropriate in the corresponding set of
|
||||
* granted or denied rights (as described above).
|
||||
*/
|
||||
if (EqualSid(GroupSid, AceSid))
|
||||
{
|
||||
if (ACCESS_ALLOWED_ACE_TYPE == Ace->AceType)
|
||||
GroupAllow |= AceAccessMask & ~GroupDeny;
|
||||
else //if (ACCESS_DENIED_ACE_TYPE == Ace->AceType)
|
||||
GroupDeny |= AceAccessMask & ~GroupAllow;
|
||||
}
|
||||
|
||||
/* [PERMS]
|
||||
* If the ACE contains the file's owner SID, then save the access rights
|
||||
* in the "owner" collection as appropriate in the corresponding set of
|
||||
* granted or denied rights (as described above).
|
||||
*/
|
||||
if (EqualSid(OwnerSid, AceSid))
|
||||
{
|
||||
if (ACCESS_ALLOWED_ACE_TYPE == Ace->AceType)
|
||||
OwnerAllow |= AceAccessMask & ~OwnerDeny;
|
||||
else //if (ACCESS_DENIED_ACE_TYPE == Ace->AceType)
|
||||
OwnerDeny |= AceAccessMask & ~OwnerAllow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mode =
|
||||
(FspPosixMapAccessMaskToPermission(OwnerAllow) << 6) |
|
||||
(FspPosixMapAccessMaskToPermission(GroupAllow) << 3) |
|
||||
(FspPosixMapAccessMaskToPermission(WorldAllow));
|
||||
if (0 != (OwnerAllow & FILE_DELETE_CHILD) &&
|
||||
(
|
||||
(0 == (GroupAllow & FILE_DELETE_CHILD) && 0 != (Mode & 0000020)) ||
|
||||
(0 == (WorldAllow & FILE_DELETE_CHILD) && 0 != (Mode & 0000002))
|
||||
))
|
||||
Mode |= 0001000; /* sticky bit */
|
||||
}
|
||||
else
|
||||
Mode = 0777;
|
||||
|
||||
*PUid = Uid;
|
||||
*PGid = Gid;
|
||||
*PMode = Mode;
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
if (0 != AuthUsersSid)
|
||||
FspDeleteSid(AuthUsersSid, FspPosixMapUidToSid);
|
||||
|
||||
if (0 != WorldSid)
|
||||
FspDeleteSid(WorldSid, FspPosixMapUidToSid);
|
||||
|
||||
return Result;
|
||||
|
||||
lasterror:
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Services for Macintosh and Cygwin compatible filename transformation:
|
||||
* Transform characters invalid for Windows filenames to the Unicode
|
||||
* private use area in the U+F0XX range.
|
||||
*
|
||||
* The invalid maps are produced by the following Python script:
|
||||
* reserved = ['<', '>', ':', '"', '\\', '|', '?', '*']
|
||||
* l = [str(int(0 < i < 32 or chr(i) in reserved)) for i in xrange(0, 128)]
|
||||
* print "0x%08x" % int("".join(l[0:32]), 2)
|
||||
* print "0x%08x" % int("".join(l[32:64]), 2)
|
||||
* print "0x%08x" % int("".join(l[64:96]), 2)
|
||||
* print "0x%08x" % int("".join(l[96:128]), 2)
|
||||
*/
|
||||
static UINT32 FspPosixInvalidPathChars[4] =
|
||||
{
|
||||
0x7fffffff,
|
||||
0x2020002b,
|
||||
0x00000008,
|
||||
0x00000008,
|
||||
};
|
||||
|
||||
FSP_API NTSTATUS FspPosixMapWindowsToPosixPath(PWSTR WindowsPath, char **PPosixPath)
|
||||
{
|
||||
NTSTATUS Result;
|
||||
ULONG Size;
|
||||
char *PosixPath = 0, *p, *q;
|
||||
|
||||
*PPosixPath = 0;
|
||||
|
||||
Size = WideCharToMultiByte(CP_UTF8, 0, WindowsPath, -1, 0, 0, 0, 0);
|
||||
if (0 == Size)
|
||||
goto lasterror;
|
||||
|
||||
PosixPath = MemAlloc(Size);
|
||||
if (0 == PosixPath)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
Size = WideCharToMultiByte(CP_UTF8, 0, WindowsPath, -1, PosixPath, Size, 0, 0);
|
||||
if (0 == Size)
|
||||
goto lasterror;
|
||||
|
||||
for (p = PosixPath, q = p; *p; p++)
|
||||
{
|
||||
unsigned char c = *p;
|
||||
|
||||
if ('\\' == c)
|
||||
*q++ = '/';
|
||||
/* encode characters in the Unicode private use area: U+F0XX -> XX */
|
||||
else if (0xef == c && 0x80 == (0xfc & p[1]) && 0x80 == (0xc0 & p[2]))
|
||||
{
|
||||
c = ((p[1] & 0x3) << 6) | (p[2] & 0x3f);
|
||||
if (128 > c && (FspPosixInvalidPathChars[c >> 5] & (0x80000000 >> (c & 0x1f))))
|
||||
*q++ = c, p += 2;
|
||||
else
|
||||
*q++ = *p++, *q++ = *p++, *q++ = *p;
|
||||
}
|
||||
else
|
||||
*q++ = c;
|
||||
}
|
||||
*q = '\0';
|
||||
|
||||
*PPosixPath = PosixPath;
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
if (!NT_SUCCESS(Result))
|
||||
MemFree(PosixPath);
|
||||
|
||||
return Result;
|
||||
|
||||
lasterror:
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspPosixMapPosixToWindowsPath(const char *PosixPath, PWSTR *PWindowsPath)
|
||||
{
|
||||
NTSTATUS Result;
|
||||
ULONG Size;
|
||||
PWSTR WindowsPath = 0, p;
|
||||
|
||||
*PWindowsPath = 0;
|
||||
|
||||
Size = MultiByteToWideChar(CP_UTF8, 0, PosixPath, -1, 0, 0);
|
||||
if (0 == Size)
|
||||
goto lasterror;
|
||||
|
||||
WindowsPath = MemAlloc(Size * sizeof(WCHAR));
|
||||
if (0 == PosixPath)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
Size = MultiByteToWideChar(CP_UTF8, 0, PosixPath, -1, WindowsPath, Size);
|
||||
if (0 == Size)
|
||||
goto lasterror;
|
||||
|
||||
for (p = WindowsPath; *p; p++)
|
||||
{
|
||||
WCHAR c = *p;
|
||||
|
||||
if (L'/' == c)
|
||||
*p = L'\\';
|
||||
else if (128 > c && (FspPosixInvalidPathChars[c >> 5] & (0x80000000 >> (c & 0x1f))))
|
||||
*p |= 0xf000;
|
||||
}
|
||||
|
||||
*PWindowsPath = WindowsPath;
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
if (!NT_SUCCESS(Result))
|
||||
MemFree(WindowsPath);
|
||||
|
||||
return Result;
|
||||
|
||||
lasterror:
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
FSP_API VOID FspPosixDeletePath(void *Path)
|
||||
{
|
||||
MemFree(Path);
|
||||
}
|
@ -61,6 +61,10 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
if (FspFsctlTransactCreateKind != Request->Kind)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
if (CheckParentDirectory &&
|
||||
L'\\' == ((PWSTR)Request->Buffer)[0] && L'\0' == ((PWSTR)Request->Buffer)[1])
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
if (0 == FileSystem->Interface->GetSecurityByName ||
|
||||
(!Request->Req.Create.UserMode && 0 == PSecurityDescriptor))
|
||||
{
|
||||
@ -78,7 +82,7 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
UINT8 PrivilegeSetBuf[sizeof(PRIVILEGE_SET) + 15 * sizeof(LUID_AND_ATTRIBUTES)];
|
||||
PPRIVILEGE_SET PrivilegeSet = (PVOID)PrivilegeSetBuf;
|
||||
DWORD PrivilegeSetLength = sizeof PrivilegeSetBuf;
|
||||
UINT32 TraverseAccess;
|
||||
UINT32 TraverseAccess, ParentAccess, DesiredAccess2;
|
||||
BOOL AccessStatus;
|
||||
|
||||
if (CheckParentDirectory)
|
||||
@ -147,7 +151,54 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
else
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
{
|
||||
/*
|
||||
* If the desired access includes the DELETE or FILE_READ_ATTRIBUTES
|
||||
* (or MAXIMUM_ALLOWED) rights we must still check with our parent to
|
||||
* see if it gives us access (through the FILE_DELETE_CHILD and
|
||||
* FILE_LIST_DIRECTORY rights).
|
||||
*
|
||||
* Does the Windows security model suck? Ermmmm...
|
||||
*/
|
||||
if (STATUS_ACCESS_DENIED != Result ||
|
||||
0 == ((MAXIMUM_ALLOWED | DELETE | FILE_READ_ATTRIBUTES) & DesiredAccess))
|
||||
goto exit;
|
||||
|
||||
Result = FspAccessCheck(FileSystem, Request, TRUE, FALSE,
|
||||
(MAXIMUM_ALLOWED & DesiredAccess) ? (FILE_DELETE_CHILD | FILE_LIST_DIRECTORY) :
|
||||
(
|
||||
((DELETE & DesiredAccess) ? FILE_DELETE_CHILD : 0) |
|
||||
((FILE_READ_ATTRIBUTES & DesiredAccess) ? FILE_LIST_DIRECTORY : 0)
|
||||
),
|
||||
&ParentAccess);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
/* any failure just becomes ACCESS DENIED at this point */
|
||||
Result = STATUS_ACCESS_DENIED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* redo the access check but remove the DELETE and/or FILE_READ_ATTRIBUTES rights */
|
||||
DesiredAccess2 = DesiredAccess & ~(
|
||||
((FILE_DELETE_CHILD & ParentAccess) ? DELETE : 0) |
|
||||
((FILE_LIST_DIRECTORY & ParentAccess) ? FILE_READ_ATTRIBUTES : 0));
|
||||
if (0 != DesiredAccess2)
|
||||
{
|
||||
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess2,
|
||||
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||
else
|
||||
/* any failure just becomes ACCESS DENIED at this point */
|
||||
Result = STATUS_ACCESS_DENIED;
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (FILE_DELETE_CHILD & ParentAccess)
|
||||
*PGrantedAccess |= DELETE;
|
||||
if (FILE_LIST_DIRECTORY & ParentAccess)
|
||||
*PGrantedAccess |= FILE_READ_ATTRIBUTES;
|
||||
}
|
||||
}
|
||||
|
||||
if (CheckParentDirectory)
|
||||
@ -192,6 +243,11 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
if (0 == SecurityDescriptorSize)
|
||||
*PGrantedAccess = (MAXIMUM_ALLOWED & DesiredAccess) ?
|
||||
FspFileGenericMapping.GenericAll : DesiredAccess;
|
||||
|
||||
if (0 != (FileAttributes & FILE_ATTRIBUTE_READONLY) &&
|
||||
0 != (MAXIMUM_ALLOWED & DesiredAccess))
|
||||
*PGrantedAccess &= ~(FILE_WRITE_DATA | FILE_APPEND_DATA |
|
||||
FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD);
|
||||
}
|
||||
else
|
||||
*PGrantedAccess = (MAXIMUM_ALLOWED & DesiredAccess) ?
|
||||
@ -306,7 +362,8 @@ FSP_API NTSTATUS FspSetSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_API VOID FspDeleteSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||
NTSTATUS (*CreateFunc)())
|
||||
{
|
||||
if ((NTSTATUS (*)())FspAccessCheckEx == CreateFunc)
|
||||
if ((NTSTATUS (*)())FspAccessCheckEx == CreateFunc ||
|
||||
(NTSTATUS (*)())FspPosixMapPermissionsToSecurityDescriptor == CreateFunc)
|
||||
MemFree(SecurityDescriptor);
|
||||
else
|
||||
if ((NTSTATUS (*)())FspCreateSecurityDescriptor == CreateFunc ||
|
||||
|
606
src/dll/service.c
Normal file
606
src/dll/service.c
Normal file
@ -0,0 +1,606 @@
|
||||
/**
|
||||
* @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);
|
||||
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
|
||||
|
||||
#define FspServiceFromTable() (0 != FspServiceTable ?\
|
||||
(FSP_SERVICE *)((PUINT8)FspServiceTable[0].lpServiceName - FIELD_OFFSET(FSP_SERVICE, ServiceName)) :\
|
||||
0)
|
||||
|
||||
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 FspServiceRunEx(PWSTR ServiceName,
|
||||
FSP_SERVICE_START *OnStart,
|
||||
FSP_SERVICE_STOP *OnStop,
|
||||
FSP_SERVICE_CONTROL *OnControl,
|
||||
PVOID UserContext)
|
||||
{
|
||||
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);
|
||||
}
|
||||
Service->UserContext = UserContext;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* expose FspServiceConsoleCtrlHandler so it can be used from fsp_fuse_signal_handler */
|
||||
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);
|
||||
}
|
165
src/dll/util.c
Normal file
165
src/dll/util.c
Normal file
@ -0,0 +1,165 @@
|
||||
/**
|
||||
* @file dll/util.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 <aclapi.h>
|
||||
|
||||
static INIT_ONCE FspDiagIdentInitOnce = INIT_ONCE_STATIC_INIT;
|
||||
static WCHAR FspDiagIdentBuf[20] = L"UNKNOWN";
|
||||
|
||||
static BOOL WINAPI FspDiagIdentInitialize(
|
||||
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
||||
{
|
||||
WCHAR ModuleFileName[MAX_PATH];
|
||||
WCHAR Root[2] = L"\\";
|
||||
PWSTR Parent, ModuleBaseName;
|
||||
|
||||
if (0 != GetModuleFileNameW(0, ModuleFileName, sizeof ModuleFileName / sizeof(WCHAR)))
|
||||
FspPathSuffix(ModuleFileName, &Parent, &ModuleBaseName, Root);
|
||||
else
|
||||
lstrcpyW(ModuleBaseName = ModuleFileName, L"UNKNOWN");
|
||||
|
||||
for (PWSTR P = ModuleBaseName, Dot = 0;; P++)
|
||||
{
|
||||
if (L'\0' == *P)
|
||||
{
|
||||
if (0 != Dot)
|
||||
*Dot = L'\0';
|
||||
break;
|
||||
}
|
||||
if (L'.' == *P)
|
||||
Dot = P;
|
||||
}
|
||||
|
||||
memcpy(FspDiagIdentBuf, ModuleBaseName, sizeof FspDiagIdentBuf);
|
||||
FspDiagIdentBuf[(sizeof FspDiagIdentBuf / sizeof(WCHAR)) - 1] = L'\0';
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
PWSTR FspDiagIdent(VOID)
|
||||
{
|
||||
/* internal only: get a diagnostic identifier (eventlog, debug) */
|
||||
|
||||
InitOnceExecuteOnce(&FspDiagIdentInitOnce, FspDiagIdentInitialize, 0, 0);
|
||||
return FspDiagIdentBuf;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
37
src/dll/version.rc
Normal file
37
src/dll/version.rc
Normal 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
|
37
src/launcher/launchctl-version.rc
Normal file
37
src/launcher/launchctl-version.rc
Normal 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
|
296
src/launcher/launchctl.c
Normal file
296
src/launcher/launchctl.c
Normal file
@ -0,0 +1,296 @@
|
||||
/**
|
||||
* @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"
|
||||
" startWithSecret ClassName InstanceName Args... Secret\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,
|
||||
BOOLEAN HasSecret)
|
||||
{
|
||||
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++ = HasSecret ? LauncherSvcInstanceStartWithSecret : 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,
|
||||
FALSE);
|
||||
}
|
||||
else
|
||||
if (0 == lstrcmpW(L"startWithSecret", argv[0]))
|
||||
{
|
||||
if (4 > argc || argc > 13)
|
||||
usage();
|
||||
|
||||
return start(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3,
|
||||
TRUE);
|
||||
}
|
||||
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;
|
||||
|
||||
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
|
||||
if (0 == Argv)
|
||||
ExitProcess(GetLastError());
|
||||
|
||||
ExitProcess(wmain(Argc, Argv));
|
||||
}
|
37
src/launcher/launcher-version.rc
Normal file
37
src/launcher/launcher-version.rc
Normal 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
|
1277
src/launcher/launcher.c
Normal file
1277
src/launcher/launcher.c
Normal file
File diff suppressed because it is too large
Load Diff
70
src/launcher/launcher.h
Normal file
70
src/launcher/launcher.h
Normal file
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @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_REGKEY "SYSTEM\\CurrentControlSet\\Services\\WinFsp.Launcher\\Services"
|
||||
|
||||
#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 4096
|
||||
#define LAUNCHER_PIPE_DEFAULT_TIMEOUT 3000
|
||||
|
||||
#define LAUNCHER_START_WITH_SECRET_TIMEOUT 15000
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
LauncherSvcInstanceStartWithSecret = 'X', /* 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
|
102
src/shared/minimal.h
Normal file
102
src/shared/minimal.h
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @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 > Runtime Library" must be set to "Multi-threaded (/MT)".
|
||||
* - "C/C++ > Code Generation > Security Check" must be disabled (/GS-).
|
||||
* - "Linker > Input > Ignore All Default Libraries" must be "Yes".
|
||||
*
|
||||
*
|
||||
* Update:
|
||||
*
|
||||
* It is possible to have the "Linker > Input > Ignore All Default Libraries"
|
||||
* setting to "No" and still eliminate most dependencies on the MSVCRT libraries.
|
||||
* For example, the WinFsp DLL does this on 32-bit builds (only) to include the
|
||||
* __allmul symbol that is used when doing int64_t multiplications.
|
||||
*
|
||||
* The following project setting must be changed:
|
||||
* - "Linker > Input > Ignore All Default Libraries" must be "No".
|
||||
*
|
||||
* Extreme care must be taken to ensure that the linker does not pull in symbols
|
||||
* that are not required (or worse create a half-baked CRT). For example, the WinFsp
|
||||
* DLL ensures this by setting the "Linker > Input > Ignore All Default Libraries"
|
||||
* to "Yes" on 64-bit builds and "No" on 32-bit builds.
|
||||
*/
|
||||
|
||||
#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 void *MemAlloc(size_t Size)
|
||||
{
|
||||
return HeapAlloc(GetProcessHeap(), 0, Size);
|
||||
}
|
||||
static inline void MemFree(void *Pointer)
|
||||
{
|
||||
if (0 != Pointer)
|
||||
HeapFree(GetProcessHeap(), 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
|
@ -105,6 +105,7 @@ NTSTATUS DriverEntry(
|
||||
FspIopPrepareFunction[IRP_MJ_WRITE] = FspFsvolWritePrepare;
|
||||
FspIopCompleteFunction[IRP_MJ_WRITE] = FspFsvolWriteComplete;
|
||||
FspIopCompleteFunction[IRP_MJ_QUERY_INFORMATION] = FspFsvolQueryInformationComplete;
|
||||
FspIopPrepareFunction[IRP_MJ_SET_INFORMATION] = FspFsvolSetInformationPrepare;
|
||||
FspIopCompleteFunction[IRP_MJ_SET_INFORMATION] = FspFsvolSetInformationComplete;
|
||||
FspIopCompleteFunction[IRP_MJ_QUERY_EA] = FspFsvolQueryEaComplete;
|
||||
FspIopCompleteFunction[IRP_MJ_SET_EA] = FspFsvolSetEaComplete;
|
||||
|
@ -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)"
|
||||
@ -316,6 +316,7 @@ FSP_IOCMPL_DISPATCH FspFsvolQueryVolumeInformationComplete;
|
||||
FSP_IOPREP_DISPATCH FspFsvolReadPrepare;
|
||||
FSP_IOCMPL_DISPATCH FspFsvolReadComplete;
|
||||
FSP_IOCMPL_DISPATCH FspFsvolSetEaComplete;
|
||||
FSP_IOPREP_DISPATCH FspFsvolSetInformationPrepare;
|
||||
FSP_IOCMPL_DISPATCH FspFsvolSetInformationComplete;
|
||||
FSP_IOPREP_DISPATCH FspFsvolSetSecurityPrepare;
|
||||
FSP_IOCMPL_DISPATCH FspFsvolSetSecurityComplete;
|
||||
@ -654,13 +655,14 @@ enum
|
||||
#define FspIopPostWorkRequestBestEffort(D, R)\
|
||||
FspIopPostWorkRequestFunnel(D, R, TRUE)
|
||||
#define FspIopCompleteIrp(I, R) FspIopCompleteIrpEx(I, R, TRUE)
|
||||
#define REQ_ALIGN_SIZE 16
|
||||
typedef VOID FSP_IOP_REQUEST_FINI(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4]);
|
||||
typedef struct
|
||||
{
|
||||
FSP_IOP_REQUEST_FINI *RequestFini;
|
||||
PVOID Context[4];
|
||||
FSP_FSCTL_TRANSACT_RSP *Response;
|
||||
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 RequestBuf[];
|
||||
__declspec(align(REQ_ALIGN_SIZE)) UINT8 RequestBuf[];
|
||||
} FSP_FSCTL_TRANSACT_REQ_HEADER;
|
||||
static inline
|
||||
PVOID *FspIopRequestContextAddress(FSP_FSCTL_TRANSACT_REQ *Request, ULONG I)
|
||||
@ -1033,4 +1035,26 @@ extern WCHAR FspFileDescDirectoryPatternMatchAll[];
|
||||
extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;
|
||||
extern ULONG FspMvMdlMappingNoWrite;
|
||||
|
||||
/*
|
||||
* Fixes
|
||||
*/
|
||||
|
||||
/* ObCloseHandle: add missing prototype */
|
||||
#if (NTDDI_VERSION < NTDDI_WIN7)
|
||||
NTKERNELAPI
|
||||
NTSTATUS
|
||||
ObCloseHandle(
|
||||
_In_ HANDLE Handle,
|
||||
_In_ KPROCESSOR_MODE PreviousMode
|
||||
);
|
||||
#endif
|
||||
|
||||
/* RtlEqualMemory: this is defined as memcmp, which does not exist on Win7 x86! */
|
||||
#undef RtlEqualMemory
|
||||
static inline
|
||||
LOGICAL RtlEqualMemory(const VOID *Source1, const VOID *Source2, SIZE_T Length)
|
||||
{
|
||||
return Length == RtlCompareMemory(Source1, Source2, Length);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -63,6 +63,7 @@ static NTSTATUS FspFsvolSetRenameInformationSuccess(
|
||||
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
static NTSTATUS FspFsvolSetInformation(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
FSP_IOPREP_DISPATCH FspFsvolSetInformationPrepare;
|
||||
FSP_IOCMPL_DISPATCH FspFsvolSetInformationComplete;
|
||||
static FSP_IOP_REQUEST_FINI FspFsvolSetInformationRequestFini;
|
||||
FSP_DRIVER_DISPATCH FspQueryInformation;
|
||||
@ -89,6 +90,7 @@ FSP_DRIVER_DISPATCH FspSetInformation;
|
||||
#pragma alloc_text(PAGE, FspFsvolSetRenameInformation)
|
||||
#pragma alloc_text(PAGE, FspFsvolSetRenameInformationSuccess)
|
||||
#pragma alloc_text(PAGE, FspFsvolSetInformation)
|
||||
#pragma alloc_text(PAGE, FspFsvolSetInformationPrepare)
|
||||
#pragma alloc_text(PAGE, FspFsvolSetInformationComplete)
|
||||
#pragma alloc_text(PAGE, FspFsvolSetInformationRequestFini)
|
||||
#pragma alloc_text(PAGE, FspQueryInformation)
|
||||
@ -106,6 +108,9 @@ enum
|
||||
/* SetInformation */
|
||||
//RequestFileNode = 0,
|
||||
RequestDeviceObject = 1,
|
||||
/* Rename */
|
||||
RequestAccessToken = 2,
|
||||
RequestProcess = 3,
|
||||
};
|
||||
|
||||
static NTSTATUS FspFsvolQueryAllInformation(PFILE_OBJECT FileObject,
|
||||
@ -845,7 +850,6 @@ static NTSTATUS FspFsvolSetRenameInformation(
|
||||
PFILE_OBJECT TargetFileObject = IrpSp->Parameters.SetFile.FileObject;
|
||||
PFILE_RENAME_INFORMATION Info = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
||||
ULONG Length = IrpSp->Parameters.SetFile.Length;
|
||||
BOOLEAN ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
|
||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||
FSP_FILE_NODE *TargetFileNode = 0 != TargetFileObject ?
|
||||
@ -922,7 +926,6 @@ static NTSTATUS FspFsvolSetRenameInformation(
|
||||
Request->Req.SetInformation.FileInformationClass = FileRenameInformation;
|
||||
Request->Req.SetInformation.Info.Rename.NewFileName.Offset = Request->FileName.Size;
|
||||
Request->Req.SetInformation.Info.Rename.NewFileName.Size = NewFileName.Length + sizeof(WCHAR);
|
||||
Request->Req.SetInformation.Info.Rename.ReplaceIfExists = ReplaceIfExists;
|
||||
|
||||
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
|
||||
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||
@ -1095,6 +1098,59 @@ static NTSTATUS FspFsvolSetInformation(
|
||||
return FSP_STATUS_IOQ_POST;
|
||||
}
|
||||
|
||||
NTSTATUS FspFsvolSetInformationPrepare(
|
||||
PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
if (FileRenameInformation != IrpSp->Parameters.SetFile.FileInformationClass ||
|
||||
!IrpSp->Parameters.SetFile.ReplaceIfExists)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
NTSTATUS Result;
|
||||
SECURITY_SUBJECT_CONTEXT SecuritySubjectContext;
|
||||
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
|
||||
SECURITY_CLIENT_CONTEXT SecurityClientContext;
|
||||
HANDLE UserModeAccessToken;
|
||||
PEPROCESS Process;
|
||||
|
||||
/* duplicate the subject context access token into an impersonation token */
|
||||
SecurityQualityOfService.Length = sizeof SecurityQualityOfService;
|
||||
SecurityQualityOfService.ImpersonationLevel = SecurityIdentification;
|
||||
SecurityQualityOfService.ContextTrackingMode = SECURITY_STATIC_TRACKING;
|
||||
SecurityQualityOfService.EffectiveOnly = FALSE;
|
||||
SeCaptureSubjectContext(&SecuritySubjectContext);
|
||||
SeLockSubjectContext(&SecuritySubjectContext);
|
||||
Result = SeCreateClientSecurityFromSubjectContext(&SecuritySubjectContext,
|
||||
&SecurityQualityOfService, FALSE, &SecurityClientContext);
|
||||
SeUnlockSubjectContext(&SecuritySubjectContext);
|
||||
SeReleaseSubjectContext(&SecuritySubjectContext);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
ASSERT(TokenImpersonation == SeTokenType(SecurityClientContext.ClientToken));
|
||||
|
||||
/* get a user-mode handle to the impersonation token */
|
||||
Result = ObOpenObjectByPointer(SecurityClientContext.ClientToken,
|
||||
0, 0, TOKEN_QUERY, *SeTokenObjectType, UserMode, &UserModeAccessToken);
|
||||
SeDeleteClientSecurity(&SecurityClientContext);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
/* get a pointer to the current process so that we can close the impersonation token later */
|
||||
Process = PsGetCurrentProcess();
|
||||
ObReferenceObject(Process);
|
||||
|
||||
/* send the user-mode handle to the user-mode file system */
|
||||
FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken;
|
||||
FspIopRequestContext(Request, RequestProcess) = Process;
|
||||
Request->Req.SetInformation.Info.Rename.AccessToken = (UINT_PTR)UserModeAccessToken;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS FspFsvolSetInformationComplete(
|
||||
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
@ -1154,12 +1210,38 @@ static VOID FspFsvolSetInformationRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
|
||||
|
||||
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
|
||||
PDEVICE_OBJECT FsvolDeviceObject = Context[RequestDeviceObject];
|
||||
HANDLE AccessToken = Context[RequestAccessToken];
|
||||
PEPROCESS Process = Context[RequestProcess];
|
||||
|
||||
if (0 != FileNode)
|
||||
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||
|
||||
if (0 != FsvolDeviceObject)
|
||||
FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, Request);
|
||||
|
||||
if (0 != AccessToken)
|
||||
{
|
||||
KAPC_STATE ApcState;
|
||||
BOOLEAN Attach;
|
||||
|
||||
ASSERT(0 != Process);
|
||||
Attach = Process != PsGetCurrentProcess();
|
||||
|
||||
if (Attach)
|
||||
KeStackAttachProcess(Process, &ApcState);
|
||||
#if DBG
|
||||
NTSTATUS Result0;
|
||||
Result0 = ObCloseHandle(AccessToken, UserMode);
|
||||
if (!NT_SUCCESS(Result0))
|
||||
DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result0));
|
||||
#else
|
||||
ObCloseHandle(AccessToken, UserMode);
|
||||
#endif
|
||||
if (Attach)
|
||||
KeUnstackDetachProcess(&ApcState);
|
||||
|
||||
ObDereferenceObject(Process);
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS FspQueryInformation(
|
||||
|
150
src/sys/ioctl.i
150
src/sys/ioctl.i
@ -89,82 +89,82 @@ SYM(FSCTL_DFSR_SET_GHOST_HANDLE_STATE)
|
||||
SYM(FSCTL_TXFS_LIST_TRANSACTIONS)
|
||||
SYM(FSCTL_QUERY_PAGEFILE_ENCRYPTION)
|
||||
SYM(FSCTL_RESET_VOLUME_ALLOCATION_HINTS)
|
||||
SYM(FSCTL_QUERY_DEPENDENT_VOLUME)
|
||||
SYM(FSCTL_SD_GLOBAL_CHANGE)
|
||||
//SYM(FSCTL_QUERY_DEPENDENT_VOLUME)
|
||||
//SYM(FSCTL_SD_GLOBAL_CHANGE)
|
||||
SYM(FSCTL_TXFS_READ_BACKUP_INFORMATION2)
|
||||
SYM(FSCTL_LOOKUP_STREAM_FROM_CLUSTER)
|
||||
SYM(FSCTL_TXFS_WRITE_BACKUP_INFORMATION2)
|
||||
SYM(FSCTL_FILE_TYPE_NOTIFICATION)
|
||||
SYM(FSCTL_FILE_LEVEL_TRIM)
|
||||
SYM(FSCTL_GET_BOOT_AREA_INFO)
|
||||
SYM(FSCTL_GET_RETRIEVAL_POINTER_BASE)
|
||||
SYM(FSCTL_SET_PERSISTENT_VOLUME_STATE)
|
||||
SYM(FSCTL_QUERY_PERSISTENT_VOLUME_STATE)
|
||||
SYM(FSCTL_REQUEST_OPLOCK)
|
||||
SYM(FSCTL_CSV_TUNNEL_REQUEST)
|
||||
SYM(FSCTL_IS_CSV_FILE)
|
||||
SYM(FSCTL_QUERY_FILE_SYSTEM_RECOGNITION)
|
||||
SYM(FSCTL_CSV_GET_VOLUME_PATH_NAME)
|
||||
SYM(FSCTL_CSV_GET_VOLUME_NAME_FOR_VOLUME_MOUNT_POINT)
|
||||
SYM(FSCTL_CSV_GET_VOLUME_PATH_NAMES_FOR_VOLUME_NAME)
|
||||
SYM(FSCTL_IS_FILE_ON_CSV_VOLUME)
|
||||
SYM(FSCTL_CORRUPTION_HANDLING)
|
||||
SYM(FSCTL_OFFLOAD_READ)
|
||||
SYM(FSCTL_OFFLOAD_WRITE)
|
||||
SYM(FSCTL_CSV_INTERNAL)
|
||||
SYM(FSCTL_SET_PURGE_FAILURE_MODE)
|
||||
SYM(FSCTL_QUERY_FILE_LAYOUT)
|
||||
SYM(FSCTL_IS_VOLUME_OWNED_BYCSVFS)
|
||||
SYM(FSCTL_GET_INTEGRITY_INFORMATION)
|
||||
SYM(FSCTL_SET_INTEGRITY_INFORMATION)
|
||||
SYM(FSCTL_QUERY_FILE_REGIONS)
|
||||
SYM(FSCTL_DEDUP_FILE)
|
||||
SYM(FSCTL_DEDUP_QUERY_FILE_HASHES)
|
||||
SYM(FSCTL_DEDUP_QUERY_RANGE_STATE)
|
||||
SYM(FSCTL_DEDUP_QUERY_REPARSE_INFO)
|
||||
SYM(FSCTL_RKF_INTERNAL)
|
||||
SYM(FSCTL_SCRUB_DATA)
|
||||
SYM(FSCTL_REPAIR_COPIES)
|
||||
SYM(FSCTL_DISABLE_LOCAL_BUFFERING)
|
||||
SYM(FSCTL_CSV_MGMT_LOCK)
|
||||
SYM(FSCTL_CSV_QUERY_DOWN_LEVEL_FILE_SYSTEM_CHARACTERISTICS)
|
||||
SYM(FSCTL_ADVANCE_FILE_ID)
|
||||
SYM(FSCTL_CSV_SYNC_TUNNEL_REQUEST)
|
||||
SYM(FSCTL_CSV_QUERY_VETO_FILE_DIRECT_IO)
|
||||
SYM(FSCTL_WRITE_USN_REASON)
|
||||
SYM(FSCTL_CSV_CONTROL)
|
||||
SYM(FSCTL_GET_REFS_VOLUME_DATA)
|
||||
SYM(FSCTL_CSV_H_BREAKING_SYNC_TUNNEL_REQUEST)
|
||||
SYM(FSCTL_QUERY_STORAGE_CLASSES)
|
||||
SYM(FSCTL_QUERY_REGION_INFO)
|
||||
SYM(FSCTL_USN_TRACK_MODIFIED_RANGES)
|
||||
SYM(FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT)
|
||||
SYM(FSCTL_SVHDX_SYNC_TUNNEL_REQUEST)
|
||||
SYM(FSCTL_SVHDX_SET_INITIATOR_INFORMATION)
|
||||
SYM(FSCTL_SET_EXTERNAL_BACKING)
|
||||
SYM(FSCTL_GET_EXTERNAL_BACKING)
|
||||
SYM(FSCTL_DELETE_EXTERNAL_BACKING)
|
||||
SYM(FSCTL_ENUM_EXTERNAL_BACKING)
|
||||
SYM(FSCTL_ENUM_OVERLAY)
|
||||
SYM(FSCTL_ADD_OVERLAY)
|
||||
SYM(FSCTL_REMOVE_OVERLAY)
|
||||
SYM(FSCTL_UPDATE_OVERLAY)
|
||||
SYM(FSCTL_DUPLICATE_EXTENTS_TO_FILE)
|
||||
SYM(FSCTL_SPARSE_OVERALLOCATE)
|
||||
SYM(FSCTL_STORAGE_QOS_CONTROL)
|
||||
SYM(FSCTL_INITIATE_FILE_METADATA_OPTIMIZATION)
|
||||
SYM(FSCTL_QUERY_FILE_METADATA_OPTIMIZATION)
|
||||
SYM(FSCTL_SVHDX_ASYNC_TUNNEL_REQUEST)
|
||||
SYM(FSCTL_GET_WOF_VERSION)
|
||||
SYM(FSCTL_HCS_SYNC_TUNNEL_REQUEST)
|
||||
SYM(FSCTL_HCS_ASYNC_TUNNEL_REQUEST)
|
||||
SYM(FSCTL_QUERY_EXTENT_READ_CACHE_INFO)
|
||||
SYM(FSCTL_QUERY_REFS_VOLUME_COUNTER_INFO)
|
||||
SYM(FSCTL_CLEAN_VOLUME_METADATA)
|
||||
SYM(FSCTL_SET_INTEGRITY_INFORMATION_EX)
|
||||
SYM(FSCTL_SUSPEND_OVERLAY)
|
||||
SYM(FSCTL_VIRTUAL_STORAGE_QUERY_PROPERTY)
|
||||
SYM(FSCTL_FILESYSTEM_GET_STATISTICS_EX)
|
||||
//SYM(FSCTL_LOOKUP_STREAM_FROM_CLUSTER)
|
||||
//SYM(FSCTL_TXFS_WRITE_BACKUP_INFORMATION2)
|
||||
//SYM(FSCTL_FILE_TYPE_NOTIFICATION)
|
||||
//SYM(FSCTL_FILE_LEVEL_TRIM)
|
||||
//SYM(FSCTL_GET_BOOT_AREA_INFO)
|
||||
//SYM(FSCTL_GET_RETRIEVAL_POINTER_BASE)
|
||||
//SYM(FSCTL_SET_PERSISTENT_VOLUME_STATE)
|
||||
//SYM(FSCTL_QUERY_PERSISTENT_VOLUME_STATE)
|
||||
//SYM(FSCTL_REQUEST_OPLOCK)
|
||||
//SYM(FSCTL_CSV_TUNNEL_REQUEST)
|
||||
//SYM(FSCTL_IS_CSV_FILE)
|
||||
//SYM(FSCTL_QUERY_FILE_SYSTEM_RECOGNITION)
|
||||
//SYM(FSCTL_CSV_GET_VOLUME_PATH_NAME)
|
||||
//SYM(FSCTL_CSV_GET_VOLUME_NAME_FOR_VOLUME_MOUNT_POINT)
|
||||
//SYM(FSCTL_CSV_GET_VOLUME_PATH_NAMES_FOR_VOLUME_NAME)
|
||||
//SYM(FSCTL_IS_FILE_ON_CSV_VOLUME)
|
||||
//SYM(FSCTL_CORRUPTION_HANDLING)
|
||||
//SYM(FSCTL_OFFLOAD_READ)
|
||||
//SYM(FSCTL_OFFLOAD_WRITE)
|
||||
//SYM(FSCTL_CSV_INTERNAL)
|
||||
//SYM(FSCTL_SET_PURGE_FAILURE_MODE)
|
||||
//SYM(FSCTL_QUERY_FILE_LAYOUT)
|
||||
//SYM(FSCTL_IS_VOLUME_OWNED_BYCSVFS)
|
||||
//SYM(FSCTL_GET_INTEGRITY_INFORMATION)
|
||||
//SYM(FSCTL_SET_INTEGRITY_INFORMATION)
|
||||
//SYM(FSCTL_QUERY_FILE_REGIONS)
|
||||
//SYM(FSCTL_DEDUP_FILE)
|
||||
//SYM(FSCTL_DEDUP_QUERY_FILE_HASHES)
|
||||
//SYM(FSCTL_DEDUP_QUERY_RANGE_STATE)
|
||||
//SYM(FSCTL_DEDUP_QUERY_REPARSE_INFO)
|
||||
//SYM(FSCTL_RKF_INTERNAL)
|
||||
//SYM(FSCTL_SCRUB_DATA)
|
||||
//SYM(FSCTL_REPAIR_COPIES)
|
||||
//SYM(FSCTL_DISABLE_LOCAL_BUFFERING)
|
||||
//SYM(FSCTL_CSV_MGMT_LOCK)
|
||||
//SYM(FSCTL_CSV_QUERY_DOWN_LEVEL_FILE_SYSTEM_CHARACTERISTICS)
|
||||
//SYM(FSCTL_ADVANCE_FILE_ID)
|
||||
//SYM(FSCTL_CSV_SYNC_TUNNEL_REQUEST)
|
||||
//SYM(FSCTL_CSV_QUERY_VETO_FILE_DIRECT_IO)
|
||||
//SYM(FSCTL_WRITE_USN_REASON)
|
||||
//SYM(FSCTL_CSV_CONTROL)
|
||||
//SYM(FSCTL_GET_REFS_VOLUME_DATA)
|
||||
//SYM(FSCTL_CSV_H_BREAKING_SYNC_TUNNEL_REQUEST)
|
||||
//SYM(FSCTL_QUERY_STORAGE_CLASSES)
|
||||
//SYM(FSCTL_QUERY_REGION_INFO)
|
||||
//SYM(FSCTL_USN_TRACK_MODIFIED_RANGES)
|
||||
//SYM(FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT)
|
||||
//SYM(FSCTL_SVHDX_SYNC_TUNNEL_REQUEST)
|
||||
//SYM(FSCTL_SVHDX_SET_INITIATOR_INFORMATION)
|
||||
//SYM(FSCTL_SET_EXTERNAL_BACKING)
|
||||
//SYM(FSCTL_GET_EXTERNAL_BACKING)
|
||||
//SYM(FSCTL_DELETE_EXTERNAL_BACKING)
|
||||
//SYM(FSCTL_ENUM_EXTERNAL_BACKING)
|
||||
//SYM(FSCTL_ENUM_OVERLAY)
|
||||
//SYM(FSCTL_ADD_OVERLAY)
|
||||
//SYM(FSCTL_REMOVE_OVERLAY)
|
||||
//SYM(FSCTL_UPDATE_OVERLAY)
|
||||
//SYM(FSCTL_DUPLICATE_EXTENTS_TO_FILE)
|
||||
//SYM(FSCTL_SPARSE_OVERALLOCATE)
|
||||
//SYM(FSCTL_STORAGE_QOS_CONTROL)
|
||||
//SYM(FSCTL_INITIATE_FILE_METADATA_OPTIMIZATION)
|
||||
//SYM(FSCTL_QUERY_FILE_METADATA_OPTIMIZATION)
|
||||
//SYM(FSCTL_SVHDX_ASYNC_TUNNEL_REQUEST)
|
||||
//SYM(FSCTL_GET_WOF_VERSION)
|
||||
//SYM(FSCTL_HCS_SYNC_TUNNEL_REQUEST)
|
||||
//SYM(FSCTL_HCS_ASYNC_TUNNEL_REQUEST)
|
||||
//SYM(FSCTL_QUERY_EXTENT_READ_CACHE_INFO)
|
||||
//SYM(FSCTL_QUERY_REFS_VOLUME_COUNTER_INFO)
|
||||
//SYM(FSCTL_CLEAN_VOLUME_METADATA)
|
||||
//SYM(FSCTL_SET_INTEGRITY_INFORMATION_EX)
|
||||
//SYM(FSCTL_SUSPEND_OVERLAY)
|
||||
//SYM(FSCTL_VIRTUAL_STORAGE_QUERY_PROPERTY)
|
||||
//SYM(FSCTL_FILESYSTEM_GET_STATISTICS_EX)
|
||||
SYM(FSCTL_LMR_GET_LINK_TRACKING_INFORMATION)
|
||||
SYM(FSCTL_LMR_SET_LINK_TRACKING_INFORMATION)
|
||||
SYM(IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER)
|
||||
|
@ -48,10 +48,12 @@ NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response
|
||||
#endif
|
||||
|
||||
/* Requests (and RequestHeaders) must be 16-byte aligned, because we use the low 4 bits for flags */
|
||||
#if 16 != MEMORY_ALLOCATION_ALIGNMENT
|
||||
#define REQ_HEADER_ALIGNMASK 15
|
||||
#if REQ_ALIGN_SIZE <= MEMORY_ALLOCATION_ALIGNMENT
|
||||
#define REQ_HEADER_ALIGN_MASK 0
|
||||
#define REQ_HEADER_ALIGN_OVERHEAD 0
|
||||
#else
|
||||
#define REQ_HEADER_ALIGNMASK 0
|
||||
#define REQ_HEADER_ALIGN_MASK (REQ_ALIGN_SIZE - 1)
|
||||
#define REQ_HEADER_ALIGN_OVERHEAD (sizeof(PVOID) + REQ_HEADER_ALIGN_MASK)
|
||||
#endif
|
||||
|
||||
NTSTATUS FspIopCreateRequestFunnel(
|
||||
@ -74,20 +76,23 @@ NTSTATUS FspIopCreateRequestFunnel(
|
||||
if (FlagOn(Flags, FspIopRequestMustSucceed))
|
||||
RequestHeader = FspAllocatePoolMustSucceed(
|
||||
FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool,
|
||||
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGNMASK,
|
||||
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGN_OVERHEAD,
|
||||
FSP_ALLOC_INTERNAL_TAG);
|
||||
else
|
||||
{
|
||||
RequestHeader = ExAllocatePoolWithTag(
|
||||
FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool,
|
||||
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGNMASK,
|
||||
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGN_OVERHEAD,
|
||||
FSP_ALLOC_INTERNAL_TAG);
|
||||
if (0 == RequestHeader)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
#if 0 != REQ_HEADER_ALIGNMASK
|
||||
RequestHeader = (PVOID)(((UINT_PTR)RequestHeader + REQ_HEADER_ALIGNMASK) & REQ_HEADER_ALIGNMASK);
|
||||
#if 0 != REQ_HEADER_ALIGN_MASK
|
||||
PVOID Allocation = RequestHeader;
|
||||
RequestHeader = (PVOID)(((UINT_PTR)RequestHeader + REQ_HEADER_ALIGN_OVERHEAD) &
|
||||
~REQ_HEADER_ALIGN_MASK);
|
||||
((PVOID *)RequestHeader)[-1] = Allocation;
|
||||
#endif
|
||||
|
||||
RtlZeroMemory(RequestHeader, sizeof *RequestHeader + sizeof *Request + ExtraSize);
|
||||
@ -127,6 +132,10 @@ VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
if (0 != RequestHeader->Response)
|
||||
FspFree(RequestHeader->Response);
|
||||
|
||||
#if 0 != REQ_HEADER_ALIGN_MASK
|
||||
RequestHeader = ((PVOID *)RequestHeader)[-1];
|
||||
#endif
|
||||
|
||||
FspFree(RequestHeader);
|
||||
}
|
||||
|
||||
|
37
src/sys/version.rc
Normal file
37
src/sys/version.rc
Normal 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
|
@ -117,7 +117,15 @@ static NTSTATUS FspFsvolQueryFsDeviceInformation(
|
||||
|
||||
PFILE_FS_DEVICE_INFORMATION Info = (PFILE_FS_DEVICE_INFORMATION)*PBuffer;
|
||||
|
||||
Info->DeviceType = FsvolDeviceObject->DeviceType;
|
||||
/*
|
||||
* The following value MUST be FILE_DEVICE_DISK or GetFileType fails,
|
||||
* which has all sorts of interesting consequences (like cmd.exe failing
|
||||
* to redirect to a file when under a network file system).
|
||||
*
|
||||
* See also (which explicitly says to use FILE_DEVICE_DISK for our case):
|
||||
* https://msdn.microsoft.com/en-us/library/cc232109.aspx
|
||||
*/
|
||||
Info->DeviceType = FILE_DEVICE_DISK;
|
||||
Info->Characteristics = FsvolDeviceObject->Characteristics;
|
||||
|
||||
*PBuffer += sizeof(FILE_FS_DEVICE_INFORMATION);
|
||||
|
@ -188,7 +188,8 @@ static NTSTATUS FspVolumeCreateNoLock(
|
||||
|
||||
/* create the volume (and virtual disk) device(s) */
|
||||
Result = FspDeviceCreate(FspFsvolDeviceExtensionKind, 0,
|
||||
FsctlDeviceObject->DeviceType, 0,
|
||||
FsctlDeviceObject->DeviceType,
|
||||
FILE_DEVICE_DISK_FILE_SYSTEM == FsctlDeviceObject->DeviceType ? 0 : FILE_REMOTE_DEVICE,
|
||||
&FsvolDeviceObject);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
@ -693,7 +694,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;
|
||||
}
|
||||
|
30
tools/DigiCert High Assurance EV Root CA.crt
Normal file
30
tools/DigiCert High Assurance EV Root CA.crt
Normal 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-----
|
46
tools/build.bat
Normal file
46
tools/build.bat
Normal file
@ -0,0 +1,46 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
|
||||
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"
|
||||
|
||||
if not X%1==X set Configuration=%1
|
||||
|
||||
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
|
||||
|
||||
cd %~dp0..\build\VStudio
|
||||
if exist build\ del /s/q build >nul
|
||||
|
||||
devenv winfsp.sln /build "%Configuration%|x64"
|
||||
if errorlevel 1 goto fail
|
||||
devenv winfsp.sln /build "%Configuration%|x86"
|
||||
if errorlevel 1 goto fail
|
||||
|
||||
set signfail=0
|
||||
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
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
signtool sign /as /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 %%f
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
)
|
||||
|
||||
devenv winfsp.sln /build "Installer.%Configuration%|x86"
|
||||
if errorlevel 1 goto fail
|
||||
|
||||
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
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
REM signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 /d %MsiName% %%f
|
||||
REM if errorlevel 1 set /a signfail=signfail+1
|
||||
)
|
||||
|
||||
if not %signfail%==0 echo SIGNING FAILED! The product has been successfully built, but not signed.
|
||||
|
||||
exit /b 0
|
||||
|
||||
:fail
|
||||
exit /b 1
|
@ -1,5 +1,7 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
|
||||
set DebugWorkspace=winfsp
|
||||
set DebugPort=50000
|
||||
set DebugKey=win8.debug.net.key
|
||||
|
@ -1,5 +1,7 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
|
||||
set CONFIG=Debug
|
||||
set SUFFIX=x64
|
||||
set TARGET_MACHINE=WIN8DBG
|
||||
|
22
tools/gensrc/errno.sh
Normal file
22
tools/gensrc/errno.sh
Normal file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
(
|
||||
echo '#include <errno.h>'
|
||||
echo '/*beginbeginbeginbegin*/'
|
||||
awk '{ printf "case %s: return %s;\n", $1, $2 }' errno.txt
|
||||
) > errno.src
|
||||
|
||||
echo "#if FSP_FUSE_ERRNO == 87 /* Windows */"
|
||||
echo
|
||||
vcvars="$(cygpath -aw "$VS140COMNTOOLS/../../VC/vcvarsall.bat")"
|
||||
cmd /c "call" "$vcvars" "x64" "&&" cl /nologo /EP /C errno.src 2>/dev/null | sed -e '1,/beginbeginbeginbegin/d'
|
||||
echo
|
||||
echo "#elif FSP_FUSE_ERRNO == 67 /* Cygwin */"
|
||||
echo
|
||||
cpp -C -P errno.src | sed -e '1,/beginbeginbeginbegin/d'
|
||||
echo
|
||||
echo "#endif"
|
||||
|
||||
rm errno.src
|
54
tools/gensrc/errno.txt
Normal file
54
tools/gensrc/errno.txt
Normal file
@ -0,0 +1,54 @@
|
||||
0 STATUS_SUCCESS
|
||||
EPERM STATUS_ACCESS_DENIED
|
||||
ENOENT STATUS_OBJECT_NAME_NOT_FOUND
|
||||
ESRCH STATUS_PROCEDURE_NOT_FOUND
|
||||
EINTR STATUS_CANCELLED
|
||||
EIO STATUS_IO_DEVICE_ERROR
|
||||
ENXIO STATUS_FILE_INVALID
|
||||
E2BIG STATUS_INSUFFICIENT_RESOURCES
|
||||
ENOEXEC STATUS_INVALID_IMAGE_FORMAT
|
||||
EBADF STATUS_INVALID_HANDLE
|
||||
ENOMEM STATUS_INSUFFICIENT_RESOURCES
|
||||
EACCES STATUS_ACCESS_DENIED
|
||||
EFAULT STATUS_ACCESS_VIOLATION
|
||||
EBUSY STATUS_DEVICE_BUSY
|
||||
EEXIST STATUS_OBJECT_NAME_COLLISION
|
||||
EXDEV STATUS_NOT_SAME_DEVICE
|
||||
ENODEV STATUS_NO_SUCH_DEVICE
|
||||
ENOTDIR STATUS_NOT_A_DIRECTORY
|
||||
EISDIR STATUS_FILE_IS_A_DIRECTORY
|
||||
EINVAL STATUS_INVALID_PARAMETER
|
||||
ENFILE STATUS_TOO_MANY_OPENED_FILES
|
||||
EMFILE STATUS_TOO_MANY_OPENED_FILES
|
||||
EFBIG STATUS_DISK_FULL
|
||||
ENOSPC STATUS_DISK_FULL
|
||||
ESPIPE STATUS_INVALID_PARAMETER
|
||||
EROFS STATUS_MEDIA_WRITE_PROTECTED
|
||||
EMLINK STATUS_TOO_MANY_LINKS
|
||||
EPIPE STATUS_PIPE_BROKEN
|
||||
EDOM STATUS_INVALID_PARAMETER
|
||||
ERANGE STATUS_INVALID_PARAMETER
|
||||
EDEADLK STATUS_POSSIBLE_DEADLOCK
|
||||
ENAMETOOLONG STATUS_NAME_TOO_LONG
|
||||
ENOLCK STATUS_LOCK_NOT_GRANTED
|
||||
ENOSYS STATUS_INVALID_DEVICE_REQUEST
|
||||
ENOTEMPTY STATUS_DIRECTORY_NOT_EMPTY
|
||||
EILSEQ STATUS_INVALID_PARAMETER
|
||||
EADDRINUSE STATUS_ADDRESS_ALREADY_ASSOCIATED
|
||||
EALREADY STATUS_CONNECTION_ACTIVE
|
||||
ECANCELED STATUS_CANCELLED
|
||||
ECONNABORTED STATUS_CONNECTION_ABORTED
|
||||
ECONNREFUSED STATUS_CONNECTION_REFUSED
|
||||
ECONNRESET STATUS_CONNECTION_RESET
|
||||
EHOSTUNREACH STATUS_HOST_UNREACHABLE
|
||||
EISCONN STATUS_CONNECTION_ACTIVE
|
||||
ELOOP STATUS_REPARSE_POINT_NOT_RESOLVED
|
||||
ENETDOWN STATUS_HOST_DOWN
|
||||
ENETRESET STATUS_CONNECTION_RESET
|
||||
ENETUNREACH STATUS_NETWORK_UNREACHABLE
|
||||
ENOBUFS STATUS_INSUFFICIENT_RESOURCES
|
||||
ENODATA STATUS_END_OF_FILE
|
||||
ENOLINK STATUS_CONNECTION_INVALID
|
||||
ENOTCONN STATUS_CONNECTION_INVALID
|
||||
ENOTSOCK STATUS_INVALID_HANDLE
|
||||
ETIMEDOUT STATUS_TRANSACTION_TIMED_OUT
|
11
tools/nmake-ext-test.bat
Normal file
11
tools/nmake-ext-test.bat
Normal file
@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
|
||||
set Configuration=Release
|
||||
if not X%1==X set Configuration=%1
|
||||
|
||||
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
|
||||
|
||||
cd %~dp0..\ext\test
|
||||
nmake /f Nmakefile
|
107
tools/run-tests.bat
Normal file
107
tools/run-tests.bat
Normal file
@ -0,0 +1,107 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
|
||||
set Configuration=Release
|
||||
if not X%1==X set Configuration=%1
|
||||
|
||||
cd %~dp0..
|
||||
set ProjRoot=%cd%
|
||||
|
||||
cd build\VStudio
|
||||
if not exist build\%Configuration% echo === No tests found >&2 & goto fail
|
||||
cd build\%Configuration%
|
||||
|
||||
launchctl-x64 start memfs64 testdsk "" M: >nul
|
||||
launchctl-x64 start memfs64 testnet \memfs64\test N: >nul
|
||||
launchctl-x64 start memfs32 testdsk "" O: >nul
|
||||
launchctl-x64 start memfs32 testnet \memfs32\test P: >nul
|
||||
rem Cannot use timeout under cygwin/mintty: "Input redirection is not supported"
|
||||
waitfor 7BF47D72F6664550B03248ECFE77C7DD /t 3 2>nul
|
||||
cd M: >nul 2>nul || (echo === Unable to find drive M: >&2 & goto fail)
|
||||
cd N: >nul 2>nul || (echo === Unable to find drive N: >&2 & goto fail)
|
||||
cd O: >nul 2>nul || (echo === Unable to find drive O: >&2 & goto fail)
|
||||
cd P: >nul 2>nul || (echo === Unable to find drive P: >&2 & goto fail)
|
||||
|
||||
set testpass=0
|
||||
set testfail=0
|
||||
for %%f in (winfsp-tests-x64 winfsp-tests-x86 :fsx-memfs-x64 :fsx-memfs-x86 :winfstest-memfs-x64 :winfstest-memfs-x86) do (
|
||||
echo === Running %%f
|
||||
|
||||
if defined APPVEYOR (
|
||||
appveyor AddTest "%%f" -FileName None -Framework None -Outcome Running
|
||||
)
|
||||
|
||||
pushd %cd%
|
||||
call %%f
|
||||
popd
|
||||
|
||||
if errorlevel 1 (
|
||||
set /a testfail=testfail+1
|
||||
|
||||
echo === Failed %%f
|
||||
|
||||
if defined APPVEYOR (
|
||||
appveyor UpdateTest "%%f" -FileName None -Framework None -Outcome Failed -Duration 0
|
||||
)
|
||||
) else (
|
||||
set /a testpass=testpass+1
|
||||
|
||||
echo === Passed %%f
|
||||
|
||||
if defined APPVEYOR (
|
||||
appveyor UpdateTest "%%f" -FileName None -Framework None -Outcome Passed -Duration 0
|
||||
)
|
||||
)
|
||||
echo:
|
||||
)
|
||||
|
||||
launchctl-x64 stop memfs64 testdsk >nul
|
||||
launchctl-x64 stop memfs64 testnet >nul
|
||||
launchctl-x64 stop memfs32 testdsk >nul
|
||||
launchctl-x64 stop memfs32 testnet >nul
|
||||
|
||||
set /a total=testpass+testfail
|
||||
echo === Total: %testpass%/%total%
|
||||
if not %testfail%==0 goto fail
|
||||
|
||||
exit /b 0
|
||||
|
||||
:fail
|
||||
exit /b 1
|
||||
|
||||
:fsx-memfs-x64
|
||||
M:
|
||||
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
||||
if errorlevel 1 goto fail
|
||||
N:
|
||||
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
||||
if errorlevel 1 goto fail
|
||||
exit /b 0
|
||||
|
||||
:fsx-memfs-x86
|
||||
O:
|
||||
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
||||
if errorlevel 1 goto fail
|
||||
P:
|
||||
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
||||
if errorlevel 1 goto fail
|
||||
exit /b 0
|
||||
|
||||
:winfstest-memfs-x64
|
||||
M:
|
||||
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" base
|
||||
if errorlevel 1 goto fail
|
||||
N:
|
||||
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" base
|
||||
if errorlevel 1 goto fail
|
||||
exit /b 0
|
||||
|
||||
:winfstest-memfs-x86
|
||||
O:
|
||||
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" base
|
||||
if errorlevel 1 goto fail
|
||||
P:
|
||||
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" base
|
||||
if errorlevel 1 goto fail
|
||||
exit /b 0
|
192
tst/memfs/memfs-main-old.c
Normal file
192
tst/memfs/memfs-main-old.c
Normal 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;
|
||||
}
|
@ -20,91 +20,24 @@
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
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;
|
||||
ULONG ul = wcstol(w, &endp, 0);
|
||||
return L'\0' != w[0] && L'\0' == *endp ? ul : deflt;
|
||||
}
|
||||
|
||||
static wchar_t *argtos(wchar_t **argp)
|
||||
NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
{
|
||||
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;
|
||||
wchar_t **argp, **arge;
|
||||
ULONG DebugFlags = 0;
|
||||
ULONG Flags = MemfsDisk;
|
||||
ULONG FileInfoTimeout = INFINITE;
|
||||
ULONG MaxFileNodes = 1024;
|
||||
@ -112,76 +45,126 @@ int wmain(int argc, wchar_t **argv)
|
||||
PWSTR MountPoint = 0;
|
||||
PWSTR VolumePrefix = 0;
|
||||
PWSTR RootSddl = 0;
|
||||
MEMFS *Memfs = 0;
|
||||
NTSTATUS Result;
|
||||
|
||||
for (argp = argv + 1; 0 != argp[0]; argp++)
|
||||
for (argp = argv + 1, arge = argv + argc; arge > argp; argp++)
|
||||
{
|
||||
if (L'-' != argp[0][0])
|
||||
break;
|
||||
switch (argp[0][1])
|
||||
{
|
||||
case L'?':
|
||||
usage();
|
||||
goto usage;
|
||||
case L'd':
|
||||
argtol(DebugFlags);
|
||||
break;
|
||||
case L'm':
|
||||
MountPoint = argtos(++argp);
|
||||
argtos(MountPoint);
|
||||
break;
|
||||
case L'n':
|
||||
MaxFileNodes = argtol(++argp, MaxFileNodes);
|
||||
argtol(MaxFileNodes);
|
||||
break;
|
||||
case L'S':
|
||||
RootSddl = argtos(++argp);
|
||||
argtos(RootSddl);
|
||||
break;
|
||||
case L's':
|
||||
MaxFileSize = argtol(++argp, MaxFileSize);
|
||||
argtol(MaxFileSize);
|
||||
break;
|
||||
case L't':
|
||||
FileInfoTimeout = argtol(++argp, FileInfoTimeout);
|
||||
argtol(FileInfoTimeout);
|
||||
break;
|
||||
case L'u':
|
||||
VolumePrefix = argtos(++argp);
|
||||
Flags = MemfsNet;
|
||||
argtos(VolumePrefix);
|
||||
if (0 != VolumePrefix && L'\0' != VolumePrefix[0])
|
||||
Flags = MemfsNet;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != argp[0])
|
||||
usage();
|
||||
if (arge > argp)
|
||||
goto usage;
|
||||
|
||||
MainEvent = CreateEvent(0, TRUE, FALSE, 0);
|
||||
if (0 == MainEvent)
|
||||
fail("error: cannot create MainEvent");
|
||||
if (MemfsDisk == Flags && 0 == MountPoint)
|
||||
goto usage;
|
||||
|
||||
Result = MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl,
|
||||
&Memfs);
|
||||
if (!NT_SUCCESS(Result))
|
||||
fail("error: cannot create MEMFS");
|
||||
{
|
||||
fail(L"cannot create MEMFS");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
FspFileSystemSetDebugLog(MemfsFileSystem(Memfs), DebugFlags);
|
||||
|
||||
if (0 != MountPoint && L'\0' != MountPoint[0])
|
||||
{
|
||||
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("error: cannot start MEMFS");
|
||||
Result = FspFileSystemSetMountPoint(MemfsFileSystem(Memfs), MountPoint);
|
||||
if (!NT_SUCCESS(Result))
|
||||
fail("error: cannot mount MEMFS");
|
||||
{
|
||||
fail(L"cannot start MEMFS");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
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");
|
||||
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"",
|
||||
0 != VolumePrefix && L'\0' != VolumePrefix[0] ? L" -u " : L"",
|
||||
0 != VolumePrefix && L'\0' != VolumePrefix[0] ? 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"
|
||||
" -d DebugFlags [-1: enable all debug logs]\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:|* (required if no UNC prefix)]\n";
|
||||
|
||||
fail(usage, L"" PROGNAME);
|
||||
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
NTSTATUS SvcStop(FSP_SERVICE *Service)
|
||||
{
|
||||
MEMFS *Memfs = Service->UserContext;
|
||||
|
||||
FspFileSystemRemoveMountPoint(MemfsFileSystem(Memfs));
|
||||
MemfsStop(Memfs);
|
||||
MemfsDelete(Memfs);
|
||||
|
||||
/* the OS will handle this! */
|
||||
// CloseHandle(MainEvent);
|
||||
// MainEvent = 0;
|
||||
|
||||
return 0;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t **argv)
|
||||
{
|
||||
return FspServiceRun(L"" PROGNAME, SvcStart, SvcStop, 0);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file memfs.c
|
||||
* @file memfs.cpp
|
||||
*
|
||||
* @copyright 2015-2016 Bill Zissimopoulos
|
||||
*/
|
||||
@ -20,6 +20,7 @@
|
||||
#include <sddl.h>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
/*
|
||||
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
|
||||
@ -79,7 +80,6 @@ typedef struct _MEMFS
|
||||
ULONG MaxFileSize;
|
||||
UINT16 VolumeLabelLength;
|
||||
WCHAR VolumeLabel[32];
|
||||
CRITICAL_SECTION Lock;
|
||||
} MEMFS;
|
||||
|
||||
static inline
|
||||
@ -274,7 +274,7 @@ BOOLEAN MemfsFileNodeMapEnumerateDescendants(MEMFS_FILE_NODE_MAP *FileNodeMap, M
|
||||
|
||||
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||
PVOID FileNode0, UINT64 FileSize,
|
||||
PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
||||
FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
|
||||
static NTSTATUS GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||
@ -379,7 +379,8 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
FileNode->FileInfo.FileAttributes = FileAttributes;
|
||||
FileNode->FileInfo.FileAttributes = (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
|
||||
FileAttributes : FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
|
||||
|
||||
if (0 != SecurityDescriptor)
|
||||
{
|
||||
@ -396,7 +397,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);
|
||||
@ -437,7 +438,19 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem,
|
||||
return Result;
|
||||
}
|
||||
|
||||
FileNode->FileInfo.LastAccessTime = MemfsGetSystemTime();
|
||||
/*
|
||||
* NTFS and FastFat do this at Cleanup time, but we are going to cheat.
|
||||
*
|
||||
* To properly implement this we should maintain some state of whether
|
||||
* we modified the file or not. Alternatively we could have the driver
|
||||
* report to us at Cleanup time whether the file was modified. [The
|
||||
* driver does not currently maintain the FO_FILE_MODIFIED bit however.]
|
||||
*
|
||||
* TBD.
|
||||
*/
|
||||
if (0 == (FileNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||
Request->Req.Create.DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA))
|
||||
FileNode->FileInfo.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
|
||||
FileNode->RefCount++;
|
||||
*PFileNode = FileNode;
|
||||
@ -455,9 +468,9 @@ NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem,
|
||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||
|
||||
if (ReplaceFileAttributes)
|
||||
FileNode->FileInfo.FileAttributes = FileAttributes;
|
||||
FileNode->FileInfo.FileAttributes = FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
|
||||
else
|
||||
FileNode->FileInfo.FileAttributes |= FileAttributes;
|
||||
FileNode->FileInfo.FileAttributes |= FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
|
||||
|
||||
FileNode->FileInfo.FileSize = 0;
|
||||
FileNode->FileInfo.LastWriteTime =
|
||||
@ -507,7 +520,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);
|
||||
|
||||
@ -527,7 +540,8 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
|
||||
__try
|
||||
{
|
||||
*P = *P | 0;
|
||||
assert(0);
|
||||
assert(!IsWindows8OrGreater());
|
||||
/* only on Windows 8 we can make the buffer read-only! */
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
@ -552,10 +566,10 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
|
||||
Offset = FileNode->FileInfo.FileSize;
|
||||
EndOffset = Offset + Length;
|
||||
if (EndOffset > FileNode->FileInfo.FileSize)
|
||||
SetFileSize(FileSystem, Request, FileNode, EndOffset, FileInfo);
|
||||
SetFileSize(FileSystem, Request, FileNode, EndOffset, FALSE, 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;
|
||||
@ -605,59 +619,52 @@ static NTSTATUS SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS SetAllocationSize(FSP_FILE_SYSTEM *FileSystem,
|
||||
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||
PVOID FileNode0, UINT64 AllocationSize,
|
||||
PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||
{
|
||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||
PVOID FileData;
|
||||
|
||||
if (FileNode->FileInfo.AllocationSize != AllocationSize)
|
||||
if (SetAllocationSize)
|
||||
{
|
||||
if (AllocationSize > Memfs->MaxFileSize)
|
||||
return STATUS_DISK_FULL;
|
||||
|
||||
FileData = realloc(FileNode->FileData, AllocationSize);
|
||||
if (0 == FileData)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
FileNode->FileData = FileData;
|
||||
|
||||
FileNode->FileInfo.AllocationSize = AllocationSize;
|
||||
if (FileNode->FileInfo.FileSize > AllocationSize)
|
||||
FileNode->FileInfo.FileSize = AllocationSize;
|
||||
}
|
||||
|
||||
*FileInfo = FileNode->FileInfo;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||
PVOID FileNode0, UINT64 FileSize,
|
||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||
{
|
||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||
|
||||
if (FileNode->FileInfo.FileSize != FileSize)
|
||||
{
|
||||
if (FileNode->FileInfo.AllocationSize < FileSize)
|
||||
if (FileNode->FileInfo.AllocationSize != NewSize)
|
||||
{
|
||||
UINT64 AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
|
||||
UINT64 AllocationSize = (FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
||||
if (NewSize > Memfs->MaxFileSize)
|
||||
return STATUS_DISK_FULL;
|
||||
|
||||
NTSTATUS Result = SetAllocationSize(FileSystem, Request, FileNode, AllocationSize, FileInfo);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
PVOID FileData = realloc(FileNode->FileData, (size_t)NewSize);
|
||||
if (0 == FileData && 0 != NewSize)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
FileNode->FileData = FileData;
|
||||
|
||||
FileNode->FileInfo.AllocationSize = NewSize;
|
||||
if (FileNode->FileInfo.FileSize > NewSize)
|
||||
FileNode->FileInfo.FileSize = NewSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FileNode->FileInfo.FileSize != NewSize)
|
||||
{
|
||||
if (FileNode->FileInfo.AllocationSize < NewSize)
|
||||
{
|
||||
UINT64 AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
|
||||
UINT64 AllocationSize = (NewSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
||||
|
||||
if (FileNode->FileInfo.FileSize < FileSize)
|
||||
memset((PUINT8)FileNode->FileData + FileNode->FileInfo.FileSize, 0,
|
||||
FileSize - FileNode->FileInfo.FileSize);
|
||||
FileNode->FileInfo.FileSize = FileSize;
|
||||
NTSTATUS Result = SetFileSize(FileSystem, Request, FileNode, AllocationSize, TRUE,
|
||||
FileInfo);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
}
|
||||
|
||||
if (FileNode->FileInfo.FileSize < NewSize)
|
||||
memset((PUINT8)FileNode->FileData + FileNode->FileInfo.FileSize, 0,
|
||||
(size_t)(NewSize - FileNode->FileInfo.FileSize));
|
||||
FileNode->FileInfo.FileSize = NewSize;
|
||||
}
|
||||
}
|
||||
|
||||
*FileInfo = FileNode->FileInfo;
|
||||
@ -940,7 +947,6 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
||||
Flush,
|
||||
GetFileInfo,
|
||||
SetBasicInfo,
|
||||
SetAllocationSize,
|
||||
SetFileSize,
|
||||
CanDelete,
|
||||
Rename,
|
||||
@ -949,20 +955,6 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
||||
ReadDirectory,
|
||||
};
|
||||
|
||||
static VOID MemfsEnterOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||
EnterCriticalSection(&Memfs->Lock);
|
||||
}
|
||||
|
||||
static VOID MemfsLeaveOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||
LeaveCriticalSection(&Memfs->Lock);
|
||||
}
|
||||
|
||||
NTSTATUS MemfsCreate(
|
||||
ULONG Flags,
|
||||
ULONG FileInfoTimeout,
|
||||
@ -1037,11 +1029,10 @@ NTSTATUS MemfsCreate(
|
||||
Memfs->VolumeLabelLength = sizeof L"MEMFS" - sizeof(WCHAR);
|
||||
memcpy(Memfs->VolumeLabel, L"MEMFS", Memfs->VolumeLabelLength);
|
||||
|
||||
InitializeCriticalSection(&Memfs->Lock);
|
||||
|
||||
FspFileSystemSetOperationGuard(Memfs->FileSystem,
|
||||
MemfsEnterOperation,
|
||||
MemfsLeaveOperation);
|
||||
#if 0
|
||||
FspFileSystemSetOperationGuardStrategy(Memfs->FileSystem,
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Create root directory.
|
||||
@ -1086,8 +1077,6 @@ NTSTATUS MemfsCreate(
|
||||
|
||||
VOID MemfsDelete(MEMFS *Memfs)
|
||||
{
|
||||
DeleteCriticalSection(&Memfs->Lock);
|
||||
|
||||
FspFileSystemDelete(Memfs->FileSystem);
|
||||
|
||||
MemfsFileNodeMapDelete(Memfs->FileNodeMap);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user