Compare commits

..

51 Commits

Author SHA1 Message Date
ba46d9fef8 update Changelog, README, etc. 2017-02-25 17:59:37 -08:00
4c0386bf8d sys: hardcode AlwaysUseDoubleBuffering for Reads 2017-02-25 11:22:22 -08:00
6774c34422 sys: FspProcessBufferAcquire: fix silly mistake when using ZwAllocateVirtualMemory 2017-02-23 22:24:32 -08:00
3215d8e26a sys: ProcessBuffer: DEBUGTEST 2017-02-23 20:26:14 -08:00
7911f1354f sys: ProcessBuffer: improvements 2017-02-23 17:39:28 -08:00
28f97c2619 sys: ProcessBuffer: conditional usage 2017-02-23 16:36:21 -08:00
4b43cc590f sys: initial ProcessBuffer implementation 2017-02-23 16:06:55 -08:00
441c45c77f sys: fix a couple of static analysis issues 2017-02-21 15:07:06 -08:00
c246acb2d3 dll: FspVersion 2017-02-17 15:22:31 -08:00
50ed020e16 dll: FspVersion 2017-02-17 15:20:57 -08:00
12704a3a4a dll: FspFileSystemSetMountPointEx and related refactoring 2017-02-16 20:30:39 -08:00
186f7cd9ee dll: fuse: minor fix 2017-02-16 17:26:07 -08:00
50830f0bf2 bump version to 2017 RC3 2017-02-16 17:25:54 -08:00
86025aa30b dll: fuse: fuse_mount: now also accepts cygwin paths 2017-02-16 16:53:06 -08:00
31e6f15eaf tst: passthrough-fuse: FSP_FUSE_CAP_*: testing 2017-02-15 18:07:25 -08:00
5ce6d74e90 tst: passthrough-fuse: FSP_FUSE_CAP_*: testing 2017-02-15 17:26:37 -08:00
02ffa6afb2 tst: passthrough-fuse: ptfs_init 2017-02-13 22:03:39 -08:00
712870ddd9 tst: passthrough-fuse: FSP_FUSE_CAP_* 2017-02-13 21:53:37 -08:00
35d1adb360 dll: fuse: improve SectorSize: handling 2017-02-13 16:21:26 -08:00
3b9f9ce93b dll: fuse: discard unused options 2017-02-13 15:11:09 -08:00
a7c5e4f80c dll: fuse: default FileInfoTimeout is now 1000ms 2017-02-12 13:25:43 -08:00
0b826f04c2 tst: winfsp-tests: exec-test: disable test that fails under shares 2017-02-12 11:49:46 -08:00
69d53b7a28 tst: winfsp-tests: exec-test: disable test that fails under shares 2017-02-12 11:33:56 -08:00
877bd97ba8 tst: winfsp-tests: exec-test 2017-02-12 10:42:14 -08:00
559b7e80a3 tst: winfsp-tests: exec-test 2017-02-12 10:29:30 -08:00
495c78eb25 tst: winfsp-tests: exec-test 2017-02-12 00:26:20 -08:00
cf69d6a08d tst: winfsp-tests: delete_standby_test 2017-02-11 10:07:03 -08:00
0d95bb9b14 tst: winfsp-tests: delete_standby_test: disable parts that fail with shares and passthrough 2017-02-10 23:24:05 -08:00
cf48d19759 tst: winfsp-tests: delete_standby_test: disable portion that fails under a share 2017-02-10 22:19:25 -08:00
14c602ccd8 tst: winfsp-tests: delete_standby_test 2017-02-10 21:31:55 -08:00
2d45082d80 tst: winfsp-tests: delete_standby_test 2017-02-10 19:50:16 -08:00
25cf527af4 tst: winfsp-tests: rename_standby_test 2017-02-10 15:47:44 -08:00
76d081937e tst: winfsp-tests: rename_standby_test 2017-02-10 15:25:36 -08:00
ccd4bb869c Experimental fix for github issue #45 2017-02-10 12:39:53 -08:00
46d5c98926 tst: winfsp-tests: rename_standby_test 2017-02-09 17:38:24 -08:00
1726ca8ccb Update README as per issue #48 2017-02-09 12:06:54 -08:00
b8c257f996 Update README as per issue #48 2017-02-09 12:04:51 -08:00
53e6894298 doc: use asciidoc for winfsp.h reference 2017-02-08 17:36:17 -08:00
10d1ba707e Update README.md 2017-02-08 13:42:49 -08:00
c234e2af2a Update README.md 2017-02-08 13:42:30 -08:00
fa652cdb56 launcher: change registry location 2017-02-07 17:15:41 -08:00
aeaeba0dd6 launcher: change registry location 2017-02-07 14:53:27 -08:00
b299027f6e Update Changelog 2017-02-07 12:48:40 -08:00
5edd9eb548 Update Changelog 2017-02-07 12:45:32 -08:00
fbc24bcca9 Update Changelog 2017-02-07 12:44:59 -08:00
4ef6dcb71d Update README.md 2017-02-07 12:35:14 -08:00
b8f0d08672 Update README.md 2017-02-07 12:32:29 -08:00
5c82044295 Update README.md 2017-02-07 12:26:11 -08:00
e3b5426e45 Update README.md 2017-02-07 12:25:27 -08:00
d34f262c02 Merge branch 'pvt-license-change' into release/1.0 2017-02-07 12:21:48 -08:00
ede72e4c5f tst: passthrough: fix missed FspFileSystemReleaseDirectoryBuffer in case of error 2017-02-06 12:05:30 -08:00
55 changed files with 3926 additions and 2201 deletions

View File

@ -1,11 +1,25 @@
= Changelog
v1.0RC3::
This is the WinFsp 2017 Release Candidate 3, which should be the last Release Candidate according to the current plan. This release fixes a major issue with some file systems and includes a few smaller changes:
- Fixes GitHub issue #55. Prior to this fix it was possible for a rogue process (or faulty file system) to crash Windows using WinFsp. For full details read http://www.osronline.com/showthread.cfm?link=282037[this thread].
- Introduces the `FspFileSystemSetMountPointEx` API, which allows the specification of a security descriptor when mounting over a directory.
- Introduces the `FspVersion` API, which allows the retrieval of the WinFsp DLL version. Currently this reports `0x00010000` (version `1.0`).
- Introduces the `FSP_FUSE_CAP_CASE_INSENSITIVE` and `FSP_FUSE_CAP_READDIR_PLUS` WinFsp-FUSE flags. The `FSP_FUSE_CAP_CASE_INSENSITIVE` flag allows a file system to mark itself as case-insensitive. The `FSP_FUSE_CAP_READDIR_PLUS` flag allows a file system to include full `stat` details when responding to the `readdir` operation (thus avoiding extraneous `getattr` calls).
- When using WinFsp-FUSE over Cygwin, POSIX paths can be used as mountpoints.
- Fixes GitHub issue #45. Prior to this fix, file systems that do not properly implement `Cleanup` (including FUSE file systems) would at times disallow renaming of directories.
v1.0RC2::
This is the WinFsp 2017 Release Candidate 2. Some important changes included below:
- The `ReadDirectory` `FSP_FILE_SYSTEM_INTERFACE` operation has been changed. Extensive testing with multiple file systems has shown that `ReadDirectory` was hard to implement correctly. The new definition should make implementation easier for most file system. [See GitHub issue #34.]
- WinFsp is now available under the GPLv3 with a special exception for Free/Libre and Open Source Software.
- The location of the WinFsp launcher registry entries is now `HKEY_LOCAL_MACHINE\Software\WinFsp\Services`. [On Win64 the actual location is `HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\WinFsp\Services`.] This change was necessary to avoid loss of third party file system registry entries during WinFsp uninstallation. [See GitHub issue #31.]
- Despite stating in the previous release that the API has been finalized the `ReadDirectory` `FSP_FILE_SYSTEM_INTERFACE` operation has been changed. Extensive testing with multiple file systems has shown that `ReadDirectory` was hard to implement correctly. The new definition should make implementation easier for most file systems. [See GitHub issue #34.]
- Some API's to facilitate `ReadDirectory` implementation have been added. Look for `FspFileSystem*DirectoryBuffer` symbols.
- The installer now (optionally) installs a sample file system called "passthrough". This is a simple file system that passes all operations to an underlying file system. There is also a tutorial for this file system (in the doc directory).
- The installer now (optionally) installs a sample file system called "passthrough-fuse". This file system performs the same function as the "passthrough" file system, but uses the FUSE compatibility layer. It builds and runs on both Windows and Cygwin.

View File

@ -3,7 +3,7 @@
![WinFsp Demo](http://www.secfs.net/winfsp/files/cap.gif)
<a href="https://github.com/billziss-gh/winfsp/releases/download/v1.0RC1/winfsp-1.0.17009.msi"><img src="http://www.secfs.net/winfsp/resources/Download-WinFsp.png" alt="Download WinFsp Installer" width="244" height="34"></a>
<a href="https://github.com/billziss-gh/winfsp/releases"><img src="http://www.secfs.net/winfsp/resources/Download-WinFsp.png" alt="Download WinFsp Installer" width="244" height="34"></a>
@ -17,7 +17,7 @@ Some of the benefits of using WinFsp are listed below:
* Easy to understand but comprehensive API. Consult the [API Reference](http://www.secfs.net/winfsp/apiref/). There is also a simple [Tutorial](doc/WinFsp-Tutorial.asciidoc).
* FUSE compatibility layer for native Windows and Cygwin. See [fuse.h](inc/fuse/fuse.h).
* Signed drivers provided on every release.
* Available under the GPLv3.
* Available under the [GPLv3](License.txt) license with a special exception for Free/Libre and Open Source Software.
To learn more about WinFsp, please visit its website: http://www.secfs.net/winfsp/
@ -45,19 +45,22 @@ The project source code is organized as follows:
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/).
To fully build WinFsp (including the installer) you must use `tools\build.bat`. By default it builds a Release build, but you can choose either the Debug or Release configuration by using the syntax:
WinFsp is designed to run on Vista and above. It has been tested on the following platforms so far:
tools\build.bat CONFIGURATION
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 on`. For more information see this [document](http://www.secfs.net/winfsp/develop/debug/).
WinFsp is designed to run on Windows 7 and above. It has been tested on the following platforms:
* Windows 7 Enterprise
* Windows 8 Pro
* Windows 10 Pro
* Windows Server 2012
* Windows 10 Pro
* Windows Server 2016
## How to Help
@ -79,4 +82,4 @@ If you wish to discuss WinFsp there are now two options:
## License
WinFsp is available under the [GPLv3](http://www.gnu.org/licenses/gpl-3.0.html) license. If you find the constraints of the GPLv3 too onerous, a commercial license is also available. Please contact Bill Zissimopoulos <billziss at navimatics.com> for more details.
WinFsp is available under the [GPLv3](License.txt) license with a special exception for Free/Libre and Open Source Software. A commercial license is also available. Please contact Bill Zissimopoulos \<billziss at navimatics.com> for more details.

View File

@ -22,7 +22,7 @@
<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.LauncherRegistryKey">Software\$(var.MyProductName)\Services</Property>
<Property Id="P.RegistryKey">Software\$(var.MyProductName)</Property>
<Property Id="INSTALLDIR">
<RegistrySearch

View File

@ -185,6 +185,7 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\dirctl-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\exec-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\hooks.c" />
@ -201,6 +202,7 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\security-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\version-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\winfsp-tests.c" />
</ItemGroup>
<ItemGroup>
@ -213,6 +215,9 @@
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\tst\winfsp-tests\helper\winfsp-tests-helper.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -79,6 +79,12 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\exec-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\version-test.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
@ -91,4 +97,9 @@
<Filter>Source</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\tst\winfsp-tests\helper\winfsp-tests-helper.rc">
<Filter>Source</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -17,7 +17,7 @@
<MyCanonicalVersion>1.0</MyCanonicalVersion>
<MyProductVersion>2017 RC2</MyProductVersion>
<MyProductVersion>2017 RC3</MyProductVersion>
<MyProductStage>RC</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>

View File

@ -174,6 +174,7 @@
<ClCompile Include="..\..\src\sys\lockctl.c" />
<ClCompile Include="..\..\src\sys\meta.c" />
<ClCompile Include="..\..\src\sys\name.c" />
<ClCompile Include="..\..\src\sys\psbuffer.c" />
<ClCompile Include="..\..\src\sys\read.c" />
<ClCompile Include="..\..\src\sys\security.c" />
<ClCompile Include="..\..\src\sys\shutdown.c" />

View File

@ -98,6 +98,9 @@
<ClCompile Include="..\..\src\sys\statistics.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sys\psbuffer.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\sys\driver.h">

View File

@ -20,19 +20,21 @@ In order to overcome the issue with launching multiple instances of a particular
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
HKEY_LOCAL_MACHINE\Software\WinFsp\Services
For example, the MEMFS sample adds the following registry entries under this key:
NOTE: Please note that in a 64-bit system the actual location is `HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\WinFsp\Services`.
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services\memfs32]
For example, the MEMFS sample adds the following registry entries in a 64-bit system:
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\WinFsp\Services\memfs32]
"Executable"="C:\\Program Files (x86)\\WinFsp\\bin\\memfs-x86.exe"
"CommandLine"="-u %1 -m %2"
"CommandLine"="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2"
"Security"="D:P(A;;RPWPLC;;;WD)"
"JobControl"=dword:00000001
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services\memfs64]
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\WinFsp\Services\memfs64]
"Executable"="C:\\Program Files (x86)\\WinFsp\\bin\\memfs-x64.exe"
"CommandLine"="-u %1 -m %2"
"CommandLine"="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2"
"Security"="D:P(A;;RPWPLC;;;WD)"
"JobControl"=dword:00000001
@ -44,4 +46,4 @@ One final note regarding security. Notice the `Security` registry value in the e
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.
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 `-i -F NTFS -n 65536 -s 67108864 -u \\memfs64\share -m Z:`. When the user disconnects the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to stop the previously started instance of the memfs64 service.

View File

@ -622,9 +622,14 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
Length = GetFinalPathNameByHandleW(Handle, FullPath, FULLPATH_SIZE - 1, 0);
if (0 == Length)
return FspNtStatusFromWin32(GetLastError());
if (Length + 1 + PatternLength >= FULLPATH_SIZE)
return STATUS_OBJECT_NAME_INVALID;
DirBufferResult = FspNtStatusFromWin32(GetLastError());
else if (Length + 1 + PatternLength >= FULLPATH_SIZE)
DirBufferResult = STATUS_OBJECT_NAME_INVALID;
if (!NT_SUCCESS(DirBufferResult))
{
FspFileSystemReleaseDirectoryBuffer(&FileContext->DirBuffer);
return DirBufferResult;
}
if (L'\\' != FullPath[Length - 1])
FullPath[Length++] = L'\\';

1741
doc/winfsp.h.asciidoc Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -41,6 +41,15 @@ extern "C" {
#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
#define FUSE_CAP_BIG_WRITES (1 << 5)
#define FUSE_CAP_DONT_MASK (1 << 6)
#define FUSE_CAP_ALLOCATE (1 << 27) /* reserved (OSXFUSE) */
#define FUSE_CAP_EXCHANGE_DATA (1 << 28) /* reserved (OSXFUSE) */
#define FUSE_CAP_CASE_INSENSITIVE (1 << 29) /* file system is case insensitive */
#define FUSE_CAP_VOL_RENAME (1 << 30) /* reserved (OSXFUSE) */
#define FUSE_CAP_XTIMES (1 << 31) /* reserved (OSXFUSE) */
#define FSP_FUSE_CAP_READDIR_PLUS (1 << 21) /* file system supports enhanced readdir */
#define FSP_FUSE_CAP_READ_ONLY (1 << 22) /* file system is marked read-only */
#define FSP_FUSE_CAP_CASE_INSENSITIVE FUSE_CAP_CASE_INSENSITIVE
#define FUSE_IOCTL_COMPAT (1 << 0)
#define FUSE_IOCTL_UNRESTRICTED (1 << 1)

View File

@ -177,6 +177,7 @@ struct fuse_flock
MemAlloc, MemFree, \
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
0/*conv_to_win_path*/, \
}
#else
#define FSP_FUSE_ENV_INIT \
@ -185,6 +186,7 @@ struct fuse_flock
malloc, free, \
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
0/*conv_to_win_path*/, \
}
#endif
@ -226,6 +228,7 @@ struct fuse_flock
malloc, free, \
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
fsp_fuse_conv_to_win_path, \
}
/*
@ -244,7 +247,8 @@ struct fsp_fuse_env
void (*memfree)(void *);
int (*daemonize)(int);
int (*set_signal_handlers)(void *);
void (*reserved[4])();
char *(*conv_to_win_path)(const char *);
void (*reserved[3])();
};
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_signal_handler)(int sig);
@ -348,6 +352,13 @@ static inline int fsp_fuse_set_signal_handlers(void *se)
#undef FSP_FUSE_SET_SIGNAL_HANDLER
}
static inline char *fsp_fuse_conv_to_win_path(const char *path)
{
void *cygwin_create_path(unsigned, const void *);
return cygwin_create_path(
0/*CCP_POSIX_TO_WIN_A*/ | 0x100/*CCP_RELATIVE*/,
path);
}
#endif

View File

@ -148,7 +148,8 @@ typedef struct
/* kernel-mode flags */
UINT32 PostCleanupWhenModifiedOnly:1; /* post Cleanup when a file was modified/deleted */
UINT32 PassQueryDirectoryPattern:1; /* pass Pattern during QueryDirectory operations */
UINT32 KmReservedFlags:4;
UINT32 AlwaysUseDoubleBuffering:1;
UINT32 KmReservedFlags:3;
/* user-mode flags */
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */

View File

@ -893,6 +893,8 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem);
* STATUS_SUCCESS or error code.
*/
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint);
FSP_API NTSTATUS FspFileSystemSetMountPointEx(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint,
PSECURITY_DESCRIPTOR SecurityDescriptor);
/**
* Remove the mount point for a file system.
*
@ -1625,6 +1627,7 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout,
PSID Sid);
FSP_API NTSTATUS FspVersion(PUINT32 PVersion);
/*
* Delay load

View File

@ -1,6 +1,6 @@
NAME="fuse"
VERSION=2.8
RELEASE=3
RELEASE=4
CATEGORY="Utils"
SUMMARY="WinFsp-FUSE compatibility layer"
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."

View File

@ -187,20 +187,63 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem)
MemFree(FileSystem);
}
static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWSTR VolumeName)
static NTSTATUS FspFileSystemSetMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName,
PHANDLE PMountHandle)
{
*PMountHandle = 0;
if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, VolumeName))
return FspNtStatusFromWin32(GetLastError());
if (0 != FspNtOpenSymbolicLinkObject)
{
NTSTATUS Result;
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(PMountHandle, DELETE, &Obja);
if (NT_SUCCESS(Result))
{
Result = FspNtMakeTemporaryObject(*PMountHandle);
if (!NT_SUCCESS(Result))
{
FspNtClose(*PMountHandle);
*PMountHandle = 0;
}
}
}
return STATUS_SUCCESS;
}
static NTSTATUS FspFileSystemSetMountPoint_Directory(PWSTR MountPoint, PWSTR VolumeName,
PSECURITY_DESCRIPTOR SecurityDescriptor, PHANDLE PMountHandle)
{
NTSTATUS Result;
HANDLE DirHandle;
BOOL Success;
SECURITY_ATTRIBUTES SecurityAttributes;
HANDLE MountHandle = INVALID_HANDLE_VALUE;
DWORD Backslashes, Bytes;
USHORT VolumeNameLength, BackslashLength, ReparseDataLength;
PREPARSE_DATA_BUFFER ReparseData = 0;
PWSTR P, PathBuffer;
*PMountHandle = 0;
/*
* Windows does not allow mount points (junctions) to point to network file systems.
*
* Count how many backslashes our VolumeName. If it is 3 or more this is a network
* Count how many backslashes our VolumeName has. If it is 3 or more this is a network
* file system. Preemptively return STATUS_NETWORK_ACCESS_DENIED.
*/
for (P = VolumeName, Backslashes = 0; *P; P++)
@ -211,25 +254,24 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
goto exit;
}
if (!CreateDirectoryW(MountPoint, 0))
memset(&SecurityAttributes, 0, sizeof SecurityAttributes);
SecurityAttributes.nLength = sizeof SecurityAttributes;
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
MountHandle = CreateFileW(MountPoint,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
&SecurityAttributes,
CREATE_NEW,
FILE_ATTRIBUTE_DIRECTORY |
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE,
0);
if (INVALID_HANDLE_VALUE == MountHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
DirHandle = CreateFileW(MountPoint,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
0);
if (INVALID_HANDLE_VALUE == DirHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto rmdir_and_exit;
}
VolumeNameLength = (USHORT)lstrlenW(VolumeName);
BackslashLength = 0 == VolumeNameLength || L'\\' != VolumeName[VolumeNameLength - 1];
VolumeNameLength *= sizeof(WCHAR);
@ -243,7 +285,7 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
if (0 == ReparseData)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto rmdir_and_exit;
goto exit;
}
ReparseData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
@ -270,86 +312,35 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\';
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
Success = DeviceIoControl(DirHandle, FSCTL_SET_REPARSE_POINT,
if (!DeviceIoControl(MountHandle, FSCTL_SET_REPARSE_POINT,
ReparseData, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseData->ReparseDataLength,
0, 0,
&Bytes, 0);
CloseHandle(DirHandle);
if (!Success)
&Bytes, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto rmdir_and_exit;
goto exit;
}
*PMountHandle = MountHandle;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result) && INVALID_HANDLE_VALUE != MountHandle)
CloseHandle(MountHandle);
MemFree(ReparseData);
return Result;
rmdir_and_exit:
RemoveDirectoryW(MountPoint);
goto exit;
}
static NTSTATUS FspFileSystemSetMountPoint_MakeTemporary(PWSTR MountPoint, PHANDLE PMountHandle)
{
NTSTATUS Result = STATUS_SUCCESS;
HANDLE MountHandle = 0;
if (FspPathIsDrive(MountPoint))
{
if (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;
}
}
}
}
else
{
/* open the directory for DELETE_ON_CLOSE; closing it will remove the directory */
MountHandle = CreateFileW(MountPoint,
FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_DELETE_ON_CLOSE,
0);
if (INVALID_HANDLE_VALUE == MountHandle)
{
MountHandle = 0;
Result = FspNtStatusFromWin32(GetLastError());
}
}
*PMountHandle = MountHandle;
return Result;
}
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint)
{
return FspFileSystemSetMountPointEx(FileSystem, MountPoint, 0);
}
FSP_API NTSTATUS FspFileSystemSetMountPointEx(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint,
PSECURITY_DESCRIPTOR SecurityDescriptor)
{
if (0 != FileSystem->MountPoint)
return STATUS_INVALID_PARAMETER;
@ -375,11 +366,10 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
if (0 == (Drives & (1 << (Drive - 'A'))))
{
MountPoint[0] = Drive;
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName))
{
Result = STATUS_SUCCESS;
Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
&MountHandle);
if (NT_SUCCESS(Result))
goto exit;
}
}
Result = STATUS_NO_SUCH_DEVICE;
}
@ -400,22 +390,16 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
MountPoint = P;
if (FspPathIsDrive(MountPoint))
{
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName))
Result = STATUS_SUCCESS;
else
Result = FspNtStatusFromWin32(GetLastError());
}
Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
&MountHandle);
else
Result = FspFileSystemSetMountPoint_CreateDirectory(MountPoint, FileSystem->VolumeName);
Result = FspFileSystemSetMountPoint_Directory(MountPoint, FileSystem->VolumeName,
SecurityDescriptor, &MountHandle);
}
exit:
if (NT_SUCCESS(Result))
{
FspFileSystemSetMountPoint_MakeTemporary(MountPoint, &MountHandle);
/* ignore result; this path always considered successful */
FileSystem->MountPoint = MountPoint;
FileSystem->MountHandle = MountHandle;
}
@ -425,33 +409,35 @@ exit:
return Result;
}
static VOID FspFileSystemRemoveMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName, HANDLE MountHandle)
{
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
MountPoint, VolumeName);
if (0 != MountHandle)
FspNtClose(MountHandle);
}
static VOID FspFileSystemRemoveMountPoint_Directory(HANDLE MountHandle)
{
/* directory is marked DELETE_ON_CLOSE */
CloseHandle(MountHandle);
}
FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
{
BOOLEAN IsDrive;
if (0 == FileSystem->MountPoint)
return;
IsDrive = FspPathIsDrive(FileSystem->MountPoint);
if (IsDrive)
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
FileSystem->MountPoint, FileSystem->VolumeName);
if (FspPathIsDrive(FileSystem->MountPoint))
FspFileSystemRemoveMountPoint_Drive(FileSystem->MountPoint, FileSystem->VolumeName,
FileSystem->MountHandle);
else
/* nothing to do! directory will be deleted when the MountHandle is closed */;
FspFileSystemRemoveMountPoint_Directory(FileSystem->MountHandle);
MemFree(FileSystem->MountPoint);
FileSystem->MountPoint = 0;
if (0 != FileSystem->MountHandle)
{
if (IsDrive)
FspNtClose(FileSystem->MountHandle);
else
/* CloseHandle really calls NtClose, but I like being defensive when programming */
CloseHandle(FileSystem->MountHandle);
FileSystem->MountHandle = 0;
}
FileSystem->MountHandle = 0;
}
static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)

View File

@ -32,16 +32,12 @@ struct fsp_fuse_core_opt_data
{
struct fsp_fuse_env *env;
int help, debug;
int hard_remove,
use_ino, readdir_ino,
set_umask, umask,
int set_umask, umask,
set_uid, uid,
set_gid, gid,
set_attr_timeout, attr_timeout,
rellinks;
int set_FileInfoTimeout;
int CaseInsensitiveSearch,
ReadOnlyVolume;
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
};
@ -56,9 +52,9 @@ static struct fuse_opt fsp_fuse_core_opts[] =
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("hard_remove", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("use_ino", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("readdir_ino", FUSE_OPT_KEY_DISCARD),
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),
@ -89,17 +85,8 @@ static struct fuse_opt fsp_fuse_core_opts[] =
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("ReadOnlyVolume", ReadOnlyVolume, 1),
FUSE_OPT_KEY("ReparsePoints", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("NamedStreams", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("HardLinks", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("ExtendedAttributes", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("--UNC=", 'U'),
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
FUSE_OPT_KEY("--FileSystemName=", 'F'),
@ -131,6 +118,9 @@ static inline void *fsp_fuse_obj_alloc(struct fsp_fuse_env *env, size_t size)
static inline void fsp_fuse_obj_free(void *obj)
{
if (0 == obj)
return;
struct fsp_fuse_obj_hdr *hdr = (PVOID)((PUINT8)obj - sizeof(struct fsp_fuse_obj_hdr));
hdr->dtor(hdr);
@ -190,23 +180,55 @@ 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;
WCHAR TempMountPointBuf[MAX_PATH], MountPointBuf[MAX_PATH];
int Size;
if (0 == mountpoint)
mountpoint = "";
if (0 == mountpoint || '\0' == mountpoint[0] ||
('*' == mountpoint[0] && '\0' == mountpoint[1]))
{
MountPointBuf[0] = L'*';
MountPointBuf[1] = L'\0';
Size = 2 * sizeof(WCHAR);
}
else if (
(
('A' <= mountpoint[0] && mountpoint[0] <= 'Z') ||
('a' <= mountpoint[0] && mountpoint[0] <= 'z')
) &&
':' == mountpoint[1] && '\0' == mountpoint[2])
{
MountPointBuf[0] = mountpoint[0];
MountPointBuf[1] = ':';
MountPointBuf[2] = '\0';
Size = 3 * sizeof(WCHAR);
}
else
{
char *win_mountpoint = 0;
Size = MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, 0, 0);
if (0 == Size)
goto fail;
if (0 != env->conv_to_win_path)
mountpoint = win_mountpoint = env->conv_to_win_path(mountpoint);
ch = fsp_fuse_obj_alloc(env, sizeof *ch + Size * sizeof(WCHAR));
Size = 0;
if (0 != mountpoint &&
0 != MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, TempMountPointBuf, MAX_PATH))
Size = GetFullPathNameW(TempMountPointBuf, MAX_PATH, MountPointBuf, 0);
env->memfree(win_mountpoint);
if (0 == Size || MAX_PATH <= Size)
goto fail;
mountpoint = 0;
Size = (Size + 1) * sizeof(WCHAR);
}
ch = fsp_fuse_obj_alloc(env, sizeof *ch + Size);
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;
memcpy(ch->MountPoint, MountPointBuf, Size);
return ch;
@ -261,9 +283,17 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
//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;
FUSE_CAP_DONT_MASK |
FSP_FUSE_CAP_READDIR_PLUS |
FSP_FUSE_CAP_READ_ONLY |
FSP_FUSE_CAP_CASE_INSENSITIVE;
if (0 != f->ops.init)
{
context->private_data = f->data = f->ops.init(&conn);
f->VolumeParams.ReadOnlyVolume = 0 != (conn.want & FSP_FUSE_CAP_READ_ONLY);
f->VolumeParams.CaseSensitiveSearch = 0 == (conn.want & FSP_FUSE_CAP_CASE_INSENSITIVE);
f->conn_want = conn.want;
}
f->fsinit = TRUE;
if (0 != f->ops.statfs)
{
@ -278,10 +308,12 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
goto fail;
}
if (stbuf.f_frsize > FSP_FUSE_SECTORSIZE_MAX)
stbuf.f_frsize = FSP_FUSE_SECTORSIZE_MAX;
if (0 == f->VolumeParams.SectorSize)
if (0 == f->VolumeParams.SectorSize && 0 != stbuf.f_frsize)
f->VolumeParams.SectorSize = (UINT16)stbuf.f_frsize;
#if 0
if (0 == f->VolumeParams.SectorsPerAllocationUnit && 0 != stbuf.f_frsize)
f->VolumeParams.SectorsPerAllocationUnit = (UINT16)(stbuf.f_bsize / stbuf.f_frsize);
#endif
if (0 == f->VolumeParams.MaxComponentLength)
f->VolumeParams.MaxComponentLength = (UINT16)stbuf.f_namemax;
}
@ -313,9 +345,8 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
}
/* 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)
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN ||
f->VolumeParams.SectorSize > FSP_FUSE_SECTORSIZE_MAX)
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MAX;
if (f->VolumeParams.SectorsPerAllocationUnit == 0)
f->VolumeParams.SectorsPerAllocationUnit = 1;
@ -419,14 +450,12 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
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 SectorSize=N sector size for Windows (512-4096, deflt: 4096)\n"
" -o SectorsPerAllocationUnit=N sectors per allocation unit (deflt: 1)\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 ReadOnlyVolume file system is read only\n"
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n"
" --FileSystemName=FSN Name of user mode file system\n");
opt_data->help = 1;
@ -479,6 +508,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
memset(&opt_data, 0, sizeof opt_data);
opt_data.env = env;
opt_data.VolumeParams.FileInfoTimeout = 1000; /* default FileInfoTimeout for FUSE file systems */
if (-1 == fsp_fuse_opt_parse(env, args, &opt_data, fsp_fuse_core_opts, fsp_fuse_core_opt_proc))
return 0;
@ -509,12 +539,12 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
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.CaseSensitiveSearch = TRUE;
opt_data.VolumeParams.PersistentAcls = TRUE;
opt_data.VolumeParams.ReparsePoints = TRUE;
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
opt_data.VolumeParams.NamedStreams = FALSE;
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
opt_data.VolumeParams.ReadOnlyVolume = FALSE;
opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])

View File

@ -311,28 +311,34 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
}
#define fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, fi, PUid, PGid, PMode, FileInfo)\
fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, PUid, PGid, PMode, 0, FileInfo)
fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, FileInfo)
static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
const char *PosixPath, struct fuse_file_info *fi,
const char *PosixPath, struct fuse_file_info *fi, const struct fuse_stat *stbufp,
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode, PUINT32 PDev,
FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;
UINT64 AllocationUnit;
struct fuse_stat stbuf;
int err;
memset(&stbuf, 0, sizeof stbuf);
if (0 != f->ops.fgetattr && 0 != fi && -1 != fi->fh)
err = f->ops.fgetattr(PosixPath, (void *)&stbuf, fi);
else if (0 != f->ops.getattr)
err = f->ops.getattr(PosixPath, (void *)&stbuf);
if (0 != stbufp)
memcpy(&stbuf, stbufp, sizeof stbuf);
else
return STATUS_INVALID_DEVICE_REQUEST;
{
int err;
if (0 != err)
return fsp_fuse_ntstatus_from_errno(f->env, err);
memset(&stbuf, 0, sizeof stbuf);
if (0 != f->ops.fgetattr && 0 != fi && -1 != fi->fh)
err = f->ops.fgetattr(PosixPath, (void *)&stbuf, fi);
else if (0 != f->ops.getattr)
err = f->ops.getattr(PosixPath, (void *)&stbuf);
else
return STATUS_INVALID_DEVICE_REQUEST;
if (0 != err)
return fsp_fuse_ntstatus_from_errno(f->env, err);
}
if (f->set_umask)
stbuf.st_mode = (stbuf.st_mode & 0170000) | (0777 & ~f->umask);
@ -513,7 +519,7 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointEx(FSP_FILE_SYSTEM *FileSystem,
SIZE_T Size;
NTSTATUS Result;
Result = fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi,
Result = fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0,
&Uid, &Gid, &Mode, &Dev, &FileInfo);
if (!NT_SUCCESS(Result))
return Result;
@ -1576,6 +1582,17 @@ static int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
memset(DirInfo, 0, sizeof *DirInfo);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + SizeW * sizeof(WCHAR));
if (dh->ReaddirPlus && 0 != stbuf)
{
UINT32 Uid, Gid, Mode;
NTSTATUS Result0;
Result0 = fsp_fuse_intf_GetFileInfoFunnel(dh->FileSystem, 0, 0, stbuf,
&Uid, &Gid, &Mode, 0, &DirInfo->FileInfo);
if (NT_SUCCESS(Result0))
DirInfo->Padding[0] = 1; /* HACK: remember that the FileInfo is valid */
}
return !FspFileSystemFillDirectoryBuffer(&filedesc->DirBuffer, DirInfo, &dh->Result);
}
@ -1619,44 +1636,53 @@ static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem,
DirInfo = (FSP_FSCTL_DIR_INFO *)(Buffer + *Index);
SizeW = (DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR);
if (1 == SizeW && L'.' == DirInfo->FileNameBuf[0])
if (DirInfo->Padding[0])
{
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 1 : PosixName;
SavedPathChar = *PosixPathEnd;
*PosixPathEnd = '\0';
}
else
if (2 == SizeW && L'.' == DirInfo->FileNameBuf[0] && L'.' == DirInfo->FileNameBuf[1])
{
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 2 : PosixName;
while (PosixPath < PosixPathEnd && '/' != *PosixPathEnd)
PosixPathEnd--;
if (PosixPath == PosixPathEnd)
PosixPathEnd++;
SavedPathChar = *PosixPathEnd;
*PosixPathEnd = '\0';
/* DirInfo has been filled already! */
DirInfo->Padding[0] = 0;
}
else
{
PosixPathEnd = 0;
SizeA = WideCharToMultiByte(CP_UTF8, 0, DirInfo->FileNameBuf, SizeW, PosixName, 255, 0, 0);
if (0 == SizeA)
if (1 == SizeW && L'.' == DirInfo->FileNameBuf[0])
{
/* this should never happen because we just converted using MultiByteToWideChar */
Result = STATUS_OBJECT_NAME_INVALID;
goto exit;
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 1 : PosixName;
SavedPathChar = *PosixPathEnd;
*PosixPathEnd = '\0';
}
PosixName[SizeA] = '\0';
else
if (2 == SizeW && L'.' == DirInfo->FileNameBuf[0] && L'.' == DirInfo->FileNameBuf[1])
{
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 2 : PosixName;
while (PosixPath < PosixPathEnd && '/' != *PosixPathEnd)
PosixPathEnd--;
if (PosixPath == PosixPathEnd)
PosixPathEnd++;
SavedPathChar = *PosixPathEnd;
*PosixPathEnd = '\0';
}
else
{
PosixPathEnd = 0;
SizeA = WideCharToMultiByte(CP_UTF8, 0, DirInfo->FileNameBuf, SizeW, PosixName, 255, 0, 0);
if (0 == SizeA)
{
/* this should never happen because we just converted using MultiByteToWideChar */
Result = STATUS_OBJECT_NAME_INVALID;
goto exit;
}
PosixName[SizeA] = '\0';
}
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0,
&Uid, &Gid, &Mode, &DirInfo->FileInfo);
if (!NT_SUCCESS(Result))
goto exit;
if (0 != PosixPathEnd)
*PosixPathEnd = SavedPathChar;
}
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0,
&Uid, &Gid, &Mode, &DirInfo->FileInfo);
if (!NT_SUCCESS(Result))
goto exit;
if (0 != PosixPathEnd)
*PosixPathEnd = SavedPathChar;
FspPosixDecodeWindowsPath(DirInfo->FileNameBuf, SizeW);
}
@ -1683,6 +1709,8 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
{
memset(&dh, 0, sizeof dh);
dh.filedesc = filedesc;
dh.FileSystem = FileSystem;
dh.ReaddirPlus = 0 != (f->conn_want & FSP_FUSE_CAP_READDIR_PLUS);
dh.Result = STATUS_SUCCESS;
if (0 != f->ops.readdir)

View File

@ -40,12 +40,13 @@ struct fuse
int rellinks;
struct fuse_operations ops;
void *data;
unsigned conn_want;
BOOLEAN fsinit;
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 */
};
@ -66,8 +67,12 @@ struct fsp_fuse_file_desc
struct fuse_dirhandle
{
/* ReadDirectory */
struct fsp_fuse_file_desc *filedesc;
FSP_FILE_SYSTEM *FileSystem;
BOOLEAN ReaddirPlus;
NTSTATUS Result;
/* CanDelete */
BOOLEAN DotFiles, HasChild;
};

View File

@ -284,7 +284,8 @@ static DWORD FspNpGetCredentialsKind(PWSTR RemoteName, PDWORD PCredentialsKind)
memcpy(ClassNameBuf, ClassName, ClassNameLen * sizeof(WCHAR));
ClassNameBuf[ClassNameLen] = '\0';
NpResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY, 0, KEY_READ, &RegKey);
NpResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY,
0, LAUNCHER_REGKEY_WOW64 | KEY_READ, &RegKey);
if (ERROR_SUCCESS != NpResult)
goto exit;

View File

@ -163,3 +163,47 @@ exit:
return Result;
}
FSP_API NTSTATUS FspVersion(PUINT32 PVersion)
{
static UINT32 Version;
if (0 == Version)
{
/*
* This check is not thread-safe, but that should be ok.
* Two threads competing to read the version will read
* the same value from the Version resource.
*/
extern HINSTANCE DllInstance;
WCHAR ModuleFileName[MAX_PATH];
PVOID VersionInfo;
DWORD Size;
VS_FIXEDFILEINFO *FixedFileInfo = 0;
if (0 != GetModuleFileNameW(DllInstance, ModuleFileName, MAX_PATH))
{
Size = GetFileVersionInfoSizeW(ModuleFileName, &Size/*dummy*/);
if (0 < Size)
{
VersionInfo = MemAlloc(Size);
if (0 != VersionInfo &&
GetFileVersionInfoW(ModuleFileName, 0, Size, VersionInfo) &&
VerQueryValueW(VersionInfo, L"\\", &FixedFileInfo, &Size))
{
/* 32-bit store should be atomic! */
Version = FixedFileInfo->dwFileVersionMS;
}
MemFree(VersionInfo);
}
}
if (0 == FixedFileInfo)
return STATUS_UNSUCCESSFUL;
}
*PVersion = Version;
return STATUS_SUCCESS;
}

View File

@ -19,7 +19,6 @@
#include <sddl.h>
#define PROGNAME "WinFsp.Launcher"
#define REGKEY LAUNCHER_REGKEY
BOOL CreateOverlappedPipe(
PHANDLE PReadPipe, PHANDLE PWritePipe, PSECURITY_ATTRIBUTES SecurityAttributes, DWORD Size,
@ -441,7 +440,8 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
goto exit;
}
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" REGKEY, 0, KEY_READ, &RegKey);
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY,
0, LAUNCHER_REGKEY_WOW64 | KEY_READ, &RegKey);
if (ERROR_SUCCESS != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);

View File

@ -21,7 +21,8 @@
#include <winfsp/winfsp.h>
#include <shared/minimal.h>
#define LAUNCHER_REGKEY "SYSTEM\\CurrentControlSet\\Services\\WinFsp.Launcher\\Services"
#define LAUNCHER_REGKEY "Software\\WinFsp\\Services"
#define LAUNCHER_REGKEY_WOW64 KEY_WOW64_32KEY
#define LAUNCHER_STOP_TIMEOUT 5500
#define LAUNCHER_KILL_TIMEOUT 5000

View File

@ -80,8 +80,18 @@ static NTSTATUS FspFsvolClose(
FspFileDescDelete(FileDesc); /* this will also close the MainFileObject if any */
FspFileNodeDereference(FileNode);
/* if we are closing files in the context of a rename make it synchronous */
if (FspFsvolDeviceFileRenameIsAcquiredExclusive(FsvolDeviceObject))
{
/* acquire ownership of the Request */
Request->Hint = (UINT_PTR)Irp;
FspIrpSetRequest(Irp, Request);
return FSP_STATUS_IOQ_POST_BEST_EFFORT;
}
/*
* Post as a BestEffort work request. This allows us to complete our own IRP
* Post as a BestEffort WORK request. This allows us to complete our own IRP
* and return immediately.
*/
FspIopPostWorkRequestBestEffort(FsvolDeviceObject, Request);

View File

@ -41,6 +41,7 @@ VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
BOOLEAN FspFsvolDeviceFileRenameIsAcquiredExclusive(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject);
NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject,
@ -80,6 +81,7 @@ VOID FspDeviceDeleteAll(VOID);
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameSetOwner)
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameRelease)
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameReleaseOwner)
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameIsAcquiredExclusive)
#pragma alloc_text(PAGE, FspFsvolDeviceLockContextTable)
#pragma alloc_text(PAGE, FspFsvolDeviceUnlockContextTable)
#pragma alloc_text(PAGE, FspFsvolDeviceCopyContextList)
@ -574,6 +576,15 @@ VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Own
ExReleaseResourceForThreadLite(&FsvolDeviceExtension->FileRenameResource, (ERESOURCE_THREAD)Owner);
}
BOOLEAN FspFsvolDeviceFileRenameIsAcquiredExclusive(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
return ExIsResourceAcquiredExclusiveLite(&FsvolDeviceExtension->FileRenameResource);
}
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();

View File

@ -78,6 +78,7 @@ enum
{
/* QueryDirectory */
RequestIrp = 0,
RequestCookie = 1,
RequestMdl = 1,
RequestAddress = 2,
RequestProcess = 3,
@ -88,6 +89,7 @@ enum
/* DirectoryControlComplete retry */
RequestDirInfoChangeNumber = 0,
};
FSP_FSCTL_STATIC_ASSERT(RequestCookie == RequestMdl, "");
static NTSTATUS FspFsvolQueryDirectoryCopy(
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
@ -833,41 +835,67 @@ NTSTATUS FspFsvolDirectoryControlPrepare(
{
PAGED_CODE();
NTSTATUS Result;
PMDL Mdl = 0;
PVOID Address;
PEPROCESS Process;
Mdl = IoAllocateMdl(
Irp->AssociatedIrp.SystemBuffer,
Request->Req.QueryDirectory.Length,
FALSE, FALSE, 0);
if (0 == Mdl)
return STATUS_INSUFFICIENT_RESOURCES;
MmBuildMdlForNonPagedPool(Mdl);
/* map the MDL into user-mode */
Result = FspMapLockedPagesInUserMode(Mdl, &Address, 0);
if (!NT_SUCCESS(Result))
if (FspQueryDirectoryIrpShouldUseProcessBuffer(Irp, Request->Req.QueryDirectory.Length))
{
if (0 != Mdl)
IoFreeMdl(Mdl);
NTSTATUS Result;
PVOID Cookie;
PVOID Address;
PEPROCESS Process;
return Result;
Result = FspProcessBufferAcquire(Request->Req.QueryDirectory.Length, &Cookie, &Address);
if (!NT_SUCCESS(Result))
return Result;
/* get a pointer to the current process so that we can release the buffer later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Request->Req.QueryDirectory.Address = (UINT64)(UINT_PTR)Address;
FspIopRequestContext(Request, RequestCookie) = (PVOID)((UINT_PTR)Cookie | 1);
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
return STATUS_SUCCESS;
}
else
{
NTSTATUS Result;
PMDL Mdl = 0;
PVOID Address;
PEPROCESS Process;
/* get a pointer to the current process so that we can unmap the address later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Mdl = IoAllocateMdl(
Irp->AssociatedIrp.SystemBuffer,
Request->Req.QueryDirectory.Length,
FALSE, FALSE, 0);
if (0 == Mdl)
return STATUS_INSUFFICIENT_RESOURCES;
Request->Req.QueryDirectory.Address = (UINT64)(UINT_PTR)Address;
MmBuildMdlForNonPagedPool(Mdl);
FspIopRequestContext(Request, RequestMdl) = Mdl;
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
/* map the MDL into user-mode */
Result = FspMapLockedPagesInUserMode(Mdl, &Address, 0);
if (!NT_SUCCESS(Result))
{
if (0 != Mdl)
IoFreeMdl(Mdl);
return STATUS_SUCCESS;
return Result;
}
/* get a pointer to the current process so that we can unmap the address later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Request->Req.QueryDirectory.Address = (UINT64)(UINT_PTR)Address;
FspIopRequestContext(Request, RequestMdl) = Mdl;
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
return STATUS_SUCCESS;
}
}
NTSTATUS FspFsvolDirectoryControlComplete(
@ -910,6 +938,23 @@ NTSTATUS FspFsvolDirectoryControlComplete(
if (FspFsctlTransactQueryDirectoryKind == Request->Kind)
{
if ((UINT_PTR)FspIopRequestContext(Request, RequestCookie) & 1)
{
PVOID Address = FspIopRequestContext(Request, RequestAddress);
ASSERT(0 != Address);
try
{
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Address, Response->IoStatus.Information);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Result = GetExceptionCode();
Result = FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
FSP_RETURN();
}
}
DirInfoChangeNumber = FspFileNodeDirInfoChangeNumber(FileNode);
Request->Kind = FspFsctlTransactReservedKind;
FspIopResetRequest(Request, 0);
@ -1010,29 +1055,56 @@ static VOID FspFsvolQueryDirectoryRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
PAGED_CODE();
PIRP Irp = Context[RequestIrp];
PMDL Mdl = Context[RequestMdl];
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
if (0 != Address)
if ((UINT_PTR)Context[RequestCookie] & 1)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
PVOID Cookie = (PVOID)((UINT_PTR)Context[RequestCookie] & ~1);
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
if (0 != Address)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
if (Attach)
KeStackAttachProcess(Process, &ApcState);
MmUnmapLockedPages(Address, Mdl);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
ObDereferenceObject(Process);
if (Attach)
KeStackAttachProcess(Process, &ApcState);
FspProcessBufferRelease(Cookie, Address);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
}
}
else
{
PMDL Mdl = Context[RequestMdl];
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
if (0 != Mdl)
IoFreeMdl(Mdl);
if (0 != Address)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
if (Attach)
KeStackAttachProcess(Process, &ApcState);
MmUnmapLockedPages(Address, Mdl);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
}
if (0 != Mdl)
IoFreeMdl(Mdl);
}
if (0 != Irp)
{

View File

@ -46,6 +46,10 @@ NTSTATUS DriverEntry(
FspDriverMultiVersionInitialize();
Result = FspProcessBufferInitialize();
if (!NT_SUCCESS(Result))
FSP_RETURN();
FspDriverObject = DriverObject;
ExInitializeResourceLite(&FspDeviceGlobalResource);
@ -59,14 +63,21 @@ NTSTATUS DriverEntry(
&DeviceSddl, &FspFsctlDeviceClassGuid,
&FspFsctlDiskDeviceObject);
if (!NT_SUCCESS(Result))
{
FspProcessBufferFinalize();
FSP_RETURN();
}
RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
&DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
&DeviceSddl, &FspFsctlDeviceClassGuid,
&FspFsctlNetDeviceObject);
if (!NT_SUCCESS(Result))
FSP_RETURN(FspDeviceDelete(FspFsctlDiskDeviceObject));
{
FspDeviceDelete(FspFsctlDiskDeviceObject);
FspProcessBufferFinalize();
FSP_RETURN();
}
Result = FspDeviceInitialize(FspFsctlDiskDeviceObject);
ASSERT(STATUS_SUCCESS == Result);
Result = FspDeviceInitialize(FspFsctlNetDeviceObject);
@ -178,6 +189,7 @@ static VOID FspDriverMultiVersionInitialize(VOID)
{
FspProcessorCount = KeQueryActiveProcessorCount(0);
#pragma prefast(suppress:30035, "FspDriverMultiVersionInitialize is called from DriverEntry")
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
if (RtlIsNtDdiVersionAvailable(NTDDI_WIN7))
@ -206,6 +218,8 @@ VOID FspUnload(
ExDeleteResourceLite(&FspDeviceGlobalResource);
FspDriverObject = 0;
FspProcessBufferFinalize();
#pragma prefast(suppress:28175, "We are in DriverUnload: ok to access DriverName")
FSP_LEAVE_VOID("DriverName=\"%wZ\"",
&DriverObject->DriverName);

View File

@ -601,6 +601,14 @@ VOID FspIrpHookReset(PIRP Irp);
PVOID FspIrpHookContext(PVOID Context);
NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
/* process buffers */
#define FspProcessBufferSizeMax (64 * 1024)
NTSTATUS FspProcessBufferInitialize(VOID);
VOID FspProcessBufferFinalize(VOID);
VOID FspProcessBufferCollect(HANDLE ProcessId);
NTSTATUS FspProcessBufferAcquire(SIZE_T BufferSize, PVOID *PBufferCookie, PVOID *PBuffer);
VOID FspProcessBufferRelease(PVOID BufferCookie, PVOID Buffer);
/* IRP context */
#define FspIrpTimestampInfinity ((ULONG)-1L)
#define FspIrpTimestamp(Irp) \
@ -1064,6 +1072,7 @@ VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
BOOLEAN FspFsvolDeviceFileRenameIsAcquiredExclusive(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject);
NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject,
@ -1112,6 +1121,35 @@ VOID FspDeviceGlobalUnlock(VOID)
//(FILE_DEVICE_DISK_FILE_SYSTEM == (DeviceObject)->DeviceType ?\
// STATUS_VOLUME_DISMOUNTED : STATUS_DEVICE_NOT_CONNECTED)
/* process buffers conditional usage */
static inline
BOOLEAN FspReadIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
{
ASSERT(0 != Irp);
#if DBG
return DEBUGTEST(50) ||
#else
return FspProcessBufferSizeMax >= BufferSize ||
#endif
FspFsvolDeviceExtension(IoGetCurrentIrpStackLocation(Irp)->DeviceObject)->
VolumeParams.AlwaysUseDoubleBuffering;
}
static inline
BOOLEAN FspWriteIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
{
ASSERT(0 != Irp);
#if DBG
return DEBUGTEST(50);
#else
return FspProcessBufferSizeMax >= BufferSize;
#endif
}
static inline
BOOLEAN FspQueryDirectoryIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
{
return FspReadIrpShouldUseProcessBuffer(Irp, BufferSize);
}
/* volume management */
#define FspVolumeTransactEarlyTimeout (1 * 10000ULL)
NTSTATUS FspVolumeCreate(

View File

@ -1243,6 +1243,50 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp
}
}
/* flush and purge cleaned up but still open files affected by rename (github issue #45) */
{
PIRP TopLevelIrp;
IO_STATUS_BLOCK IoStatus;
/* reset the top-level IRP to avoid deadlock on the FileNodes' resources */
TopLevelIrp = IoGetTopLevelIrp();
IoSetTopLevelIrp(0);
/* enumerate in reverse order so that files are flushed before containing directories */
for (
DescendantFileNodeIndex = DescendantFileNodeCount - 1;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex--)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
HasHandles = (UINT_PTR)DescendantFileNode & 1;
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
if (HasHandles)
continue;
if (CheckingOldName &&
(DescendantFileNode->FileName.Length <= FileName->Length ||
L'\\' != DescendantFileNode->FileName.Buffer[FileName->Length / sizeof(WCHAR)]))
continue;
if (MmDoesFileHaveUserWritableReferences(&DescendantFileNode->NonPaged->SectionObjectPointers))
continue;
/*
* There are no handles and no writable user mappings. [Ideally we would want to know
* that there are no handles and no user mappings, period. Is there an DDI/method to
* do that?] There may be a read-only user mapping, but in this case CcFlushCache
* should be a no-op and MmForceSectionClosed will fail (which is fine).
*/
ASSERT(DescendantFileNode != FileNode && DescendantFileNode->MainFileNode != FileNode);
FspCcFlushCache(&DescendantFileNode->NonPaged->SectionObjectPointers, 0, 0, &IoStatus);
MmForceSectionClosed(&DescendantFileNode->NonPaged->SectionObjectPointers, FALSE);
}
IoSetTopLevelIrp(TopLevelIrp);
}
/* break any Batch or Handle oplocks on descendants */
Result = STATUS_SUCCESS;
for (
@ -2073,6 +2117,8 @@ NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName)
{
PAGED_CODE();
if (&FileDesc->DirectoryMarker == FileName)
return STATUS_SUCCESS;

277
src/sys/psbuffer.c Normal file
View File

@ -0,0 +1,277 @@
/**
* @file sys/psbuffer.c
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* 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 <sys/driver.h>
#define SafeGetCurrentProcessId() (PsGetProcessId(PsGetCurrentProcess()))
#define FspProcessBufferCountMax (2 >= FspProcessorCount ? 2 : (8 <= FspProcessorCount ? 8 : FspProcessorCount))
#define ProcessBufferBucketCount 61 /* are you going to have that many file systems? */
typedef struct _FSP_PROCESS_BUFFER_ITEM
{
struct _FSP_PROCESS_BUFFER_ITEM *DictNext;
struct _FSP_PROCESS_BUFFER_LIST_ENTRY *BufferList;
ULONG BufferCount;
HANDLE ProcessId;
} FSP_PROCESS_BUFFER_ITEM;
typedef struct _FSP_PROCESS_BUFFER_LIST_ENTRY
{
struct _FSP_PROCESS_BUFFER_LIST_ENTRY *Next;
PVOID Buffer;
} FSP_PROCESS_BUFFER_LIST_ENTRY;
static KSPIN_LOCK ProcessBufferLock;
static FSP_PROCESS_BUFFER_ITEM *ProcessBufferBuckets[ProcessBufferBucketCount];
static VOID FspProcessBufferNotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create);
static inline FSP_PROCESS_BUFFER_ITEM *FspProcessBufferLookupItemAtDpcLevel(HANDLE ProcessId)
{
FSP_PROCESS_BUFFER_ITEM *Item = 0;
ULONG HashIndex = FspHashMixPointer(ProcessId) % ProcessBufferBucketCount;
for (FSP_PROCESS_BUFFER_ITEM *ItemX = ProcessBufferBuckets[HashIndex]; ItemX; ItemX = ItemX->DictNext)
if (ItemX->ProcessId == ProcessId)
{
Item = ItemX;
break;
}
return Item;
}
static inline VOID FspProcessBufferAddItemAtDpcLevel(FSP_PROCESS_BUFFER_ITEM *Item)
{
ULONG HashIndex = FspHashMixPointer(Item->ProcessId) % ProcessBufferBucketCount;
#if DBG
for (FSP_PROCESS_BUFFER_ITEM *ItemX = ProcessBufferBuckets[HashIndex]; ItemX; ItemX = ItemX->DictNext)
ASSERT(ItemX->ProcessId != Item->ProcessId);
#endif
Item->DictNext = ProcessBufferBuckets[HashIndex];
ProcessBufferBuckets[HashIndex] = Item;
}
static inline FSP_PROCESS_BUFFER_ITEM *FspProcessBufferRemoveItemAtDpcLevel(HANDLE ProcessId)
{
FSP_PROCESS_BUFFER_ITEM *Item = 0;
ULONG HashIndex = FspHashMixPointer(ProcessId) % ProcessBufferBucketCount;
for (FSP_PROCESS_BUFFER_ITEM **P = &ProcessBufferBuckets[HashIndex]; *P; P = &(*P)->DictNext)
if ((*P)->ProcessId == ProcessId)
{
Item = *P;
*P = (*P)->DictNext;
break;
}
return Item;
}
static inline VOID FspProcessBufferReuseEntry(HANDLE ProcessId,
FSP_PROCESS_BUFFER_LIST_ENTRY *BufferEntry)
{
KIRQL Irql;
FSP_PROCESS_BUFFER_ITEM *Item;
KeAcquireSpinLock(&ProcessBufferLock, &Irql);
Item = FspProcessBufferLookupItemAtDpcLevel(ProcessId);
if (0 != Item)
{
BufferEntry->Next = Item->BufferList;
Item->BufferList = BufferEntry;
}
KeReleaseSpinLock(&ProcessBufferLock, Irql);
if (0 == Item)
{
if (0 != BufferEntry->Buffer)
{
SIZE_T BufferSize = 0;
ZwFreeVirtualMemory(ZwCurrentProcess(), &BufferEntry->Buffer, &BufferSize, MEM_RELEASE);
}
FspFree(BufferEntry);
}
}
NTSTATUS FspProcessBufferInitialize(VOID)
{
KeInitializeSpinLock(&ProcessBufferLock);
return PsSetCreateProcessNotifyRoutine(FspProcessBufferNotifyRoutine, FALSE);
}
VOID FspProcessBufferFinalize(VOID)
{
PsSetCreateProcessNotifyRoutine(FspProcessBufferNotifyRoutine, TRUE);
}
static VOID FspProcessBufferNotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)
{
if (!Create)
FspProcessBufferCollect(ProcessId);
}
VOID FspProcessBufferCollect(HANDLE ProcessId)
{
KIRQL Irql;
FSP_PROCESS_BUFFER_ITEM *Item = 0;
KeAcquireSpinLock(&ProcessBufferLock, &Irql);
Item = FspProcessBufferRemoveItemAtDpcLevel(ProcessId);
KeReleaseSpinLock(&ProcessBufferLock, Irql);
if (0 != Item)
{
DEBUGLOG("pid=%ld", (ULONG)(UINT_PTR)ProcessId);
for (FSP_PROCESS_BUFFER_LIST_ENTRY *P = Item->BufferList, *Next; P; P = Next)
{
Next = P->Next;
FspFree(P);
}
FspFree(Item);
}
}
NTSTATUS FspProcessBufferAcquire(SIZE_T BufferSize, PVOID *PBufferCookie, PVOID *PBuffer)
{
if (FspProcessBufferSizeMax >= BufferSize)
{
HANDLE ProcessId = SafeGetCurrentProcessId();
KIRQL Irql;
FSP_PROCESS_BUFFER_ITEM *Item, *NewItem;
FSP_PROCESS_BUFFER_LIST_ENTRY *BufferEntry = 0;
BOOLEAN AllocNoReuse;
NTSTATUS Result;
KeAcquireSpinLock(&ProcessBufferLock, &Irql);
Item = FspProcessBufferLookupItemAtDpcLevel(ProcessId);
if (0 != Item)
{
BufferEntry = Item->BufferList;
if (0 != BufferEntry)
Item->BufferList = BufferEntry->Next;
}
AllocNoReuse = 0 == BufferEntry &&
(0 != Item && FspProcessBufferCountMax <= Item->BufferCount);
KeReleaseSpinLock(&ProcessBufferLock, Irql);
if (AllocNoReuse)
goto alloc_no_reuse;
if (0 == BufferEntry)
{
*PBufferCookie = 0;
*PBuffer = 0;
BufferEntry = FspAllocNonPaged(sizeof *BufferEntry);
if (0 == BufferEntry)
return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(BufferEntry, sizeof *BufferEntry);
NewItem = FspAllocNonPaged(sizeof *NewItem);
if (0 == NewItem)
{
FspFree(BufferEntry);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(NewItem, sizeof *NewItem);
KeAcquireSpinLock(&ProcessBufferLock, &Irql);
Item = FspProcessBufferLookupItemAtDpcLevel(ProcessId);
if (0 == Item)
{
Item = NewItem;
NewItem = 0;
Item->BufferCount = 1;
Item->ProcessId = ProcessId;
FspProcessBufferAddItemAtDpcLevel(Item);
}
else if (FspProcessBufferCountMax > Item->BufferCount)
Item->BufferCount++;
else
AllocNoReuse = TRUE;
KeReleaseSpinLock(&ProcessBufferLock, Irql);
if (0 != NewItem)
FspFree(NewItem);
if (AllocNoReuse)
{
FspFree(BufferEntry);
goto alloc_no_reuse;
}
}
if (0 == BufferEntry->Buffer)
{
BufferSize = FspProcessBufferSizeMax;
Result = ZwAllocateVirtualMemory(ZwCurrentProcess(),
&BufferEntry->Buffer, 0, &BufferSize, MEM_COMMIT, PAGE_READWRITE);
if (!NT_SUCCESS(Result))
{
/* failed to allocate actual buffer; reuse BufferEntry */
FspProcessBufferReuseEntry(ProcessId, BufferEntry);
return Result;
}
}
*PBufferCookie = BufferEntry;
*PBuffer = BufferEntry->Buffer;
return STATUS_SUCCESS;
}
else
{
alloc_no_reuse:
*PBufferCookie = 0;
*PBuffer = 0;
return ZwAllocateVirtualMemory(ZwCurrentProcess(),
PBuffer, 0, &BufferSize, MEM_COMMIT, PAGE_READWRITE);
}
}
VOID FspProcessBufferRelease(PVOID BufferCookie, PVOID Buffer)
{
if (0 != BufferCookie)
{
HANDLE ProcessId = SafeGetCurrentProcessId();
FSP_PROCESS_BUFFER_LIST_ENTRY *BufferEntry = BufferCookie;
ASSERT(Buffer == BufferEntry->Buffer);
FspProcessBufferReuseEntry(ProcessId, BufferEntry);
}
else
{
SIZE_T BufferSize = 0;
ZwFreeVirtualMemory(ZwCurrentProcess(), &Buffer, &BufferSize, MEM_RELEASE);
}
}

View File

@ -44,10 +44,12 @@ enum
{
/* ReadNonCached */
RequestIrp = 0,
RequestCookie = 1,
RequestSafeMdl = 1,
RequestAddress = 2,
RequestProcess = 3,
};
FSP_FSCTL_STATIC_ASSERT(RequestCookie == RequestSafeMdl, "");
static NTSTATUS FspFsvolRead(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
@ -346,41 +348,70 @@ NTSTATUS FspFsvolReadPrepare(
{
PAGED_CODE();
NTSTATUS Result;
FSP_SAFE_MDL *SafeMdl = 0;
PVOID Address;
PEPROCESS Process;
/* create a "safe" MDL if necessary */
if (!FspSafeMdlCheck(Irp->MdlAddress))
if (FspReadIrpShouldUseProcessBuffer(Irp, Request->Req.Read.Length))
{
Result = FspSafeMdlCreate(Irp->MdlAddress, IoWriteAccess, &SafeMdl);
NTSTATUS Result;
PVOID Cookie;
PVOID Address;
PEPROCESS Process;
if (0 == MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority))
return STATUS_INSUFFICIENT_RESOURCES; /* something is seriously screwy! */
Result = FspProcessBufferAcquire(Request->Req.Read.Length, &Cookie, &Address);
if (!NT_SUCCESS(Result))
return Result;
}
/* map the MDL into user-mode */
Result = FspMapLockedPagesInUserMode(
0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress, &Address, 0);
if (!NT_SUCCESS(Result))
/* get a pointer to the current process so that we can release the buffer later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Request->Req.Read.Address = (UINT64)(UINT_PTR)Address;
FspIopRequestContext(Request, RequestCookie) = (PVOID)((UINT_PTR)Cookie | 1);
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
return STATUS_SUCCESS;
}
else
{
if (0 != SafeMdl)
FspSafeMdlDelete(SafeMdl);
NTSTATUS Result;
FSP_SAFE_MDL *SafeMdl = 0;
PVOID Address;
PEPROCESS Process;
return Result;
/* create a "safe" MDL if necessary */
if (!FspSafeMdlCheck(Irp->MdlAddress))
{
Result = FspSafeMdlCreate(Irp->MdlAddress, IoWriteAccess, &SafeMdl);
if (!NT_SUCCESS(Result))
return Result;
}
/* map the MDL into user-mode */
Result = FspMapLockedPagesInUserMode(
0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress, &Address, 0);
if (!NT_SUCCESS(Result))
{
if (0 != SafeMdl)
FspSafeMdlDelete(SafeMdl);
return Result;
}
/* get a pointer to the current process so that we can unmap the address later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Request->Req.Read.Address = (UINT64)(UINT_PTR)Address;
FspIopRequestContext(Request, RequestSafeMdl) = SafeMdl;
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
return STATUS_SUCCESS;
}
/* get a pointer to the current process so that we can unmap the address later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Request->Req.Read.Address = (UINT64)(UINT_PTR)Address;
FspIopRequestContext(Request, RequestSafeMdl) = SafeMdl;
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
return STATUS_SUCCESS;
}
NTSTATUS FspFsvolReadComplete(
@ -400,15 +431,36 @@ NTSTATUS FspFsvolReadComplete(
if (Response->IoStatus.Information > Request->Req.Read.Length)
FSP_RETURN(Result = STATUS_INTERNAL_ERROR);
FSP_SAFE_MDL *SafeMdl = FspIopRequestContext(Request, RequestSafeMdl);
if ((UINT_PTR)FspIopRequestContext(Request, RequestCookie) & 1)
{
PVOID Address = FspIopRequestContext(Request, RequestAddress);
PVOID SystemAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
ASSERT(0 != Address);
try
{
RtlCopyMemory(SystemAddress, Address, Response->IoStatus.Information);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Result = GetExceptionCode();
Result = FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
FSP_RETURN();
}
}
else
{
FSP_SAFE_MDL *SafeMdl = FspIopRequestContext(Request, RequestSafeMdl);
if (0 != SafeMdl)
FspSafeMdlCopyBack(SafeMdl);
}
PFILE_OBJECT FileObject = IrpSp->FileObject;
LARGE_INTEGER ReadOffset = IrpSp->Parameters.Read.ByteOffset;
BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
BOOLEAN SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
if (0 != SafeMdl)
FspSafeMdlCopyBack(SafeMdl);
/* if we are top-level */
if (0 == FspIrpTopFlags(Irp))
{
@ -442,29 +494,56 @@ static VOID FspFsvolReadNonCachedRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PV
PAGED_CODE();
PIRP Irp = Context[RequestIrp];
FSP_SAFE_MDL *SafeMdl = Context[RequestSafeMdl];
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
if (0 != Address)
if ((UINT_PTR)Context[RequestCookie] & 1)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
PVOID Cookie = (PVOID)((UINT_PTR)Context[RequestCookie] & ~1);
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
if (0 != Address)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
if (Attach)
KeStackAttachProcess(Process, &ApcState);
MmUnmapLockedPages(Address, 0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
ObDereferenceObject(Process);
if (Attach)
KeStackAttachProcess(Process, &ApcState);
FspProcessBufferRelease(Cookie, Address);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
}
}
else
{
FSP_SAFE_MDL *SafeMdl = Context[RequestSafeMdl];
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
if (0 != SafeMdl)
FspSafeMdlDelete(SafeMdl);
if (0 != Address)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
if (Attach)
KeStackAttachProcess(Process, &ApcState);
MmUnmapLockedPages(Address, 0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
}
if (0 != SafeMdl)
FspSafeMdlDelete(SafeMdl);
}
if (0 != Irp)
{

View File

@ -29,6 +29,8 @@ NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLen
NTSTATUS FspStatisticsCreate(FSP_STATISTICS **PStatistics)
{
PAGED_CODE();
*PStatistics = FspAllocNonPaged(sizeof(FSP_STATISTICS) * FspProcessorCount);
if (0 == *PStatistics)
return STATUS_INSUFFICIENT_RESOURCES;
@ -49,11 +51,15 @@ NTSTATUS FspStatisticsCreate(FSP_STATISTICS **PStatistics)
VOID FspStatisticsDelete(FSP_STATISTICS *Statistics)
{
PAGED_CODE();
FspFree(Statistics);
}
NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLength)
{
PAGED_CODE();
NTSTATUS Result;
ULONG StatLength;

View File

@ -171,6 +171,16 @@ static NTSTATUS FspVolumeCreateNoLock(
}
VolumeParams.FileSystemName[sizeof VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0';
#if !DBG
/*
* In Release builds we hardcode AlwaysUseDoubleBuffering for Reads as we do not want someone
* to use WinFsp to crash Windows.
*
* See http://www.osronline.com/showthread.cfm?link=282037
*/
VolumeParams.AlwaysUseDoubleBuffering = 1;
#endif
/* create volume guid */
Result = FspCreateGuid(&Guid);
if (!NT_SUCCESS(Result))

View File

@ -45,10 +45,12 @@ enum
{
/* WriteNonCached */
RequestIrp = 0,
RequestCookie = 1,
RequestSafeMdl = 1,
RequestAddress = 2,
RequestProcess = 3,
};
FSP_FSCTL_STATIC_ASSERT(RequestCookie == RequestSafeMdl, "");
static NTSTATUS FspFsvolWrite(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
@ -416,41 +418,86 @@ NTSTATUS FspFsvolWritePrepare(
{
PAGED_CODE();
NTSTATUS Result;
FSP_SAFE_MDL *SafeMdl = 0;
PVOID Address;
PEPROCESS Process;
/* create a "safe" MDL if necessary */
if (!FspSafeMdlCheck(Irp->MdlAddress))
if (FspWriteIrpShouldUseProcessBuffer(Irp, Request->Req.Write.Length))
{
Result = FspSafeMdlCreate(Irp->MdlAddress, IoReadAccess, &SafeMdl);
NTSTATUS Result;
PVOID Cookie;
PVOID Address;
PEPROCESS Process;
PVOID SystemAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
if (0 == SystemAddress)
return STATUS_INSUFFICIENT_RESOURCES; /* something is seriously screwy! */
Result = FspProcessBufferAcquire(Request->Req.Write.Length, &Cookie, &Address);
if (!NT_SUCCESS(Result))
return Result;
}
/* map the MDL into user-mode */
Result = FspMapLockedPagesInUserMode(
0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress, &Address, FspMvMdlMappingNoWrite);
if (!NT_SUCCESS(Result))
ASSERT(0 != Address);
try
{
RtlCopyMemory(Address, SystemAddress, Request->Req.Write.Length);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Result = GetExceptionCode();
Result = FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
FspProcessBufferRelease(Cookie, Address);
return Result;
}
/* get a pointer to the current process so that we can release the buffer later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Request->Req.Write.Address = (UINT64)(UINT_PTR)Address;
FspIopRequestContext(Request, RequestCookie) = (PVOID)((UINT_PTR)Cookie | 1);
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
return STATUS_SUCCESS;
}
else
{
if (0 != SafeMdl)
FspSafeMdlDelete(SafeMdl);
NTSTATUS Result;
FSP_SAFE_MDL *SafeMdl = 0;
PVOID Address;
PEPROCESS Process;
return Result;
/* create a "safe" MDL if necessary */
if (!FspSafeMdlCheck(Irp->MdlAddress))
{
Result = FspSafeMdlCreate(Irp->MdlAddress, IoReadAccess, &SafeMdl);
if (!NT_SUCCESS(Result))
return Result;
}
/* map the MDL into user-mode */
Result = FspMapLockedPagesInUserMode(
0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress, &Address, FspMvMdlMappingNoWrite);
if (!NT_SUCCESS(Result))
{
if (0 != SafeMdl)
FspSafeMdlDelete(SafeMdl);
return Result;
}
/* get a pointer to the current process so that we can unmap the address later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Request->Req.Write.Address = (UINT64)(UINT_PTR)Address;
FspIopRequestContext(Request, RequestSafeMdl) = SafeMdl;
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
return STATUS_SUCCESS;
}
/* get a pointer to the current process so that we can unmap the address later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Request->Req.Write.Address = (UINT64)(UINT_PTR)Address;
FspIopRequestContext(Request, RequestSafeMdl) = SafeMdl;
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
return STATUS_SUCCESS;
}
NTSTATUS FspFsvolWriteComplete(
@ -524,29 +571,56 @@ static VOID FspFsvolWriteNonCachedRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
PAGED_CODE();
PIRP Irp = Context[RequestIrp];
FSP_SAFE_MDL *SafeMdl = Context[RequestSafeMdl];
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
if (0 != Address)
if ((UINT_PTR)Context[RequestCookie] & 1)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
PVOID Cookie = (PVOID)((UINT_PTR)Context[RequestCookie] & ~1);
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
if (0 != Address)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
if (Attach)
KeStackAttachProcess(Process, &ApcState);
MmUnmapLockedPages(Address, 0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
ObDereferenceObject(Process);
if (Attach)
KeStackAttachProcess(Process, &ApcState);
FspProcessBufferRelease(Cookie, Address);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
}
}
else
{
FSP_SAFE_MDL *SafeMdl = Context[RequestSafeMdl];
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
if (0 != SafeMdl)
FspSafeMdlDelete(SafeMdl);
if (0 != Address)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
if (Attach)
KeStackAttachProcess(Process, &ApcState);
MmUnmapLockedPages(Address, 0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
}
if (0 != SafeMdl)
FspSafeMdlDelete(SafeMdl);
}
if (0 != Irp)
{

View File

@ -2,8 +2,8 @@
setlocal
echo WINFSP INSTALLATION DIRECTORY
reg query HKLM\SOFTWARE\WinFsp /reg:32
echo WINFSP INSTALLATION DIRECTORY AND LAUNCHER REGISTRATIONS
reg query HKLM\SOFTWARE\WinFsp /s /reg:32
echo.
echo WINFSP DLL REGISTRATIONS
@ -12,10 +12,6 @@ reg query HKLM\SYSTEM\CurrentControlSet\Services\WinFsp.Np\NetworkProvider
reg query HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\WinFsp
echo.
echo WINFSP LAUNCHER REGISTRATIONS
reg query HKLM\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services /s
echo.
echo WINFSP FSD CONFIGURATION AND STATUS
sc query WinFsp
sc qc WinFsp

View File

@ -3,7 +3,7 @@
setlocal
setlocal EnableDelayedExpansion
set RegKey=HKLM\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services
set RegKey=HKLM\Software\WinFsp\Services
if not X%1==X-u (
set unreg=0
@ -16,9 +16,9 @@ if not X%1==X-u (
if X!fscmdl!==X goto usage
if not exist !fsexec! goto notfound
reg add !RegKey!\!fsname! /v Executable /t REG_SZ /d !fsexec! /f
reg add !RegKey!\!fsname! /v CommandLine /t REG_SZ /d !fscmdl! /f
if not X!fssecu!==X reg add !RegKey!\!fsname! /v Security /t REG_SZ /d !fssecu! /f
reg add !RegKey!\!fsname! /v Executable /t REG_SZ /d !fsexec! /f /reg:32
reg add !RegKey!\!fsname! /v CommandLine /t REG_SZ /d !fscmdl! /f /reg:32
if not X!fssecu!==X reg add !RegKey!\!fsname! /v Security /t REG_SZ /d !fssecu! /f /reg:32
) else (
set unreg=1
@ -26,7 +26,7 @@ if not X%1==X-u (
if X!fsname!==X goto usage
reg delete !RegKey!\!fsname! /f
reg delete !RegKey!\!fsname! /f /reg:32
)
exit /b 0

View File

@ -508,7 +508,8 @@ L:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-%1.exe" ^
--external --resilient --case-insensitive-cmp --share-prefix="\passthrough\%TMP::=$%\passthrough-%1\test" ^
-create_allocation_test -getfileinfo_name_test -rename_flipflop_test -rename_mmap_test -reparse* -stream*
-create_allocation_test -getfileinfo_name_test -rename_flipflop_test -rename_mmap_test -exec_rename_dir_test ^
-reparse* -stream*
if !ERRORLEVEL! neq 0 set SamplePassthroughExit=1
popd
@ -534,7 +535,7 @@ call %ProjRoot%\tools\build-sample %Configuration% %1 passthrough-fuse "%TMP%\pa
if !ERRORLEVEL! neq 0 goto fail
mkdir "%TMP%\passthrough-fuse-%1\test"
call "%ProjRoot%\tools\fsreg" passthrough-fuse "%TMP%\passthrough-fuse-%1\build\%Configuration%\passthrough-fuse-%1.exe" ^
"-ouid=65792,gid=65792 -oCaseInsensitiveSearch --VolumePrefix=%%%%1 %%%%2" "D:P(A;;RPWPLC;;;WD)"
"-ouid=65792,gid=65792 --VolumePrefix=%%%%1 %%%%2" "D:P(A;;RPWPLC;;;WD)"
echo net use L: "\\passthrough-fuse\%TMP::=$%\passthrough-fuse-%1\test"
net use L: "\\passthrough-fuse\%TMP::=$%\passthrough-fuse-%1\test"
if !ERRORLEVEL! neq 0 goto fail
@ -547,7 +548,7 @@ L:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-%1.exe" ^
--external --resilient --case-insensitive-cmp --share-prefix="\passthrough-fuse\%TMP::=$%\passthrough-fuse-%1\test" ^
-create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^
-getfileinfo_name_test -setfileinfo_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test ^
-getfileinfo_name_test -setfileinfo_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test -exec_rename_dir_test ^
-reparse* -stream*
if !ERRORLEVEL! neq 0 set SamplePassthroughExit=1

View File

@ -45,9 +45,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
/*
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
* a check for the Write buffer to ensure that it is read-only.
*
* Since ProcessBuffer support in the FSD, this is no longer a guarantee.
*/
#if !defined(NDEBUG)
#define DEBUG_BUFFER_CHECK
//#define DEBUG_BUFFER_CHECK
#endif
#define MEMFS_SECTOR_SIZE 512

View File

@ -187,7 +187,11 @@ static int ptfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, fus
errno = 0;
if (0 == (de = readdir(dirp)))
break;
#if defined(_WIN64) || defined(_WIN32)
if (0 != filler(buf, de->d_name, &de->d_stat, 0))
#else
if (0 != filler(buf, de->d_name, 0, 0))
#endif
return -ENOMEM;
}
@ -201,6 +205,21 @@ static int ptfs_releasedir(const char *path, struct fuse_file_info *fi)
return -1 != closedir(dirp) ? 0 : -errno;
}
static void *ptfs_init(struct fuse_conn_info *conn)
{
#if defined(_WIN64) || defined(_WIN32)
#if defined(FSP_FUSE_CAP_READDIR_PLUS)
conn->want |= (conn->capable & FSP_FUSE_CAP_READDIR_PLUS);
#endif
#if defined(FSP_FUSE_CAP_CASE_INSENSITIVE)
conn->want |= (conn->capable & FSP_FUSE_CAP_CASE_INSENSITIVE);
#endif
#endif
return fuse_get_context()->private_data;
}
static int ptfs_create(const char *path, fuse_mode_t mode, struct fuse_file_info *fi)
{
ptfs_impl_fullpath(path);
@ -254,7 +273,7 @@ static struct fuse_operations ptfs_ops =
ptfs_readdir,
ptfs_releasedir,
0, //fsyncdir
0, //init
ptfs_init,
0, //destroy
0, //access
ptfs_create,

View File

@ -115,7 +115,7 @@ int statvfs(const char *path, struct fuse_statvfs *stbuf)
memset(stbuf, 0, sizeof *stbuf);
stbuf->f_bsize = SectorsPerCluster * BytesPerSector;
stbuf->f_frsize = BytesPerSector;
stbuf->f_frsize = SectorsPerCluster * BytesPerSector;
stbuf->f_blocks = TotalNumberOfClusters;
stbuf->f_bfree = NumberOfFreeClusters;
stbuf->f_bavail = TotalNumberOfClusters;
@ -388,6 +388,8 @@ void rewinddir(DIR *dirp)
struct dirent *readdir(DIR *dirp)
{
WIN32_FIND_DATAA FindData;
UINT64 CreationTime, LastAccessTime, LastWriteTime;
struct fuse_stat *stbuf = &dirp->de.d_stat;
if (INVALID_HANDLE_VALUE == dirp->fh)
{
@ -405,6 +407,24 @@ struct dirent *readdir(DIR *dirp)
}
}
CreationTime = ((PLARGE_INTEGER)(&FindData.ftCreationTime))->QuadPart - 116444736000000000;
LastAccessTime = ((PLARGE_INTEGER)(&FindData.ftLastAccessTime))->QuadPart - 116444736000000000;
LastWriteTime = ((PLARGE_INTEGER)(&FindData.ftLastWriteTime))->QuadPart - 116444736000000000;
memset(stbuf, 0, sizeof *stbuf);
stbuf->st_mode = 0777 |
((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0040000/* S_IFDIR */ : 0);
stbuf->st_nlink = 1;
stbuf->st_size = ((UINT64)FindData.nFileSizeHigh << 32) | ((UINT64)FindData.nFileSizeLow);
stbuf->st_atim.tv_sec = LastAccessTime / 10000000;
stbuf->st_atim.tv_nsec = LastAccessTime % 10000000 * 100;
stbuf->st_mtim.tv_sec = LastWriteTime / 10000000;
stbuf->st_mtim.tv_nsec = LastWriteTime % 10000000 * 100;
stbuf->st_ctim.tv_sec = LastWriteTime / 10000000;
stbuf->st_ctim.tv_nsec = LastWriteTime % 10000000 * 100;
stbuf->st_birthtim.tv_sec = CreationTime / 10000000;
stbuf->st_birthtim.tv_nsec = CreationTime % 10000000 * 100;
strcpy(dirp->de.d_name, FindData.cFileName);
return &dirp->de;

View File

@ -31,6 +31,7 @@
typedef struct _DIR DIR;
struct dirent
{
struct fuse_stat d_stat;
char d_name[255];
};

View File

@ -538,9 +538,14 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
Length = GetFinalPathNameByHandleW(Handle, FullPath, FULLPATH_SIZE - 1, 0);
if (0 == Length)
return FspNtStatusFromWin32(GetLastError());
if (Length + 1 + PatternLength >= FULLPATH_SIZE)
return STATUS_OBJECT_NAME_INVALID;
DirBufferResult = FspNtStatusFromWin32(GetLastError());
else if (Length + 1 + PatternLength >= FULLPATH_SIZE)
DirBufferResult = STATUS_OBJECT_NAME_INVALID;
if (!NT_SUCCESS(DirBufferResult))
{
FspFileSystemReleaseDirectoryBuffer(&FileContext->DirBuffer);
return DirBufferResult;
}
if (L'\\' != FullPath[Length - 1])
FullPath[Length++] = L'\\';

View File

@ -0,0 +1,352 @@
/**
* @file exec-test.c
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* 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 <tlib/testsuite.h>
#include <strsafe.h>
#include "memfs.h"
#include "winfsp-tests.h"
static NTSTATUS WriteResource(
HANDLE Handle, HANDLE Module, PWSTR ResourceName, PULONG PBytesTransferred)
{
HRSRC Resource;
HGLOBAL ResourceGlob;
PVOID ResourceData;
DWORD ResourceSize;
if ((Resource = FindResourceW(Module, ResourceName, RT_RCDATA)) &&
(ResourceGlob = LoadResource(Module, Resource)) &&
(ResourceData = LockResource(ResourceGlob)) &&
(ResourceSize = SizeofResource(Module, Resource)) &&
(WriteFile(Handle, ResourceData, ResourceSize, PBytesTransferred, 0)))
return STATUS_SUCCESS;
else
return FspNtStatusFromWin32(GetLastError());
}
static NTSTATUS ExtractHelperProgram(PWSTR FileName)
{
HANDLE Handle;
ULONG BytesTransferred;
NTSTATUS Result;
Handle = CreateFileW(FileName,
FILE_WRITE_DATA, FILE_SHARE_WRITE, 0,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (INVALID_HANDLE_VALUE == Handle)
return FspNtStatusFromWin32(GetLastError());
Result = WriteResource(
Handle,
0,
#if defined(_WIN64)
L"winfsp-tests-helper-x64.exe",
#elif defined(_WIN32)
L"winfsp-tests-helper-x86.exe",
#else
#error
#endif
&BytesTransferred);
CloseHandle(Handle);
return Result;
}
static NTSTATUS CreateHelperProcess(PWSTR FileName, ULONG Timeout, PHANDLE PProcess)
{
HANDLE Event;
SECURITY_ATTRIBUTES EventAttributes;
WCHAR CommandLine[MAX_PATH + 64];
STARTUPINFOW StartupInfo;
PROCESS_INFORMATION ProcessInfo;
DWORD WaitResult;
NTSTATUS Result;
memset(&EventAttributes, 0, sizeof EventAttributes);
EventAttributes.nLength = sizeof EventAttributes;
EventAttributes.bInheritHandle = TRUE;
Event = CreateEventW(&EventAttributes, TRUE, FALSE, 0);
if (0 == Event)
return FspNtStatusFromWin32(GetLastError());
StringCbPrintfW(CommandLine, sizeof CommandLine, L"\"%s\" %lx %lx",
FileName, (ULONG)(UINT_PTR)Event, Timeout);
memset(&StartupInfo, 0, sizeof StartupInfo);
StartupInfo.cb = sizeof StartupInfo;
// !!!: need hook
if (!CreateProcessW(FileName, CommandLine, 0, 0, TRUE, 0, 0, 0, &StartupInfo, &ProcessInfo))
{
Result = FspNtStatusFromWin32(GetLastError());
CloseHandle(Event);
return Result;
}
WaitResult = WaitForSingleObject(Event, 3000);
if (WaitResult == WAIT_FAILED)
Result = FspNtStatusFromWin32(GetLastError());
else if (WaitResult == WAIT_TIMEOUT)
Result = STATUS_UNSUCCESSFUL;
else
Result = STATUS_SUCCESS;
CloseHandle(Event);
CloseHandle(ProcessInfo.hThread);
if (!NT_SUCCESS(Result))
CloseHandle(ProcessInfo.hProcess);
else
*PProcess = ProcessInfo.hProcess;
return Result;
}
static VOID ExecHelper(PWSTR FileName, ULONG Timeout, PHANDLE PProcess)
{
NTSTATUS Result;
Result = ExtractHelperProgram(FileName);
ASSERT(NT_SUCCESS(Result));
Result = CreateHelperProcess(FileName, Timeout, PProcess);
ASSERT(NT_SUCCESS(Result));
}
static VOID WaitHelper(HANDLE Process, ULONG Timeout)
{
DWORD ExitCode;
ASSERT(WAIT_OBJECT_0 == WaitForSingleObject(Process, Timeout + 1000));
ASSERT(GetExitCodeProcess(Process, &ExitCode));
ASSERT(0 == ExitCode);
ASSERT(CloseHandle(Process));
}
static void exec_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
WCHAR FilePath[MAX_PATH];
HANDLE Process;
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\helper.exe",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
ExecHelper(FilePath, 0, &Process);
WaitHelper(Process, 0);
ASSERT(DeleteFileW(FilePath));
memfs_stop(memfs);
}
static void exec_test(void)
{
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
exec_dotest(-1, DirBuf, 0);
}
if (WinFspDiskTests)
{
exec_dotest(MemfsDisk, 0, 0);
exec_dotest(MemfsDisk, 0, 1000);
}
if (WinFspNetTests)
{
exec_dotest(MemfsNet, L"\\\\memfs\\share", 0);
exec_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
}
}
static void exec_delete_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
WCHAR FilePath[MAX_PATH];
HANDLE Process;
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\helper.exe",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
ExecHelper(FilePath, 1000, &Process);
ASSERT(!DeleteFileW(FilePath));
ASSERT(ERROR_ACCESS_DENIED == GetLastError());
WaitHelper(Process, 1000);
ASSERT(DeleteFileW(FilePath));
memfs_stop(memfs);
}
static void exec_delete_test(void)
{
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
exec_delete_dotest(-1, DirBuf, 0);
}
if (WinFspDiskTests)
{
exec_delete_dotest(MemfsDisk, 0, 0);
exec_delete_dotest(MemfsDisk, 0, 1000);
}
if (WinFspNetTests)
{
exec_delete_dotest(MemfsNet, L"\\\\memfs\\share", 0);
exec_delete_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
}
}
static void exec_rename_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
WCHAR FilePath[MAX_PATH], File2Path[MAX_PATH], File3Path[MAX_PATH];
HANDLE Process;
HANDLE Handle;
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\helper.exe",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(File2Path, sizeof File2Path, L"%s%s\\helper2.exe",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(File3Path, sizeof File3Path, L"%s%s\\helper3.exe",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Handle = CreateFileW(File3Path,
FILE_WRITE_DATA, FILE_SHARE_WRITE, 0,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
ExecHelper(FilePath, 1000, &Process);
ASSERT(MoveFileExW(FilePath, File2Path, MOVEFILE_REPLACE_EXISTING));
ASSERT(MoveFileExW(File2Path, FilePath, MOVEFILE_REPLACE_EXISTING));
ASSERT(!MoveFileExW(File3Path, FilePath, MOVEFILE_REPLACE_EXISTING));
ASSERT(ERROR_ACCESS_DENIED == GetLastError());
WaitHelper(Process, 1000);
ASSERT(MoveFileExW(File3Path, FilePath, MOVEFILE_REPLACE_EXISTING));
ASSERT(DeleteFileW(FilePath));
memfs_stop(memfs);
}
static void exec_rename_test(void)
{
if (OptShareName)
return;
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
exec_rename_dotest(-1, DirBuf, 0);
}
if (WinFspDiskTests)
{
exec_rename_dotest(MemfsDisk, 0, 0);
exec_rename_dotest(MemfsDisk, 0, 1000);
}
if (WinFspNetTests)
{
exec_rename_dotest(MemfsNet, L"\\\\memfs\\share", 0);
exec_rename_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
}
}
static void exec_rename_dir_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
WCHAR Dir1Path[MAX_PATH], Dir2Path[MAX_PATH], FilePath[MAX_PATH];
HANDLE Process;
StringCbPrintfW(Dir1Path, sizeof Dir1Path, L"%s%s\\dir1",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(Dir2Path, sizeof Dir2Path, L"%s%s\\dir2",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\helper.exe",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
ASSERT(CreateDirectoryW(Dir1Path, 0));
ExecHelper(FilePath, 1000, &Process);
ASSERT(MoveFileExW(Dir1Path, Dir2Path, MOVEFILE_REPLACE_EXISTING));
ASSERT(MoveFileExW(Dir2Path, Dir1Path, MOVEFILE_REPLACE_EXISTING));
WaitHelper(Process, 1000);
ASSERT(DeleteFileW(FilePath));
ASSERT(RemoveDirectoryW(Dir1Path));
memfs_stop(memfs);
}
static void exec_rename_dir_test(void)
{
if (OptShareName)
return;
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
exec_rename_dir_dotest(-1, DirBuf, 0);
}
if (WinFspDiskTests)
{
exec_rename_dir_dotest(MemfsDisk, 0, 0);
exec_rename_dir_dotest(MemfsDisk, 0, 1000);
}
if (WinFspNetTests)
{
exec_rename_dir_dotest(MemfsNet, L"\\\\memfs\\share", 0);
exec_rename_dir_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
}
}
void exec_tests(void)
{
TEST(exec_test);
TEST(exec_delete_test);
if (!OptShareName)
TEST(exec_rename_test);
if (!OptShareName)
TEST(exec_rename_dir_test);
}

View File

@ -0,0 +1,13 @@
@echo off
setlocal
cd %~dp0
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
cl /Fewinfsp-tests-helper-x64.exe /MT /W2 winfsp-tests-helper.c kernel32.lib shell32.lib /link /subsystem:console /nodefaultlib
del *.obj
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x86
cl /Fewinfsp-tests-helper-x86.exe /MT /W2 winfsp-tests-helper.c kernel32.lib shell32.lib /link /subsystem:console
del *.obj

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,104 @@
/**
* @file winfsp-tests-helper.c
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* 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 <windows.h>
/* based on src/dll/fuse/fuse_opt.c */
static long long wcstoint(const wchar_t *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;
}
int wmain(int argc, wchar_t **argv)
{
HANDLE Event;
ULONG Timeout;
if (argc != 3)
return 1;
Event = (HANDLE)(UINT_PTR)wcstoint(argv[1], 16, 0);
Timeout = wcstoint(argv[2], 16, 0);
SetEvent(Event);
CloseHandle(Event);
Sleep(Timeout);
return 0;
}
void wmainCRTStartup(void)
{
DWORD Argc;
PWSTR *Argv;
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
if (0 == Argv)
ExitProcess(GetLastError());
ExitProcess(wmain(Argc, Argv));
}

View File

@ -0,0 +1,2 @@
winfsp-tests-helper-x64.exe RCDATA "winfsp-tests-helper-x64.exe"
winfsp-tests-helper-x86.exe RCDATA "winfsp-tests-helper-x86.exe"

View File

@ -427,3 +427,35 @@ BOOL WINAPI HookSetCurrentDirectoryW(
MaybeAdjustTraversePrivilege(TRUE);
return Success;
}
BOOL WINAPI HookCreateProcessW(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation)
{
WCHAR FileNameBuf[FILENAMEBUF_SIZE];
BOOL Success;
PrepareFileName(lpApplicationName, FileNameBuf);
MaybeAdjustTraversePrivilege(FALSE);
Success = CreateProcessW(FileNameBuf,
lpCommandLine, /* we should probably change this as well */
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
MaybeAdjustTraversePrivilege(TRUE);
return Success;
}

View File

@ -19,6 +19,7 @@
#include <tlib/testsuite.h>
#include <sddl.h>
#include <strsafe.h>
#include <time.h>
#include "memfs.h"
#include "winfsp-tests.h"
@ -604,6 +605,157 @@ void delete_mmap_test(void)
}
}
static void delete_standby_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
HANDLE Handle, Mapping0, Mapping1;
PUINT8 MappedView0, MappedView1;
BOOL Success;
WCHAR Dir1Path[MAX_PATH];
WCHAR File0Path[MAX_PATH];
WCHAR File1Path[MAX_PATH];
SYSTEM_INFO SystemInfo;
unsigned seed = (unsigned)time(0);
GetSystemInfo(&SystemInfo);
StringCbPrintfW(Dir1Path, sizeof Dir1Path, L"%s%s\\dir1",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(File0Path, sizeof File0Path, L"%s%s\\dir1\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(File1Path, sizeof File1Path, L"%s%s\\dir1\\file1",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = CreateDirectoryW(Dir1Path, 0);
ASSERT(Success);
srand(seed);
Handle = CreateFileW(File0Path,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping0 = CreateFileMappingW(Handle, 0, PAGE_READWRITE,
0, 16 * SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping0);
Success = CloseHandle(Handle);
ASSERT(Success);
MappedView0 = MapViewOfFile(Mapping0, FILE_MAP_ALL_ACCESS, 0, 0, 0);
ASSERT(0 != MappedView0);
for (PUINT8 P = MappedView0, EndP = P + 16 * SystemInfo.dwAllocationGranularity; EndP > P; P++)
*P = rand() & 0xff;
Success = UnmapViewOfFile(MappedView0);
ASSERT(Success);
Success = CloseHandle(Mapping0);
ASSERT(Success);
Handle = CreateFileW(File1Path,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping1 = CreateFileMappingW(Handle, 0, PAGE_READWRITE,
0, 16 * SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping1);
Success = CloseHandle(Handle);
ASSERT(Success);
MappedView1 = MapViewOfFile(Mapping1, FILE_MAP_ALL_ACCESS, 0, 0, 0);
ASSERT(0 != MappedView1);
for (PUINT8 P = MappedView1, EndP = P + 16 * SystemInfo.dwAllocationGranularity; EndP > P; P++)
*P = rand() & 0xff;
Success = UnmapViewOfFile(MappedView1);
ASSERT(Success);
Success = CloseHandle(Mapping1);
ASSERT(Success);
Success = DeleteFileW(File0Path);
ASSERT(Success);
Success = DeleteFileW(File1Path);
ASSERT(Success);
Success = RemoveDirectoryW(Dir1Path);
ASSERT(Success);
Success = RemoveDirectoryW(Dir1Path);
ASSERT(!Success);
ASSERT(ERROR_FILE_NOT_FOUND == GetLastError());
Success = CreateDirectoryW(Dir1Path, 0);
ASSERT(Success);
srand(seed);
Handle = CreateFileW(File0Path,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping0 = CreateFileMappingW(Handle, 0, PAGE_READWRITE,
0, 16 * SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping0);
MappedView0 = MapViewOfFile(Mapping0, FILE_MAP_ALL_ACCESS, 0, 0, 0);
ASSERT(0 != MappedView0);
for (PUINT8 P = MappedView0, EndP = P + 16 * SystemInfo.dwAllocationGranularity; EndP > P; P++)
*P = rand() & 0xff;
Success = UnmapViewOfFile(MappedView0);
ASSERT(Success);
Success = CloseHandle(Mapping0);
ASSERT(Success);
Success = CloseHandle(Handle);
ASSERT(Success);
Handle = CreateFileW(File1Path,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping1 = CreateFileMappingW(Handle, 0, PAGE_READWRITE,
0, 16 * SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping1);
MappedView1 = MapViewOfFile(Mapping1, FILE_MAP_ALL_ACCESS, 0, 0, 0);
ASSERT(0 != MappedView1);
for (PUINT8 P = MappedView1, EndP = P + 16 * SystemInfo.dwAllocationGranularity; EndP > P; P++)
*P = rand() & 0xff;
Success = UnmapViewOfFile(MappedView1);
ASSERT(Success);
Success = CloseHandle(Mapping1);
ASSERT(Success);
Success = CloseHandle(Handle);
ASSERT(Success);
Success = RemoveDirectoryW(Dir1Path);
ASSERT(Success);
Success = RemoveDirectoryW(Dir1Path);
ASSERT(!Success);
ASSERT(ERROR_FILE_NOT_FOUND == GetLastError());
memfs_stop(memfs);
}
void delete_standby_test(void)
{
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
delete_standby_dotest(-1, DirBuf, 0);
}
if (WinFspDiskTests)
{
delete_standby_dotest(MemfsDisk, 0, 0);
delete_standby_dotest(MemfsDisk, 0, 1000);
delete_standby_dotest(MemfsDisk, 0, INFINITE);
}
if (WinFspNetTests)
{
delete_standby_dotest(MemfsNet, L"\\\\memfs\\share", 0);
delete_standby_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
delete_standby_dotest(MemfsDisk, 0, INFINITE);
}
}
static void rename_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
@ -1116,6 +1268,250 @@ void rename_mmap_test(void)
}
}
static void rename_standby_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
HANDLE Handle, Mapping0, Mapping1;
PUINT8 MappedView0, MappedView1;
BOOL Success;
WCHAR Dir1Path[MAX_PATH];
WCHAR Dir2Path[MAX_PATH];
WCHAR File0Path[MAX_PATH];
WCHAR File1Path[MAX_PATH];
SYSTEM_INFO SystemInfo;
unsigned seed = (unsigned)time(0);
GetSystemInfo(&SystemInfo);
StringCbPrintfW(Dir1Path, sizeof Dir1Path, L"%s%s\\dir1",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(Dir2Path, sizeof Dir2Path, L"%s%s\\dir2",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(File0Path, sizeof File0Path, L"%s%s\\dir1\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(File1Path, sizeof File1Path, L"%s%s\\dir1\\file1",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = CreateDirectoryW(Dir1Path, 0);
ASSERT(Success);
srand(seed);
Handle = CreateFileW(File0Path,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping0 = CreateFileMappingW(Handle, 0, PAGE_READWRITE,
0, 16 * SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping0);
Success = CloseHandle(Handle);
ASSERT(Success);
MappedView0 = MapViewOfFile(Mapping0, FILE_MAP_ALL_ACCESS, 0, 0, 0);
ASSERT(0 != MappedView0);
for (PUINT8 P = MappedView0, EndP = P + 16 * SystemInfo.dwAllocationGranularity; EndP > P; P++)
*P = rand() & 0xff;
Success = UnmapViewOfFile(MappedView0);
ASSERT(Success);
Success = CloseHandle(Mapping0);
ASSERT(Success);
Handle = CreateFileW(File1Path,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping1 = CreateFileMappingW(Handle, 0, PAGE_READWRITE,
0, 16 * SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping1);
Success = CloseHandle(Handle);
ASSERT(Success);
MappedView1 = MapViewOfFile(Mapping1, FILE_MAP_ALL_ACCESS, 0, 0, 0);
ASSERT(0 != MappedView1);
for (PUINT8 P = MappedView1, EndP = P + 16 * SystemInfo.dwAllocationGranularity; EndP > P; P++)
*P = rand() & 0xff;
Success = UnmapViewOfFile(MappedView1);
ASSERT(Success);
Success = CloseHandle(Mapping1);
ASSERT(Success);
Success = MoveFileExW(Dir1Path, Dir2Path, MOVEFILE_REPLACE_EXISTING);
ASSERT(Success);
StringCbPrintfW(File0Path, sizeof File0Path, L"%s%s\\dir2\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(File1Path, sizeof File1Path, L"%s%s\\dir2\\file1",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
srand(seed);
Handle = CreateFileW(File0Path,
GENERIC_READ, FILE_SHARE_READ, 0,
OPEN_EXISTING, 0, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping0 = CreateFileMappingW(Handle, 0, PAGE_READONLY,
0, 16 * SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping0);
Success = CloseHandle(Handle);
ASSERT(Success);
MappedView0 = MapViewOfFile(Mapping0, FILE_MAP_READ, 0, 0, 0);
ASSERT(0 != MappedView0);
for (PUINT8 P = MappedView0, EndP = P + 16 * SystemInfo.dwAllocationGranularity; EndP > P; P++)
ASSERT(*P == (rand() & 0xff));
Success = UnmapViewOfFile(MappedView0);
ASSERT(Success);
Success = CloseHandle(Mapping0);
ASSERT(Success);
Handle = CreateFileW(File1Path,
GENERIC_READ, FILE_SHARE_READ, 0,
OPEN_EXISTING, 0, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping1 = CreateFileMappingW(Handle, 0, PAGE_READONLY,
0, 16 * SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping1);
Success = CloseHandle(Handle);
ASSERT(Success);
MappedView1 = MapViewOfFile(Mapping1, FILE_MAP_READ, 0, 0, 0);
ASSERT(0 != MappedView1);
for (PUINT8 P = MappedView1, EndP = P + 16 * SystemInfo.dwAllocationGranularity; EndP > P; P++)
ASSERT(*P == (rand() & 0xff));
Success = UnmapViewOfFile(MappedView1);
ASSERT(Success);
Success = CloseHandle(Mapping1);
ASSERT(Success);
Success = MoveFileExW(Dir2Path, Dir1Path, MOVEFILE_REPLACE_EXISTING);
ASSERT(Success);
StringCbPrintfW(File0Path, sizeof File0Path, L"%s%s\\dir1\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(File1Path, sizeof File1Path, L"%s%s\\dir1\\file1",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
srand(seed);
Handle = CreateFileW(File0Path,
GENERIC_READ, FILE_SHARE_READ, 0,
OPEN_EXISTING, 0, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping0 = CreateFileMappingW(Handle, 0, PAGE_READONLY,
0, 16 * SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping0);
Success = CloseHandle(Handle);
ASSERT(Success);
MappedView0 = MapViewOfFile(Mapping0, FILE_MAP_READ, 0, 0, 0);
ASSERT(0 != MappedView0);
for (PUINT8 P = MappedView0, EndP = P + 16 * SystemInfo.dwAllocationGranularity; EndP > P; P++)
ASSERT(*P == (rand() & 0xff));
Success = UnmapViewOfFile(MappedView0);
ASSERT(Success);
Success = CloseHandle(Mapping0);
ASSERT(Success);
Handle = CreateFileW(File1Path,
GENERIC_READ, FILE_SHARE_READ, 0,
OPEN_EXISTING, 0, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping1 = CreateFileMappingW(Handle, 0, PAGE_READONLY,
0, 16 * SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping1);
Success = CloseHandle(Handle);
ASSERT(Success);
MappedView1 = MapViewOfFile(Mapping1, FILE_MAP_READ, 0, 0, 0);
ASSERT(0 != MappedView1);
for (PUINT8 P = MappedView1, EndP = P + 16 * SystemInfo.dwAllocationGranularity; EndP > P; P++)
ASSERT(*P == (rand() & 0xff));
Success = UnmapViewOfFile(MappedView1);
ASSERT(Success);
Success = CloseHandle(Mapping1);
ASSERT(Success);
Success = MoveFileExW(File0Path, File1Path, MOVEFILE_REPLACE_EXISTING);
ASSERT(Success);
srand(seed);
Handle = CreateFileW(File1Path,
GENERIC_READ, FILE_SHARE_READ, 0,
OPEN_EXISTING, 0, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping1 = CreateFileMappingW(Handle, 0, PAGE_READONLY,
0, 16 * SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping1);
Success = CloseHandle(Handle);
ASSERT(Success);
MappedView1 = MapViewOfFile(Mapping1, FILE_MAP_READ, 0, 0, 0);
ASSERT(0 != MappedView1);
for (PUINT8 P = MappedView1, EndP = P + 16 * SystemInfo.dwAllocationGranularity; EndP > P; P++)
ASSERT(*P == (rand() & 0xff));
Success = UnmapViewOfFile(MappedView1);
ASSERT(Success);
Success = CloseHandle(Mapping1);
ASSERT(Success);
Success = MoveFileExW(File1Path, File0Path, MOVEFILE_REPLACE_EXISTING);
ASSERT(Success);
srand(seed);
Handle = CreateFileW(File0Path,
GENERIC_READ, FILE_SHARE_READ, 0,
OPEN_EXISTING, 0, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping0 = CreateFileMappingW(Handle, 0, PAGE_READONLY,
0, 16 * SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping0);
Success = CloseHandle(Handle);
ASSERT(Success);
MappedView0 = MapViewOfFile(Mapping0, FILE_MAP_READ, 0, 0, 0);
ASSERT(0 != MappedView0);
for (PUINT8 P = MappedView0, EndP = P + 16 * SystemInfo.dwAllocationGranularity; EndP > P; P++)
ASSERT(*P == (rand() & 0xff));
Success = UnmapViewOfFile(MappedView0);
ASSERT(Success);
Success = CloseHandle(Mapping0);
ASSERT(Success);
Success = DeleteFileW(File0Path);
ASSERT(Success);
Success = RemoveDirectoryW(Dir1Path);
ASSERT(Success);
Success = RemoveDirectoryW(Dir1Path);
ASSERT(!Success);
ASSERT(ERROR_FILE_NOT_FOUND == GetLastError());
memfs_stop(memfs);
}
void rename_standby_test(void)
{
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
rename_standby_dotest(-1, DirBuf, 0);
}
if (WinFspDiskTests)
{
rename_standby_dotest(MemfsDisk, 0, 0);
rename_standby_dotest(MemfsDisk, 0, 1000);
rename_standby_dotest(MemfsDisk, 0, INFINITE);
}
if (WinFspNetTests)
{
rename_standby_dotest(MemfsNet, L"\\\\memfs\\share", 0);
rename_standby_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
rename_standby_dotest(MemfsDisk, 0, INFINITE);
}
}
void getvolinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
@ -1331,6 +1727,7 @@ void info_tests(void)
TEST(delete_pending_test);
if (!OptShareName)
TEST(delete_mmap_test);
TEST(delete_standby_test);
TEST(rename_test);
TEST(rename_open_test);
TEST(rename_caseins_test);
@ -1338,6 +1735,7 @@ void info_tests(void)
TEST(rename_flipflop_test);
if (!OptShareName)
TEST(rename_mmap_test);
TEST(rename_standby_test);
TEST(getvolinfo_test);
TEST(setvolinfo_test);
}

View File

@ -0,0 +1,42 @@
/**
* @file version-test.c
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* 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 <tlib/testsuite.h>
#include "winfsp-tests.h"
static void version_test(void)
{
UINT32 Version1, Version2;
NTSTATUS Result;
Result = FspVersion(&Version1);
ASSERT(NT_SUCCESS(Result));
Result = FspVersion(&Version2);
ASSERT(NT_SUCCESS(Result));
ASSERT(Version1 == Version2);
FspDebugLog(__FUNCTION__ ": FspVersion=%d.%d\n", HIWORD(Version1), LOWORD(Version1));
}
void version_tests(void)
{
TEST(version_test);
}

View File

@ -184,6 +184,7 @@ int main(int argc, char *argv[])
TESTSUITE(eventlog_tests);
TESTSUITE(path_tests);
TESTSUITE(dirbuf_tests);
TESTSUITE(version_tests);
TESTSUITE(mount_tests);
TESTSUITE(timeout_tests);
TESTSUITE(memfs_tests);
@ -194,6 +195,7 @@ int main(int argc, char *argv[])
TESTSUITE(flush_tests);
TESTSUITE(lock_tests);
TESTSUITE(dirctl_tests);
TESTSUITE(exec_tests);
TESTSUITE(reparse_tests);
TESTSUITE(stream_tests);
TESTSUITE(oplock_tests);

View File

@ -85,6 +85,17 @@ static inline BOOL RealSetCurrentDirectoryW(
{
return SetCurrentDirectoryW(lpPathName);
}
BOOL WINAPI HookCreateProcessW(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation);
#if !defined(WINFSP_TESTS_NO_HOOKS)
#define CreateFileW HookCreateFileW
#define CloseHandle HookCloseHandle
@ -99,6 +110,7 @@ static inline BOOL RealSetCurrentDirectoryW(
#define GetVolumeInformationW HookGetVolumeInformationW
#define SetVolumeLabelW HookSetVolumeLabelW
#define SetCurrentDirectoryW HookSetCurrentDirectoryW
#define CreateProcessW HookCreateProcessW
#endif
HANDLE WINAPI ResilientCreateFileW(