mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-03 01:12:58 -05:00
Compare commits
40 Commits
Author | SHA1 | Date | |
---|---|---|---|
ba46d9fef8 | |||
4c0386bf8d | |||
6774c34422 | |||
3215d8e26a | |||
7911f1354f | |||
28f97c2619 | |||
4b43cc590f | |||
441c45c77f | |||
c246acb2d3 | |||
50ed020e16 | |||
12704a3a4a | |||
186f7cd9ee | |||
50830f0bf2 | |||
86025aa30b | |||
31e6f15eaf | |||
5ce6d74e90 | |||
02ffa6afb2 | |||
712870ddd9 | |||
35d1adb360 | |||
3b9f9ce93b | |||
a7c5e4f80c | |||
0b826f04c2 | |||
69d53b7a28 | |||
877bd97ba8 | |||
559b7e80a3 | |||
495c78eb25 | |||
cf69d6a08d | |||
0d95bb9b14 | |||
cf48d19759 | |||
14c602ccd8 | |||
2d45082d80 | |||
25cf527af4 | |||
76d081937e | |||
ccd4bb869c | |||
46d5c98926 | |||
1726ca8ccb | |||
b8c257f996 | |||
53e6894298 | |||
10d1ba707e | |||
c234e2af2a |
@ -1,6 +1,18 @@
|
|||||||
= Changelog
|
= 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::
|
v1.0RC2::
|
||||||
|
|
||||||
This is the WinFsp 2017 Release Candidate 2. Some important changes included below:
|
This is the WinFsp 2017 Release Candidate 2. Some important changes included below:
|
||||||
|
13
README.md
13
README.md
@ -3,7 +3,7 @@
|
|||||||

|

|
||||||
|
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -45,19 +45,22 @@ The project source code is organized as follows:
|
|||||||
|
|
||||||
In order to build WinFsp you will need the following:
|
In order to build WinFsp you will need the following:
|
||||||
|
|
||||||
* Windows 10
|
|
||||||
* Visual Studio 2015
|
* Visual Studio 2015
|
||||||
* Windows Driver Kit (WDK) 10
|
* Windows Driver Kit (WDK) 10
|
||||||
* [Wix toolset](http://wixtoolset.org)
|
* [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 7 Enterprise
|
||||||
* Windows 8 Pro
|
* Windows 8 Pro
|
||||||
* Windows 10 Pro
|
|
||||||
* Windows Server 2012
|
* Windows Server 2012
|
||||||
|
* Windows 10 Pro
|
||||||
* Windows Server 2016
|
* Windows Server 2016
|
||||||
|
|
||||||
## How to Help
|
## How to Help
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\dirctl-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\dirctl-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-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\flush-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\hooks.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\security-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.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" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\winfsp-tests.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -213,6 +215,9 @@
|
|||||||
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
|
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="..\..\..\tst\winfsp-tests\helper\winfsp-tests-helper.rc" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
@ -79,6 +79,12 @@
|
|||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c">
|
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c">
|
||||||
<Filter>Source</Filter>
|
<Filter>Source</Filter>
|
||||||
</ClCompile>
|
</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>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
||||||
@ -91,4 +97,9 @@
|
|||||||
<Filter>Source</Filter>
|
<Filter>Source</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="..\..\..\tst\winfsp-tests\helper\winfsp-tests-helper.rc">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
<MyCanonicalVersion>1.0</MyCanonicalVersion>
|
<MyCanonicalVersion>1.0</MyCanonicalVersion>
|
||||||
|
|
||||||
<MyProductVersion>2017 RC2</MyProductVersion>
|
<MyProductVersion>2017 RC3</MyProductVersion>
|
||||||
<MyProductStage>RC</MyProductStage>
|
<MyProductStage>RC</MyProductStage>
|
||||||
|
|
||||||
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
||||||
|
@ -174,6 +174,7 @@
|
|||||||
<ClCompile Include="..\..\src\sys\lockctl.c" />
|
<ClCompile Include="..\..\src\sys\lockctl.c" />
|
||||||
<ClCompile Include="..\..\src\sys\meta.c" />
|
<ClCompile Include="..\..\src\sys\meta.c" />
|
||||||
<ClCompile Include="..\..\src\sys\name.c" />
|
<ClCompile Include="..\..\src\sys\name.c" />
|
||||||
|
<ClCompile Include="..\..\src\sys\psbuffer.c" />
|
||||||
<ClCompile Include="..\..\src\sys\read.c" />
|
<ClCompile Include="..\..\src\sys\read.c" />
|
||||||
<ClCompile Include="..\..\src\sys\security.c" />
|
<ClCompile Include="..\..\src\sys\security.c" />
|
||||||
<ClCompile Include="..\..\src\sys\shutdown.c" />
|
<ClCompile Include="..\..\src\sys\shutdown.c" />
|
||||||
|
@ -98,6 +98,9 @@
|
|||||||
<ClCompile Include="..\..\src\sys\statistics.c">
|
<ClCompile Include="..\..\src\sys\statistics.c">
|
||||||
<Filter>Source</Filter>
|
<Filter>Source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\sys\psbuffer.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\src\sys\driver.h">
|
<ClInclude Include="..\..\src\sys\driver.h">
|
||||||
|
1741
doc/winfsp.h.asciidoc
Normal file
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
@ -41,6 +41,15 @@ extern "C" {
|
|||||||
#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
|
#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
|
||||||
#define FUSE_CAP_BIG_WRITES (1 << 5)
|
#define FUSE_CAP_BIG_WRITES (1 << 5)
|
||||||
#define FUSE_CAP_DONT_MASK (1 << 6)
|
#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_COMPAT (1 << 0)
|
||||||
#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
|
#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
|
||||||
|
@ -177,6 +177,7 @@ struct fuse_flock
|
|||||||
MemAlloc, MemFree, \
|
MemAlloc, MemFree, \
|
||||||
fsp_fuse_daemonize, \
|
fsp_fuse_daemonize, \
|
||||||
fsp_fuse_set_signal_handlers, \
|
fsp_fuse_set_signal_handlers, \
|
||||||
|
0/*conv_to_win_path*/, \
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define FSP_FUSE_ENV_INIT \
|
#define FSP_FUSE_ENV_INIT \
|
||||||
@ -185,6 +186,7 @@ struct fuse_flock
|
|||||||
malloc, free, \
|
malloc, free, \
|
||||||
fsp_fuse_daemonize, \
|
fsp_fuse_daemonize, \
|
||||||
fsp_fuse_set_signal_handlers, \
|
fsp_fuse_set_signal_handlers, \
|
||||||
|
0/*conv_to_win_path*/, \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -226,6 +228,7 @@ struct fuse_flock
|
|||||||
malloc, free, \
|
malloc, free, \
|
||||||
fsp_fuse_daemonize, \
|
fsp_fuse_daemonize, \
|
||||||
fsp_fuse_set_signal_handlers, \
|
fsp_fuse_set_signal_handlers, \
|
||||||
|
fsp_fuse_conv_to_win_path, \
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -244,7 +247,8 @@ struct fsp_fuse_env
|
|||||||
void (*memfree)(void *);
|
void (*memfree)(void *);
|
||||||
int (*daemonize)(int);
|
int (*daemonize)(int);
|
||||||
int (*set_signal_handlers)(void *);
|
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);
|
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
|
#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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -148,7 +148,8 @@ typedef struct
|
|||||||
/* kernel-mode flags */
|
/* kernel-mode flags */
|
||||||
UINT32 PostCleanupWhenModifiedOnly:1; /* post Cleanup when a file was modified/deleted */
|
UINT32 PostCleanupWhenModifiedOnly:1; /* post Cleanup when a file was modified/deleted */
|
||||||
UINT32 PassQueryDirectoryPattern:1; /* pass Pattern during QueryDirectory operations */
|
UINT32 PassQueryDirectoryPattern:1; /* pass Pattern during QueryDirectory operations */
|
||||||
UINT32 KmReservedFlags:4;
|
UINT32 AlwaysUseDoubleBuffering:1;
|
||||||
|
UINT32 KmReservedFlags:3;
|
||||||
/* user-mode flags */
|
/* user-mode flags */
|
||||||
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
|
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
|
||||||
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */
|
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */
|
||||||
|
@ -893,6 +893,8 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem);
|
|||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint);
|
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.
|
* 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,
|
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
|
||||||
PULONG PBytesTransferred, ULONG Timeout,
|
PULONG PBytesTransferred, ULONG Timeout,
|
||||||
PSID Sid);
|
PSID Sid);
|
||||||
|
FSP_API NTSTATUS FspVersion(PUINT32 PVersion);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delay load
|
* Delay load
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
NAME="fuse"
|
NAME="fuse"
|
||||||
VERSION=2.8
|
VERSION=2.8
|
||||||
RELEASE=3
|
RELEASE=4
|
||||||
CATEGORY="Utils"
|
CATEGORY="Utils"
|
||||||
SUMMARY="WinFsp-FUSE compatibility layer"
|
SUMMARY="WinFsp-FUSE compatibility layer"
|
||||||
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."
|
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."
|
||||||
|
218
src/dll/fs.c
218
src/dll/fs.c
@ -187,20 +187,63 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem)
|
|||||||
MemFree(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;
|
NTSTATUS Result;
|
||||||
HANDLE DirHandle;
|
SECURITY_ATTRIBUTES SecurityAttributes;
|
||||||
BOOL Success;
|
HANDLE MountHandle = INVALID_HANDLE_VALUE;
|
||||||
DWORD Backslashes, Bytes;
|
DWORD Backslashes, Bytes;
|
||||||
USHORT VolumeNameLength, BackslashLength, ReparseDataLength;
|
USHORT VolumeNameLength, BackslashLength, ReparseDataLength;
|
||||||
PREPARSE_DATA_BUFFER ReparseData = 0;
|
PREPARSE_DATA_BUFFER ReparseData = 0;
|
||||||
PWSTR P, PathBuffer;
|
PWSTR P, PathBuffer;
|
||||||
|
|
||||||
|
*PMountHandle = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Windows does not allow mount points (junctions) to point to network file systems.
|
* 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.
|
* file system. Preemptively return STATUS_NETWORK_ACCESS_DENIED.
|
||||||
*/
|
*/
|
||||||
for (P = VolumeName, Backslashes = 0; *P; P++)
|
for (P = VolumeName, Backslashes = 0; *P; P++)
|
||||||
@ -211,25 +254,24 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
|
|||||||
goto exit;
|
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());
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
goto exit;
|
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);
|
VolumeNameLength = (USHORT)lstrlenW(VolumeName);
|
||||||
BackslashLength = 0 == VolumeNameLength || L'\\' != VolumeName[VolumeNameLength - 1];
|
BackslashLength = 0 == VolumeNameLength || L'\\' != VolumeName[VolumeNameLength - 1];
|
||||||
VolumeNameLength *= sizeof(WCHAR);
|
VolumeNameLength *= sizeof(WCHAR);
|
||||||
@ -243,7 +285,7 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
|
|||||||
if (0 == ReparseData)
|
if (0 == ReparseData)
|
||||||
{
|
{
|
||||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
goto rmdir_and_exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReparseData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
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 / sizeof(WCHAR)] = L'\\';
|
||||||
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
|
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,
|
ReparseData, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseData->ReparseDataLength,
|
||||||
0, 0,
|
0, 0,
|
||||||
&Bytes, 0);
|
&Bytes, 0))
|
||||||
CloseHandle(DirHandle);
|
|
||||||
if (!Success)
|
|
||||||
{
|
{
|
||||||
Result = FspNtStatusFromWin32(GetLastError());
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
goto rmdir_and_exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*PMountHandle = MountHandle;
|
||||||
|
|
||||||
Result = STATUS_SUCCESS;
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
if (!NT_SUCCESS(Result) && INVALID_HANDLE_VALUE != MountHandle)
|
||||||
|
CloseHandle(MountHandle);
|
||||||
|
|
||||||
MemFree(ReparseData);
|
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;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint)
|
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)
|
if (0 != FileSystem->MountPoint)
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
@ -375,11 +366,10 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
|
|||||||
if (0 == (Drives & (1 << (Drive - 'A'))))
|
if (0 == (Drives & (1 << (Drive - 'A'))))
|
||||||
{
|
{
|
||||||
MountPoint[0] = Drive;
|
MountPoint[0] = Drive;
|
||||||
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName))
|
Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
|
||||||
{
|
&MountHandle);
|
||||||
Result = STATUS_SUCCESS;
|
if (NT_SUCCESS(Result))
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Result = STATUS_NO_SUCH_DEVICE;
|
Result = STATUS_NO_SUCH_DEVICE;
|
||||||
}
|
}
|
||||||
@ -400,22 +390,16 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
|
|||||||
MountPoint = P;
|
MountPoint = P;
|
||||||
|
|
||||||
if (FspPathIsDrive(MountPoint))
|
if (FspPathIsDrive(MountPoint))
|
||||||
{
|
Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
|
||||||
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName))
|
&MountHandle);
|
||||||
Result = STATUS_SUCCESS;
|
|
||||||
else
|
|
||||||
Result = FspNtStatusFromWin32(GetLastError());
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
Result = FspFileSystemSetMountPoint_CreateDirectory(MountPoint, FileSystem->VolumeName);
|
Result = FspFileSystemSetMountPoint_Directory(MountPoint, FileSystem->VolumeName,
|
||||||
|
SecurityDescriptor, &MountHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
if (NT_SUCCESS(Result))
|
if (NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
FspFileSystemSetMountPoint_MakeTemporary(MountPoint, &MountHandle);
|
|
||||||
/* ignore result; this path always considered successful */
|
|
||||||
|
|
||||||
FileSystem->MountPoint = MountPoint;
|
FileSystem->MountPoint = MountPoint;
|
||||||
FileSystem->MountHandle = MountHandle;
|
FileSystem->MountHandle = MountHandle;
|
||||||
}
|
}
|
||||||
@ -425,33 +409,35 @@ exit:
|
|||||||
return Result;
|
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)
|
FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
|
||||||
{
|
{
|
||||||
BOOLEAN IsDrive;
|
|
||||||
|
|
||||||
if (0 == FileSystem->MountPoint)
|
if (0 == FileSystem->MountPoint)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
IsDrive = FspPathIsDrive(FileSystem->MountPoint);
|
if (FspPathIsDrive(FileSystem->MountPoint))
|
||||||
if (IsDrive)
|
FspFileSystemRemoveMountPoint_Drive(FileSystem->MountPoint, FileSystem->VolumeName,
|
||||||
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
|
FileSystem->MountHandle);
|
||||||
FileSystem->MountPoint, FileSystem->VolumeName);
|
|
||||||
else
|
else
|
||||||
/* nothing to do! directory will be deleted when the MountHandle is closed */;
|
FspFileSystemRemoveMountPoint_Directory(FileSystem->MountHandle);
|
||||||
|
|
||||||
MemFree(FileSystem->MountPoint);
|
MemFree(FileSystem->MountPoint);
|
||||||
FileSystem->MountPoint = 0;
|
FileSystem->MountPoint = 0;
|
||||||
|
FileSystem->MountHandle = 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
|
static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
|
||||||
|
@ -32,16 +32,12 @@ struct fsp_fuse_core_opt_data
|
|||||||
{
|
{
|
||||||
struct fsp_fuse_env *env;
|
struct fsp_fuse_env *env;
|
||||||
int help, debug;
|
int help, debug;
|
||||||
int hard_remove,
|
int set_umask, umask,
|
||||||
use_ino, readdir_ino,
|
|
||||||
set_umask, umask,
|
|
||||||
set_uid, uid,
|
set_uid, uid,
|
||||||
set_gid, gid,
|
set_gid, gid,
|
||||||
set_attr_timeout, attr_timeout,
|
set_attr_timeout, attr_timeout,
|
||||||
rellinks;
|
rellinks;
|
||||||
int set_FileInfoTimeout;
|
int set_FileInfoTimeout;
|
||||||
int CaseInsensitiveSearch,
|
|
||||||
ReadOnlyVolume;
|
|
||||||
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
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("-d", debug, 1),
|
||||||
FSP_FUSE_CORE_OPT("debug", debug, 1),
|
FSP_FUSE_CORE_OPT("debug", debug, 1),
|
||||||
|
|
||||||
FSP_FUSE_CORE_OPT("hard_remove", hard_remove, 1),
|
FUSE_OPT_KEY("hard_remove", FUSE_OPT_KEY_DISCARD),
|
||||||
FSP_FUSE_CORE_OPT("use_ino", use_ino, 1),
|
FUSE_OPT_KEY("use_ino", FUSE_OPT_KEY_DISCARD),
|
||||||
FSP_FUSE_CORE_OPT("readdir_ino", readdir_ino, 1),
|
FUSE_OPT_KEY("readdir_ino", FUSE_OPT_KEY_DISCARD),
|
||||||
FUSE_OPT_KEY("direct_io", 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("kernel_cache", FUSE_OPT_KEY_DISCARD),
|
||||||
FUSE_OPT_KEY("auto_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("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
|
||||||
FSP_FUSE_CORE_OPT("VolumeCreationTime=%lli", VolumeParams.VolumeCreationTime, 0),
|
FSP_FUSE_CORE_OPT("VolumeCreationTime=%lli", VolumeParams.VolumeCreationTime, 0),
|
||||||
FSP_FUSE_CORE_OPT("VolumeSerialNumber=%lx", VolumeParams.VolumeSerialNumber, 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=", set_FileInfoTimeout, 1),
|
||||||
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
|
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("--UNC=", 'U'),
|
||||||
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
|
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
|
||||||
FUSE_OPT_KEY("--FileSystemName=", 'F'),
|
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)
|
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));
|
struct fsp_fuse_obj_hdr *hdr = (PVOID)((PUINT8)obj - sizeof(struct fsp_fuse_obj_hdr));
|
||||||
|
|
||||||
hdr->dtor(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)
|
const char *mountpoint, struct fuse_args *args)
|
||||||
{
|
{
|
||||||
struct fuse_chan *ch = 0;
|
struct fuse_chan *ch = 0;
|
||||||
|
WCHAR TempMountPointBuf[MAX_PATH], MountPointBuf[MAX_PATH];
|
||||||
int Size;
|
int Size;
|
||||||
|
|
||||||
if (0 == mountpoint)
|
if (0 == mountpoint || '\0' == mountpoint[0] ||
|
||||||
mountpoint = "";
|
('*' == 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 != env->conv_to_win_path)
|
||||||
if (0 == Size)
|
mountpoint = win_mountpoint = env->conv_to_win_path(mountpoint);
|
||||||
goto fail;
|
|
||||||
|
|
||||||
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)
|
if (0 == ch)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
ch->MountPoint = (PVOID)ch->Buffer;
|
ch->MountPoint = (PVOID)ch->Buffer;
|
||||||
Size = MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, ch->MountPoint, Size);
|
memcpy(ch->MountPoint, MountPointBuf, Size);
|
||||||
if (0 == Size)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
return ch;
|
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_ATOMIC_O_TRUNC | /* due to Windows/WinFsp design, no support */
|
||||||
//FUSE_CAP_EXPORT_SUPPORT | /* not needed in Windows/WinFsp */
|
//FUSE_CAP_EXPORT_SUPPORT | /* not needed in Windows/WinFsp */
|
||||||
FUSE_CAP_BIG_WRITES |
|
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)
|
if (0 != f->ops.init)
|
||||||
|
{
|
||||||
context->private_data = f->data = f->ops.init(&conn);
|
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;
|
f->fsinit = TRUE;
|
||||||
if (0 != f->ops.statfs)
|
if (0 != f->ops.statfs)
|
||||||
{
|
{
|
||||||
@ -278,10 +308,12 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stbuf.f_frsize > FSP_FUSE_SECTORSIZE_MAX)
|
if (0 == f->VolumeParams.SectorSize && 0 != stbuf.f_frsize)
|
||||||
stbuf.f_frsize = FSP_FUSE_SECTORSIZE_MAX;
|
|
||||||
if (0 == f->VolumeParams.SectorSize)
|
|
||||||
f->VolumeParams.SectorSize = (UINT16)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)
|
if (0 == f->VolumeParams.MaxComponentLength)
|
||||||
f->VolumeParams.MaxComponentLength = (UINT16)stbuf.f_namemax;
|
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! */
|
/* the FSD does not currently limit these VolumeParams fields; do so here! */
|
||||||
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN)
|
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN ||
|
||||||
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MIN;
|
f->VolumeParams.SectorSize > FSP_FUSE_SECTORSIZE_MAX)
|
||||||
if (f->VolumeParams.SectorSize > FSP_FUSE_SECTORSIZE_MAX)
|
|
||||||
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MAX;
|
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MAX;
|
||||||
if (f->VolumeParams.SectorsPerAllocationUnit == 0)
|
if (f->VolumeParams.SectorsPerAllocationUnit == 0)
|
||||||
f->VolumeParams.SectorsPerAllocationUnit = 1;
|
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':
|
case 'h':
|
||||||
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
|
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
|
||||||
FSP_FUSE_LIBRARY_NAME " options:\n"
|
FSP_FUSE_LIBRARY_NAME " options:\n"
|
||||||
" -o SectorSize=N sector size for Windows (512-4096, deflt: 512)\n"
|
" -o SectorSize=N sector size for Windows (512-4096, deflt: 4096)\n"
|
||||||
" -o SectorsPerAllocationUnit=N allocation unit size (deflt: 1*SectorSize)\n"
|
" -o SectorsPerAllocationUnit=N sectors per allocation unit (deflt: 1)\n"
|
||||||
" -o MaxComponentLength=N max file name component length (deflt: 255)\n"
|
" -o MaxComponentLength=N max file name component length (deflt: 255)\n"
|
||||||
" -o VolumeCreationTime=T volume creation time (FILETIME hex format)\n"
|
" -o VolumeCreationTime=T volume creation time (FILETIME hex format)\n"
|
||||||
" -o VolumeSerialNumber=N 32-bit wide\n"
|
" -o VolumeSerialNumber=N 32-bit wide\n"
|
||||||
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\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"
|
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n"
|
||||||
" --FileSystemName=FSN Name of user mode file system\n");
|
" --FileSystemName=FSN Name of user mode file system\n");
|
||||||
opt_data->help = 1;
|
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);
|
memset(&opt_data, 0, sizeof opt_data);
|
||||||
opt_data.env = env;
|
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))
|
if (-1 == fsp_fuse_opt_parse(env, args, &opt_data, fsp_fuse_core_opts, fsp_fuse_core_opt_proc))
|
||||||
return 0;
|
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)
|
if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout)
|
||||||
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
|
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.PersistentAcls = TRUE;
|
||||||
opt_data.VolumeParams.ReparsePoints = TRUE;
|
opt_data.VolumeParams.ReparsePoints = TRUE;
|
||||||
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
|
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
|
||||||
opt_data.VolumeParams.NamedStreams = 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.PostCleanupWhenModifiedOnly = TRUE;
|
||||||
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
|
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
|
||||||
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
|
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
|
||||||
|
@ -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)\
|
#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,
|
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,
|
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode, PUINT32 PDev,
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
{
|
{
|
||||||
struct fuse *f = FileSystem->UserContext;
|
struct fuse *f = FileSystem->UserContext;
|
||||||
UINT64 AllocationUnit;
|
UINT64 AllocationUnit;
|
||||||
struct fuse_stat stbuf;
|
struct fuse_stat stbuf;
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&stbuf, 0, sizeof stbuf);
|
if (0 != stbufp)
|
||||||
|
memcpy(&stbuf, stbufp, 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
|
else
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
if (0 != err)
|
memset(&stbuf, 0, sizeof stbuf);
|
||||||
return fsp_fuse_ntstatus_from_errno(f->env, err);
|
|
||||||
|
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)
|
if (f->set_umask)
|
||||||
stbuf.st_mode = (stbuf.st_mode & 0170000) | (0777 & ~f->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;
|
SIZE_T Size;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
Result = fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi,
|
Result = fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0,
|
||||||
&Uid, &Gid, &Mode, &Dev, &FileInfo);
|
&Uid, &Gid, &Mode, &Dev, &FileInfo);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
@ -1576,6 +1582,17 @@ static int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
|
|||||||
memset(DirInfo, 0, sizeof *DirInfo);
|
memset(DirInfo, 0, sizeof *DirInfo);
|
||||||
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + SizeW * sizeof(WCHAR));
|
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);
|
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);
|
DirInfo = (FSP_FSCTL_DIR_INFO *)(Buffer + *Index);
|
||||||
SizeW = (DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR);
|
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;
|
/* DirInfo has been filled already! */
|
||||||
SavedPathChar = *PosixPathEnd;
|
|
||||||
*PosixPathEnd = '\0';
|
DirInfo->Padding[0] = 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
|
else
|
||||||
{
|
{
|
||||||
PosixPathEnd = 0;
|
if (1 == SizeW && L'.' == DirInfo->FileNameBuf[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 */
|
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 1 : PosixName;
|
||||||
Result = STATUS_OBJECT_NAME_INVALID;
|
SavedPathChar = *PosixPathEnd;
|
||||||
goto exit;
|
*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);
|
FspPosixDecodeWindowsPath(DirInfo->FileNameBuf, SizeW);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1683,6 +1709,8 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
{
|
{
|
||||||
memset(&dh, 0, sizeof dh);
|
memset(&dh, 0, sizeof dh);
|
||||||
dh.filedesc = filedesc;
|
dh.filedesc = filedesc;
|
||||||
|
dh.FileSystem = FileSystem;
|
||||||
|
dh.ReaddirPlus = 0 != (f->conn_want & FSP_FUSE_CAP_READDIR_PLUS);
|
||||||
dh.Result = STATUS_SUCCESS;
|
dh.Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
if (0 != f->ops.readdir)
|
if (0 != f->ops.readdir)
|
||||||
|
@ -40,12 +40,13 @@ struct fuse
|
|||||||
int rellinks;
|
int rellinks;
|
||||||
struct fuse_operations ops;
|
struct fuse_operations ops;
|
||||||
void *data;
|
void *data;
|
||||||
|
unsigned conn_want;
|
||||||
|
BOOLEAN fsinit;
|
||||||
UINT32 DebugLog;
|
UINT32 DebugLog;
|
||||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
|
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
|
||||||
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
||||||
PWSTR MountPoint;
|
PWSTR MountPoint;
|
||||||
FSP_FILE_SYSTEM *FileSystem;
|
FSP_FILE_SYSTEM *FileSystem;
|
||||||
BOOLEAN fsinit;
|
|
||||||
FSP_SERVICE *Service; /* weak */
|
FSP_SERVICE *Service; /* weak */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,8 +67,12 @@ struct fsp_fuse_file_desc
|
|||||||
|
|
||||||
struct fuse_dirhandle
|
struct fuse_dirhandle
|
||||||
{
|
{
|
||||||
|
/* ReadDirectory */
|
||||||
struct fsp_fuse_file_desc *filedesc;
|
struct fsp_fuse_file_desc *filedesc;
|
||||||
|
FSP_FILE_SYSTEM *FileSystem;
|
||||||
|
BOOLEAN ReaddirPlus;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
/* CanDelete */
|
||||||
BOOLEAN DotFiles, HasChild;
|
BOOLEAN DotFiles, HasChild;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -163,3 +163,47 @@ exit:
|
|||||||
|
|
||||||
return Result;
|
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;
|
||||||
|
}
|
||||||
|
@ -80,8 +80,18 @@ static NTSTATUS FspFsvolClose(
|
|||||||
FspFileDescDelete(FileDesc); /* this will also close the MainFileObject if any */
|
FspFileDescDelete(FileDesc); /* this will also close the MainFileObject if any */
|
||||||
FspFileNodeDereference(FileNode);
|
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.
|
* and return immediately.
|
||||||
*/
|
*/
|
||||||
FspIopPostWorkRequestBestEffort(FsvolDeviceObject, Request);
|
FspIopPostWorkRequestBestEffort(FsvolDeviceObject, Request);
|
||||||
|
@ -41,6 +41,7 @@ VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject);
|
|||||||
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
|
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
|
||||||
VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
|
VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
|
||||||
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
|
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
|
||||||
|
BOOLEAN FspFsvolDeviceFileRenameIsAcquiredExclusive(PDEVICE_OBJECT DeviceObject);
|
||||||
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject);
|
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject);
|
||||||
VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject);
|
VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject);
|
||||||
NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject,
|
NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject,
|
||||||
@ -80,6 +81,7 @@ VOID FspDeviceDeleteAll(VOID);
|
|||||||
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameSetOwner)
|
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameSetOwner)
|
||||||
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameRelease)
|
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameRelease)
|
||||||
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameReleaseOwner)
|
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameReleaseOwner)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameIsAcquiredExclusive)
|
||||||
#pragma alloc_text(PAGE, FspFsvolDeviceLockContextTable)
|
#pragma alloc_text(PAGE, FspFsvolDeviceLockContextTable)
|
||||||
#pragma alloc_text(PAGE, FspFsvolDeviceUnlockContextTable)
|
#pragma alloc_text(PAGE, FspFsvolDeviceUnlockContextTable)
|
||||||
#pragma alloc_text(PAGE, FspFsvolDeviceCopyContextList)
|
#pragma alloc_text(PAGE, FspFsvolDeviceCopyContextList)
|
||||||
@ -574,6 +576,15 @@ VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Own
|
|||||||
ExReleaseResourceForThreadLite(&FsvolDeviceExtension->FileRenameResource, (ERESOURCE_THREAD)Owner);
|
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)
|
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
160
src/sys/dirctl.c
160
src/sys/dirctl.c
@ -78,6 +78,7 @@ enum
|
|||||||
{
|
{
|
||||||
/* QueryDirectory */
|
/* QueryDirectory */
|
||||||
RequestIrp = 0,
|
RequestIrp = 0,
|
||||||
|
RequestCookie = 1,
|
||||||
RequestMdl = 1,
|
RequestMdl = 1,
|
||||||
RequestAddress = 2,
|
RequestAddress = 2,
|
||||||
RequestProcess = 3,
|
RequestProcess = 3,
|
||||||
@ -88,6 +89,7 @@ enum
|
|||||||
/* DirectoryControlComplete retry */
|
/* DirectoryControlComplete retry */
|
||||||
RequestDirInfoChangeNumber = 0,
|
RequestDirInfoChangeNumber = 0,
|
||||||
};
|
};
|
||||||
|
FSP_FSCTL_STATIC_ASSERT(RequestCookie == RequestMdl, "");
|
||||||
|
|
||||||
static NTSTATUS FspFsvolQueryDirectoryCopy(
|
static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||||
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
|
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
|
||||||
@ -833,41 +835,67 @@ NTSTATUS FspFsvolDirectoryControlPrepare(
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
NTSTATUS Result;
|
if (FspQueryDirectoryIrpShouldUseProcessBuffer(Irp, Request->Req.QueryDirectory.Length))
|
||||||
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 (0 != Mdl)
|
NTSTATUS Result;
|
||||||
IoFreeMdl(Mdl);
|
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 */
|
Mdl = IoAllocateMdl(
|
||||||
Process = PsGetCurrentProcess();
|
Irp->AssociatedIrp.SystemBuffer,
|
||||||
ObReferenceObject(Process);
|
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;
|
/* map the MDL into user-mode */
|
||||||
FspIopRequestContext(Request, RequestAddress) = Address;
|
Result = FspMapLockedPagesInUserMode(Mdl, &Address, 0);
|
||||||
FspIopRequestContext(Request, RequestProcess) = Process;
|
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(
|
NTSTATUS FspFsvolDirectoryControlComplete(
|
||||||
@ -910,6 +938,23 @@ NTSTATUS FspFsvolDirectoryControlComplete(
|
|||||||
|
|
||||||
if (FspFsctlTransactQueryDirectoryKind == Request->Kind)
|
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);
|
DirInfoChangeNumber = FspFileNodeDirInfoChangeNumber(FileNode);
|
||||||
Request->Kind = FspFsctlTransactReservedKind;
|
Request->Kind = FspFsctlTransactReservedKind;
|
||||||
FspIopResetRequest(Request, 0);
|
FspIopResetRequest(Request, 0);
|
||||||
@ -1010,29 +1055,56 @@ static VOID FspFsvolQueryDirectoryRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
|
|||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
PIRP Irp = Context[RequestIrp];
|
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;
|
PVOID Cookie = (PVOID)((UINT_PTR)Context[RequestCookie] & ~1);
|
||||||
BOOLEAN Attach;
|
PVOID Address = Context[RequestAddress];
|
||||||
|
PEPROCESS Process = Context[RequestProcess];
|
||||||
|
|
||||||
ASSERT(0 != Process);
|
if (0 != Address)
|
||||||
Attach = Process != PsGetCurrentProcess();
|
{
|
||||||
|
KAPC_STATE ApcState;
|
||||||
|
BOOLEAN Attach;
|
||||||
|
|
||||||
if (Attach)
|
ASSERT(0 != Process);
|
||||||
KeStackAttachProcess(Process, &ApcState);
|
Attach = Process != PsGetCurrentProcess();
|
||||||
MmUnmapLockedPages(Address, Mdl);
|
|
||||||
if (Attach)
|
|
||||||
KeUnstackDetachProcess(&ApcState);
|
|
||||||
|
|
||||||
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)
|
if (0 != Address)
|
||||||
IoFreeMdl(Mdl);
|
{
|
||||||
|
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)
|
if (0 != Irp)
|
||||||
{
|
{
|
||||||
|
@ -46,6 +46,10 @@ NTSTATUS DriverEntry(
|
|||||||
|
|
||||||
FspDriverMultiVersionInitialize();
|
FspDriverMultiVersionInitialize();
|
||||||
|
|
||||||
|
Result = FspProcessBufferInitialize();
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
FSP_RETURN();
|
||||||
|
|
||||||
FspDriverObject = DriverObject;
|
FspDriverObject = DriverObject;
|
||||||
ExInitializeResourceLite(&FspDeviceGlobalResource);
|
ExInitializeResourceLite(&FspDeviceGlobalResource);
|
||||||
|
|
||||||
@ -59,14 +63,21 @@ NTSTATUS DriverEntry(
|
|||||||
&DeviceSddl, &FspFsctlDeviceClassGuid,
|
&DeviceSddl, &FspFsctlDeviceClassGuid,
|
||||||
&FspFsctlDiskDeviceObject);
|
&FspFsctlDiskDeviceObject);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
FspProcessBufferFinalize();
|
||||||
FSP_RETURN();
|
FSP_RETURN();
|
||||||
|
}
|
||||||
RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
|
RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
|
||||||
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
|
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
|
||||||
&DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
|
&DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
|
||||||
&DeviceSddl, &FspFsctlDeviceClassGuid,
|
&DeviceSddl, &FspFsctlDeviceClassGuid,
|
||||||
&FspFsctlNetDeviceObject);
|
&FspFsctlNetDeviceObject);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
FSP_RETURN(FspDeviceDelete(FspFsctlDiskDeviceObject));
|
{
|
||||||
|
FspDeviceDelete(FspFsctlDiskDeviceObject);
|
||||||
|
FspProcessBufferFinalize();
|
||||||
|
FSP_RETURN();
|
||||||
|
}
|
||||||
Result = FspDeviceInitialize(FspFsctlDiskDeviceObject);
|
Result = FspDeviceInitialize(FspFsctlDiskDeviceObject);
|
||||||
ASSERT(STATUS_SUCCESS == Result);
|
ASSERT(STATUS_SUCCESS == Result);
|
||||||
Result = FspDeviceInitialize(FspFsctlNetDeviceObject);
|
Result = FspDeviceInitialize(FspFsctlNetDeviceObject);
|
||||||
@ -178,6 +189,7 @@ static VOID FspDriverMultiVersionInitialize(VOID)
|
|||||||
{
|
{
|
||||||
FspProcessorCount = KeQueryActiveProcessorCount(0);
|
FspProcessorCount = KeQueryActiveProcessorCount(0);
|
||||||
|
|
||||||
|
#pragma prefast(suppress:30035, "FspDriverMultiVersionInitialize is called from DriverEntry")
|
||||||
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
|
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
|
||||||
|
|
||||||
if (RtlIsNtDdiVersionAvailable(NTDDI_WIN7))
|
if (RtlIsNtDdiVersionAvailable(NTDDI_WIN7))
|
||||||
@ -206,6 +218,8 @@ VOID FspUnload(
|
|||||||
ExDeleteResourceLite(&FspDeviceGlobalResource);
|
ExDeleteResourceLite(&FspDeviceGlobalResource);
|
||||||
FspDriverObject = 0;
|
FspDriverObject = 0;
|
||||||
|
|
||||||
|
FspProcessBufferFinalize();
|
||||||
|
|
||||||
#pragma prefast(suppress:28175, "We are in DriverUnload: ok to access DriverName")
|
#pragma prefast(suppress:28175, "We are in DriverUnload: ok to access DriverName")
|
||||||
FSP_LEAVE_VOID("DriverName=\"%wZ\"",
|
FSP_LEAVE_VOID("DriverName=\"%wZ\"",
|
||||||
&DriverObject->DriverName);
|
&DriverObject->DriverName);
|
||||||
|
@ -601,6 +601,14 @@ VOID FspIrpHookReset(PIRP Irp);
|
|||||||
PVOID FspIrpHookContext(PVOID Context);
|
PVOID FspIrpHookContext(PVOID Context);
|
||||||
NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, 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 */
|
/* IRP context */
|
||||||
#define FspIrpTimestampInfinity ((ULONG)-1L)
|
#define FspIrpTimestampInfinity ((ULONG)-1L)
|
||||||
#define FspIrpTimestamp(Irp) \
|
#define FspIrpTimestamp(Irp) \
|
||||||
@ -1064,6 +1072,7 @@ VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject);
|
|||||||
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
|
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
|
||||||
VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
|
VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
|
||||||
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
|
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
|
||||||
|
BOOLEAN FspFsvolDeviceFileRenameIsAcquiredExclusive(PDEVICE_OBJECT DeviceObject);
|
||||||
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject);
|
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject);
|
||||||
VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject);
|
VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject);
|
||||||
NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject,
|
NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject,
|
||||||
@ -1112,6 +1121,35 @@ VOID FspDeviceGlobalUnlock(VOID)
|
|||||||
//(FILE_DEVICE_DISK_FILE_SYSTEM == (DeviceObject)->DeviceType ?\
|
//(FILE_DEVICE_DISK_FILE_SYSTEM == (DeviceObject)->DeviceType ?\
|
||||||
// STATUS_VOLUME_DISMOUNTED : STATUS_DEVICE_NOT_CONNECTED)
|
// 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 */
|
/* volume management */
|
||||||
#define FspVolumeTransactEarlyTimeout (1 * 10000ULL)
|
#define FspVolumeTransactEarlyTimeout (1 * 10000ULL)
|
||||||
NTSTATUS FspVolumeCreate(
|
NTSTATUS FspVolumeCreate(
|
||||||
|
@ -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 */
|
/* break any Batch or Handle oplocks on descendants */
|
||||||
Result = STATUS_SUCCESS;
|
Result = STATUS_SUCCESS;
|
||||||
for (
|
for (
|
||||||
@ -2073,6 +2117,8 @@ NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
|
|||||||
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
|
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
|
||||||
PUNICODE_STRING FileName)
|
PUNICODE_STRING FileName)
|
||||||
{
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
if (&FileDesc->DirectoryMarker == FileName)
|
if (&FileDesc->DirectoryMarker == FileName)
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
277
src/sys/psbuffer.c
Normal file
277
src/sys/psbuffer.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
175
src/sys/read.c
175
src/sys/read.c
@ -44,10 +44,12 @@ enum
|
|||||||
{
|
{
|
||||||
/* ReadNonCached */
|
/* ReadNonCached */
|
||||||
RequestIrp = 0,
|
RequestIrp = 0,
|
||||||
|
RequestCookie = 1,
|
||||||
RequestSafeMdl = 1,
|
RequestSafeMdl = 1,
|
||||||
RequestAddress = 2,
|
RequestAddress = 2,
|
||||||
RequestProcess = 3,
|
RequestProcess = 3,
|
||||||
};
|
};
|
||||||
|
FSP_FSCTL_STATIC_ASSERT(RequestCookie == RequestSafeMdl, "");
|
||||||
|
|
||||||
static NTSTATUS FspFsvolRead(
|
static NTSTATUS FspFsvolRead(
|
||||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||||
@ -346,41 +348,70 @@ NTSTATUS FspFsvolReadPrepare(
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
NTSTATUS Result;
|
if (FspReadIrpShouldUseProcessBuffer(Irp, Request->Req.Read.Length))
|
||||||
FSP_SAFE_MDL *SafeMdl = 0;
|
|
||||||
PVOID Address;
|
|
||||||
PEPROCESS Process;
|
|
||||||
|
|
||||||
/* create a "safe" MDL if necessary */
|
|
||||||
if (!FspSafeMdlCheck(Irp->MdlAddress))
|
|
||||||
{
|
{
|
||||||
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))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
}
|
|
||||||
|
|
||||||
/* map the MDL into user-mode */
|
/* get a pointer to the current process so that we can release the buffer later */
|
||||||
Result = FspMapLockedPagesInUserMode(
|
Process = PsGetCurrentProcess();
|
||||||
0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress, &Address, 0);
|
ObReferenceObject(Process);
|
||||||
if (!NT_SUCCESS(Result))
|
|
||||||
|
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)
|
NTSTATUS Result;
|
||||||
FspSafeMdlDelete(SafeMdl);
|
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(
|
NTSTATUS FspFsvolReadComplete(
|
||||||
@ -400,15 +431,36 @@ NTSTATUS FspFsvolReadComplete(
|
|||||||
if (Response->IoStatus.Information > Request->Req.Read.Length)
|
if (Response->IoStatus.Information > Request->Req.Read.Length)
|
||||||
FSP_RETURN(Result = STATUS_INTERNAL_ERROR);
|
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;
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
LARGE_INTEGER ReadOffset = IrpSp->Parameters.Read.ByteOffset;
|
LARGE_INTEGER ReadOffset = IrpSp->Parameters.Read.ByteOffset;
|
||||||
BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
|
BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
|
||||||
BOOLEAN SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
|
BOOLEAN SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
|
||||||
|
|
||||||
if (0 != SafeMdl)
|
|
||||||
FspSafeMdlCopyBack(SafeMdl);
|
|
||||||
|
|
||||||
/* if we are top-level */
|
/* if we are top-level */
|
||||||
if (0 == FspIrpTopFlags(Irp))
|
if (0 == FspIrpTopFlags(Irp))
|
||||||
{
|
{
|
||||||
@ -442,29 +494,56 @@ static VOID FspFsvolReadNonCachedRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PV
|
|||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
PIRP Irp = Context[RequestIrp];
|
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;
|
PVOID Cookie = (PVOID)((UINT_PTR)Context[RequestCookie] & ~1);
|
||||||
BOOLEAN Attach;
|
PVOID Address = Context[RequestAddress];
|
||||||
|
PEPROCESS Process = Context[RequestProcess];
|
||||||
|
|
||||||
ASSERT(0 != Process);
|
if (0 != Address)
|
||||||
Attach = Process != PsGetCurrentProcess();
|
{
|
||||||
|
KAPC_STATE ApcState;
|
||||||
|
BOOLEAN Attach;
|
||||||
|
|
||||||
if (Attach)
|
ASSERT(0 != Process);
|
||||||
KeStackAttachProcess(Process, &ApcState);
|
Attach = Process != PsGetCurrentProcess();
|
||||||
MmUnmapLockedPages(Address, 0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress);
|
|
||||||
if (Attach)
|
|
||||||
KeUnstackDetachProcess(&ApcState);
|
|
||||||
|
|
||||||
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)
|
if (0 != Address)
|
||||||
FspSafeMdlDelete(SafeMdl);
|
{
|
||||||
|
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)
|
if (0 != Irp)
|
||||||
{
|
{
|
||||||
|
@ -29,6 +29,8 @@ NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLen
|
|||||||
|
|
||||||
NTSTATUS FspStatisticsCreate(FSP_STATISTICS **PStatistics)
|
NTSTATUS FspStatisticsCreate(FSP_STATISTICS **PStatistics)
|
||||||
{
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
*PStatistics = FspAllocNonPaged(sizeof(FSP_STATISTICS) * FspProcessorCount);
|
*PStatistics = FspAllocNonPaged(sizeof(FSP_STATISTICS) * FspProcessorCount);
|
||||||
if (0 == *PStatistics)
|
if (0 == *PStatistics)
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
@ -49,11 +51,15 @@ NTSTATUS FspStatisticsCreate(FSP_STATISTICS **PStatistics)
|
|||||||
|
|
||||||
VOID FspStatisticsDelete(FSP_STATISTICS *Statistics)
|
VOID FspStatisticsDelete(FSP_STATISTICS *Statistics)
|
||||||
{
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
FspFree(Statistics);
|
FspFree(Statistics);
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLength)
|
NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLength)
|
||||||
{
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
ULONG StatLength;
|
ULONG StatLength;
|
||||||
|
|
||||||
|
@ -171,6 +171,16 @@ static NTSTATUS FspVolumeCreateNoLock(
|
|||||||
}
|
}
|
||||||
VolumeParams.FileSystemName[sizeof VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0';
|
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 */
|
/* create volume guid */
|
||||||
Result = FspCreateGuid(&Guid);
|
Result = FspCreateGuid(&Guid);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
|
162
src/sys/write.c
162
src/sys/write.c
@ -45,10 +45,12 @@ enum
|
|||||||
{
|
{
|
||||||
/* WriteNonCached */
|
/* WriteNonCached */
|
||||||
RequestIrp = 0,
|
RequestIrp = 0,
|
||||||
|
RequestCookie = 1,
|
||||||
RequestSafeMdl = 1,
|
RequestSafeMdl = 1,
|
||||||
RequestAddress = 2,
|
RequestAddress = 2,
|
||||||
RequestProcess = 3,
|
RequestProcess = 3,
|
||||||
};
|
};
|
||||||
|
FSP_FSCTL_STATIC_ASSERT(RequestCookie == RequestSafeMdl, "");
|
||||||
|
|
||||||
static NTSTATUS FspFsvolWrite(
|
static NTSTATUS FspFsvolWrite(
|
||||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||||
@ -416,41 +418,86 @@ NTSTATUS FspFsvolWritePrepare(
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
NTSTATUS Result;
|
if (FspWriteIrpShouldUseProcessBuffer(Irp, Request->Req.Write.Length))
|
||||||
FSP_SAFE_MDL *SafeMdl = 0;
|
|
||||||
PVOID Address;
|
|
||||||
PEPROCESS Process;
|
|
||||||
|
|
||||||
/* create a "safe" MDL if necessary */
|
|
||||||
if (!FspSafeMdlCheck(Irp->MdlAddress))
|
|
||||||
{
|
{
|
||||||
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))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
}
|
|
||||||
|
|
||||||
/* map the MDL into user-mode */
|
ASSERT(0 != Address);
|
||||||
Result = FspMapLockedPagesInUserMode(
|
try
|
||||||
0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress, &Address, FspMvMdlMappingNoWrite);
|
{
|
||||||
if (!NT_SUCCESS(Result))
|
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)
|
NTSTATUS Result;
|
||||||
FspSafeMdlDelete(SafeMdl);
|
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(
|
NTSTATUS FspFsvolWriteComplete(
|
||||||
@ -524,29 +571,56 @@ static VOID FspFsvolWriteNonCachedRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
|
|||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
PIRP Irp = Context[RequestIrp];
|
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;
|
PVOID Cookie = (PVOID)((UINT_PTR)Context[RequestCookie] & ~1);
|
||||||
BOOLEAN Attach;
|
PVOID Address = Context[RequestAddress];
|
||||||
|
PEPROCESS Process = Context[RequestProcess];
|
||||||
|
|
||||||
ASSERT(0 != Process);
|
if (0 != Address)
|
||||||
Attach = Process != PsGetCurrentProcess();
|
{
|
||||||
|
KAPC_STATE ApcState;
|
||||||
|
BOOLEAN Attach;
|
||||||
|
|
||||||
if (Attach)
|
ASSERT(0 != Process);
|
||||||
KeStackAttachProcess(Process, &ApcState);
|
Attach = Process != PsGetCurrentProcess();
|
||||||
MmUnmapLockedPages(Address, 0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress);
|
|
||||||
if (Attach)
|
|
||||||
KeUnstackDetachProcess(&ApcState);
|
|
||||||
|
|
||||||
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)
|
if (0 != Address)
|
||||||
FspSafeMdlDelete(SafeMdl);
|
{
|
||||||
|
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)
|
if (0 != Irp)
|
||||||
{
|
{
|
||||||
|
@ -508,7 +508,8 @@ L:
|
|||||||
|
|
||||||
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-%1.exe" ^
|
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-%1.exe" ^
|
||||||
--external --resilient --case-insensitive-cmp --share-prefix="\passthrough\%TMP::=$%\passthrough-%1\test" ^
|
--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
|
if !ERRORLEVEL! neq 0 set SamplePassthroughExit=1
|
||||||
|
|
||||||
popd
|
popd
|
||||||
@ -534,7 +535,7 @@ call %ProjRoot%\tools\build-sample %Configuration% %1 passthrough-fuse "%TMP%\pa
|
|||||||
if !ERRORLEVEL! neq 0 goto fail
|
if !ERRORLEVEL! neq 0 goto fail
|
||||||
mkdir "%TMP%\passthrough-fuse-%1\test"
|
mkdir "%TMP%\passthrough-fuse-%1\test"
|
||||||
call "%ProjRoot%\tools\fsreg" passthrough-fuse "%TMP%\passthrough-fuse-%1\build\%Configuration%\passthrough-fuse-%1.exe" ^
|
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"
|
echo net use L: "\\passthrough-fuse\%TMP::=$%\passthrough-fuse-%1\test"
|
||||||
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
|
if !ERRORLEVEL! neq 0 goto fail
|
||||||
@ -547,7 +548,7 @@ L:
|
|||||||
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-%1.exe" ^
|
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-%1.exe" ^
|
||||||
--external --resilient --case-insensitive-cmp --share-prefix="\passthrough-fuse\%TMP::=$%\passthrough-fuse-%1\test" ^
|
--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 ^
|
-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*
|
-reparse* -stream*
|
||||||
if !ERRORLEVEL! neq 0 set SamplePassthroughExit=1
|
if !ERRORLEVEL! neq 0 set SamplePassthroughExit=1
|
||||||
|
|
||||||
|
@ -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
|
* 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.
|
* 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)
|
#if !defined(NDEBUG)
|
||||||
#define DEBUG_BUFFER_CHECK
|
//#define DEBUG_BUFFER_CHECK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MEMFS_SECTOR_SIZE 512
|
#define MEMFS_SECTOR_SIZE 512
|
||||||
|
@ -187,7 +187,11 @@ static int ptfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, fus
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
if (0 == (de = readdir(dirp)))
|
if (0 == (de = readdir(dirp)))
|
||||||
break;
|
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))
|
if (0 != filler(buf, de->d_name, 0, 0))
|
||||||
|
#endif
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,6 +205,21 @@ static int ptfs_releasedir(const char *path, struct fuse_file_info *fi)
|
|||||||
return -1 != closedir(dirp) ? 0 : -errno;
|
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)
|
static int ptfs_create(const char *path, fuse_mode_t mode, struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
ptfs_impl_fullpath(path);
|
ptfs_impl_fullpath(path);
|
||||||
@ -254,7 +273,7 @@ static struct fuse_operations ptfs_ops =
|
|||||||
ptfs_readdir,
|
ptfs_readdir,
|
||||||
ptfs_releasedir,
|
ptfs_releasedir,
|
||||||
0, //fsyncdir
|
0, //fsyncdir
|
||||||
0, //init
|
ptfs_init,
|
||||||
0, //destroy
|
0, //destroy
|
||||||
0, //access
|
0, //access
|
||||||
ptfs_create,
|
ptfs_create,
|
||||||
|
@ -115,7 +115,7 @@ int statvfs(const char *path, struct fuse_statvfs *stbuf)
|
|||||||
|
|
||||||
memset(stbuf, 0, sizeof *stbuf);
|
memset(stbuf, 0, sizeof *stbuf);
|
||||||
stbuf->f_bsize = SectorsPerCluster * BytesPerSector;
|
stbuf->f_bsize = SectorsPerCluster * BytesPerSector;
|
||||||
stbuf->f_frsize = BytesPerSector;
|
stbuf->f_frsize = SectorsPerCluster * BytesPerSector;
|
||||||
stbuf->f_blocks = TotalNumberOfClusters;
|
stbuf->f_blocks = TotalNumberOfClusters;
|
||||||
stbuf->f_bfree = NumberOfFreeClusters;
|
stbuf->f_bfree = NumberOfFreeClusters;
|
||||||
stbuf->f_bavail = TotalNumberOfClusters;
|
stbuf->f_bavail = TotalNumberOfClusters;
|
||||||
@ -388,6 +388,8 @@ void rewinddir(DIR *dirp)
|
|||||||
struct dirent *readdir(DIR *dirp)
|
struct dirent *readdir(DIR *dirp)
|
||||||
{
|
{
|
||||||
WIN32_FIND_DATAA FindData;
|
WIN32_FIND_DATAA FindData;
|
||||||
|
UINT64 CreationTime, LastAccessTime, LastWriteTime;
|
||||||
|
struct fuse_stat *stbuf = &dirp->de.d_stat;
|
||||||
|
|
||||||
if (INVALID_HANDLE_VALUE == dirp->fh)
|
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);
|
strcpy(dirp->de.d_name, FindData.cFileName);
|
||||||
|
|
||||||
return &dirp->de;
|
return &dirp->de;
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
typedef struct _DIR DIR;
|
typedef struct _DIR DIR;
|
||||||
struct dirent
|
struct dirent
|
||||||
{
|
{
|
||||||
|
struct fuse_stat d_stat;
|
||||||
char d_name[255];
|
char d_name[255];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
352
tst/winfsp-tests/exec-test.c
Normal file
352
tst/winfsp-tests/exec-test.c
Normal 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);
|
||||||
|
}
|
13
tst/winfsp-tests/helper/build.bat
Normal file
13
tst/winfsp-tests/helper/build.bat
Normal 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
|
BIN
tst/winfsp-tests/helper/winfsp-tests-helper-x64.exe
Normal file
BIN
tst/winfsp-tests/helper/winfsp-tests-helper-x64.exe
Normal file
Binary file not shown.
BIN
tst/winfsp-tests/helper/winfsp-tests-helper-x86.exe
Normal file
BIN
tst/winfsp-tests/helper/winfsp-tests-helper-x86.exe
Normal file
Binary file not shown.
104
tst/winfsp-tests/helper/winfsp-tests-helper.c
Normal file
104
tst/winfsp-tests/helper/winfsp-tests-helper.c
Normal 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));
|
||||||
|
}
|
2
tst/winfsp-tests/helper/winfsp-tests-helper.rc
Normal file
2
tst/winfsp-tests/helper/winfsp-tests-helper.rc
Normal 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"
|
@ -427,3 +427,35 @@ BOOL WINAPI HookSetCurrentDirectoryW(
|
|||||||
MaybeAdjustTraversePrivilege(TRUE);
|
MaybeAdjustTraversePrivilege(TRUE);
|
||||||
return Success;
|
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;
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <tlib/testsuite.h>
|
#include <tlib/testsuite.h>
|
||||||
#include <sddl.h>
|
#include <sddl.h>
|
||||||
#include <strsafe.h>
|
#include <strsafe.h>
|
||||||
|
#include <time.h>
|
||||||
#include "memfs.h"
|
#include "memfs.h"
|
||||||
|
|
||||||
#include "winfsp-tests.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)
|
static void rename_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
|
||||||
{
|
{
|
||||||
void *memfs = memfs_start_ex(Flags, 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 getvolinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
|
||||||
{
|
{
|
||||||
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
|
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
|
||||||
@ -1331,6 +1727,7 @@ void info_tests(void)
|
|||||||
TEST(delete_pending_test);
|
TEST(delete_pending_test);
|
||||||
if (!OptShareName)
|
if (!OptShareName)
|
||||||
TEST(delete_mmap_test);
|
TEST(delete_mmap_test);
|
||||||
|
TEST(delete_standby_test);
|
||||||
TEST(rename_test);
|
TEST(rename_test);
|
||||||
TEST(rename_open_test);
|
TEST(rename_open_test);
|
||||||
TEST(rename_caseins_test);
|
TEST(rename_caseins_test);
|
||||||
@ -1338,6 +1735,7 @@ void info_tests(void)
|
|||||||
TEST(rename_flipflop_test);
|
TEST(rename_flipflop_test);
|
||||||
if (!OptShareName)
|
if (!OptShareName)
|
||||||
TEST(rename_mmap_test);
|
TEST(rename_mmap_test);
|
||||||
|
TEST(rename_standby_test);
|
||||||
TEST(getvolinfo_test);
|
TEST(getvolinfo_test);
|
||||||
TEST(setvolinfo_test);
|
TEST(setvolinfo_test);
|
||||||
}
|
}
|
||||||
|
42
tst/winfsp-tests/version-test.c
Normal file
42
tst/winfsp-tests/version-test.c
Normal 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);
|
||||||
|
}
|
@ -184,6 +184,7 @@ int main(int argc, char *argv[])
|
|||||||
TESTSUITE(eventlog_tests);
|
TESTSUITE(eventlog_tests);
|
||||||
TESTSUITE(path_tests);
|
TESTSUITE(path_tests);
|
||||||
TESTSUITE(dirbuf_tests);
|
TESTSUITE(dirbuf_tests);
|
||||||
|
TESTSUITE(version_tests);
|
||||||
TESTSUITE(mount_tests);
|
TESTSUITE(mount_tests);
|
||||||
TESTSUITE(timeout_tests);
|
TESTSUITE(timeout_tests);
|
||||||
TESTSUITE(memfs_tests);
|
TESTSUITE(memfs_tests);
|
||||||
@ -194,6 +195,7 @@ int main(int argc, char *argv[])
|
|||||||
TESTSUITE(flush_tests);
|
TESTSUITE(flush_tests);
|
||||||
TESTSUITE(lock_tests);
|
TESTSUITE(lock_tests);
|
||||||
TESTSUITE(dirctl_tests);
|
TESTSUITE(dirctl_tests);
|
||||||
|
TESTSUITE(exec_tests);
|
||||||
TESTSUITE(reparse_tests);
|
TESTSUITE(reparse_tests);
|
||||||
TESTSUITE(stream_tests);
|
TESTSUITE(stream_tests);
|
||||||
TESTSUITE(oplock_tests);
|
TESTSUITE(oplock_tests);
|
||||||
|
@ -85,6 +85,17 @@ static inline BOOL RealSetCurrentDirectoryW(
|
|||||||
{
|
{
|
||||||
return SetCurrentDirectoryW(lpPathName);
|
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)
|
#if !defined(WINFSP_TESTS_NO_HOOKS)
|
||||||
#define CreateFileW HookCreateFileW
|
#define CreateFileW HookCreateFileW
|
||||||
#define CloseHandle HookCloseHandle
|
#define CloseHandle HookCloseHandle
|
||||||
@ -99,6 +110,7 @@ static inline BOOL RealSetCurrentDirectoryW(
|
|||||||
#define GetVolumeInformationW HookGetVolumeInformationW
|
#define GetVolumeInformationW HookGetVolumeInformationW
|
||||||
#define SetVolumeLabelW HookSetVolumeLabelW
|
#define SetVolumeLabelW HookSetVolumeLabelW
|
||||||
#define SetCurrentDirectoryW HookSetCurrentDirectoryW
|
#define SetCurrentDirectoryW HookSetCurrentDirectoryW
|
||||||
|
#define CreateProcessW HookCreateProcessW
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
HANDLE WINAPI ResilientCreateFileW(
|
HANDLE WINAPI ResilientCreateFileW(
|
||||||
|
Reference in New Issue
Block a user