Compare commits

..

103 Commits

Author SHA1 Message Date
6f22828060 tools: build: ensure that driver.cab is properly signed 2017-01-09 12:56:13 -08:00
7c2de68892 tools: build: create single driver.cab file 2017-01-09 12:37:39 -08:00
4656e8ed26 tools: build: incorporate sysdev signed drivers in build 2017-01-08 00:07:03 -08:00
be98326bbb tools: build: create driver.cab for sysdev 2017-01-07 20:59:36 -08:00
52acc3bc48 update Changelog 2017-01-06 12:47:11 -08:00
f68bc75255 build: include git short hash when versioning 2017-01-06 11:35:10 -08:00
029942bbac Update README 2017-01-05 16:54:46 -08:00
cb0c7def54 update README 2017-01-05 16:45:07 -08:00
5fbd75926b update README 2017-01-05 16:11:49 -08:00
bc9bcefc62 doc: add NTFS compatibility document 2017-01-05 15:56:15 -08:00
a57325e8af update source copyright notices for 2017 2017-01-05 13:56:18 -08:00
466922787d doc: update winfsp.h reference 2017-01-05 13:48:50 -08:00
9dc8aca710 inc: winfsp.h: update source documentation 2017-01-05 13:45:30 -08:00
88aeb83211 doc: fix file name case 2017-01-05 12:54:40 -08:00
a7cee1eafe doc: update testing document 2017-01-05 12:34:06 -08:00
eb0816db56 sys: create: do FspFsvolCreatePostClose when normalized name check fails 2017-01-04 16:26:12 -08:00
51833751d0 appveyor: reenable all jobs 2017-01-04 15:15:14 -08:00
155344ea61 appveyor: memory.dmp test 2017-01-04 15:03:03 -08:00
3874e2a6b5 appveyor: upload perf-tests results as artifact 2017-01-04 14:53:45 -08:00
c5740029f7 appveyor: optimize yml file 2017-01-04 14:41:15 -08:00
9973c4c963 appveyor: optimize yml file 2017-01-04 14:39:12 -08:00
6cfda75447 tools: run-perf-tests: 'self' option changed to 'baseline' 2017-01-04 14:28:52 -08:00
c7d6fc355b tools: run-perf-tests: specialized testing using the self option 2017-01-04 14:26:02 -08:00
b062f8683c appveyor: temporary change 2017-01-04 13:47:50 -08:00
cec5f0be08 appveyor: temporary change 2017-01-04 13:45:23 -08:00
40b61f7667 tools: run-perf-tests: fix 2017-01-04 13:44:22 -08:00
7c383654bd appveyor: perf tests job 2017-01-04 13:07:51 -08:00
9e4e7d4bcf tools: run-tests: ifstest: disable StreamNotifyNameTest 2017-01-03 23:40:49 -08:00
638e5a20b6 sys: FspFileNodeCopyActiveList, FspFileNodeCopyOpenList 2017-01-03 23:14:33 -08:00
95bbb584eb sys: FspFileNodeOpen,FspFileNode: maintain active list 2017-01-03 18:57:00 -08:00
1d8241cba7 sys: FspFileNodeNotifyChange: FILE_NOTIFY_CHANGE_STREAM_WRITE 2017-01-03 12:17:52 -08:00
460726df83 tst: memfs: Cleanup now properly update metadata on MainFileNode 2017-01-03 12:07:52 -08:00
b5cefc59e9 tools: run-tests.bat 2017-01-03 10:43:57 -08:00
e9ca1a8996 tools: run-tests 2017-01-03 10:12:44 -08:00
8c0f609a93 tools: run-tests: ifstest 2017-01-03 00:56:58 -08:00
23eabe5939 sys: FspFsvolFileSystemControlReparsePoint: FSCL_DELETE_REPARSE_POINT 2017-01-03 00:48:12 -08:00
eecca688bc sys: FspFileNodeInvalidateFileInfo: use after setting/deleting reparse point 2017-01-01 12:53:58 -08:00
23d2083d8f sys: FspFsvolFileSystemControlReparsePoint 2017-01-01 11:23:38 -08:00
8d379a4c8b tools: run-tests: ifstest: enable ReparsePoints tests 2016-12-31 23:36:45 -08:00
830985d331 sys: FspFsvolFileSystemControlReparsePoint: STATUS_ACCESS_DENIED 2016-12-31 23:01:40 -08:00
6b37e2ef12 sys: FspFsvolFileSystemControlReparsePointComplete 2016-12-31 21:26:12 -08:00
62dbaf56e3 sys: FspFsvolFileSystemControlReparsePointComplete 2016-12-31 20:50:03 -08:00
d301164609 sys: FspFsvolFileSystemControlReparsePointComplete: STATUS_INVALID_PARAMETER 2016-12-31 16:56:02 -08:00
ada3e1b0e5 tools: run-tests: ifstest: do not output unnamed tests 2016-12-31 16:32:33 -08:00
13d6ec3638 sys: FspFileNodeRenameCheck: allow multiple handles open on the file being renamed 2016-12-31 15:28:26 -08:00
2210561b65 sys: FspIopDispatchComplete: check user mode file system response 2016-12-31 11:22:27 -08:00
1713ce9c9e sys: FSP_STATUS_IGNORE_BIT 2016-12-30 19:48:19 -08:00
8f25dd6cab sys: FspIopCompleteIrpEx:
- only update statistics if we actually have a reference to the DeviceObject
2016-12-30 15:36:06 -08:00
c9485ff214 tools: run-tests: ifstest: add information about disabled tests 2016-12-30 15:03:42 -08:00
5ce1a722b3 tools: run-tests: ifstest: FileInformation tests 2016-12-30 14:43:15 -08:00
27315c1111 sys: FspFsvolQueryInformation,FspFsvolSetInformation:
- return STATUS_INVALID_PARAMETER on volume handles
2016-12-30 14:40:28 -08:00
bd38a39dbd sys: FileHardLinkInformation,FileLinkInformation: return STATUS_NOT_SUPPORTED 2016-12-30 14:14:54 -08:00
766734a8e3 sys: FileAlternateNameInformation: return STATUS_OBJECT_NAME_NOT_FOUND 2016-12-30 13:59:56 -08:00
b242a449b8 tools: run-tests: ifstest: enable FileInformation (not all tests pass yet) 2016-12-30 13:43:17 -08:00
c6a6fdfc36 sys: FSCTL_GET_RETRIEVAL_POINTERS 2016-12-30 13:42:46 -08:00
843d3f0362 sys: FspFsvolSetBasicInformation: invalidate dir caches 2016-12-30 11:01:52 -08:00
5190923c9a sys: FspFsvolQueryDirectoryRetry: on RestartScan do not always reset DirectoryPattern 2016-12-29 15:57:02 -08:00
2f8ac3765d sys: FspFileNodeCleanup:
- Handle the scenario where there are cleaned up, but unclosed streams in the context table.
2016-12-29 14:18:04 -08:00
e4b4e6a1f9 sys: FSP_FILE_NODE::MainFileNode: reference/dereference on create/delete 2016-12-29 13:16:11 -08:00
fa54898c64 appveyor: improvements 2016-12-28 21:50:22 -08:00
2f82d91e1f appveyor: save memory.dmp 2016-12-28 21:30:24 -08:00
7574c39ffb tools: run-tests: check whether ifstest could remove its directories 2016-12-28 17:41:35 -08:00
bdc02c8ab5 tst: memfs: ReadDirectory fix with concurrent deletes 2016-12-28 16:49:21 -08:00
15c16d7070 tools: run-tests: ifstest: enable ChangeNotification 2016-12-27 22:27:13 -08:00
ba312de59b sys: security: change notification 2016-12-27 22:24:42 -08:00
5824a24bf4 sys: FspFileNodeNotifyChange: significant improvements 2016-12-27 21:30:56 -08:00
f0a0787f6b update submodules 2016-12-27 17:07:58 -08:00
c17b84cff2 sys: statistics: fix stupid mistake when having multiple processors 2016-12-27 16:43:53 -08:00
168acb1a1f sys: statistics: implement FSCTL_FILESYSTEM_GET_STATISTICS 2016-12-26 22:45:48 -08:00
c8206751d2 sys,dll: Flush now takes FileInfo parameter 2016-12-26 13:59:53 -08:00
bec91873fe inc: fsctl: HasTrailingBackslash: allows for better checking user mode 2016-12-24 11:28:59 -08:00
9bf0d5d46d tools: run-tests: ifstest: enable CloseCleanupDelete (-UpdateOnCloseTest) 2016-12-23 17:16:07 -08:00
2d85c7bf73 tst: memfs: update parent timestamp on create/delete 2016-12-23 17:12:23 -08:00
ff3436718c sys: FSP_FILE_DESC::DidSetMetadata 2016-12-23 16:26:16 -08:00
69f6f661ba sys,dll: Cleanup, file times overhaul 2016-12-23 15:30:39 -08:00
6e52def53c tools: run-tests: ifstest: enable all tests that pass 2016-12-22 15:59:26 -08:00
2212d021e1 appveyor: run ifstest 2016-12-22 13:23:03 -08:00
7b94f2bebf sys: FspFileNodeSetFileInfo: TruncateOnClose 2016-12-21 16:45:01 -08:00
c897ddd864 sys,dll: Cleanup/TruncateOnClose overhaul 2016-12-21 16:09:24 -08:00
8d6314e2db tst: winfsp-tests: create_allocation_test 2016-12-20 10:56:35 -08:00
eec63332e0 sys: fileinfo: correctly set AllInformation and StandardInformation DeletePending flag 2016-12-19 13:36:11 -08:00
04186ea834 installer: change product name to WinFsp 2017 2016-12-19 10:46:32 -08:00
3adcf70748 sys: disallow creating a ReadOnly and DeleteOnClose file 2016-12-18 21:50:11 -08:00
33e8b5df04 sys,dll: create: correctly handle FILE_SUPERSEDE 2016-12-18 16:56:11 -08:00
154933ecab sys: overwrite: check hidde/system attributes (IFSTEST) 2016-12-18 16:02:32 -08:00
c760cf9563 tst: winfsp-tests: create_namelen_test: disable test in cases that it cannot work 2016-12-18 14:15:08 -08:00
245bba0a17 sys: name: fix warning on x86 builds 2016-12-18 13:35:25 -08:00
3008575bdf tst: winfsp-tests: create_namelen_test 2016-12-18 12:51:57 -08:00
2ce434efbd tst: run-tests: ifstest 2016-12-18 12:04:20 -08:00
94ea4f65f7 sys: FspFileNameIsValid, FspFileNameIsValidPattern: check path component length
tst: memfs: allow filenames to be 512 chars long
2016-12-18 11:51:23 -08:00
c780912810 sys: create: fix status return (IFSTEST) 2016-12-17 12:43:00 -08:00
299605b8fc sys: FILE_ATTRIBUTE_DIRECTORY support 2016-12-17 12:13:53 -08:00
86bccd763c tools: run-tests: ifstest 2016-12-16 23:55:19 -08:00
856d3bdefe tools: run-tests: ifstest 2016-12-16 23:10:13 -08:00
104c830437 tools: run-tests: ifstest 2016-12-16 22:54:40 -08:00
f35a93d1f7 tools: run-tests: ifstest 2016-12-16 20:20:49 -08:00
2d9b1b80fa sys: lockctl: fix hang uncovered by IFSTEST 2016-12-16 16:31:00 -08:00
f1ee19d8dc tst: winfsp-tests: getvolinfo_test: do not do short name testing with shares 2016-12-15 16:52:36 -08:00
671c0c12ab sys: FSCTL_QUERY_PERSISTENT_VOLUME_STATE 2016-12-15 16:15:22 -08:00
6eb2879374 tst: memfs: check FileName length in Create/Open 2016-12-15 14:54:15 -08:00
1e03c1a465 sys: FspFsvolQueryFsAttributeInformation: allow file system to fully specify file system name
tst: memfs: add -F FileSystemName option
2016-12-15 14:26:36 -08:00
b55c20b393 tools: deploy ifstest.bat 2016-12-15 13:08:25 -08:00
406af6901f tools: ifstest 2016-12-15 11:58:38 -08:00
125 changed files with 2277 additions and 538 deletions

View File

@ -3,9 +3,13 @@
v1.0RC1::
This is the first Release Candidate. It has been tested for robustness and correct file system semantics in a variety of scenarios. Some of the more important changes:
This is the WinFsp 2017 Release Candidate 1. It has been tested extensively in a variety of scenarios for stability and correct file system semantics. Some of the more important changes:
- API has been polished and finalized.
- Extensively tested against multiple test suites including Microsoft's IfsTest.
- WinFsp I/O Queues (the fundamental WinFsp IPC mechanism) have been improved to work similar to I/O Completion Ports.
- Opportunistic locks have been implemented.
- File system statistics have been implemented.
- Sharing a (disk) file system over the network is supported.
- Case insensitive file systems are supported.
- Directories are supported as mount points.

View File

@ -4,15 +4,15 @@
WinFsp is a set of software components for Windows computers that allows the creation of user mode file systems. In this sense it is similar to FUSE (Filesystem in Userspace), which provides the same functionality on UNIX-like computers.
Some of the benefits and features of using WinFsp are listed below:
Some of the benefits of using WinFsp are listed below:
* Allows for easy development of file systems in user mode. There are no restrictions on what a process can do in order to implement a file system (other than respond in a timely manner to file system requests).
* Support for disk and network based file systems.
* Support for NTFS level security and access control.
* Support for memory mapped files, cached files and the NT cache manager.
* Support for file change notifications.
* Support for file locking.
* Correct NT semantics with respect to file sharing, file deletion and renaming.
* Very well-tested and stable. Read about its [Testing Strategy](doc/WinFsp-Testing.asciidoc).
* Very fast. Read about its [Performance](doc/WinFsp-Performance-Testing.asciidoc).
* Strives for compatibility with NTFS. Read about its [Compatibility](doc/NTFS-Compatibility.asciidoc ).
* Easy to understand but comprehensive API. Consult the [API Reference](http://www.secfs.net/winfsp/apiref/).
* FUSE compatibility layer for native Windows and Cygwin. See [fuse.h](inc/fuse/fuse.h).
* Signed drivers provided on every release.
* Available under the GPLv3.
To learn more about WinFsp, please visit its website: http://www.secfs.net/winfsp/
@ -53,6 +53,7 @@ WinFsp is designed to run on Vista and above. It has been tested on the followin
* Windows 8 Pro
* Windows 10 Pro
* Windows Server 2012
* Windows Server 2016
## How to Help
@ -60,7 +61,7 @@ I am looking for help in the following areas:
* If you have a file system that runs on FUSE please consider porting it to WinFsp. WinFsp has a native API, but it also has a FUSE (high-level) API.
* If you are working with a language other than C/C++ (e.g. Delphi, C#, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you.
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues) ~~[BitBucket repository](https://bitbucket.org/billziss/winfsp/issues?status=new&status=open)~~. Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart. If you decide to tackle any of those please coordinate with me as I am actively working on that issue list.
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues). Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart.
In all cases I can provide ideas and/or support.

View File

@ -2,6 +2,10 @@ version: '{build}'
environment:
matrix:
- CONFIGURATION: Debug
TESTING: Func
- CONFIGURATION: Release
TESTING: Func
- CONFIGURATION: Release
TESTING: Perf

View File

@ -1,7 +1,7 @@
/**
* @file CustomActions.cpp
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -155,7 +155,7 @@
<RegistryValue
Type="string"
Name="CommandLine"
Value="-i -n 65536 -s 67108864 -u %1 -m %2" />
Value="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2" />
<RegistryValue
Type="string"
Name="Security"
@ -181,7 +181,7 @@
<RegistryValue
Type="string"
Name="CommandLine"
Value="-i -n 65536 -s 67108864 -u %1 -m %2" />
Value="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2" />
<RegistryValue
Type="string"
Name="Security"

View File

@ -16,7 +16,7 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<IntermediateOutputPath>$(SolutionDir)build\$(Name).build\$(Configuration)\$(Platform)\</IntermediateOutputPath>
<DefineConstants>Debug;MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion)</DefineConstants>
<DefineConstants>Debug;MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyFullVersion=$(MyFullVersion)</DefineConstants>
<SuppressAllWarnings>False</SuppressAllWarnings>
<Pedantic>True</Pedantic>
<SuppressPdbOutput>True</SuppressPdbOutput>
@ -25,7 +25,7 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<IntermediateOutputPath>$(SolutionDir)build\$(Name).build\$(Configuration)\$(Platform)\</IntermediateOutputPath>
<DefineConstants>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion)</DefineConstants>
<DefineConstants>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyFullVersion=$(MyFullVersion)</DefineConstants>
<SuppressAllWarnings>False</SuppressAllWarnings>
<Pedantic>True</Pedantic>
<SuppressPdbOutput>True</SuppressPdbOutput>

View File

@ -193,10 +193,10 @@
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\src\launcher\launchctl-version.rc">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemGroup>
<ItemGroup>

View File

@ -202,10 +202,10 @@
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\src\launcher\launcher-version.rc">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -1,6 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- build number: concat 2-digit year with 3-digit day of the year (16-bits until 2066) -->
<MyBuildNumber>$([System.DateTime]::Now.ToString(`yy`))$([System.DateTime]::Now.DayOfYear.ToString(`000`))</MyBuildNumber>
<!-- git revision -->
<MyGitRoot>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), .git/HEAD))</MyGitRoot>
<MyGitHead>$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/HEAD).Trim())</MyGitHead>
<MyGitRevision Condition="$(MyGitHead.StartsWith(ref: ))">$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/$(MyGitHead.Substring(5))).Trim().Substring(0, 7))</MyGitRevision>
<MyGitRevision Condition="!$(MyGitHead.StartsWith(ref: ))">$(MyGitHead.Substring(0, 7))</MyGitRevision>
<MyProductName>WinFsp</MyProductName>
<MyDescription>Windows File System Proxy</MyDescription>
<MyCompanyName>Navimatics Corporation</MyCompanyName>
@ -8,19 +17,20 @@
<MyCanonicalVersion>1.0</MyCanonicalVersion>
<MyProductVersion>$(MyCanonicalVersion) RC1</MyProductVersion>
<MyProductVersion>2017 RC1</MyProductVersion>
<MyProductStage>RC</MyProductStage>
<!-- build number: concat 2-digit year with 3-digit day of the year (16-bits until 2066) -->
<MyBuildNumber>$([System.DateTime]::Now.ToString(`yy`))$([System.DateTime]::Now.DayOfYear.ToString(`000`))</MyBuildNumber>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
<MyFullVersion>$(MyCanonicalVersion).$(MyBuildNumber).$(MyGitRevision)</MyFullVersion>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>NTDDI_VERSION=0x06010000;_WIN32_WINNT=0x0601</PreprocessorDefinitions>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas);MyFullVersion=$(MyFullVersion)</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
</Project>

View File

@ -78,10 +78,10 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
<ItemGroup>
<ResourceCompile Include="..\..\src\dll\eventlog\eventlog.rc" />
<ResourceCompile Include="..\..\src\dll\version.rc">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemGroup>
<PropertyGroup Label="Globals">

View File

@ -177,6 +177,7 @@
<ClCompile Include="..\..\src\sys\read.c" />
<ClCompile Include="..\..\src\sys\security.c" />
<ClCompile Include="..\..\src\sys\shutdown.c" />
<ClCompile Include="..\..\src\sys\statistics.c" />
<ClCompile Include="..\..\src\sys\util.c" />
<ClCompile Include="..\..\src\sys\volinfo.c" />
<ClCompile Include="..\..\src\sys\volume.c" />
@ -189,12 +190,77 @@
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\sys\version.rc">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_WIN64;_AMD64_=1;AMD64;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WIN64;_AMD64_=1;AMD64;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_WIN64;_AMD64_=1;AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WIN64;_AMD64_=1;AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\sys\driver.inf.in">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)"
set CatalogFile=driver-$(PlatformTarget).cat
setlocal EnableDelayedExpansion
if exist $(OutDir)driver-$(PlatformTarget).inf del $(OutDir)driver-$(PlatformTarget).inf
for /f "delims=" %%l in (%(FullPath)) do (
set line=%%l
echo !line! &gt;&gt;$(OutDir)driver-$(PlatformTarget).inf
)
stampinf -v $(MyVersion) -f $(OutDir)driver-$(PlatformTarget).inf</Command>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkObjects>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)"
set CatalogFile=driver-$(PlatformTarget).cat
setlocal EnableDelayedExpansion
if exist $(OutDir)driver-$(PlatformTarget).inf del $(OutDir)driver-$(PlatformTarget).inf
for /f "delims=" %%l in (%(FullPath)) do (
set line=%%l
echo !line! &gt;&gt;$(OutDir)driver-$(PlatformTarget).inf
)
stampinf -v $(MyVersion) -f $(OutDir)driver-$(PlatformTarget).inf</Command>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkObjects>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)"
set CatalogFile=driver-$(PlatformTarget).cat
setlocal EnableDelayedExpansion
if exist $(OutDir)driver-$(PlatformTarget).inf del $(OutDir)driver-$(PlatformTarget).inf
for /f "delims=" %%l in (%(FullPath)) do (
set line=%%l
echo !line! &gt;&gt;$(OutDir)driver-$(PlatformTarget).inf
)
stampinf -v $(MyVersion) -f $(OutDir)driver-$(PlatformTarget).inf</Command>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkObjects>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)"
set CatalogFile=driver-$(PlatformTarget).cat
setlocal EnableDelayedExpansion
if exist $(OutDir)driver-$(PlatformTarget).inf del $(OutDir)driver-$(PlatformTarget).inf
for /f "delims=" %%l in (%(FullPath)) do (
set line=%%l
echo !line! &gt;&gt;$(OutDir)driver-$(PlatformTarget).inf
)
stampinf -v $(MyVersion) -f $(OutDir)driver-$(PlatformTarget).inf</Command>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkObjects>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Writing driver-$(PlatformTarget).inf</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)driver-$(PlatformTarget).inf</Outputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Writing driver-$(PlatformTarget).inf</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)driver-$(PlatformTarget).inf</Outputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Writing driver-$(PlatformTarget).inf</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)driver-$(PlatformTarget).inf</Outputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Writing driver-$(PlatformTarget).inf</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)driver-$(PlatformTarget).inf</Outputs>
</CustomBuild>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -95,6 +95,9 @@
<ClCompile Include="..\..\src\sys\name.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sys\statistics.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\sys\driver.h">
@ -109,4 +112,9 @@
<Filter>Source</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\src\sys\driver.inf.in">
<Filter>Source</Filter>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,46 @@
= NTFS Compatibility
WinFsp enables the creation of user mode file systems that behave similar to NTFS or FAT. Generic Windows applications that access files on a WinFsp file system cannot and should not be able to determine that it is not a native Windows file system. However specialized applications that access NTFS or FAT specific extensions (such as Defrag) will not work properly on WinFsp file systems.
== Supported features
WinFsp supports the following NTFS features:
- Query and set volume information.
- Open, create, close, delete files and directories.
- Query and set file and directory information.
- Query and set security information (ACL's).
- Read and write files.
- Memory mapped I/O.
- Directory change notifications.
- Lock and unlock files.
- Opportunistic locks.
- Open, create, close, delete, query named streams.
- Reparse points with special support for symbolic links.
== Unsupported features
WinFsp does not support the following NTFS features:
- Hard links. Rather rarely used on Windows. However it might be worthwhile to implement them for WinFsp.
- Extended attributes. Although popular with POSIX file systems, they are severely hampered and rarely used on Windows. They are also not exposed via the Win32 API.
- Short file names. Short file names are a relic of the past. WinFsp made a conscious decision not to support them.
- Paging files. Providing paging file support via a user mode file system is impossible for a number of reasons.
- Object ID's. Opening files by ID (+FILE_OPEN_BY_FILE_ID+) is not supported.
- Volume access. Volume handles can be opened and closed, but volumes cannot be read or written. Such an operation makes little sense for most user mode file systems, that do not store information on disks.
- Sparse files. A user mode file system is free to implement sparse files. However WinFsp does not support any sparse file related FSCTL or information class codes.
- Compressed files. A user mode file system is free to implement compressed files. However WinFsp does not support any compression related FSCTL or information class codes.
- Encrypted files. A user mode file system is free to implement encrypted files. However WinFsp does not support any encryption related FSCTL or information class codes.
- Quotas.
- The Change Journal.
- Defragmentation support.
== Incompatibilities
This section lists incompatibilites with NTFS in those features that they both support:
- WinFsp supports case sensitive and case insensitive file systems. However it does not support case sensitive lookups on a case insensitive file system (+SL_CASE_SENSITIVE+).
- NTFS updates the file size information in the directory entry when a file is cleaned up. WinFsp file systems do not (and probably should not attempt to) replicate this behavior. [Related article: https://blogs.msdn.microsoft.com/oldnewthing/20111226-00/?p=8813]
- NTFS supports change notifications on streams (these are mostly undocumented). WinFsp supports them as well but it differs from NTFS in that it issues a single notification when a file with streams is deleted; NTFS appears to issue one notification per deleted stream.
- WinFsp does not support renaming a stream.
- NTFS allows for enumeration and change notifications of all reparse points by opening a special NTFS-only "directory" that "contains" all reparse points (+\$Extend\$Reparse:$R:$INDEX_ALLOCATION+). WinFsp does not support this feature.

View File

@ -16,17 +16,21 @@ WinFsp currently has the following test suites:
+
This test suite is developed together with WinFsp. It is written in C/C++ and provides a form of gray box testing.
- *Winfstest*: This is a file system test suite that was originally developed for the secfs.test collection of file system test programs by the WinFsp author. However none of its tests are WinFsp specific and all its tests pass on NTFS. Winfstest is used for testing by other Windows file systems.
- *Winfstest*: This is another test suite that verifies general file system functionality. It is not WinFsp specific and all its tests pass on NTFS.
+
This test suite is written in Python and C. It provides a form of black box testing.
This test suite is written in Python and C and was originally developed for the secfs.test collection of file system test programs by the WinFsp author. It provides a form of black box testing.
- *FSX*: This is Apple's FSX ported to Windows by the WinFsp author. This FSX port is not WinFsp specific and is used for testing by other Windows file systems.
- *IfsTest*: This is Microsoft's Installable File System Test Suite. It is used to verify that WinFsp behavior closely resembles that of NTFS.
+
This test suite is part of the Windows Hardware Lab Kit (HLK). It provides a form of black box testing.
- *FSX*: This is Apple's FSX ported to Windows by the WinFsp author. FSX is very good at finding problems with read/write and memory-mapped I/O.
- *Fscrash*: This is a tool that simulates a faulty or crashing user mode file system. It is used to test the fault tolerance of WinFsp.
+
This test is WinFsp specific and is developed together with WinFsp. It is written in C/C++.
This test is developed together with WinFsp. It is written in C/C++.
- *Fsbench*: This is a tool that can be used to test the performance of Windows file systems under different scenarios. It is not WinFsp specific.
- *Fsbench*: This is a tool that can be used to test the performance of Windows file systems under different scenarios. It can work with any Windows file system and is not specific to WinFsp.
+
This tool is currently developed together with WinFsp. It is written in C.
@ -34,7 +38,7 @@ These test suites and a few smaller tests are run through Continuous Integration
=== Test File System
WinFsp includes a test user mode file system called *MEMFS*. This is a simple in memory file system written in C/C++. MEMFS attempts to achieve parity with NTFS (barring a few WinFsp limitations -- notably no support for hard links). MEMFS also performs some user mode file system checks during testing, for example, it checks that the buffer received during WRITE calls is read-only.
WinFsp includes a test user mode file system called *MEMFS*. This is a simple in memory file system written in C/C++. MEMFS implements all file system features that WinFsp supports. MEMFS also performs various user mode file system checks during testing, for example, it checks that the buffer received during WRITE calls is read-only.
== Tested Scenarios
@ -91,6 +95,12 @@ if (!Success)
In Release builds the +DEBUGTEST(90)+ macro will evaluate to +TRUE+ and the Cache Manager will be asked directly via +CcCanIWrite+ whether a WRITE should be deferred. In Debug builds the +DEBUGTEST(90)+ macro will evaluate to +FALSE+ sometimes (10% of the time) and the WRITE will be deferred, thus allowing us to test the retry code path.
== Compatibility Testing
WinFsp allows the creation of user mode file systems that exhibit behavior similar to NTFS. This means that Windows applications that use such a file system should not be able to tell the difference between NTFS and the WinFsp-based file system. OTOH specialized applications (such as Defrag) will not work properly on WinFsp file systems.
WinFsp uses the winfsp-tests, winfstest and ifstest test suites for compatibility testing. These test suites verify that WinFsp and NTFS have very similar behavior. There is a separate document that examines the differences between WinFsp and NTFS in more detail.
== Fault Tolerance Testing
User mode file systems are normal user mode processes and as such they may fail in a variety of conditions. For example, a user mode file system may trigger an access violation while servicing a file operation. As another example, the developer of a user mode file system may terminate the file system process forcefully from within a debugger.

View File

@ -215,7 +215,7 @@ not need to perform access checks, but may performs tasks such as check for empt
directories, etc.
This function should **NEVER** delete the file or directory in question. Deletion should
happen during Cleanup with Delete==TRUE.
happen during Cleanup with the FspCleanupDelete flag set.
This function gets called when Win32 API's such as DeleteFile or RemoveDirectory are used.
It does not get called when a file or directory is opened with FILE\_DELETE\_ON\_CLOSE.
@ -233,16 +233,14 @@ It does not get called when a file or directory is opened with FILE\_DELETE\_ON\
FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext,
PWSTR FileName,
BOOLEAN Delete);
ULONG Flags);
**Parameters**
- _FileSystem_ \- The file system on which this request is posted.
- _FileContext_ \- The file context of the file or directory to cleanup.
- _FileName_ \- The name of the file or directory to cleanup. Sent only when a Delete is requested.
- _Delete_ \- Determines whether to delete the file. Note that there is no way to report failure of
this operation. Also note that when this parameter is TRUE this is the last outstanding
cleanup for this particular file node.
- _Flags_ \- These flags determine whether the file was modified and whether to delete the file.
**Discussion**
@ -253,18 +251,43 @@ file object. When all handles for a particular file object get closed (using Clo
the system sends a Cleanup request to the file system.
There will be a Cleanup operation for every Create or Open operation posted to the user mode
file system. However the Cleanup operation is **not** the final close operation on a file. The
file system must be ready to receive additional operations until close time. This is true
file system. However the Cleanup operation is **not** the final close operation on a file.
The file system must be ready to receive additional operations until close time. This is true
even when the file is being deleted!
The Flags parameter contains information about the cleanup operation:
- FspCleanupDelete -
An important function of the Cleanup operation is to complete a delete operation. Deleting
a file or directory in Windows is a three-stage process where the file is first opened, then
tested to see if the delete can proceed and if the answer is positive the file is then
deleted during Cleanup.
When this flag is set, this is the last outstanding cleanup for this particular file node.
- FspCleanupSetAllocationSize -
The NTFS and FAT file systems reset a file's allocation size when they receive the last
outstanding cleanup for a particular file node. User mode file systems that implement
allocation size and wish to duplicate the NTFS and FAT behavior can use this flag.
- FspCleanupSetArchiveBit -
File systems that support the archive bit should set the file node's archive bit when this
flag is set.
- FspCleanupSetLastAccessTime, FspCleanupSetLastWriteTime, FspCleanupSetChangeTime - File
systems should set the corresponding file time when each one of these flags is set. Note that
updating the last access time is expensive and a file system may choose to not implement it.
There is no way to report failure of this operation. This is a Windows limitation.
As an optimization a file system may specify the FSP\_FSCTL\_VOLUME\_PARAMS ::
PostCleanupOnDeleteOnly flag. In this case the FSD will only post Cleanup requests when a
file is being deleted.
PostCleanupWhenModifiedOnly flag. In this case the FSD will only post Cleanup requests when
the file was modified/deleted.
**See Also**
@ -362,12 +385,17 @@ STATUS\_SUCCESS or error code.
:::c
NTSTATUS ( *Flush)(
FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext);
PVOID FileContext,
FSP_FSCTL_FILE_INFO *FileInfo);
**Parameters**
- _FileSystem_ \- The file system on which this request is posted.
- _FileContext_ \- The file context of the file to be flushed. When NULL the whole volume is being flushed.
- _FileInfo_ \- [out]
Pointer to a structure that will receive the file information on successful return
from this call. This information includes file attributes, file times, etc. Used when
flushing file (not volume).
**Return Value**
@ -589,6 +617,7 @@ STATUS\_SUCCESS or error code.
PVOID FileContext,
UINT32 FileAttributes,
BOOLEAN ReplaceFileAttributes,
UINT64 AllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo);
**Parameters**
@ -598,6 +627,7 @@ STATUS\_SUCCESS or error code.
- _FileAttributes_ \- File attributes to apply to the overwritten file.
- _ReplaceFileAttributes_ \- When TRUE the existing file attributes should be replaced with the new ones.
When FALSE the existing file attributes should be merged (or'ed) with the new ones.
- _AllocationSize_ \- Allocation size for the overwritten file.
- _FileInfo_ \- [out]
Pointer to a structure that will receive the file information on successful return
from this call. This information includes file attributes, file times, etc.
@ -658,6 +688,16 @@ which is used solely by the file system to locate directory entries. However the
special value 0 indicates that the read should start from the first entries. The first
two entries returned by ReadDirectory should always be the "." and ".." entries,
except for the root directory which does not have these entries.
This parameter is used by the WinFsp FSD to break directory listings into chunks.
In this case all 64-bits of the Offset are valid. In some cases the Windows kernel
(NTOS) may also use this parameter. In this case only the lower 32-bits of this
parameter will be valid. This is an unfortunate limitation of Windows (for more
information see the documentation for IRP\_MJ\_DIRECTORY\_CONTROL and the flag
SL\_INDEX\_SPECIFIED).
In practice this means that you should only rely on the lower 32-bits of this value
to be valid.
- _Length_ \- Length of data to read.
- _Pattern_ \- The pattern to match against files in this directory. Can be NULL. The file system
can choose to ignore this parameter as the FSD will always perform its own pattern
@ -702,10 +742,6 @@ STATUS\_SUCCESS or error code.
The kernel mode FSD provides certain guarantees prior to posting a rename operation:
- A file cannot be renamed if it has any open handles, other than the one used to perform
the rename.
- A file cannot be renamed if a file with the same name exists and has open handles.
@ -776,6 +812,7 @@ should be returned to the FSD with status STATUS\_REPARSE/IO\_REPARSE.
UINT64 CreationTime,
UINT64 LastAccessTime,
UINT64 LastWriteTime,
UINT64 ChangeTime,
FSP_FSCTL_FILE_INFO *FileInfo);
**Parameters**
@ -790,6 +827,8 @@ time should not be changed.
access time should not be changed.
- _LastWriteTime_ \- Last write time to apply to the file or directory. If the value 0 is sent, the last
write time should not be changed.
- _ChangeTime_ \- Change time to apply to the file or directory. If the value 0 is sent, the change time
should not be changed.
- _FileInfo_ \- [out]
Pointer to a structure that will receive the file information on successful return
from this call. This information includes file attributes, file times, etc.
@ -886,8 +925,7 @@ STATUS\_SUCCESS or error code.
FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR ModificationDescriptor,
HANDLE AccessToken);
PSECURITY_DESCRIPTOR ModificationDescriptor);
**Parameters**
@ -896,8 +934,6 @@ STATUS\_SUCCESS or error code.
- _SecurityInformation_ \- Describes what parts of the file or directory security descriptor should
be modified.
- _ModificationDescriptor_ \- Describes the modifications to apply to the file or directory security descriptor.
- _AccessToken_ \- A handle to a token that can be used to verify whether the requested modifications
are allowed.
**Return Value**
@ -1463,7 +1499,6 @@ file system requests from the kernel.
PSECURITY_DESCRIPTOR InputDescriptor,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR ModificationDescriptor,
HANDLE AccessToken,
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
**Parameters**
@ -1473,9 +1508,6 @@ file system requests from the kernel.
the same value passed to the SetSecurity SecurityInformation parameter.
- _ModificationDescriptor_ \- Describes the modifications to apply to the InputDescriptor. This should contain
the same value passed to the SetSecurity ModificationDescriptor parameter.
- _AccessToken_ \- A handle to a token that can be used to verify whether the requested modifications
are allowed. This should contain the same value passed to the SetSecurity AccessToken
parameter.
- _PSecurityDescriptor_ \- [out]
Pointer to a memory location that will receive the resulting security descriptor.
This security descriptor can be later freed using FspDeleteSecurityDescriptor.

View File

@ -1,7 +1,7 @@
/**
* @file tlib/callstack.c
*
* @copyright 2014-2015 Bill Zissimopoulos
* @copyright 2014-2017 Bill Zissimopoulos
*/
#include <tlib/callstack.h>

View File

@ -1,7 +1,7 @@
/**
* @file tlib/callstack.h
*
* @copyright 2014-2015 Bill Zissimopoulos
* @copyright 2014-2017 Bill Zissimopoulos
*/
#ifndef TLIB_CALLSTACK_H_INCLUDED

View File

@ -1,7 +1,7 @@
/**
* @file tlib/injected/allfunc.h
*
* @copyright 2014-2015 Bill Zissimopoulos
* @copyright 2014-2017 Bill Zissimopoulos
*/
#ifndef TLIB_INJECTED_ALLFUNC_H_INCLUDED

View File

@ -1,7 +1,7 @@
/**
* @file tlib/injected/curlfunc.c
*
* @copyright 2014-2015 Bill Zissimopoulos
* @copyright 2014-2017 Bill Zissimopoulos
*/
#include <tlib/injected/curlfunc.h>

View File

@ -1,7 +1,7 @@
/**
* @file tlib/injected/curlfunc.h
*
* @copyright 2014-2015 Bill Zissimopoulos
* @copyright 2014-2017 Bill Zissimopoulos
*/
#ifndef TLIB_INJECTED_CURLFUNC_H_INCLUDED

View File

@ -1,7 +1,7 @@
/**
* @file tlib/injected/stdfunc.c
*
* @copyright 2014-2015 Bill Zissimopoulos
* @copyright 2014-2017 Bill Zissimopoulos
*/
#include <tlib/injected/stdfunc.h>

View File

@ -1,7 +1,7 @@
/**
* @file tlib/injected/stdfunc.h
*
* @copyright 2014-2015 Bill Zissimopoulos
* @copyright 2014-2017 Bill Zissimopoulos
*/
#ifndef TLIB_INJECTED_STDFUNC_H_INCLUDED

View File

@ -1,7 +1,7 @@
/**
* @file tlib/injection.c
*
* @copyright 2014-2015 Bill Zissimopoulos
* @copyright 2014-2017 Bill Zissimopoulos
*/
#include <tlib/injection.h>

View File

@ -1,7 +1,7 @@
/**
* @file tlib/injection.h
*
* @copyright 2014-2015 Bill Zissimopoulos
* @copyright 2014-2017 Bill Zissimopoulos
*/
/* NOTE: This header may usefully be included multiple times.

View File

@ -1,7 +1,7 @@
/**
* @file tlib/testsuite.c
*
* @copyright 2014-2015 Bill Zissimopoulos
* @copyright 2014-2017 Bill Zissimopoulos
*/
#include <tlib/testsuite.h>

View File

@ -1,7 +1,7 @@
/**
* @file tlib/testsuite.h
*
* @copyright 2014-2015 Bill Zissimopoulos
* @copyright 2014-2017 Bill Zissimopoulos
*/
#ifndef TLIB_TESTSUITE_H_INCLUDED

View File

@ -6,7 +6,7 @@
* FUSE: Filesystem in Userspace
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -6,7 +6,7 @@
* FUSE: Filesystem in Userspace
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -6,7 +6,7 @@
* FUSE: Filesystem in Userspace
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -2,7 +2,7 @@
* @file fuse/winfsp_fuse.h
* WinFsp FUSE compatible API.
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file winfsp/fsctl.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -146,7 +146,7 @@ typedef struct
UINT32 ExtendedAttributes:1; /* unimplemented; set to 0 */
UINT32 ReadOnlyVolume:1;
/* kernel-mode flags */
UINT32 PostCleanupOnDeleteOnly:1; /* post Cleanup when deleting a file only */
UINT32 PostCleanupWhenModifiedOnly:1; /* post Cleanup when a file was modified/deleted */
UINT32 KmReservedFlags:5;
/* user-mode flags */
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
@ -232,7 +232,8 @@ typedef struct
UINT32 HasRestorePrivilege:1; /* requestor has TOKEN_HAS_RESTORE_PRIVILEGE */
UINT32 OpenTargetDirectory:1; /* open target dir and report FILE_{EXISTS,DOES_NOT_EXIST} */
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
UINT32 ReservedFlags:26;
UINT32 HasTrailingBackslash:1; /* FileName had trailing backslash */
UINT32 ReservedFlags:25;
UINT16 NamedStream; /* request targets named stream; colon offset in FileName */
} Create;
struct
@ -248,6 +249,11 @@ typedef struct
UINT64 UserContext;
UINT64 UserContext2;
UINT32 Delete:1; /* file must be deleted */
UINT32 SetAllocationSize:1;
UINT32 SetArchiveBit:1;
UINT32 SetLastAccessTime:1;
UINT32 SetLastWriteTime:1;
UINT32 SetChangeTime:1;
} Cleanup;
struct
{
@ -295,6 +301,7 @@ typedef struct
UINT64 CreationTime;
UINT64 LastAccessTime;
UINT64 LastWriteTime;
UINT64 ChangeTime;
} Basic;
struct
{
@ -415,6 +422,10 @@ typedef struct
FSP_FSCTL_FILE_INFO FileInfo; /* valid: File{Allocation,Basic,EndOfFile}Information */
} SetInformation;
struct
{
FSP_FSCTL_FILE_INFO FileInfo; /* valid when flushing file (not volume) */
} FlushBuffers;
struct
{
FSP_FSCTL_VOLUME_INFO VolumeInfo;
} QueryVolumeInformation;

View File

@ -5,7 +5,7 @@
* In order to use the WinFsp API the user mode file system must include &lt;winfsp/winfsp.h&gt;
* and link with the winfsp_x64.dll (or winfsp_x86.dll) library.
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -122,6 +122,15 @@ typedef enum
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0,
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE,
} FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY;
enum
{
FspCleanupDelete = 0x01,
FspCleanupSetAllocationSize = 0x02,
FspCleanupSetArchiveBit = 0x10,
FspCleanupSetLastAccessTime = 0x20,
FspCleanupSetLastWriteTime = 0x40,
FspCleanupSetChangeTime = 0x80,
};
/**
* @class FSP_FILE_SYSTEM
* File system interface.
@ -322,18 +331,40 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* the system sends a Cleanup request to the file system.
*
* There will be a Cleanup operation for every Create or Open operation posted to the user mode
* file system. However the Cleanup operation is <b>not</b> the final close operation on a file. The
* file system must be ready to receive additional operations until close time. This is true
* file system. However the Cleanup operation is <b>not</b> the final close operation on a file.
* The file system must be ready to receive additional operations until close time. This is true
* even when the file is being deleted!
*
* The Flags parameter contains information about the cleanup operation:
* <ul>
* <li>FspCleanupDelete -
* An important function of the Cleanup operation is to complete a delete operation. Deleting
* a file or directory in Windows is a three-stage process where the file is first opened, then
* tested to see if the delete can proceed and if the answer is positive the file is then
* deleted during Cleanup.
*
* When this flag is set, this is the last outstanding cleanup for this particular file node.
* </li>
* <li>FspCleanupSetAllocationSize -
* The NTFS and FAT file systems reset a file's allocation size when they receive the last
* outstanding cleanup for a particular file node. User mode file systems that implement
* allocation size and wish to duplicate the NTFS and FAT behavior can use this flag.
* </li>
* <li>
* FspCleanupSetArchiveBit -
* File systems that support the archive bit should set the file node's archive bit when this
* flag is set.
* </li>
* <li>FspCleanupSetLastAccessTime, FspCleanupSetLastWriteTime, FspCleanupSetChangeTime - File
* systems should set the corresponding file time when each one of these flags is set. Note that
* updating the last access time is expensive and a file system may choose to not implement it.
* </ul>
*
* There is no way to report failure of this operation. This is a Windows limitation.
*
* As an optimization a file system may specify the FSP_FSCTL_VOLUME_PARAMS ::
* PostCleanupOnDeleteOnly flag. In this case the FSD will only post Cleanup requests when a
* file is being deleted.
* PostCleanupWhenModifiedOnly flag. In this case the FSD will only post Cleanup requests when
* the file was modified/deleted.
*
* @param FileSystem
* The file system on which this request is posted.
@ -341,16 +372,14 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* The file context of the file or directory to cleanup.
* @param FileName
* The name of the file or directory to cleanup. Sent only when a Delete is requested.
* @param Delete
* Determines whether to delete the file. Note that there is no way to report failure of
* this operation. Also note that when this parameter is TRUE this is the last outstanding
* cleanup for this particular file node.
* @param Flags
* These flags determine whether the file was modified and whether to delete the file.
* @see
* Close
* CanDelete
*/
VOID (*Cleanup)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PWSTR FileName, BOOLEAN Delete);
PVOID FileContext, PWSTR FileName, ULONG Flags);
/**
* Close a file.
*
@ -423,11 +452,16 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* The file system on which this request is posted.
* @param FileContext
* The file context of the file to be flushed. When NULL the whole volume is being flushed.
* @param FileInfo [out]
* Pointer to a structure that will receive the file information on successful return
* from this call. This information includes file attributes, file times, etc. Used when
* flushing file (not volume).
* @return
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*Flush)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext);
PVOID FileContext,
FSP_FSCTL_FILE_INFO *FileInfo);
/**
* Get file or directory information.
*
@ -463,6 +497,9 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* @param LastWriteTime
* Last write time to apply to the file or directory. If the value 0 is sent, the last
* write time should not be changed.
* @param ChangeTime
* Change time to apply to the file or directory. If the value 0 is sent, the change time
* should not be changed.
* @param FileInfo [out]
* Pointer to a structure that will receive the file information on successful return
* from this call. This information includes file attributes, file times, etc.
@ -471,7 +508,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*/
NTSTATUS (*SetBasicInfo)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, UINT32 FileAttributes,
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime, UINT64 ChangeTime,
FSP_FSCTL_FILE_INFO *FileInfo);
/**
* Set file/allocation size.
@ -518,7 +555,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* directories, etc.
*
* This function should <b>NEVER</b> delete the file or directory in question. Deletion should
* happen during Cleanup with Delete==TRUE.
* happen during Cleanup with the FspCleanupDelete flag set.
*
* This function gets called when Win32 API's such as DeleteFile or RemoveDirectory are used.
* It does not get called when a file or directory is opened with FILE_DELETE_ON_CLOSE.
@ -541,8 +578,6 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*
* The kernel mode FSD provides certain guarantees prior to posting a rename operation:
* <ul>
* <li>A file cannot be renamed if it has any open handles, other than the one used to perform
* the rename.</li>
* <li>A file cannot be renamed if a file with the same name exists and has open handles.</li>
* <li>A directory cannot be renamed if it or any of its subdirectories contains a file that
* has open handles.</li>

View File

@ -1,7 +1,7 @@
/**
* @file cygfuse/cygfuse.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/debug.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/eventlog.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/fs.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/fsctl.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/fsop.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -189,6 +189,13 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
ParentDesiredAccess = FILE_ADD_SUBDIRECTORY;
else
ParentDesiredAccess = FILE_ADD_FILE;
if (Request->Req.Create.HasTrailingBackslash &&
!(Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE))
Result = STATUS_OBJECT_NAME_INVALID;
else if ((Request->Req.Create.FileAttributes & FILE_ATTRIBUTE_READONLY) &&
(Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE))
Result = STATUS_CANNOT_DELETE;
else
Result = FspAccessCheckEx(FileSystem, Request, TRUE, AllowTraverseCheck,
ParentDesiredAccess,
&GrantedAccess, PSecurityDescriptor);
@ -205,6 +212,9 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
{
*PSecurityDescriptor = 0;
if (Request->Req.Create.HasTrailingBackslash)
Result = STATUS_OBJECT_NAME_INVALID;
else
Result = FspAccessCheckEx(FileSystem, Request, TRUE, AllowTraverseCheck,
Request->Req.Create.DesiredAccess |
FILE_WRITE_DATA |
@ -546,7 +556,6 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwrite(FSP_FILE_SYSTEM *FileSystem,
UINT32 GrantedAccess;
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
BOOLEAN Supersede = FILE_SUPERSEDE == ((Request->Req.Create.CreateOptions >> 24) & 0xff);
Result = FspFileSystemOverwriteCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
@ -570,7 +579,7 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwrite(FSP_FILE_SYSTEM *FileSystem,
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
}
Response->IoStatus.Information = Supersede ? FILE_SUPERSEDED : FILE_OVERWRITTEN;
Response->IoStatus.Information = FILE_OVERWRITTEN;
SetFileContext(Response->Rsp.Create.Opened, FullContext);
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo,
@ -586,6 +595,7 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
PSECURITY_DESCRIPTOR ParentDescriptor, ObjectDescriptor;
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
BOOLEAN Supersede = FILE_SUPERSEDE == ((Request->Req.Create.CreateOptions >> 24) & 0xff);
BOOLEAN Create = FALSE;
Result = FspFileSystemOverwriteCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
@ -647,7 +657,8 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
}
Response->IoStatus.Information = Create ? FILE_CREATED : FILE_OVERWRITTEN;
Response->IoStatus.Information = Create ? FILE_CREATED :
(Supersede ? FILE_SUPERSEDED : FILE_OVERWRITTEN);
SetFileContext(Response->Rsp.Create.Opened, FullContext);
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo,
@ -816,10 +827,10 @@ FSP_API NTSTATUS FspFileSystemOpCreate(FSP_FILE_SYSTEM *FileSystem,
Result = FspFileSystemOpCreate_FileOpenIf(FileSystem, Request, Response);
break;
case FILE_OVERWRITE:
case FILE_SUPERSEDE:
Result = FspFileSystemOpCreate_FileOverwrite(FileSystem, Request, Response);
break;
case FILE_OVERWRITE_IF:
case FILE_SUPERSEDE:
Result = FspFileSystemOpCreate_FileOverwriteIf(FileSystem, Request, Response);
break;
default:
@ -870,7 +881,12 @@ FSP_API NTSTATUS FspFileSystemOpCleanup(FSP_FILE_SYSTEM *FileSystem,
FileSystem->Interface->Cleanup(FileSystem,
(PVOID)ValOfFileContext(Request->Req.Cleanup),
0 != Request->FileName.Size ? (PWSTR)Request->Buffer : 0,
0 != Request->Req.Cleanup.Delete);
(0 != Request->Req.Cleanup.Delete ? FspCleanupDelete : 0) |
(0 != Request->Req.Cleanup.SetAllocationSize ? FspCleanupSetAllocationSize : 0) |
(0 != Request->Req.Cleanup.SetArchiveBit ? FspCleanupSetArchiveBit : 0) |
(0 != Request->Req.Cleanup.SetLastAccessTime ? FspCleanupSetLastAccessTime : 0) |
(0 != Request->Req.Cleanup.SetLastWriteTime ? FspCleanupSetLastWriteTime : 0) |
(0 != Request->Req.Cleanup.SetChangeTime ? FspCleanupSetChangeTime : 0));
return STATUS_SUCCESS;
}
@ -945,11 +961,21 @@ FSP_API NTSTATUS FspFileSystemOpWrite(FSP_FILE_SYSTEM *FileSystem,
FSP_API NTSTATUS FspFileSystemOpFlushBuffers(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{
if (0 == FileSystem->Interface->Flush)
return STATUS_SUCCESS; /* liar! */
NTSTATUS Result;
FSP_FSCTL_FILE_INFO FileInfo;
return FileSystem->Interface->Flush(FileSystem,
(PVOID)ValOfFileContext(Request->Req.FlushBuffers));
memset(&FileInfo, 0, sizeof FileInfo);
if (0 == FileSystem->Interface->Flush)
Result = FileSystem->Interface->GetFileInfo(FileSystem,
(PVOID)ValOfFileContext(Request->Req.FlushBuffers), &FileInfo);
else
Result = FileSystem->Interface->Flush(FileSystem,
(PVOID)ValOfFileContext(Request->Req.FlushBuffers), &FileInfo);
if (!NT_SUCCESS(Result))
return Result;
memcpy(&Response->Rsp.FlushBuffers.FileInfo, &FileInfo, sizeof FileInfo);
return STATUS_SUCCESS;
}
FSP_API NTSTATUS FspFileSystemOpQueryInformation(FSP_FILE_SYSTEM *FileSystem,
@ -989,6 +1015,7 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
Request->Req.SetInformation.Info.Basic.CreationTime,
Request->Req.SetInformation.Info.Basic.LastAccessTime,
Request->Req.SetInformation.Info.Basic.LastWriteTime,
Request->Req.SetInformation.Info.Basic.ChangeTime,
&FileInfo);
break;
case 19/*FileAllocationInformation*/:

View File

@ -1,7 +1,7 @@
/**
* @file dll/fuse/fuse.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -523,7 +523,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
opt_data.VolumeParams.NamedStreams = FALSE;
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
opt_data.VolumeParams.PostCleanupOnDeleteOnly = TRUE;
opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));

View File

@ -1,7 +1,7 @@
/**
* @file dll/fuse/fuse_intf.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -1050,7 +1050,7 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
}
static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, PWSTR FileName, BOOLEAN Delete)
PVOID FileNode, PWSTR FileName, ULONG Flags)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileNode;
@ -1072,7 +1072,7 @@ static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem,
* FUSE option and can safely remove the file at this time.
*/
if (Delete)
if (Flags & FspCleanupDelete)
if (filedesc->IsDirectory && !filedesc->IsReparsePoint)
{
if (0 != f->ops.rmdir)
@ -1215,11 +1215,14 @@ success:
}
static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode)
PVOID FileNode,
FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileNode;
UINT32 Uid, Gid, Mode;
struct fuse_file_info fi;
FSP_FSCTL_FILE_INFO FileInfoBuf;
int err;
NTSTATUS Result;
@ -1249,8 +1252,17 @@ static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
}
}
if (!NT_SUCCESS(Result))
return Result;
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi,
&Uid, &Gid, &Mode, &FileInfoBuf);
if (!NT_SUCCESS(Result))
return Result;
memcpy(FileInfo, &FileInfoBuf, sizeof FileInfoBuf);
return STATUS_SUCCESS;
}
static NTSTATUS fsp_fuse_intf_GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
@ -1272,7 +1284,7 @@ static NTSTATUS fsp_fuse_intf_GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, UINT32 FileAttributes,
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime, UINT64 ChangeTime,
FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;

View File

@ -1,7 +1,7 @@
/**
* @file dll/fuse/fuse_main.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/fuse/fuse_opt.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/fuse/library.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/library.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/library.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/np.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/ntstatus.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/path.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -14,7 +14,7 @@
* [SNAME]
* https://www.cygwin.com/cygwin-ug-net/using-specialnames.html
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/security.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -191,6 +191,13 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
goto exit;
if (!CheckParentOrMain && Request->Req.Create.HasTrailingBackslash &&
!(FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
Result = STATUS_OBJECT_NAME_INVALID;
goto exit;
}
if (Request->Req.Create.UserMode && 0 < SecurityDescriptorSize)
{
if (0 == DesiredAccess)

View File

@ -1,7 +1,7 @@
/**
* @file dll/service.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dll/util.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -22,7 +22,7 @@ BEGIN
BEGIN
VALUE "CompanyName", STR(MyCompanyName)
VALUE "FileDescription", STR(MyDescription)
VALUE "FileVersion", STR(MyVersion)
VALUE "FileVersion", STR(MyFullVersion)
VALUE "InternalName", "winfsp.dll"
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "winfsp.dll"

View File

@ -22,7 +22,7 @@ BEGIN
BEGIN
VALUE "CompanyName", STR(MyCompanyName)
VALUE "FileDescription", STR(MyDescription)
VALUE "FileVersion", STR(MyVersion)
VALUE "FileVersion", STR(MyFullVersion)
VALUE "InternalName", "launchctl.exe"
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "launchctl.exe"

View File

@ -1,7 +1,7 @@
/**
* @file launcher/launchctl.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -22,7 +22,7 @@ BEGIN
BEGIN
VALUE "CompanyName", STR(MyCompanyName)
VALUE "FileDescription", STR(MyDescription)
VALUE "FileVersion", STR(MyVersion)
VALUE "FileVersion", STR(MyFullVersion)
VALUE "InternalName", "launcher.exe"
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "launcher.exe"

View File

@ -1,7 +1,7 @@
/**
* @file launcher/launcher.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file launcher/launcher.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file shared/minimal.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -2,7 +2,7 @@
* @file sys/callbacks.c
* Fast I/O and resource acquisition callbacks.
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file sys/cleanup.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -77,13 +77,17 @@ static NTSTATUS FspFsvolCleanup(
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
FSP_FSCTL_TRANSACT_REQ *Request;
BOOLEAN DeletePending;
ULONG CleanupFlags;
BOOLEAN DeletePending, SetAllocationSize, FileModified;
ASSERT(FileNode == FileDesc->FileNode);
FspFileNodeAcquireExclusive(FileNode, Main);
FspFileNodeCleanup(FileNode, FileObject, &DeletePending);
FspFileNodeCleanup(FileNode, FileObject, &CleanupFlags);
DeletePending = CleanupFlags & 1;
SetAllocationSize = !!(CleanupFlags & 2);
FileModified = BooleanFlagOn(FileObject->Flags, FO_FILE_MODIFIED);
/* if this is a directory inform the FSRTL Notify mechanism */
if (FileNode->IsDirectory)
@ -106,13 +110,25 @@ static NTSTATUS FspFsvolCleanup(
Request->Req.Cleanup.UserContext = FileNode->UserContext;
Request->Req.Cleanup.UserContext2 = FileDesc->UserContext2;
Request->Req.Cleanup.Delete = DeletePending;
Request->Req.Cleanup.SetAllocationSize = SetAllocationSize;
Request->Req.Cleanup.SetArchiveBit = (FileModified || FileDesc->DidSetSecurity) &&
!FileDesc->DidSetFileAttributes;
Request->Req.Cleanup.SetLastAccessTime = !FileDesc->DidSetLastAccessTime;
Request->Req.Cleanup.SetLastWriteTime = FileModified && !FileDesc->DidSetLastWriteTime;
Request->Req.Cleanup.SetChangeTime = (FileModified || FileDesc->DidSetMetadata) &&
!FileDesc->DidSetChangeTime;
FspFileNodeAcquireExclusive(FileNode, Pgio);
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp;
if (DeletePending || !FsvolDeviceExtension->VolumeParams.PostCleanupOnDeleteOnly)
if (Request->Req.Cleanup.Delete ||
Request->Req.Cleanup.SetAllocationSize ||
Request->Req.Cleanup.SetArchiveBit ||
Request->Req.Cleanup.SetLastWriteTime ||
Request->Req.Cleanup.SetChangeTime ||
!FsvolDeviceExtension->VolumeParams.PostCleanupWhenModifiedOnly)
/*
* Note that it is still possible for this request to not be delivered,
* if the volume device Ioq is stopped. But such failures are benign
@ -122,9 +138,13 @@ static NTSTATUS FspFsvolCleanup(
return FSP_STATUS_IOQ_POST_BEST_EFFORT;
else
{
/* if the file is being resized invalidate the volume info */
if (FileNode->TruncateOnClose)
FspFsvolDeviceInvalidateVolumeInfo(IrpSp->DeviceObject);
if (FileDesc->DidSetMetadata)
{
if (0 == FileNode->MainFileNode)
FspFileNodeInvalidateParentDirInfo(FileNode);
else
FspFileNodeInvalidateStreamInfo(FileNode);
}
return STATUS_SUCCESS; /* FspFsvolCleanupRequestFini will take care of the rest! */
}
@ -138,15 +158,51 @@ NTSTATUS FspFsvolCleanupComplete(
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
ULONG NotifyFilter, NotifyAction;
/* if the file is being deleted do a change notification */
ASSERT(FileNode == FileDesc->FileNode);
/* send the appropriate notification; also invalidate dirinfo/etc. caches */
if (Request->Req.Cleanup.Delete)
FspFileNodeNotifyChange(FileNode,
FileNode->IsDirectory ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_REMOVED);
/* if the file is being resized invalidate the volume info */
else if (FileNode->TruncateOnClose)
FspFsvolDeviceInvalidateVolumeInfo(IrpSp->DeviceObject);
{
NotifyFilter = FileNode->IsDirectory ?
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME;
NotifyAction = FILE_ACTION_REMOVED;
}
else
{
/* send notification for any metadata changes */
NotifyFilter = 0;
#if 0
/* do not send notification when resetting the allocation size */
if (Request->Req.Cleanup.SetAllocationSize)
NotifyFilter |= FILE_NOTIFY_CHANGE_SIZE;
#endif
if (Request->Req.Cleanup.SetArchiveBit)
NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
#if 0
/* do not send notification for implicit LastAccessTime changes */
if (Request->Req.Cleanup.SetLastAccessTime)
NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
#endif
if (Request->Req.Cleanup.SetLastWriteTime)
NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyAction = FILE_ACTION_MODIFIED;
}
if (0 != NotifyFilter)
FspFileNodeNotifyChange(FileNode, NotifyFilter, NotifyAction, TRUE);
else
{
if (FileDesc->DidSetMetadata)
{
if (0 == FileNode->MainFileNode)
FspFileNodeInvalidateParentDirInfo(FileNode);
else
FspFileNodeInvalidateStreamInfo(FileNode);
}
}
FSP_LEAVE_IOC("FileObject=%p", IrpSp->FileObject);
}

View File

@ -1,7 +1,7 @@
/**
* @file sys/close.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file sys/create.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -193,6 +193,7 @@ static NTSTATUS FspFsvolCreateNoLock(
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_BACKUP_PRIVILEGE);
BOOLEAN HasRestorePrivilege =
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE);
BOOLEAN HasTrailingBackslash = FALSE;
FSP_FILE_NODE *FileNode, *RelatedFileNode;
FSP_FILE_DESC *FileDesc;
UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 };
@ -216,6 +217,12 @@ static NTSTATUS FspFsvolCreateNoLock(
FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
return STATUS_INVALID_PARAMETER;
/* do not allow the temporary bit on a directory */
if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE) &&
FlagOn(FileAttributes, FILE_ATTRIBUTE_TEMPORARY) &&
(FILE_CREATE == CreateDisposition || FILE_OPEN_IF == CreateDisposition))
return STATUS_INVALID_PARAMETER;
/* check security descriptor validity */
if (0 != SecurityDescriptor)
{
@ -257,7 +264,7 @@ static NTSTATUS FspFsvolCreateNoLock(
/* must be a relative path */
if (sizeof(WCHAR) <= FileName.Length && L'\\' == FileName.Buffer[0])
return STATUS_OBJECT_NAME_INVALID;
return STATUS_INVALID_PARAMETER; /* IFSTEST */
BOOLEAN AppendBackslash =
sizeof(WCHAR) * 2/* not empty or root */ <= RelatedFileNode->FileName.Length &&
@ -293,7 +300,7 @@ static NTSTATUS FspFsvolCreateNoLock(
ASSERT(NT_SUCCESS(Result));
/* check filename validity */
if (!FspFileNameIsValid(&FileNode->FileName,
if (!FspFileNameIsValid(&FileNode->FileName, FsvolDeviceExtension->VolumeParams.MaxComponentLength,
FsvolDeviceExtension->VolumeParams.NamedStreams ? &StreamPart : 0,
&StreamType))
{
@ -344,12 +351,7 @@ static NTSTATUS FspFsvolCreateNoLock(
if (sizeof(WCHAR) * 2/* not empty or root */ <= FileNode->FileName.Length &&
L'\\' == FileNode->FileName.Buffer[FileNode->FileName.Length / sizeof(WCHAR) - 1])
{
if (!FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
{
FspFileNodeDereference(FileNode);
return STATUS_OBJECT_NAME_INVALID;
}
HasTrailingBackslash = TRUE;
FileNode->FileName.Length -= sizeof(WCHAR);
}
@ -442,7 +444,9 @@ static NTSTATUS FspFsvolCreateNoLock(
FileAttributes = 0;
/* remember the main file node */
ASSERT(0 == FileNode->MainFileNode);
FileNode->MainFileNode = FileDesc->MainFileObject->FsContext;
FspFileNodeReference(FileNode->MainFileNode);
Result = STATUS_SUCCESS;
@ -501,6 +505,7 @@ static NTSTATUS FspFsvolCreateNoLock(
Request->Req.Create.HasRestorePrivilege = HasRestorePrivilege;
Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY);
Request->Req.Create.CaseSensitive = CaseSensitive;
Request->Req.Create.HasTrailingBackslash = HasTrailingBackslash;
Request->Req.Create.NamedStream = MainFileName.Length;
ASSERT(
@ -818,7 +823,10 @@ NTSTATUS FspFsvolCreateComplete(
if (Response->Buffer + Response->Rsp.Create.Opened.FileName.Size >
(PUINT8)Response + Response->Size)
{
FspFsvolCreatePostClose(FileDesc);
FSP_RETURN(Result = STATUS_OBJECT_NAME_INVALID);
}
NormalizedName.Length = NormalizedName.MaximumLength =
Response->Rsp.Create.Opened.FileName.Size;
@ -826,7 +834,10 @@ NTSTATUS FspFsvolCreateComplete(
/* normalized file name can only differ in case from requested one */
if (0 != FspFileNameCompare(&FileNode->FileName, &NormalizedName, TRUE, 0))
{
FspFsvolCreatePostClose(FileDesc);
FSP_RETURN(Result = STATUS_OBJECT_NAME_INVALID);
}
ASSERT(FileNode->FileName.Length == NormalizedName.Length);
RtlCopyMemory(FileNode->FileName.Buffer, NormalizedName.Buffer, NormalizedName.Length);
@ -892,6 +903,7 @@ NTSTATUS FspFsvolCreateComplete(
/* set up the AccessState */
AccessState->RemainingDesiredAccess = 0;
AccessState->PreviouslyGrantedAccess = Response->Rsp.Create.Opened.GrantedAccess;
FileDesc->GrantedAccess = Response->Rsp.Create.Opened.GrantedAccess;
/* set up the FileObject */
if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
@ -901,6 +913,13 @@ NTSTATUS FspFsvolCreateComplete(
FileObject->PrivateCacheMap = 0;
FileObject->FsContext = FileNode;
FileObject->FsContext2 = FileDesc;
if (!FileNode->IsDirectory)
{
/* properly set temporary bit for lazy writer */
if (FlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes,
FILE_ATTRIBUTE_TEMPORARY))
SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
}
if (FspTimeoutInfinity32 == FsvolDeviceExtension->VolumeParams.FileInfoTimeout &&
!FlagOn(IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING) &&
!Response->Rsp.Create.Opened.DisableCache)
@ -939,6 +958,19 @@ NTSTATUS FspFsvolCreateComplete(
if (FileNode->IsDirectory)
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
/* overwrite/supersede operations must have the correct hidden/system attributes set */
if ((FlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes, FILE_ATTRIBUTE_HIDDEN) &&
!FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) ||
(FlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes, FILE_ATTRIBUTE_SYSTEM) &&
!FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM)))
{
FspFsvolCreatePostClose(FileDesc);
FspFileNodeClose(FileNode, FileObject, TRUE);
Result = STATUS_ACCESS_DENIED;
FSP_RETURN();
}
PVOID RequestDeviceObjectValue = FspIopRequestContext(Request, RequestDeviceObject);
/* disassociate the FileDesc momentarily from the Request */
@ -998,10 +1030,11 @@ NTSTATUS FspFsvolCreateComplete(
/* file was successfully overwritten/superseded */
if (0 == FileNode->MainFileNode)
FspFileNodeOverwriteStreams(FileNode);
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Overwrite.FileInfo);
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Overwrite.FileInfo, TRUE);
FspFileNodeNotifyChange(FileNode,
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE,
FILE_ACTION_MODIFIED);
FILE_ACTION_MODIFIED,
FALSE);
FspFileNodeReleaseOwner(FileNode, Full, Request);
@ -1064,7 +1097,8 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
return Result;
}
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Create.Opened.FileInfo);
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Create.Opened.FileInfo,
FILE_CREATED == Response->IoStatus.Information);
if (FlushImage)
{
@ -1091,7 +1125,8 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
if (FILE_CREATED == Response->IoStatus.Information)
FspFileNodeNotifyChange(FileNode,
FileNode->IsDirectory ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_ADDED);
FILE_ACTION_ADDED,
TRUE);
FspFileNodeRelease(FileNode, Main);

View File

@ -1,7 +1,7 @@
/**
* @file sys/debug.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file sys/devctl.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file sys/device.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -43,9 +43,11 @@ VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject);
NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount);
NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount);
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
VOID FspFsvolDeviceDeleteContextList(PVOID *Contexts, ULONG ContextCount);
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
BOOLEAN NextFlag, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY *RestartKey);
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
@ -80,8 +82,9 @@ VOID FspDeviceDeleteAll(VOID);
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameReleaseOwner)
#pragma alloc_text(PAGE, FspFsvolDeviceLockContextTable)
#pragma alloc_text(PAGE, FspFsvolDeviceUnlockContextTable)
#pragma alloc_text(PAGE, FspFsvolDeviceCopyContextList)
#pragma alloc_text(PAGE, FspFsvolDeviceCopyContextByNameList)
#pragma alloc_text(PAGE, FspFsvolDeviceDeleteContextByNameList)
#pragma alloc_text(PAGE, FspFsvolDeviceDeleteContextList)
#pragma alloc_text(PAGE, FspFsvolDeviceEnumerateContextByName)
#pragma alloc_text(PAGE, FspFsvolDeviceLookupContextByName)
#pragma alloc_text(PAGE, FspFsvolDeviceInsertContextByName)
@ -364,9 +367,16 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
InitializeListHead(&FsvolDeviceExtension->NotifyList);
FsvolDeviceExtension->InitDoneNotify = 1;
/* create file system statistics */
Result = FspStatisticsCreate(&FsvolDeviceExtension->Statistics);
if (!NT_SUCCESS(Result))
return Result;
FsvolDeviceExtension->InitDoneStat = 1;
/* initialize our context table */
ExInitializeResourceLite(&FsvolDeviceExtension->FileRenameResource);
ExInitializeResourceLite(&FsvolDeviceExtension->ContextTableResource);
InitializeListHead(&FsvolDeviceExtension->ContextList);
RtlInitializeGenericTableAvl(&FsvolDeviceExtension->ContextByNameTable,
FspFsvolDeviceCompareContextByName,
FspFsvolDeviceAllocateContextByName,
@ -408,6 +418,10 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
if (FsvolDeviceExtension->InitDoneTimer)
IoStopTimer(DeviceObject);
/* delete the file system statistics */
if (FsvolDeviceExtension->InitDoneStat)
FspStatisticsDelete(FsvolDeviceExtension->Statistics);
/* uninitialize the FSRTL Notify mechanism */
if (FsvolDeviceExtension->InitDoneNotify)
{
@ -576,6 +590,50 @@ VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject)
ExReleaseResourceLite(&FsvolDeviceExtension->ContextTableResource);
}
NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount)
{
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
PVOID *Contexts;
ULONG ContextCount, Index;
*PContexts = 0;
*PContextCount = 0;
ContextCount = 0;
for (
PLIST_ENTRY Head = &FsvolDeviceExtension->ContextList, Entry = Head->Flink;
Head != Entry;
Entry = Entry->Flink)
{
ContextCount++;
}
/* if ContextCount == 0 allocate an empty Context list */
Contexts = FspAlloc(sizeof(PVOID) * (0 != ContextCount ? ContextCount : 1));
if (0 == Contexts)
return STATUS_INSUFFICIENT_RESOURCES;
Index = 0;
for (
PLIST_ENTRY Head = &FsvolDeviceExtension->ContextList, Entry = Head->Flink;
Head != Entry;
Entry = Entry->Flink)
{
ASSERT(Index < ContextCount);
Contexts[Index++] = CONTAINING_RECORD(Entry, FSP_FILE_NODE, ActiveEntry);
/* assume that Contexts can only be FSP_FILE_NODE's */
}
ASSERT(Index == ContextCount);
*PContexts = Contexts;
*PContextCount = Index;
return STATUS_SUCCESS;
}
NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount)
{
@ -610,7 +668,7 @@ NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
return STATUS_SUCCESS;
}
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount)
VOID FspFsvolDeviceDeleteContextList(PVOID *Contexts, ULONG ContextCount)
{
PAGED_CODE();

View File

@ -1,7 +1,7 @@
/**
* @file sys/dirctl.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -512,7 +512,8 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
}
/* set the DirectoryPattern in the FileDesc */
Result = FspFileDescResetDirectoryPattern(FileDesc, FileName, RestartScan);
Result = FspFileDescResetDirectoryPattern(FileDesc, FileName,
RestartScan && 0 != FileName && 0 != FileName->Length);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
@ -617,6 +618,7 @@ static NTSTATUS FspFsvolQueryDirectory(
return STATUS_INVALID_DEVICE_REQUEST;
NTSTATUS Result;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
@ -636,7 +638,8 @@ static NTSTATUS FspFsvolQueryDirectory(
return STATUS_INVALID_PARAMETER;
/* check that FileName is valid (if supplied) */
if (0 != FileName && !FspFileNameIsValidPattern(FileName))
if (0 != FileName &&
!FspFileNameIsValidPattern(FileName, FsvolDeviceExtension->VolumeParams.MaxComponentLength))
return STATUS_INVALID_PARAMETER;
/* is this an allowed file information class? */

View File

@ -1,7 +1,7 @@
/**
* @file sys/driver.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -176,6 +176,8 @@ NTSTATUS DriverEntry(
static VOID FspDriverMultiVersionInitialize(VOID)
{
FspProcessorCount = KeQueryActiveProcessorCount(0);
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
if (RtlIsNtDdiVersionAvailable(NTDDI_WIN7))
@ -216,5 +218,6 @@ PDEVICE_OBJECT FspFsctlNetDeviceObject;
FAST_IO_DISPATCH FspFastIoDispatch;
CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks;
ULONG FspProcessorCount;
FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;
ULONG FspMvMdlMappingNoWrite = 0;

View File

@ -1,7 +1,7 @@
/**
* @file sys/driver.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -40,6 +40,7 @@
/* private NTSTATUS codes */
#define FSP_STATUS_PRIVATE_BIT (0x20000000)
#define FSP_STATUS_IGNORE_BIT (0x10000000)
#define FSP_STATUS_IOQ_POST (FSP_STATUS_PRIVATE_BIT | 0x0000)
#define FSP_STATUS_IOQ_POST_BEST_EFFORT (FSP_STATUS_PRIVATE_BIT | 0x0001)
@ -198,7 +199,7 @@ VOID FspDebugLogIrp(const char *func, PIRP Irp, NTSTATUS Result);
} while (0,0)
#define FSP_LEAVE_MJ(fmt, ...) \
FSP_LEAVE_( \
if (STATUS_PENDING != Result) \
if (STATUS_PENDING != Result && !(FSP_STATUS_IGNORE_BIT & Result))\
{ \
ASSERT(0 == (FSP_STATUS_PRIVATE_BIT & Result) ||\
FSP_STATUS_IOQ_POST == Result || FSP_STATUS_IOQ_POST_BEST_EFFORT == Result);\
@ -225,6 +226,8 @@ VOID FspDebugLogIrp(const char *func, PIRP Irp, NTSTATUS Result);
else \
FspIopCompleteIrpEx(Irp, Result, fsp_device_deref);\
} \
else \
Result &= ~FSP_STATUS_IGNORE_BIT;\
IoSetTopLevelIrp(fsp_top_level_irp);\
); \
return Result
@ -437,8 +440,9 @@ enum
FspFileNameStreamTypeNone = 0,
FspFileNameStreamTypeData = 1,
};
BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType);
BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Pattern);
BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, ULONG MaxComponentLength,
PUNICODE_STRING StreamPart, PULONG StreamType);
BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Pattern, ULONG MaxComponentLength);
VOID FspFileNameSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
#if 0
NTSTATUS FspFileNameUpcase(
@ -910,7 +914,7 @@ BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
VOID FspIopSetIrpResponse(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
FSP_FSCTL_TRANSACT_RSP *FspIopIrpResponse(PIRP Irp);
NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request);
NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
NTSTATUS FspIopDispatchComplete(PIRP Irp, FSP_FSCTL_TRANSACT_RSP *Response);
static inline
VOID FspIrpDeleteRequest(PIRP Irp)
{
@ -948,6 +952,21 @@ VOID FspWqPostIrpWorkItem(PIRP Irp);
#define FspWqRepostIrpWorkItem(I, RW, RF)\
FspWqCreateAndPostIrpWorkItem(I, RW, RF, TRUE)
/* file system statistics */
typedef struct
{
FILESYSTEM_STATISTICS Base;
FAT_STATISTICS Specific; /* pretend that we are FAT when it comes to stats */
/* align to 64 bytes */
__declspec(align(64)) UINT8 EndOfStruct[];
} FSP_STATISTICS;
NTSTATUS FspStatisticsCreate(FSP_STATISTICS **PStatistics);
VOID FspStatisticsDelete(FSP_STATISTICS *Statistics);
NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLength);
#define FspStatistics(S) (&(S)[KeGetCurrentProcessorNumber() % FspProcessorCount])
#define FspStatisticsInc(S,F) ((S)->F++)
#define FspStatisticsAdd(S,F,V) ((S)->F += (V))
/* device management */
enum
{
@ -989,7 +1008,7 @@ typedef struct
{
FSP_DEVICE_EXTENSION Base;
UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, InitDoneStrm:1,
InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1;
InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1, InitDoneStat:1;
PDEVICE_OBJECT FsctlDeviceObject;
PDEVICE_OBJECT FsvrtDeviceObject;
HANDLE MupHandle;
@ -1006,6 +1025,7 @@ typedef struct
BOOLEAN ExpirationInProgress;
ERESOURCE FileRenameResource;
ERESOURCE ContextTableResource;
LIST_ENTRY ContextList;
RTL_AVL_TABLE ContextByNameTable;
PVOID ContextByNameTableElementStorage;
UNICODE_STRING VolumeName;
@ -1015,6 +1035,7 @@ typedef struct
FSP_FSCTL_VOLUME_INFO VolumeInfo;
PNOTIFY_SYNC NotifySync;
LIST_ENTRY NotifyList;
FSP_STATISTICS *Statistics;
} FSP_FSVOL_DEVICE_EXTENSION;
static inline
FSP_DEVICE_EXTENSION *FspDeviceExtension(PDEVICE_OBJECT DeviceObject)
@ -1045,9 +1066,11 @@ VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject);
NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount);
NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount);
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
VOID FspFsvolDeviceDeleteContextList(PVOID *Contexts, ULONG ContextCount);
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
BOOLEAN NextFlag, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY *RestartKey);
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
@ -1082,6 +1105,8 @@ VOID FspDeviceGlobalUnlock(VOID)
extern ERESOURCE FspDeviceGlobalResource;
ExReleaseResourceLite(&FspDeviceGlobalResource);
}
#define FspFsvolDeviceStatistics(DeviceObject)\
FspStatistics(FspFsvolDeviceExtension(DeviceObject)->Statistics)
#define FspFsvolDeviceStoppedStatus(DeviceObject)\
STATUS_VOLUME_DISMOUNTED
//(FILE_DEVICE_DISK_FILE_SYSTEM == (DeviceObject)->DeviceType ?\
@ -1147,11 +1172,13 @@ typedef struct FSP_FILE_NODE
LONG RefCount;
UINT32 DeletePending;
/* locked under FSP_FSVOL_DEVICE_EXTENSION::ContextTableResource */
LONG ActiveCount; /* CREATE w/o CLOSE count */
LONG OpenCount; /* ContextTable ref count */
LONG HandleCount; /* HANDLE count (CREATE/CLEANUP) */
SHARE_ACCESS ShareAccess;
ULONG MainFileDenyDeleteCount; /* number of times main file is denying delete */
ULONG StreamDenyDeleteCount; /* number of times open streams are denying delete */
LIST_ENTRY ActiveEntry;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT ContextByNameElementStorage;
/* locked under FSP_FSVOL_DEVICE_EXTENSION::FileRenameResource or Header.Resource */
UNICODE_STRING FileName;
@ -1189,17 +1216,20 @@ typedef struct FSP_FILE_NODE
UINT64 IndexNumber;
BOOLEAN IsDirectory;
BOOLEAN IsRootDirectory;
struct FSP_FILE_NODE *MainFileNode; /* this becomes invalid after our last desc close */
struct FSP_FILE_NODE *MainFileNode;
WCHAR FileNameBuf[];
} FSP_FILE_NODE;
typedef struct
{
FSP_FILE_NODE *FileNode;
UINT64 UserContext2;
BOOLEAN CaseSensitive;
BOOLEAN HasTraversePrivilege;
BOOLEAN DeleteOnClose;
BOOLEAN DirectoryHasSuchFile;
UINT32 GrantedAccess;
UINT32
CaseSensitive:1, HasTraversePrivilege:1, DeleteOnClose:1,
DidSetMetadata:1,
DidSetFileAttributes:1, DidSetReparsePoint:1, DidSetSecurity:1,
DidSetCreationTime:1, DidSetLastAccessTime:1, DidSetLastWriteTime:1, DidSetChangeTime:1,
DirectoryHasSuchFile:1;
UNICODE_STRING DirectoryPattern;
UINT64 DirectoryOffset;
UINT64 DirInfo;
@ -1208,7 +1238,9 @@ typedef struct
HANDLE MainFileHandle;
PFILE_OBJECT MainFileObject;
} FSP_FILE_DESC;
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
NTSTATUS FspFileNodeCopyActiveList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
NTSTATUS FspFileNodeCopyOpenList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
VOID FspFileNodeDeleteList(FSP_FILE_NODE **FileNodes, ULONG FileNodeCount);
NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
@ -1258,8 +1290,7 @@ VOID FspFileNodeReleaseForeign(FSP_FILE_NODE *FileNode)
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
UINT32 GrantedAccess, UINT32 ShareAccess,
FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PBOOLEAN PDeletePending);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PULONG PCleanupFlags);
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
PFILE_OBJECT FileObject, /* non-0 to remove share access */
@ -1280,9 +1311,10 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo);
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
static inline
ULONG FspFileNodeFileInfoChangeNumber(FSP_FILE_NODE *FileNode)
{
@ -1312,6 +1344,7 @@ ULONG FspFileNodeDirInfoChangeNumber(FSP_FILE_NODE *FileNode)
{
return FileNode->DirInfoChangeNumber;
}
VOID FspFileNodeInvalidateParentDirInfo(FSP_FILE_NODE *FileNode);
BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
VOID FspFileNodeSetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
@ -1323,7 +1356,9 @@ ULONG FspFileNodeStreamInfoChangeNumber(FSP_FILE_NODE *FileNode)
FileNode = FileNode->MainFileNode;
return FileNode->StreamInfoChangeNumber;
}
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action);
VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode);
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action,
BOOLEAN InvalidateCaches);
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
@ -1483,6 +1518,7 @@ extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[];
extern ERESOURCE FspDeviceGlobalResource;
extern WCHAR FspFileDescDirectoryPatternMatchAll[];
extern const GUID FspMainFileOpenEcpGuid;
extern ULONG FspProcessorCount;
extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;
extern ULONG FspMvMdlMappingNoWrite;

21
src/sys/driver.inf.in Normal file
View File

@ -0,0 +1,21 @@
[Version]
Signature = "$WINDOWS NT$"
Class = Volume
ClassGuid = {71a27cdd-812a-11d0-bec7-08002be2092f}
CatalogFile = !CatalogFile!
Provider = !Provider!
[DestinationDirs]
DefaultDestDir = 12
[DefaultInstall]
CopyFiles = Driver.CopyFiles
[Driver.CopyFiles]
!DriverFile!
[SourceDisksFiles]
!DriverFile! = 1
[SourceDisksNames]
1 = Disk1

View File

@ -1,7 +1,7 @@
/**
* @file sys/ea.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file sys/file.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -17,7 +17,9 @@
#include <sys/driver.h>
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
NTSTATUS FspFileNodeCopyActiveList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
NTSTATUS FspFileNodeCopyOpenList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
VOID FspFileNodeDeleteList(FSP_FILE_NODE **FileNodes, ULONG FileNodeCount);
NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
@ -34,8 +36,7 @@ VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
UINT32 GrantedAccess, UINT32 ShareAccess,
FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PBOOLEAN PDeletePending);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PULONG PCleanupFlags);
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
PFILE_OBJECT FileObject, /* non-0 to remove share access */
@ -56,9 +57,10 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo);
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
@ -68,13 +70,16 @@ VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG DirInfoChangeNumber);
static VOID FspFileNodeInvalidateDirInfo(FSP_FILE_NODE *FileNode);
static VOID FspFileNodeInvalidateDirInfoByName(PDEVICE_OBJECT FsvolDeviceObject,
PUNICODE_STRING FileName);
VOID FspFileNodeInvalidateParentDirInfo(FSP_FILE_NODE *FileNode);
BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
VOID FspFileNodeSetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG StreamInfoChangeNumber);
static VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode);
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
ULONG Filter, ULONG Action);
VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode);
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action,
BOOLEAN InvalidateCaches);
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
static NTSTATUS FspFileNodeCompleteLockIrp(PVOID Context, PIRP Irp);
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
@ -97,7 +102,8 @@ VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp);
VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFileNodeCopyList)
#pragma alloc_text(PAGE, FspFileNodeCopyActiveList)
#pragma alloc_text(PAGE, FspFileNodeCopyOpenList)
#pragma alloc_text(PAGE, FspFileNodeDeleteList)
#pragma alloc_text(PAGE, FspFileNodeCreate)
#pragma alloc_text(PAGE, FspFileNodeDelete)
@ -122,6 +128,7 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
#pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeSetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeInvalidateFileInfo)
#pragma alloc_text(PAGE, FspFileNodeReferenceSecurity)
#pragma alloc_text(PAGE, FspFileNodeSetSecurity)
#pragma alloc_text(PAGE, FspFileNodeTrySetSecurity)
@ -129,6 +136,8 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
// !#pragma alloc_text(PAGE, FspFileNodeSetDirInfo)
// !#pragma alloc_text(PAGE, FspFileNodeTrySetDirInfo)
// !#pragma alloc_text(PAGE, FspFileNodeInvalidateDirInfo)
#pragma alloc_text(PAGE, FspFileNodeInvalidateDirInfoByName)
#pragma alloc_text(PAGE, FspFileNodeInvalidateParentDirInfo)
// !#pragma alloc_text(PAGE, FspFileNodeReferenceStreamInfo)
// !#pragma alloc_text(PAGE, FspFileNodeSetStreamInfo)
// !#pragma alloc_text(PAGE, FspFileNodeTrySetStreamInfo)
@ -162,7 +171,86 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
if (IrpValid) \
FspIrpSetFlags(Irp, FspIrpFlags(Irp) & (~Flags & 3))
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
#define GATHER_DESCENDANTS(FILENAME, REFERENCE, ...)\
FSP_FILE_NODE *DescendantFileNode;\
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;\
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;\
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;\
DescendantFileNodes = DescendantFileNodeArray;\
DescendantFileNodeCount = 0;\
memset(&RestartKey, 0, sizeof RestartKey);\
for (;;) \
{ \
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
FILENAME, FALSE, &RestartKey);\
if (0 == DescendantFileNode) \
break; \
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
__VA_ARGS__; \
if (REFERENCE) \
FspFileNodeReference((PVOID)((UINT_PTR)DescendantFileNode & ~7));\
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)\
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;\
DescendantFileNodeCount++; \
} \
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount ||\
DEBUGTEST_EX(0 != DescendantFileNodeCount, 10, FALSE)) \
{ \
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));\
DescendantFileNodeIndex = 0; \
memset(&RestartKey, 0, sizeof RestartKey);\
for (;;) \
{ \
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
FILENAME, FALSE, &RestartKey);\
if (0 == DescendantFileNode)\
break; \
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
__VA_ARGS__; \
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode;\
DescendantFileNodeIndex++; \
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);\
} \
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);\
} \
((VOID)0)
#define SCATTER_DESCENDANTS(REFERENCE) \
if (REFERENCE) \
{ \
for ( \
DescendantFileNodeIndex = 0;\
DescendantFileNodeCount > DescendantFileNodeIndex;\
DescendantFileNodeIndex++) \
{ \
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];\
FspFileNodeDereference((PVOID)((UINT_PTR)DescendantFileNode & ~7));\
} \
} \
if (DescendantFileNodeArray != DescendantFileNodes)\
FspFree(DescendantFileNodes); \
((VOID)0)
NTSTATUS FspFileNodeCopyActiveList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount)
{
PAGED_CODE();
NTSTATUS Result;
ULONG Index;
FspFsvolDeviceLockContextTable(DeviceObject);
Result = FspFsvolDeviceCopyContextList(DeviceObject, PFileNodes, PFileNodeCount);
if (NT_SUCCESS(Result))
{
for (Index = 0; *PFileNodeCount > Index; Index++)
FspFileNodeReference((*PFileNodes)[Index]);
}
FspFsvolDeviceUnlockContextTable(DeviceObject);
return Result;
}
NTSTATUS FspFileNodeCopyOpenList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount)
{
PAGED_CODE();
@ -191,7 +279,7 @@ VOID FspFileNodeDeleteList(FSP_FILE_NODE **FileNodes, ULONG FileNodeCount)
for (Index = 0; FileNodeCount > Index; Index++)
FspFileNodeDereference(FileNodes[Index]);
FspFsvolDeviceDeleteContextByNameList(FileNodes, FileNodeCount);
FspFsvolDeviceDeleteContextList(FileNodes, FileNodeCount);
}
NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
@ -248,6 +336,9 @@ VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode)
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
if (0 != FileNode->MainFileNode)
FspFileNodeDereference(FileNode->MainFileNode);
FsRtlUninitializeOplock(FspFileNodeAddrOfOplock(FileNode));
FsRtlUninitializeFileLock(&FileNode->FileLock);
@ -624,6 +715,14 @@ exit:
if (0 != OpenedFileNode)
{
FspFileNodeReference(OpenedFileNode);
ASSERT(0 <= OpenedFileNode->ActiveCount);
ASSERT(0 <= OpenedFileNode->OpenCount);
ASSERT(0 <= OpenedFileNode->HandleCount);
if (0 == OpenedFileNode->ActiveCount++)
InsertTailList(&FspFsvolDeviceExtension(FsvolDeviceObject)->ContextList,
&FileNode->ActiveEntry);
OpenedFileNode->OpenCount++;
OpenedFileNode->HandleCount++;
}
@ -635,8 +734,7 @@ exit:
return Result;
}
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PBOOLEAN PDeletePending)
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PULONG PCleanupFlags)
{
/*
* Determine whether a FileNode should be deleted. Note that when FileNode->DeletePending
@ -650,7 +748,7 @@ VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
BOOLEAN DeletePending, SingleHandle;
BOOLEAN DeletePending, SetAllocationSize, SingleHandle;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
@ -659,12 +757,13 @@ VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
DeletePending = 0 != FileNode->DeletePending;
MemoryBarrier();
SetAllocationSize = !DeletePending && FileNode->TruncateOnClose;
SingleHandle = 1 == FileNode->HandleCount;
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (0 != PDeletePending)
*PDeletePending = SingleHandle && DeletePending;
*PCleanupFlags = SingleHandle ? DeletePending | (SetAllocationSize << 1) : 0;
}
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject)
@ -684,7 +783,7 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
PAGED_CODE();
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
LARGE_INTEGER TruncateSize = { 0 }, *PTruncateSize = 0;
LARGE_INTEGER TruncateSize, *PTruncateSize = 0;
BOOLEAN DeletePending;
BOOLEAN DeletedFromContextTable = FALSE;
@ -708,6 +807,7 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
IoRemoveShareAccess(FileObject, &FileNode->ShareAccess);
ASSERT(0 < FileNode->HandleCount);
if (0 == --FileNode->HandleCount)
{
DeletePending = 0 != FileNode->DeletePending;
@ -715,23 +815,72 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
if (DeletePending)
{
PTruncateSize = &TruncateSize;
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName,
&DeletedFromContextTable);
ASSERT(DeletedFromContextTable);
FileNode->OpenCount = 0;
}
else if (FileNode->TruncateOnClose && FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
FileNode->Header.FileSize.QuadPart = 0;
/*
* We now have to deal with the scenario where there are cleaned up,
* but unclosed streams for this file still in the context table.
*/
if (FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.NamedStreams &&
0 == FileNode->MainFileNode)
{
BOOLEAN StreamDeletedFromContextTable;
USHORT FileNameLength = FileNode->FileName.Length;
GATHER_DESCENDANTS(&FileNode->FileName, FALSE,
if (DescendantFileNode->FileName.Length > FileNameLength &&
L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)])
break;
ASSERT(FileNode != DescendantFileNode);
ASSERT(0 != DescendantFileNode->OpenCount);
ASSERT(0 == DescendantFileNode->HandleCount);
);
for (
DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &DescendantFileNode->FileName,
&StreamDeletedFromContextTable);
if (StreamDeletedFromContextTable)
{
DescendantFileNode->OpenCount = 0;
FspFileNodeDereference(DescendantFileNode);
}
}
SCATTER_DESCENDANTS(FALSE);
}
}
if (DeletePending || FileNode->TruncateOnClose)
{
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FsvolDeviceObject);
UINT64 AllocationUnit =
FsvolDeviceExtension->VolumeParams.SectorSize *
FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit;
/*
* Even when the FileInfo is expired, this is the best guess for a file size
* without asking the user-mode file system.
*/
TruncateSize = FileNode->Header.FileSize;
PTruncateSize = &TruncateSize;
FileNode->Header.AllocationSize.QuadPart = (TruncateSize.QuadPart + AllocationUnit - 1)
/ AllocationUnit * AllocationUnit;
}
FileNode->TruncateOnClose = FALSE;
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
@ -791,6 +940,15 @@ VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
ASSERT(DeletedFromContextTable);
}
ASSERT(0 < FileNode->ActiveCount);
if (0 == --FileNode->ActiveCount)
{
ASSERT(0 == FileNode->OpenCount);
ASSERT(0 == FileNode->HandleCount);
RemoveEntryList(&FileNode->ActiveEntry);
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (DeletedFromContextTable)
@ -854,65 +1012,6 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
return IoStatus.Status;
}
#define GATHER_DESCENDANTS(FILENAME, REFERENCE, ...)\
FSP_FILE_NODE *DescendantFileNode;\
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;\
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;\
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;\
DescendantFileNodes = DescendantFileNodeArray;\
DescendantFileNodeCount = 0;\
memset(&RestartKey, 0, sizeof RestartKey);\
for (;;) \
{ \
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
FILENAME, FALSE, &RestartKey);\
if (0 == DescendantFileNode) \
break; \
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
__VA_ARGS__; \
if (REFERENCE) \
FspFileNodeReference((PVOID)((UINT_PTR)DescendantFileNode & ~7));\
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)\
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;\
DescendantFileNodeCount++; \
} \
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount ||\
DEBUGTEST_EX(0 != DescendantFileNodeCount, 10, FALSE)) \
{ \
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));\
DescendantFileNodeIndex = 0; \
memset(&RestartKey, 0, sizeof RestartKey);\
for (;;) \
{ \
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
FILENAME, FALSE, &RestartKey);\
if (0 == DescendantFileNode)\
break; \
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
__VA_ARGS__; \
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode;\
DescendantFileNodeIndex++; \
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);\
} \
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);\
} \
((VOID)0)
#define SCATTER_DESCENDANTS(REFERENCE) \
if (REFERENCE) \
{ \
for ( \
DescendantFileNodeIndex = 0;\
DescendantFileNodeCount > DescendantFileNodeIndex;\
DescendantFileNodeIndex++) \
{ \
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];\
FspFileNodeDereference((PVOID)((UINT_PTR)DescendantFileNode & ~7));\
} \
} \
if (DescendantFileNodeArray != DescendantFileNodes)\
FspFree(DescendantFileNodes); \
((VOID)0)
VOID FspFileNodeOverwriteStreams(FSP_FILE_NODE *FileNode)
{
/*
@ -1237,8 +1336,7 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp
if (0 == DescendantFileNode)
break;
/* if this is the FileNode being renamed then HandleCount must be 1, else 0 */
if ((DescendantFileNode == FileNode) < DescendantFileNode->HandleCount)
if (DescendantFileNode != FileNode && 0 < DescendantFileNode->HandleCount)
{
/* release the FileNode in case of failure! */
FspFileNodeReleaseF(FileNode, AcquireFlags);
@ -1406,7 +1504,7 @@ BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *
}
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo)
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose)
{
PAGED_CODE();
@ -1420,8 +1518,20 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit;
AllocationSize = (AllocationSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
if (TruncateOnClose)
{
if ((UINT64)FileNode->Header.AllocationSize.QuadPart != AllocationSize ||
(UINT64)FileNode->Header.FileSize.QuadPart != FileInfo->FileSize)
FileNode->TruncateOnClose = TRUE;
FileNode->Header.AllocationSize.QuadPart = AllocationSize;
FileNode->Header.FileSize.QuadPart = FileInfo->FileSize;
}
else
{
FileNode->Header.AllocationSize.QuadPart = AllocationSize;
FileNode->Header.FileSize.QuadPart = FileInfo->FileSize;
}
FileNode->FileInfoExpirationTime = FileNode->BasicInfoExpirationTime =
FspExpirationTimeFromMillis(FsvolDeviceExtension->VolumeParams.FileInfoTimeout);
@ -1511,10 +1621,20 @@ BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileOb
if (FspFileNodeFileInfoChangeNumber(FileNode) != InfoChangeNumber)
return FALSE;
FspFileNodeSetFileInfo(FileNode, CcFileObject, FileInfo);
FspFileNodeSetFileInfo(FileNode, CcFileObject, FileInfo, FALSE);
return TRUE;
}
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode)
{
PAGED_CODE();
FileNode->FileInfoExpirationTime = FileNode->BasicInfoExpirationTime = 0;
if (0 != FileNode->MainFileNode)
FileNode->MainFileNode->BasicInfoExpirationTime = 0;
}
BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize)
{
PAGED_CODE();
@ -1627,6 +1747,40 @@ static VOID FspFileNodeInvalidateDirInfo(FSP_FILE_NODE *FileNode)
FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, DirInfo);
}
static VOID FspFileNodeInvalidateDirInfoByName(PDEVICE_OBJECT FsvolDeviceObject,
PUNICODE_STRING FileName)
{
PAGED_CODE();
FSP_FILE_NODE *FileNode;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
FileNode = FspFsvolDeviceLookupContextByName(FsvolDeviceObject, FileName);
if (0 != FileNode)
FspFileNodeReference(FileNode);
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (0 != FileNode)
{
FspFileNodeInvalidateDirInfo(FileNode);
FspFileNodeDereference(FileNode);
}
}
VOID FspFileNodeInvalidateParentDirInfo(FSP_FILE_NODE *FileNode)
{
PAGED_CODE();
if (sizeof(WCHAR) == FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0])
return; /* root does not have a parent */
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
UNICODE_STRING Parent, Suffix;
FspFileNameSuffix(&FileNode->FileName, &Parent, &Suffix);
FspFileNodeInvalidateDirInfoByName(FsvolDeviceObject, &Parent);
}
BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize)
{
// !PAGED_CODE();
@ -1685,7 +1839,7 @@ BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULON
return TRUE;
}
static VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode)
VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode)
{
// !PAGED_CODE();
@ -1706,8 +1860,8 @@ static VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode)
FspMetaCacheInvalidateItem(FsvolDeviceExtension->StreamInfoCache, StreamInfo);
}
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
ULONG Filter, ULONG Action)
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action,
BOOLEAN InvalidateCaches)
{
/* FileNode must be acquired (exclusive or shared) Main */
@ -1716,32 +1870,6 @@ VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
UNICODE_STRING Parent, Suffix;
FSP_FILE_NODE *ParentNode;
FspFileNameSuffix(&FileNode->FileName, &Parent, &Suffix);
switch (Action)
{
case FILE_ACTION_ADDED:
case FILE_ACTION_REMOVED:
//case FILE_ACTION_MODIFIED:
case FILE_ACTION_RENAMED_OLD_NAME:
case FILE_ACTION_RENAMED_NEW_NAME:
FspFsvolDeviceInvalidateVolumeInfo(FsvolDeviceObject);
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
ParentNode = FspFsvolDeviceLookupContextByName(FsvolDeviceObject, &Parent);
if (0 != ParentNode)
FspFileNodeReference(ParentNode);
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (0 != ParentNode)
{
FspFileNodeInvalidateDirInfo(ParentNode);
FspFileNodeDereference(ParentNode);
}
break;
}
if (0 != FileNode->MainFileNode)
{
@ -1749,65 +1877,78 @@ VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
SetFlag(Filter, FILE_NOTIFY_CHANGE_STREAM_NAME);
if (FlagOn(Filter, FILE_NOTIFY_CHANGE_SIZE))
SetFlag(Filter, FILE_NOTIFY_CHANGE_STREAM_SIZE);
/* ???: what about FILE_NOTIFY_CHANGE_STREAM_WRITE */
ClearFlag(Filter, ~(FILE_NOTIFY_CHANGE_STREAM_NAME | FILE_NOTIFY_CHANGE_STREAM_SIZE));
if (FlagOn(Filter, FILE_NOTIFY_CHANGE_LAST_WRITE))
SetFlag(Filter, FILE_NOTIFY_CHANGE_STREAM_WRITE);
ClearFlag(Filter, ~(FILE_NOTIFY_CHANGE_STREAM_NAME | FILE_NOTIFY_CHANGE_STREAM_SIZE |
FILE_NOTIFY_CHANGE_STREAM_WRITE));
switch (Action)
{
case FILE_ACTION_ADDED:
Action = FILE_ACTION_ADDED_STREAM;
FspFileNodeInvalidateStreamInfo(FileNode);
break;
case FILE_ACTION_REMOVED:
Action = FILE_ACTION_REMOVED_STREAM;
FspFileNodeInvalidateStreamInfo(FileNode);
break;
case FILE_ACTION_MODIFIED:
Action = FILE_ACTION_MODIFIED_STREAM;
//FspFileNodeInvalidateStreamInfo(FileNode);
break;
}
}
if (0 != Filter)
{
FspFileNameSuffix(&FileNode->FileName, &Parent, &Suffix);
if (InvalidateCaches)
{
FspFsvolDeviceInvalidateVolumeInfo(FsvolDeviceObject);
if (0 == FileNode->MainFileNode)
{
if (sizeof(WCHAR) == FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0])
; /* root does not have a parent */
else
FspFileNodeInvalidateDirInfoByName(FsvolDeviceObject, &Parent);
}
else
FspFileNodeInvalidateStreamInfo(FileNode);
}
FspNotifyReportChange(
FsvolDeviceExtension->NotifySync, &FsvolDeviceExtension->NotifyList,
&FileNode->FileName,
(USHORT)((PUINT8)Suffix.Buffer - (PUINT8)FileNode->FileName.Buffer),
0, Filter, Action);
}
}
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp)
{
PAGED_CODE();
IoMarkIrpPending(Irp);
FspFileNodeSetOwnerF(FileNode, FspIrpFlags(Irp), Irp);
NTSTATUS Result;
try
{
FsRtlProcessFileLock(&FileNode->FileLock, Irp, FileNode);
Result = FsRtlProcessFileLock(&FileNode->FileLock, Irp, FileNode);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Irp->IoStatus.Status = GetExceptionCode();
Irp->IoStatus.Information = 0;
FspFileNodeCompleteLockIrp(FileNode, Irp);
Result = FspFileNodeCompleteLockIrp(FileNode, Irp);
}
return STATUS_PENDING;
return Result;
}
static NTSTATUS FspFileNodeCompleteLockIrp(PVOID Context, PIRP Irp)
{
PAGED_CODE();
FSP_FILE_NODE *FileNode = Context;
NTSTATUS Result = Irp->IoStatus.Status;
FspFileNodeReleaseOwnerF(FileNode, FspIrpFlags(Irp), Irp);
DEBUGLOGIRP(Irp, Result);
FspIopCompleteIrp(Irp, Result);
@ -1915,7 +2056,9 @@ NTSTATUS FspMainFileOpen(
PFILE_OBJECT MainFileObject;
/* assert that the supplied name is actually a main file name */
ASSERT(FspFileNameIsValid(MainFileName, 0, 0));
ASSERT(FspFileNameIsValid(MainFileName,
FsvolDeviceExtension->VolumeParams.MaxComponentLength,
0, 0));
*PMainFileHandle = 0;
*PMainFileObject = 0;
@ -1925,11 +2068,11 @@ NTSTATUS FspMainFileOpen(
case FILE_CREATE:
case FILE_OPEN_IF:
case FILE_OVERWRITE_IF:
case FILE_SUPERSEDE:
Disposition = FILE_OPEN_IF;
break;
case FILE_OPEN:
case FILE_OVERWRITE:
case FILE_SUPERSEDE:
Disposition = FILE_OPEN;
break;
default:

View File

@ -1,7 +1,7 @@
/**
* @file sys/fileinfo.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -134,6 +134,7 @@ static NTSTATUS FspFsvolQueryAllInformation(PFILE_OBJECT FileObject,
PFILE_ALL_INFORMATION Info = (PFILE_ALL_INFORMATION)*PBuffer;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
BOOLEAN DeletePending;
if (0 == FileInfo)
{
@ -144,6 +145,9 @@ static NTSTATUS FspFsvolQueryAllInformation(PFILE_OBJECT FileObject,
return FspFsvolQueryNameInformation(FileObject, PBuffer, BufferEnd);
}
DeletePending = 0 != FileNode->DeletePending;
MemoryBarrier();
Info->BasicInformation.CreationTime.QuadPart = FileInfo->CreationTime;
Info->BasicInformation.LastAccessTime.QuadPart = FileInfo->LastAccessTime;
Info->BasicInformation.LastWriteTime.QuadPart = FileInfo->LastWriteTime;
@ -154,7 +158,7 @@ static NTSTATUS FspFsvolQueryAllInformation(PFILE_OBJECT FileObject,
Info->StandardInformation.AllocationSize.QuadPart = FileInfo->AllocationSize;
Info->StandardInformation.EndOfFile.QuadPart = FileInfo->FileSize;
Info->StandardInformation.NumberOfLinks = 1;
Info->StandardInformation.DeletePending = FileObject->DeletePending;
Info->StandardInformation.DeletePending = DeletePending || FileObject->DeletePending;
Info->StandardInformation.Directory = FileNode->IsDirectory;
Info->InternalInformation.IndexNumber.QuadPart = FileNode->IndexNumber;
@ -363,6 +367,7 @@ static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject,
PFILE_STANDARD_INFORMATION Info = (PFILE_STANDARD_INFORMATION)*PBuffer;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
BOOLEAN DeletePending;
if (0 == FileInfo)
{
@ -372,10 +377,13 @@ static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject,
return STATUS_SUCCESS;
}
DeletePending = 0 != FileNode->DeletePending;
MemoryBarrier();
Info->AllocationSize.QuadPart = FileInfo->AllocationSize;
Info->EndOfFile.QuadPart = FileInfo->FileSize;
Info->NumberOfLinks = 1;
Info->DeletePending = FileObject->DeletePending;
Info->DeletePending = DeletePending || FileObject->DeletePending;
Info->Directory = FileNode->IsDirectory;
*PBuffer = (PVOID)(Info + 1);
@ -619,7 +627,7 @@ static NTSTATUS FspFsvolQueryInformation(
/* is this a valid FileObject? */
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
return STATUS_INVALID_DEVICE_REQUEST;
return STATUS_INVALID_PARAMETER;
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
@ -663,7 +671,7 @@ static NTSTATUS FspFsvolQueryInformation(
Irp->IoStatus.Information = (UINT_PTR)((PUINT8)Buffer - (PUINT8)Irp->AssociatedIrp.SystemBuffer);
return Result;
case FileHardLinkInformation:
Result = STATUS_INVALID_PARAMETER; /* no hard link support */
Result = STATUS_NOT_SUPPORTED; /* no hard link support */
return Result;
case FileInternalInformation:
Result = FspFsvolQueryInternalInformation(FileObject, &Buffer, BufferEnd);
@ -674,6 +682,9 @@ static NTSTATUS FspFsvolQueryInformation(
Result = FspFsvolQueryNameInformation(FileObject, &Buffer, BufferEnd);
Irp->IoStatus.Information = (UINT_PTR)((PUINT8)Buffer - (PUINT8)Irp->AssociatedIrp.SystemBuffer);
return Result;
case FileAlternateNameInformation:
Result = STATUS_OBJECT_NAME_NOT_FOUND; /* WinFsp does not support short names */
return Result;
case FileNetworkOpenInformation:
Result = FspFsvolQueryNetworkOpenInformation(FileObject, &Buffer, BufferEnd, 0);
break;
@ -893,13 +904,12 @@ static NTSTATUS FspFsvolSetAllocationInformation(PFILE_OBJECT FileObject,
{
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetInformation.FileInfo);
FileNode->TruncateOnClose = TRUE;
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetInformation.FileInfo, TRUE);
/* mark the file object as modified */
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED, FALSE);
}
return STATUS_SUCCESS;
@ -915,6 +925,15 @@ static NTSTATUS FspFsvolSetBasicInformation(PFILE_OBJECT FileObject,
{
if (sizeof(FILE_BASIC_INFORMATION) > Length)
return STATUS_INVALID_PARAMETER;
PFILE_BASIC_INFORMATION Info = (PFILE_BASIC_INFORMATION)Buffer;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
UINT32 FileAttributes = Info->FileAttributes;
/* do not allow the temporary bit on a directory */
if (FileNode->IsDirectory &&
FlagOn(FileAttributes, FILE_ATTRIBUTE_TEMPORARY))
return STATUS_INVALID_PARAMETER;
}
else if (0 == Response)
{
@ -935,23 +954,53 @@ static NTSTATUS FspFsvolSetBasicInformation(PFILE_OBJECT FileObject,
Request->Req.SetInformation.Info.Basic.CreationTime = Info->CreationTime.QuadPart;
Request->Req.SetInformation.Info.Basic.LastAccessTime = Info->LastAccessTime.QuadPart;
Request->Req.SetInformation.Info.Basic.LastWriteTime = Info->LastWriteTime.QuadPart;
Request->Req.SetInformation.Info.Basic.ChangeTime = Info->ChangeTime.QuadPart;
}
else
{
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
ULONG NotifyFilter = 0;
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetInformation.FileInfo);
ASSERT(FileNode == FileDesc->FileNode);
if (!FileNode->IsDirectory)
{
/* properly set temporary bit for lazy writer */
if (FlagOn(Response->Rsp.SetInformation.FileInfo.FileAttributes,
FILE_ATTRIBUTE_TEMPORARY))
SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
else
ClearFlag(FileObject->Flags, FO_TEMPORARY_FILE);
}
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetInformation.FileInfo, FALSE);
if ((UINT32)-1 != Request->Req.SetInformation.Info.Basic.FileAttributes)
{
FileDesc->DidSetFileAttributes = TRUE;
NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
}
if (0 != Request->Req.SetInformation.Info.Basic.CreationTime)
{
FileDesc->DidSetCreationTime = TRUE;
NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION;
}
if (0 != Request->Req.SetInformation.Info.Basic.LastAccessTime)
{
FileDesc->DidSetLastAccessTime = TRUE;
NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
}
if (0 != Request->Req.SetInformation.Info.Basic.LastWriteTime)
{
FileDesc->DidSetLastWriteTime = TRUE;
NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
FspFileNodeNotifyChange(FileNode, NotifyFilter, FILE_ACTION_MODIFIED);
}
if (0 != Request->Req.SetInformation.Info.Basic.ChangeTime)
FileDesc->DidSetChangeTime = TRUE;
FileDesc->DidSetMetadata = TRUE;
FspFileNodeNotifyChange(FileNode, NotifyFilter, FILE_ACTION_MODIFIED, TRUE/*FALSE*/);
}
return STATUS_SUCCESS;
@ -996,13 +1045,12 @@ static NTSTATUS FspFsvolSetEndOfFileInformation(PFILE_OBJECT FileObject,
{
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetInformation.FileInfo);
FileNode->TruncateOnClose = TRUE;
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetInformation.FileInfo, TRUE);
/* mark the file object as modified -- FastFat does this only for Allocation though! */
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED, FALSE);
}
return STATUS_SUCCESS;
@ -1151,6 +1199,7 @@ static NTSTATUS FspFsvolSetRenameInformation(
PAGED_CODE();
NTSTATUS Result;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PFILE_OBJECT FileObject = IrpSp->FileObject;
PFILE_OBJECT TargetFileObject = IrpSp->Parameters.SetFile.FileObject;
BOOLEAN ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
@ -1176,7 +1225,9 @@ static NTSTATUS FspFsvolSetRenameInformation(
if (FileNode->IsRootDirectory)
/* cannot rename root directory */
return STATUS_INVALID_PARAMETER;
if (!FspFileNameIsValid(&FileNode->FileName, 0, 0))
if (!FspFileNameIsValid(&FileNode->FileName,
FsvolDeviceExtension->VolumeParams.MaxComponentLength,
0, 0))
/* cannot rename streams (WinFsp limitation) */
return STATUS_INVALID_PARAMETER;
@ -1210,7 +1261,12 @@ retry:
}
Suffix.MaximumLength = Suffix.Length;
if (!FspFileNameIsValid(&Remain, 0, 0) || !FspFileNameIsValid(&Suffix, 0, 0))
if (!FspFileNameIsValid(&Remain,
FsvolDeviceExtension->VolumeParams.MaxComponentLength,
0, 0) ||
!FspFileNameIsValid(&Suffix,
FsvolDeviceExtension->VolumeParams.MaxComponentLength,
0, 0))
{
/* cannot rename streams (WinFsp limitation) */
Result = STATUS_INVALID_PARAMETER;
@ -1341,7 +1397,8 @@ static NTSTATUS FspFsvolSetRenameInformationSuccess(
/* fastfat has some really arcane rules on rename notifications; simplify! */
FspFileNodeNotifyChange(FileNode,
FileNode->IsDirectory ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_RENAMED_OLD_NAME);
FILE_ACTION_RENAMED_OLD_NAME,
TRUE);
NewFileName.Length = NewFileName.MaximumLength =
Request->Req.SetInformation.Info.Rename.NewFileName.Size - sizeof(WCHAR);
@ -1352,7 +1409,8 @@ static NTSTATUS FspFsvolSetRenameInformationSuccess(
/* fastfat has some really arcane rules on rename notifications; simplify! */
FspFileNodeNotifyChange(FileNode,
FileNode->IsDirectory ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_RENAMED_NEW_NAME);
FILE_ACTION_RENAMED_NEW_NAME,
TRUE);
FspIopRequestContext(Request, RequestFileNode) = 0;
FspIopRequestContext(Request, RequestDeviceObject) = 0;
@ -1371,7 +1429,7 @@ static NTSTATUS FspFsvolSetInformation(
/* is this a valid FileObject? */
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
return STATUS_INVALID_DEVICE_REQUEST;
return STATUS_INVALID_PARAMETER;
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass;
@ -1402,7 +1460,7 @@ static NTSTATUS FspFsvolSetInformation(
Result = FspFsvolSetEndOfFileInformation(FileObject, Buffer, Length, 0, 0);
break;
case FileLinkInformation:
Result = STATUS_INVALID_PARAMETER; /* no hard link support */
Result = STATUS_NOT_SUPPORTED; /* no hard link support */
return Result;
case FilePositionInformation:
Result = FspFsvolSetPositionInformation(FileObject, Buffer, Length);

View File

@ -1,7 +1,7 @@
/**
* @file sys/flush.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -58,7 +58,7 @@ static NTSTATUS FspFsvolFlushBuffers(
*/
if (!FspFileNodeIsValid(FileNode) || FileNode->IsRootDirectory)
{
Result = FspFileNodeCopyList(FsvolDeviceObject, &FileNodes, &FileNodeCount);
Result = FspFileNodeCopyOpenList(FsvolDeviceObject, &FileNodes, &FileNodeCount);
if (!NT_SUCCESS(Result))
return Result;
@ -149,7 +149,21 @@ NTSTATUS FspFsvolFlushBuffersComplete(
else if (!NT_SUCCESS(FlushResult))
Result = FlushResult;
else
{
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
/*
* A flush request on the volume (or the root directory according to FastFat)
* is a request to flush the whole volume.
*/
if (!FspFileNodeIsValid(FileNode) || FileNode->IsRootDirectory)
;
else
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.FlushBuffers.FileInfo, TRUE);
Result = STATUS_SUCCESS;
}
FSP_LEAVE_IOC("FileObject=%p",
IrpSp->FileObject);

View File

@ -1,7 +1,7 @@
/**
* @file sys/fsctl.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -29,6 +29,12 @@ static NTSTATUS FspFsvolFileSystemControlOplock(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static IO_COMPLETION_ROUTINE FspFsvolFileSystemControlOplockCompletion;
static WORKER_THREAD_ROUTINE FspFsvolFileSystemControlOplockCompletionWork;
static NTSTATUS FspFsvolFileSystemControlQueryPersistentVolumeState(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolFileSystemControlGetStatistics(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolFileSystemControlGetRetrievalPointers(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolFileSystemControl(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
@ -42,6 +48,9 @@ FSP_DRIVER_DISPATCH FspFileSystemControl;
#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplock)
// !#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplockCompletion)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplockCompletionWork)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlQueryPersistentVolumeState)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlGetStatistics)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlGetRetrievalPointers)
#pragma alloc_text(PAGE, FspFsvolFileSystemControl)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlComplete)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlRequestFini)
@ -105,7 +114,7 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
/* is this a valid FileObject? */
if (!FspFileNodeIsValid(FileObject->FsContext))
return STATUS_INVALID_DEVICE_REQUEST;
return STATUS_INVALID_PARAMETER;
NTSTATUS Result;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
@ -125,16 +134,50 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
if (IsWrite)
{
if (0 == InputBuffer || 0 == InputBufferLength ||
FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMAX - (FileNode->FileName.Length + sizeof(WCHAR)) <
InputBufferLength)
ASSERT(
FSCTL_SET_REPARSE_POINT == FsControlCode ||
FSCTL_DELETE_REPARSE_POINT == FsControlCode);
if (0 == InputBuffer || 0 == InputBufferLength)
return STATUS_INVALID_BUFFER_SIZE;
if (0 != OutputBufferLength)
return STATUS_INVALID_PARAMETER;
ReparseData = (PREPARSE_DATA_BUFFER)InputBuffer;
if (FSCTL_SET_REPARSE_POINT == FsControlCode)
{
if (FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMAX - (FileNode->FileName.Length + sizeof(WCHAR)) <
InputBufferLength)
return STATUS_IO_REPARSE_DATA_INVALID;
Result = FsRtlValidateReparsePointBuffer(InputBufferLength, InputBuffer);
if (!NT_SUCCESS(Result))
return Result;
}
else
{
if ((ULONG)FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer) != InputBufferLength &&
(ULONG)FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer) != InputBufferLength)
return STATUS_IO_REPARSE_DATA_INVALID;
ReparseData = (PREPARSE_DATA_BUFFER)InputBuffer;
if (0 != ReparseData->ReparseDataLength)
return STATUS_IO_REPARSE_DATA_INVALID;
if (IO_REPARSE_TAG_RESERVED_ZERO == ReparseData->ReparseTag ||
IO_REPARSE_TAG_RESERVED_ONE == ReparseData->ReparseTag)
return STATUS_IO_REPARSE_TAG_INVALID;
if (!IsReparseTagMicrosoft(ReparseData->ReparseTag) &&
(ULONG)FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer) != InputBufferLength)
return STATUS_IO_REPARSE_DATA_INVALID;
}
/* NTFS seems to require one of these rights to allow FSCTL_{SET,DELETE}_REPARSE_POINT */
if (!FlagOn(FileDesc->GrantedAccess,
FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES))
return STATUS_ACCESS_DENIED;
if (IO_REPARSE_TAG_SYMLINK == ReparseData->ReparseTag)
{
@ -229,9 +272,14 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
}
else
{
if (0 == OutputBuffer || 0 == OutputBufferLength)
ASSERT(FSCTL_GET_REPARSE_POINT == FsControlCode);
if (0 != InputBufferLength)
return STATUS_INVALID_PARAMETER;
if (0 == OutputBuffer || 0 == OutputBufferLength)
return STATUS_INVALID_USER_BUFFER;
/*
* NtFsControlFile (IopXxxControlFile) will setup Irp->AssociatedIrp.SystemBuffer
* with enough space for either InputBufferLength or OutputBufferLength. There is
@ -276,7 +324,21 @@ static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
PAGED_CODE();
if (IsWrite)
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = IrpSp->FileObject->FsContext2;
ASSERT(FileNode == FileDesc->FileNode);
FspFileNodeInvalidateFileInfo(FileNode);
FileDesc->DidSetReparsePoint = TRUE;
FileDesc->DidSetMetadata = TRUE;
return STATUS_SUCCESS;
}
NTSTATUS Result;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
@ -433,18 +495,15 @@ static NTSTATUS FspFsvolFileSystemControlOplock(
/*
* FspOplockFsctrl takes ownership of the IRP under all circumstances.
*
* We mark the IRP pending so that we can safely return STATUS_PENDING.
*/
IoSetTopLevelIrp(0);
IoMarkIrpPending(Irp);
Result = FspFileNodeOplockFsctl(FileNode, Irp, OplockCount);
FspFileNodeRelease(FileNode, Main);
return STATUS_PENDING;
return Result | FSP_STATUS_IGNORE_BIT;
unlock_exit:
FspFileNodeRelease(FileNode, Main);
@ -473,6 +532,140 @@ static VOID FspFsvolFileSystemControlOplockCompletionWork(PVOID Context)
FspFree(CompletionContext);
}
static NTSTATUS FspFsvolFileSystemControlQueryPersistentVolumeState(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
PFILE_FS_PERSISTENT_VOLUME_INFORMATION Info;
if (0 == Buffer)
return STATUS_INVALID_PARAMETER;
if (sizeof(FILE_FS_PERSISTENT_VOLUME_INFORMATION) > InputBufferLength ||
sizeof(FILE_FS_PERSISTENT_VOLUME_INFORMATION) > OutputBufferLength)
return STATUS_BUFFER_TOO_SMALL;
Info = Buffer;
if (1 != Info->Version ||
!FlagOn(Info->FlagMask, PERSISTENT_VOLUME_STATE_SHORT_NAME_CREATION_DISABLED))
return STATUS_INVALID_PARAMETER;
RtlZeroMemory(Info, sizeof(FILE_FS_PERSISTENT_VOLUME_INFORMATION));
Info->VolumeFlags = PERSISTENT_VOLUME_STATE_SHORT_NAME_CREATION_DISABLED;
Irp->IoStatus.Information = sizeof(FILE_FS_PERSISTENT_VOLUME_INFORMATION);
return STATUS_SUCCESS;
}
static NTSTATUS FspFsvolFileSystemControlGetStatistics(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
NTSTATUS Result;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
ULONG Length = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
Result = FspStatisticsCopy(FsvolDeviceExtension->Statistics, Buffer, &Length);
Irp->IoStatus.Information = Length;
return Result;
}
static NTSTATUS FspFsvolFileSystemControlGetRetrievalPointers(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
/*
* FSCTL_GET_RETRIEVAL_POINTERS is normally used for defragmentation support,
* which WinFsp does NOT support. However some tools (notably IFSTEST) use it
* to determine whether files are "resident" or "non-resident" which is an NTFS
* concept. To support such tools we respond in a manner that indicates that
* WinFsp files are always non-resident.
*/
PAGED_CODE();
PFILE_OBJECT FileObject = IrpSp->FileObject;
/* is this a valid FileObject? */
if (!FspFileNodeIsValid(FileObject->FsContext))
return STATUS_INVALID_DEVICE_REQUEST;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
FSP_FILE_NODE *FileNode = FileObject->FsContext;
PSTARTING_VCN_INPUT_BUFFER InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
PRETRIEVAL_POINTERS_BUFFER OutputBuffer = Irp->UserBuffer;
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
STARTING_VCN_INPUT_BUFFER StartingVcn;
RETRIEVAL_POINTERS_BUFFER RetrievalPointers;
UINT64 AllocationUnit;
if (0 == InputBuffer || 0 == OutputBuffer)
return STATUS_INVALID_PARAMETER;
if (sizeof(STARTING_VCN_INPUT_BUFFER) > InputBufferLength ||
sizeof(RETRIEVAL_POINTERS_BUFFER) > OutputBufferLength)
return STATUS_BUFFER_TOO_SMALL;
if (UserMode == Irp->RequestorMode)
{
try
{
ProbeForRead(InputBuffer, InputBufferLength, sizeof(UCHAR)/*FastFat*/);
StartingVcn = *InputBuffer;
}
except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
}
else
StartingVcn = *InputBuffer;
RetrievalPointers.ExtentCount = 1;
RetrievalPointers.StartingVcn.QuadPart = 0;
RetrievalPointers.Extents[0].NextVcn.QuadPart = 0;
RetrievalPointers.Extents[0].Lcn.QuadPart = -1LL;
AllocationUnit = FsvolDeviceExtension->VolumeParams.SectorSize *
FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit;
FspFileNodeAcquireShared(FileNode, Main);
RetrievalPointers.Extents[0].NextVcn.QuadPart =
FileNode->Header.AllocationSize.QuadPart / AllocationUnit;
FspFileNodeRelease(FileNode, Main);
if (StartingVcn.StartingVcn.QuadPart > RetrievalPointers.Extents[0].NextVcn.QuadPart)
return STATUS_END_OF_FILE;
if (UserMode == Irp->RequestorMode)
{
try
{
ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(UCHAR)/*FastFat*/);
*OutputBuffer = RetrievalPointers;
}
except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
}
else
*OutputBuffer = RetrievalPointers;
Irp->IoStatus.Information = sizeof RetrievalPointers;
return STATUS_SUCCESS;
}
static NTSTATUS FspFsvolFileSystemControl(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
@ -506,6 +699,15 @@ static NTSTATUS FspFsvolFileSystemControl(
case FSCTL_REQUEST_OPLOCK:
Result = FspFsvolFileSystemControlOplock(FsvolDeviceObject, Irp, IrpSp);
break;
case FSCTL_QUERY_PERSISTENT_VOLUME_STATE:
Result = FspFsvolFileSystemControlQueryPersistentVolumeState(FsvolDeviceObject, Irp, IrpSp);
break;
case FSCTL_FILESYSTEM_GET_STATISTICS:
Result = FspFsvolFileSystemControlGetStatistics(FsvolDeviceObject, Irp, IrpSp);
break;
case FSCTL_GET_RETRIEVAL_POINTERS:
Result = FspFsvolFileSystemControlGetRetrievalPointers(FsvolDeviceObject, Irp, IrpSp);
break;
}
break;
}

View File

@ -1,7 +1,7 @@
/**
* @file sys/iop.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -33,7 +33,7 @@ BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
VOID FspIopSetIrpResponse(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
FSP_FSCTL_TRANSACT_RSP *FspIopIrpResponse(PIRP Irp);
NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request);
NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
NTSTATUS FspIopDispatchComplete(PIRP Irp, FSP_FSCTL_TRANSACT_RSP *Response);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspIopCreateRequestFunnel)
@ -281,6 +281,32 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceDereference)
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_OBJECT DeviceObject = IrpSp->DeviceObject;
/*
* HACK:
*
* We update the Create statistics here to avoid doing it in multiple places.
*/
if (IRP_MJ_CREATE == IrpSp->MajorFunction)
{
/* only update statistics if we actually have a reference to the DeviceObject */
if (DeviceDereference)
{
FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject);
if (FspFsvolDeviceExtensionKind == FspDeviceExtension(DeviceObject)->Kind)
{
FSP_STATISTICS *Statistics = FspStatistics(
((FSP_FSVOL_DEVICE_EXTENSION *)DeviceExtension)->Statistics);
FspStatisticsInc(Statistics, Specific.CreateHits);
if (STATUS_SUCCESS == Result)
FspStatisticsInc(Statistics, Specific.SuccessfulCreates);
else
FspStatisticsInc(Statistics, Specific.FailedCreates);
}
}
}
else
/*
* HACK:
*
@ -422,7 +448,7 @@ NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request)
return STATUS_SUCCESS;
}
NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
NTSTATUS FspIopDispatchComplete(PIRP Irp, FSP_FSCTL_TRANSACT_RSP *Response)
{
PAGED_CODE();
@ -431,6 +457,9 @@ NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response
ASSERT(IRP_MJ_MAXIMUM_FUNCTION >= IrpSp->MajorFunction);
ASSERT(0 != FspIopCompleteFunction[IrpSp->MajorFunction]);
if (STATUS_PENDING == Response->IoStatus.Status ||
FlagOn(Response->IoStatus.Status, FSP_STATUS_PRIVATE_BIT | FSP_STATUS_IGNORE_BIT))
Response->IoStatus.Status = (UINT32)STATUS_INTERNAL_ERROR;
return FspIopCompleteFunction[IrpSp->MajorFunction](Irp, Response);
}

View File

@ -1,7 +1,7 @@
/**
* @file sys/ioq.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file sys/lockctl.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -61,10 +61,15 @@ static NTSTATUS FspFsvolLockControlRetry(
return Result;
}
ULONG IrpFlags = FspIrpFlags(Irp);
IoSetTopLevelIrp(0);
/* let the FSRTL package handle this one! */
Result = FspFileNodeProcessLockIrp(FileNode, Irp);
return Result;
FspFileNodeReleaseF(FileNode, IrpFlags);
return Result | FSP_STATUS_IGNORE_BIT;
}
static NTSTATUS FspFsvolLockControl(

View File

@ -1,7 +1,7 @@
/**
* @file sys/meta.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file sys/name.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -17,8 +17,9 @@
#include <sys/driver.h>
BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType);
BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Pattern);
BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, ULONG MaxComponentLength,
PUNICODE_STRING StreamPart, PULONG StreamType);
BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Pattern, ULONG MaxComponentLength);
VOID FspFileNameSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
NTSTATUS FspFileNameInExpression(
PUNICODE_STRING Expression,
@ -34,7 +35,8 @@ NTSTATUS FspFileNameInExpression(
#pragma alloc_text(PAGE, FspFileNameInExpression)
#endif
BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType)
BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, ULONG MaxComponentLength,
PUNICODE_STRING StreamPart, PULONG StreamType)
{
PAGED_CODE();
@ -44,7 +46,7 @@ BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PUL
if (0 == Path->Length || 0 != Path->Length % sizeof(WCHAR))
return FALSE;
PWSTR PathBgn, PathEnd, PathPtr, StreamTypeStr = 0;
PWSTR PathBgn, PathEnd, PathPtr, ComponentPtr, StreamTypeStr = 0;
UCHAR Flags = FSRTL_NTFS_LEGAL;
ULONG Colons = 0;
WCHAR Char;
@ -52,6 +54,7 @@ BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PUL
PathBgn = Path->Buffer;
PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length);
PathPtr = PathBgn;
ComponentPtr = PathPtr;
while (PathEnd > PathPtr)
{
@ -63,7 +66,12 @@ BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PUL
if (0 < Colons)
return FALSE;
/* path component cannot be longer than MaxComponentLength */
if ((ULONG)(PathPtr - ComponentPtr) > MaxComponentLength)
return FALSE;
PathPtr++;
ComponentPtr = PathPtr;
/* don't like multiple backslashes */
if (PathEnd > PathPtr && L'\\' == *PathPtr)
@ -106,6 +114,10 @@ BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PUL
PathPtr++;
}
/* path component cannot be longer than MaxComponentLength */
if ((ULONG)(PathPtr - ComponentPtr) > MaxComponentLength)
return FALSE;
/* if we had no colons the path is valid */
if (0 == Colons)
return TRUE;
@ -133,19 +145,20 @@ BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PUL
return FALSE;
}
BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Path)
BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Path, ULONG MaxComponentLength)
{
PAGED_CODE();
if (0 != Path->Length % sizeof(WCHAR))
return FALSE;
PWSTR PathBgn, PathEnd, PathPtr;
PWSTR PathBgn, PathEnd, PathPtr, ComponentPtr;
WCHAR Char;
PathBgn = Path->Buffer;
PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length);
PathPtr = PathBgn;
ComponentPtr = PathPtr;
while (PathEnd > PathPtr)
{
@ -167,6 +180,10 @@ BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Path)
PathPtr++;
}
/* path component cannot be longer than MaxComponentLength */
if ((ULONG)(PathPtr - ComponentPtr) > MaxComponentLength)
return FALSE;
return TRUE;
}

View File

@ -1,7 +1,7 @@
/**
* @file sys/read.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -324,6 +324,20 @@ static NTSTATUS FspFsvolReadNonCached(
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp;
FSP_STATISTICS *Statistics = FspFsvolDeviceStatistics(FsvolDeviceObject);
if (PagingIo)
{
FspStatisticsInc(Statistics, Base.UserFileReads);
FspStatisticsAdd(Statistics, Base.UserFileReadBytes, ReadLength);
FspStatisticsInc(Statistics, Base.UserDiskReads);
}
else
{
FspStatisticsInc(Statistics, Specific.NonCachedReads);
FspStatisticsAdd(Statistics, Specific.NonCachedReadBytes, ReadLength);
FspStatisticsInc(Statistics, Specific.NonCachedDiskReads);
}
return FSP_STATUS_IOQ_POST;
}

View File

@ -1,7 +1,7 @@
/**
* @file sys/security.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -254,8 +254,11 @@ NTSTATUS FspFsvolSetSecurityComplete(
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
ASSERT(FileNode == FileDesc->FileNode);
/* if the security descriptor that we got back is valid */
if (0 < Response->Rsp.SetSecurity.SecurityDescriptor.Size &&
Response->Buffer + Response->Rsp.SetSecurity.SecurityDescriptor.Size <=
@ -273,6 +276,11 @@ NTSTATUS FspFsvolSetSecurityComplete(
FspFileNodeSetSecurity(FileNode, 0, 0);
}
FileDesc->DidSetSecurity = TRUE;
FileDesc->DidSetMetadata = TRUE;
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SECURITY, FILE_ACTION_MODIFIED, FALSE);
FspIopRequestContext(Request, RequestFileNode) = 0;
FspFileNodeReleaseOwner(FileNode, Full, Request);

View File

@ -1,7 +1,7 @@
/**
* @file sys/shutdown.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

84
src/sys/statistics.c Normal file
View File

@ -0,0 +1,84 @@
/**
* @file sys/statistics.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>
NTSTATUS FspStatisticsCreate(FSP_STATISTICS **PStatistics);
VOID FspStatisticsDelete(FSP_STATISTICS *Statistics);
NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLength);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspStatisticsCreate)
#pragma alloc_text(PAGE, FspStatisticsDelete)
#pragma alloc_text(PAGE, FspStatisticsCopy)
#endif
NTSTATUS FspStatisticsCreate(FSP_STATISTICS **PStatistics)
{
*PStatistics = FspAllocNonPaged(sizeof(FSP_STATISTICS) * FspProcessorCount);
if (0 == *PStatistics)
return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(*PStatistics, sizeof(FSP_STATISTICS) * FspProcessorCount);
for (ULONG Index = 0; FspProcessorCount > Index; Index++)
{
FSP_STATISTICS *Statistics = *PStatistics + Index;
/* pretend that we are FAT when it comes to stats */
Statistics->Base.FileSystemType = FILESYSTEM_STATISTICS_TYPE_FAT;
Statistics->Base.Version = 1;
Statistics->Base.SizeOfCompleteStructure = sizeof(FSP_STATISTICS);
}
return STATUS_SUCCESS;
}
VOID FspStatisticsDelete(FSP_STATISTICS *Statistics)
{
FspFree(Statistics);
}
NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLength)
{
NTSTATUS Result;
ULONG StatLength;
if (0 == Buffer)
{
*PLength = 0;
return STATUS_INVALID_PARAMETER;
}
if (sizeof(FILESYSTEM_STATISTICS) > *PLength)
{
*PLength = 0;
return STATUS_BUFFER_TOO_SMALL;
}
StatLength = sizeof(FSP_STATISTICS) * FspProcessorCount;
if (*PLength >= StatLength)
{
*PLength = StatLength;
Result = STATUS_SUCCESS;
}
else
Result = STATUS_BUFFER_OVERFLOW;
RtlCopyMemory(Buffer, Statistics, *PLength);
return Result;
}

View File

@ -1,7 +1,7 @@
/**
* @file sys/util.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -22,7 +22,7 @@ BEGIN
BEGIN
VALUE "CompanyName", STR(MyCompanyName)
VALUE "FileDescription", STR(MyDescription)
VALUE "FileVersion", STR(MyVersion)
VALUE "FileVersion", STR(MyFullVersion)
VALUE "InternalName", "winfsp.sys"
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "winfsp.sys"

View File

@ -1,7 +1,7 @@
/**
* @file sys/volinfo.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -98,16 +98,22 @@ static NTSTATUS FspFsvolQueryFsAttributeInformation(
RtlInitUnicodeString(&FileSystemName, FsvolDeviceExtension->VolumeParams.FileSystemName);
if (0 == FileSystemName.Length ||
(L'-' == FileSystemName.Buffer[0] ||
L'/' == FileSystemName.Buffer[0] ||
L'\\' == FileSystemName.Buffer[0]))
{
CopyLength = sizeof L"" DRIVER_NAME - sizeof(WCHAR);
RtlCopyMemory(FileSystemNameBuf, L"" DRIVER_NAME, CopyLength);
if (0 != FileSystemName.Length)
{
FileSystemNameBuf[CopyLength / sizeof(WCHAR)] = L'-';
CopyLength += sizeof(WCHAR);
RtlCopyMemory(FileSystemNameBuf + CopyLength / sizeof(WCHAR), FileSystemName.Buffer,
FileSystemName.Length);
CopyLength += FileSystemName.Length;
}
else
{
CopyLength = FileSystemName.Length;
RtlCopyMemory(FileSystemNameBuf, FileSystemName.Buffer, CopyLength);
}
Info->FileSystemNameLength = CopyLength;
if (Buffer + CopyLength > BufferEnd)

View File

@ -1,7 +1,7 @@
/**
* @file sys/volume.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -294,9 +294,9 @@ VOID FspVolumeDelete(
FspDeviceGlobalUnlock();
/*
* Call MmForceSectionClosed on open files to ensure that Mm removes them from Standby List.
* Call MmForceSectionClosed on active files to ensure that Mm removes them from Standby List.
*/
Result = FspFileNodeCopyList(FsvolDeviceObject, &FileNodes, &FileNodeCount);
Result = FspFileNodeCopyActiveList(FsvolDeviceObject, &FileNodes, &FileNodeCount);
if (NT_SUCCESS(Result))
{
for (Index = FileNodeCount - 1; FileNodeCount > Index; Index--)

View File

@ -1,7 +1,7 @@
/**
* @file sys/wq.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -145,7 +145,7 @@ static VOID FspWqWorkRoutine(PVOID Context)
IoSetTopLevelIrp(Irp);
Result = WorkRoutine(DeviceObject, Irp, IrpSp, TRUE);
if (STATUS_PENDING != Result)
if (STATUS_PENDING != Result && !(FSP_STATUS_IGNORE_BIT & Result))
{
ASSERT(0 == (FSP_STATUS_PRIVATE_BIT & Result) ||
FSP_STATUS_IOQ_POST == Result || FSP_STATUS_IOQ_POST_BEST_EFFORT == Result);

View File

@ -1,7 +1,7 @@
/**
* @file sys/write.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -195,6 +195,7 @@ static NTSTATUS FspFsvolWriteCached(
{
ASSERT(CanWait);
/* send EndOfFileInformation IRP; this will also set TruncateOnClose, etc. */
EndOfFileInformation.EndOfFile.QuadPart = WriteEndOffset;
Result = FspSendSetInformationIrp(FsvolDeviceObject/* bypass filters */, FileObject,
FileEndOfFileInformation, &EndOfFileInformation, sizeof EndOfFileInformation);
@ -393,6 +394,20 @@ static NTSTATUS FspFsvolWriteNonCached(
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp;
FSP_STATISTICS *Statistics = FspFsvolDeviceStatistics(FsvolDeviceObject);
if (PagingIo)
{
FspStatisticsInc(Statistics, Base.UserFileWrites);
FspStatisticsAdd(Statistics, Base.UserFileWriteBytes, WriteLength);
FspStatisticsInc(Statistics, Base.UserDiskWrites);
}
else
{
FspStatisticsInc(Statistics, Specific.NonCachedWrites);
FspStatisticsAdd(Statistics, Specific.NonCachedWriteBytes, WriteLength);
FspStatisticsInc(Statistics, Specific.NonCachedDiskWrites);
}
return FSP_STATUS_IOQ_POST;
}
@ -469,10 +484,10 @@ NTSTATUS FspFsvolWriteComplete(
UINT64 OriginalFileSize = FileNode->Header.FileSize.QuadPart;
/* update file info */
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Write.FileInfo);
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Write.FileInfo, TRUE);
if (OriginalFileSize != Response->Rsp.Write.FileInfo.FileSize)
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED, FALSE);
/* update the current file offset if synchronous I/O (and not paging I/O) */
if (SynchronousIo && !PagingIo)

View File

@ -2,25 +2,41 @@
setlocal
set Configuration=Release
set MsiName="WinFsp - Windows File System Proxy"
set CrossCert="%~dp0DigiCert High Assurance EV Root CA.crt"
set Issuer="DigiCert"
set Subject="Navimatics Corporation"
set Configuration=Release
set SignedPackage=
if not X%1==X set Configuration=%1
if not X%2==X set SignedPackage=%2
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
if not X%SignedPackage%==X (
if not exist "%~dp0..\build\VStudio\build\%Configuration%\winfsp-*.msi" (echo previous build not found >&2 & exit /b 1)
if not exist "%SignedPackage%" (echo signed package not found >&2 & exit /b 1)
del "%~dp0..\build\VStudio\build\%Configuration%\winfsp-*.msi"
for /R "%SignedPackage%" %%f in (*.sys) do (
copy "%%f" "%~dp0..\build\VStudio\build\%Configuration%" >nul
)
)
cd %~dp0..\build\VStudio
if exist build\ del /s/q build >nul
set signfail=0
if X%SignedPackage%==X (
if exist build\ for /R build\ %%d in (%Configuration%) do (
if exist "%%d" rmdir /s/q "%%d"
)
devenv winfsp.sln /build "%Configuration%|x64"
if errorlevel 1 goto fail
devenv winfsp.sln /build "%Configuration%|x86"
if errorlevel 1 goto fail
set signfail=0
for %%f in (build\%Configuration%\winfsp-x64.sys build\%Configuration%\winfsp-x86.sys) do (
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com %%f
if errorlevel 1 set /a signfail=signfail+1
@ -28,6 +44,31 @@ for %%f in (build\%Configuration%\winfsp-x64.sys build\%Configuration%\winfsp-x8
if errorlevel 1 set /a signfail=signfail+1
)
pushd build\%Configuration%
echo .OPTION EXPLICIT >driver.ddf
echo .Set CabinetFileCountThreshold=0 >>driver.ddf
echo .Set FolderFileCountThreshold=0 >>driver.ddf
echo .Set FolderSizeThreshold=0 >>driver.ddf
echo .Set MaxCabinetSize=0 >>driver.ddf
echo .Set MaxDiskFileCount=0 >>driver.ddf
echo .Set MaxDiskSize=0 >>driver.ddf
echo .Set CompressionType=MSZIP >>driver.ddf
echo .Set Cabinet=on >>driver.ddf
echo .Set Compress=on >>driver.ddf
echo .Set CabinetNameTemplate=driver.cab >>driver.ddf
echo .Set DiskDirectory1=. >>driver.ddf
echo .Set DestinationDir=x64 >>driver.ddf
echo driver-x64.inf >>driver.ddf
echo winfsp-x64.sys >>driver.ddf
echo .Set DestinationDir=x86 >>driver.ddf
echo driver-x86.inf >>driver.ddf
echo winfsp-x86.sys >>driver.ddf
makecab /F driver.ddf
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /t http://timestamp.digicert.com driver.cab
if errorlevel 1 set /a signfail=signfail+1
popd
)
devenv winfsp.sln /build "Installer.%Configuration%|x86"
if errorlevel 1 goto fail

View File

@ -13,6 +13,7 @@ mkdir %TARGET% 2>nul
for %%f in (winfsp-%SUFFIX%.sys winfsp-%SUFFIX%.dll winfsp-tests-%SUFFIX%.exe fsbench-%SUFFIX%.exe fscrash-%SUFFIX%.exe memfs-%SUFFIX%.exe) do (
copy build\VStudio\build\%CONFIG%\%%f %TARGET% >nul
)
copy tools\ifstest.bat %TARGET% >nul
echo sc create WinFsp type=filesys binPath=%%~dp0%DRIVER% >%TARGET%sc-create.bat
echo sc start WinFsp >%TARGET%sc-start.bat
echo sc stop WinFsp >%TARGET%sc-stop.bat

21
tools/ifstest.bat Executable file
View File

@ -0,0 +1,21 @@
@echo off
setlocal
setlocal EnableDelayedExpansion
set Arch=amd64
set RegKey="HKLM\SOFTWARE\Microsoft\Windows Kits\Installed Roots"
set RegVal="KitsRoot10"
reg query %RegKey% /v %RegVal% >nul 2>&1
if !ERRORLEVEL! equ 0 (
for /f "tokens=2,*" %%i in ('reg query %RegKey% /v %RegVal% ^| findstr %RegVal%') do (
set KitRoot=%%jHardware Lab Kit\
)
)
if not exist "%KitRoot%" set "KitRoot=C:\Program Files (x86)\Windows Kits\8.1\Hardware Certification Kit\"
set BaseDir=%KitRoot%Tests\%Arch%
set PATH=%BaseDir%\nttest\commontest\ntlog;%BaseDir%\nttest\basetest\core_file_services\shared_libs\fbslog;%PATH%
"%BaseDir%\nttest\basetest\core_file_services\ifs_test_kit\ifstest.exe" %*

View File

@ -24,40 +24,62 @@ cd N: >nul 2>nul || (echo === Unable to find drive N: >&2 & goto fail)
cd O: >nul 2>nul || (echo === Unable to find drive O: >&2 & goto fail)
cd P: >nul 2>nul || (echo === Unable to find drive P: >&2 & goto fail)
set dfl_tests=^
winfsp-tests-x64 ^
winfsp-tests-x64-case-randomize ^
winfsp-tests-x64-mountpoint-drive ^
winfsp-tests-x64-mountpoint-dir ^
winfsp-tests-x64-no-traverse ^
winfsp-tests-x64-oplock ^
winfsp-tests-x64-external-share ^
fsx-memfs-x64-disk ^
fsx-memfs-x64-net ^
standby-memfs-x64-disk ^
standby-memfs-x64-net ^
net-use-memfs-x64 ^
winfstest-memfs-x64-disk ^
winfstest-memfs-x64-net ^
fscrash-x64 ^
winfsp-tests-x86 ^
winfsp-tests-x86-case-randomize ^
winfsp-tests-x86-mountpoint-drive ^
winfsp-tests-x86-mountpoint-dir ^
winfsp-tests-x86-no-traverse ^
winfsp-tests-x86-oplock ^
winfsp-tests-x86-external-share ^
fsx-memfs-x86-disk ^
fsx-memfs-x86-net ^
standby-memfs-x86-disk ^
standby-memfs-x86-net ^
net-use-memfs-x86 ^
winfstest-memfs-x86-disk ^
winfstest-memfs-x86-net ^
fscrash-x86
set opt_tests=^
ifstest-memfs-x64-disk ^
ifstest-memfs-x86-disk
set tests=
for %%f in (%dfl_tests%) do (
if X%2==X (
set tests=!tests! %%f
) else (
set test=%%f
if not "X!test:%2=!"=="X!test!" set tests=!tests! %%f
)
)
for %%f in (%opt_tests%) do (
if X%2==X (
rem
) else (
set test=%%f
if not "X!test:%2=!"=="X!test!" set tests=!tests! %%f
)
)
set testpass=0
set testfail=0
for %%f in (^
:winfsp-tests-x64 ^
:winfsp-tests-x64-case-randomize ^
:winfsp-tests-x64-mountpoint-drive ^
:winfsp-tests-x64-mountpoint-dir ^
:winfsp-tests-x64-no-traverse ^
:winfsp-tests-x64-oplock ^
:winfsp-tests-x64-external-share ^
:fsx-memfs-x64-disk ^
:fsx-memfs-x64-net ^
:standby-memfs-x64-disk ^
:standby-memfs-x64-net ^
:net-use-memfs-x64 ^
:winfstest-memfs-x64-disk ^
:winfstest-memfs-x64-net ^
:fscrash-x64 ^
:winfsp-tests-x86 ^
:winfsp-tests-x86-case-randomize ^
:winfsp-tests-x86-mountpoint-drive ^
:winfsp-tests-x86-mountpoint-dir ^
:winfsp-tests-x86-no-traverse ^
:winfsp-tests-x86-oplock ^
:winfsp-tests-x86-external-share ^
:fsx-memfs-x86-disk ^
:fsx-memfs-x86-net ^
:standby-memfs-x86-disk ^
:standby-memfs-x86-net ^
:net-use-memfs-x86 ^
:winfstest-memfs-x86-disk ^
:winfstest-memfs-x86-net ^
:fscrash-x86 ^
) do (
for %%f in (%tests%) do (
echo === Running %%f
if defined APPVEYOR (
@ -65,7 +87,7 @@ for %%f in (^
)
pushd %cd%
call %%f
call :%%f
popd
if !ERRORLEVEL! neq 0 (
@ -322,6 +344,139 @@ fscrash-x86 --huge-alloc-size --cached >nul 2>&1
if !ERRORLEVEL! neq 1 goto fail
exit /b 0
:ifstest-memfs-x64-disk
call :__ifstest-memfs M: \Device\WinFsp.Disk C:
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:ifstest-memfs-x86-disk
call :__ifstest-memfs O: \Device\WinFsp.Disk C:
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:__ifstest-memfs
%1
set IfsTestDirectories=^
securit^
opcreatg^
opcreatp^
closedel^
volinfo^
fileinfo^
dirinfo^
filelock^
oplocks^
chgnotif^
readwr^
seccache^
reparspt^
estream
set IfsTestMemfsExit=0
call :__ifstest %1 /g Security
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
rem OpenCreateGeneral.FileOpenByIDTest: FILE_OPEN_BY_FILE_ID not implemented
rem OpenCreateGeneral.OpenVolumeTest: volume handles can be opened/closed but no other support
call :__ifstest %1 /d %2 /g OpenCreateGeneral -t FileOpenByIDTest -t OpenVolumeTest
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
call :__ifstest %1 /g OpenCreateParameters
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
rem CloseCleanupDelete.UpdateOnCloseTest: WinFsp updates size information in directories immediately
rem CloseCleanupDelete.TunnelingTest: short names and tunneling not supported
call :__ifstest %1 /g CloseCleanupDelete -t UpdateOnCloseTest -t TunnelingTest
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
call :__ifstest %1 /g VolumeInformation
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
rem FileInformation.LinkInformationTest: WinFsp does not support hard links
rem FileInformation.StreamStandardInformationTest: test requires FileLinkInformation support (no hard links)
call :__ifstest %1 /g FileInformation -t LinkInformationTest -t StreamStandardInformationTest /r %3
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
call :__ifstest %1 /g DirectoryInformation
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
call :__ifstest %1 /g FileLocking
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
call :__ifstest %1 /g OpLocks
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
call :__ifstest %1 /g ChangeNotification
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
call :__ifstest %1 /g ReadWrite
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
call :__ifstest %1 /g SectionsCaching
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
rem ReparsePoints.SetPointEASNotSupportedTest: EA's not supported
rem ReparsePoints.EnumReparsePointsTest: enumeration of reparse points not supported
rem ReparsePoints.ChangeNotificationReparseTest: change notifications of reparse points not supported
call :__ifstest %1 /g ReparsePoints -t SetPointEASNotSupportedTest -t EnumReparsePointsTest -t ChangeNotificationReparseTest /c
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
rem IfsTest ReparsePoints seems to have a bug in that it cannot handle STATUS_PENDING for FSCTL_GET_REPARSE_POINT
rmdir /s/q reparspt
rem StreamEnhancements.StreamRenameTest: WinFsp does not support stream renaming
rem StreamEnhancements.StreamNotifyNameTest: WinFsp does not notify when streams are deleted because main file is deleted
call :__ifstest %1 /g StreamEnhancements -t StreamRenameTest -t StreamNotifyNameTest
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
for %%d in (!IfsTestDirectories!) do (
if exist %%d (echo :ifstest directory %%d still exists & set IfsTestMemfsExit=1)
)
exit /b !IfsTestMemfsExit!
:__ifstest
set IfsTestFound=
set IfsTestName=
set IfsTestGroup=
set IfsTestStatus=
set IfsTestLines=
set IfsTestExit=0
(SET LF=^
%=this line is empty=%
)
for /F "delims=" %%l in ('call "%ProjRoot%\tools\ifstest.bat" %* /z /v ^| findstr /n "^"') do (
set IfsTestLine=%%l
set IfsTestLine=!IfsTestLine:*:=!
for /F "tokens=1,2,3 delims=:" %%h in ("%%l") do (
set FieldName=%%i
set FieldName=!FieldName: =!
set FieldValue=%%j
if not X!IfsTestLine!==X (
set IfsTestLines=!IfsTestLines!!LF! !IfsTestLine!
if X!FieldName!==XTest (
set IfsTestName=!FieldValue!
set IfsTestFound=YES
) else if X!FieldName!==XGroup (
set IfsTestGroup=!FieldValue!
) else if X!FieldName!==XStatus (
set IfsTestStatus=!FieldValue!
)
) else (
set IfsTestPrefix=!IfsTestGroup!.!IfsTestName!..............................................................
set IfsTestPrefix=!IfsTestPrefix:~0,63!
if X!IfsTestName!==X (
rem
) else if X!IfsTestStatus!==X (
rem
) else if not "X!IfsTestStatus:(IFSTEST_SUCCESS)=!"=="X!IfsTestStatus!" (
echo !IfsTestPrefix! OK
) else if not "X!IfsTestStatus:(IFSTEST_TEST_NOT_SUPPORTED)=!"=="X!IfsTestStatus!" (
echo !IfsTestPrefix! SKIP
) else if not "X!IfsTestStatus:(IFSTEST_SUCCESS_NOT_SUPPORTED)=!"=="X!IfsTestStatus!" (
echo !IfsTestPrefix! SKIP
) else if not "X!IfsTestStatus:(IFSTEST_INFO_END_OF_GROUP)=!"=="X!IfsTestStatus!" (
rem
) else (
echo !IfsTestPrefix! KO!IfsTestLines!
set IfsTestExit=1
)
set IfsTestName=
set IfsTestGroup=
set IfsTestStatus=
set IfsTestLines=
)
)
)
if not X!IfsTestFound!==XYES set IfsTestExit=1
exit /b !IfsTestExit!
:leak-test
for /F "tokens=1,2 delims=:" %%i in ('verifier /query ^| findstr ^
/c:"Current Pool Allocations:" ^

View File

@ -1,7 +1,7 @@
/**
* @file fsbench.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file fscrash-main.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file fscrash.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file fscrash.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

Some files were not shown because too many files have changed in this diff Show More