Compare commits

..

86 Commits
v0.16 ... GPLv3

Author SHA1 Message Date
bd952253fb cosmetic fix 2016-10-11 11:39:17 -07:00
c7780cf7fa license: switch to GPLv3 from AGPLv3 2016-10-10 21:33:27 -07:00
31b54ecc47 dll: FspAccessCheckEx: fix DELETE access check for named streams 2016-10-10 18:04:55 -07:00
4084448bd5 sys,dll: properly implement stream create check 2016-10-10 17:29:16 -07:00
4dc1828e1f update submodules 2016-10-10 15:36:17 -07:00
79b7b66b62 update submodules 2016-10-10 14:46:25 -07:00
612c820630 tst: memfs: add -D option to specify debug log file 2016-10-10 13:25:47 -07:00
e13233ef32 tst: memfs: add -D option to specify debug log file 2016-10-10 13:21:20 -07:00
dd815f3c39 doc: update Changelog 2016-10-10 11:50:34 -07:00
5faafc4d11 doc: update Changelog 2016-10-10 11:49:22 -07:00
78e5d031c0 installer: add RC and GOLD banners 2016-10-09 18:10:52 -07:00
9ef562df15 installer: choose install banner based on MyDevStage project variable 2016-10-09 17:27:33 -07:00
a7cdc815d0 installer: choose install banner based on MyDevStage project variable 2016-10-09 17:10:23 -07:00
bd5e15fe24 sys: FspFileNodeNotifyChange: implement/test stream notifications 2016-10-09 16:08:11 -07:00
214a8406eb art: wix dialog banner 2016-10-08 23:55:52 -07:00
6bd6f0ee35 inc: fsctl: increase request/response size to 16K
dll: remove /Gs[size] switch, fix FspFileSystemResolveReparsePoints to not use more than 4K of stack space
2016-10-08 23:33:59 -07:00
f8cebd1f92 dll: FspDebugLogSetHandle 2016-10-08 18:49:28 -07:00
f8f6d0f1bc tools: run-tests: include stream tests 2016-10-07 12:22:19 -07:00
b06132cb6b tst: winfsp-tests: stream_create_related_test 2016-10-06 20:42:05 -07:00
748c9b6409 tst: winfsp-tests: stream_getstreaminfo_test 2016-10-06 17:20:23 -07:00
bfc7fc5dec tst: winfsp-tests: stream_getstreaminfo_test 2016-10-06 17:06:23 -07:00
03f906f966 sys: FspFsvolQueryDirectoryCopy: minor fix 2016-10-06 16:51:40 -07:00
4b1111fcc5 tst: winfsp-tests: stream_getstreaminfo_test 2016-10-06 15:36:33 -07:00
86ddeed129 tst: memfs: GetStreamInfo 2016-10-06 15:36:09 -07:00
e2d4b36057 sys: FspFsvolQueryStreamInformation* testing 2016-10-06 15:35:40 -07:00
ab2908a9ee sys: FspFileNodeTrySetSecurity, FspFileNodeTrySetDirInfo 2016-10-06 12:41:23 -07:00
fd7b12bb61 tst: memfs: minor fix 2016-10-06 12:13:34 -07:00
eb2000a194 sys: FSP_FILE_NODE: correctly handle FileInfo cache in the presence of streams 2016-10-06 12:13:16 -07:00
e4cabc50c5 tst: winfsp-tests: stream_setfileinfo_test 2016-10-05 18:18:57 -07:00
92dc2feecd sys: use main file security cache 2016-10-05 17:38:16 -07:00
43f333e8a6 sys: FSP_FILE_NODE: change number field access through inline functions 2016-10-05 17:30:50 -07:00
59eb40fd9b tst: winfsp-tests: stream_getsecurity_test 2016-10-05 16:59:54 -07:00
d85d36c94f tst: memfs: MemfsFileNodeMapHasChild: fix problems with streams on directory 2016-10-05 15:21:33 -07:00
27b841faf8 sys: FspFileNodeOpen: refine main file vs stream sharing violations 2016-10-05 14:55:37 -07:00
c6967c737a sys: FspUnicodePathIsValid: check and return stream type 2016-10-05 13:44:32 -07:00
4ccbd1bdf6 tst: winfsp-tests: stream_create_test 2016-10-05 10:48:33 -07:00
0a8b8e8444 sys: create: validate FileName only after FileNode->FileName has been constructed 2016-10-05 10:27:17 -07:00
352450d538 sys: FspMainFileOpen 2016-10-05 00:32:04 -07:00
7e1861a9f5 tst: memfs: GetSecurityByName: fix FileAttributes for streams on directories 2016-10-04 23:00:42 -07:00
860e9db8a7 sys: FspMainFileOpen, FspMainFileClose, FspMainFileOpenCheck 2016-10-04 22:19:41 -07:00
1d435269bd sys: create: correctly compute file name lengths when streams are involved 2016-10-04 11:35:39 -07:00
e58ac1fbde sys,dll: pass NULL security descriptor to user-mode file system during Create 2016-10-03 21:02:43 -07:00
1f0f2fe094 tst: winfsp-tests: stream testing 2016-10-03 20:15:17 -07:00
d7ec331c74 tst: winfsp-tests: stream testing 2016-10-03 20:14:22 -07:00
938c036387 tst: winfsp-tests: stream testing 2016-10-03 18:27:09 -07:00
16f5bd089d tst: winfsp-tests: stream testing 2016-10-03 17:30:30 -07:00
6afea44e31 tst: winfsp-tests: stream testing 2016-10-03 17:13:19 -07:00
2859355fd8 tst: winfsp-tests: stream testing 2016-10-03 16:52:44 -07:00
75012d1301 tst: winfsp-tests: stream testing 2016-10-03 16:40:03 -07:00
8e1512c067 tst: winfsp-tests: stream testing 2016-10-03 16:31:43 -07:00
fa6b621042 tst: winfsp-tests: stream testing 2016-10-03 16:16:09 -07:00
8ffb359f20 tst: winfsp-tests: stream testing 2016-10-03 16:13:17 -07:00
203873ef04 tst: winfsp-tests: stream testing 2016-10-03 16:08:45 -07:00
e73bda3926 tst: winfsp-tests: stream testing 2016-10-03 15:57:34 -07:00
0186b82fea tst: winfsp-tests: stream testing 2016-10-03 15:30:08 -07:00
db38d2f7f8 tst: winfsp-tests: stream testing 2016-10-03 15:19:18 -07:00
016d015fe6 sys: file, callbacks: acquire MainFileNode resources if exists 2016-10-03 14:21:34 -07:00
87b2d4ca4c tst: memfs: MEMFS_NAMED_STREAMS macro 2016-10-03 11:55:39 -07:00
dfd6cbbde1 tst: memfs: support named streams 2016-10-03 10:58:55 -07:00
6a126da51d sys: IRP_MJ_CREATE: handle security descriptor and file attributes correctly for named streams 2016-10-03 10:29:46 -07:00
03df0a9c26 sys: renamed "main stream" to "main file" 2016-10-02 16:57:15 -07:00
5c3a82a074 tst: memfs: Cleanup: remove all named streams on delete 2016-09-28 17:11:30 -07:00
b591015b28 tst: memfs: Cleanup: remove all named streams on delete 2016-09-28 16:59:39 -07:00
fb9b798d3d tst: memfs: implement GetStreamInfo 2016-09-28 16:17:50 -07:00
cc408b71e1 sys: FspFsvolQueryStreamInformationCopy: add stream type ($DATA) to stream names 2016-09-28 16:17:10 -07:00
19a73ca01d update submodules 2016-09-27 17:01:40 -07:00
3992b9ebb1 update submodules 2016-09-27 15:56:29 -07:00
a46c0610c4 tst: memfs: MemfsFileNameHasPrefix: work to support named streams 2016-09-27 15:35:26 -07:00
495fc7a5dc sys: implement named stream open/close and related delete/share access issues 2016-09-27 14:53:59 -07:00
2ba46fdb71 ensure that all source files use UNIX newlines 2016-09-25 21:50:44 -07:00
7cb56bb132 sys: FspUnicodePathIsValid: improvements 2016-09-25 21:38:41 -07:00
687b02c1e6 tools: ntstatus,winerror: lookup status/error codes 2016-09-24 23:55:15 -07:00
218b162d75 update submodules 2016-09-24 22:46:49 -07:00
5e13c8750e sys: FspUnicodePathIsValid, FspUnicodePathIsValidPattern 2016-09-24 22:21:05 -07:00
2e71d2fe14 sys: FspFsvolQueryStreamInformationCopy: improvements 2016-09-24 17:32:35 -07:00
866e4abe10 sys: IRP_MN_QUERY_DIRECTORY: correctly handle STATUS_BUFFER_OVERFLOW cases 2016-09-24 17:16:58 -07:00
7894cc8b7b sys: fileinfo.c: minor comment change 2016-09-24 15:09:15 -07:00
0c810c52fa sys: IRP_MJ_QUERY_INFORMATION: FileStreamInformation 2016-09-24 13:59:02 -07:00
b06e947e0e tst: winfsp-tests: troubleshoot appveyor dirnotify failure 2016-09-21 15:07:51 -07:00
aed134080c inc: fsctl: PostCleanupOnDeleteOnly 2016-09-21 14:22:08 -07:00
3ce490d405 inc: fsctl: UmFileNodeIsUserContext2 2016-09-21 10:40:18 -07:00
76aabecbfb dll: fuse: fstypename, FileSystemName command line options 2016-09-20 21:27:48 -07:00
8eebfe811d sys: FspFsvolQueryFsAttributeInformation: fix buffer overrun error 2016-09-20 20:55:10 -07:00
5798527237 sys: FspFsvolQueryFsAttributeInformation: return full file system name 2016-09-20 16:30:03 -07:00
817beebb63 inc: fsctl: FSP_FSCTL_VOLUME_PARAMS changes:
- increase size of VolumePrefix
- add FileSystemName field (currently unused)
2016-09-20 15:37:42 -07:00
b7a2b5e17a build: bump version to 0.17 2016-09-20 14:26:20 -07:00
87 changed files with 4455 additions and 636 deletions

View File

@ -73,4 +73,4 @@ If you wish to discuss WinFsp there are now two options:
## License
WinFsp is available under the [AGPLv3](http://www.gnu.org/licenses/agpl-3.0.html) license. If you find the constraints of the AGPLv3 too onerous, a commercial license is also available. Please contact Bill Zissimopoulos <billziss at navimatics.com> for more details.
WinFsp is available under the [GPLv3](http://www.gnu.org/licenses/gpl-3.0.html) license. If you find the constraints of the GPLv3 too onerous, a commercial license is also available. Please contact Bill Zissimopoulos <billziss at navimatics.com> for more details.

Binary file not shown.

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -378,7 +378,7 @@
</Feature>
<WixVariable Id="WixUIBannerBmp" Value="wixbanner.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="wixdialog.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="wixdialog-$(var.MyDevStage).bmp" />
<UI Id="FeatureTree">
<UIRef Id="WixUI_FeatureTree" />
<!-- skip the license agreement dialog; higher Order takes priority (weird) -->

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);MyVersion=$(MyVersion)</DefineConstants>
<DefineConstants>Debug;MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyDevStage=$(MyDevStage);MyVersion=$(MyVersion)</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);MyVersion=$(MyVersion)</DefineConstants>
<DefineConstants>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyDevStage=$(MyDevStage);MyVersion=$(MyVersion)</DefineConstants>
<SuppressAllWarnings>False</SuppressAllWarnings>
<Pedantic>True</Pedantic>
<SuppressPdbOutput>True</SuppressPdbOutput>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 601 KiB

After

Width:  |  Height:  |  Size: 601 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 KiB

View File

@ -105,7 +105,8 @@
<BufferSecurityCheck>false</BufferSecurityCheck>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>/Gs16384 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -125,7 +126,8 @@
<BufferSecurityCheck>false</BufferSecurityCheck>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>/Gs16384 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -146,7 +148,8 @@
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>/Gs16384 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -169,7 +172,8 @@
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>/Gs16384 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

View File

@ -105,7 +105,8 @@
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>/Gs16384 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -126,7 +127,8 @@
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>/Gs16384 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -148,7 +150,8 @@
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>/Gs16384 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -172,7 +175,8 @@
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>/Gs16384 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

View File

@ -196,6 +196,7 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\rdwr-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\reparse-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\security-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\winfsp-tests.c" />
</ItemGroup>

View File

@ -67,6 +67,9 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\hook.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">

View File

@ -5,9 +5,10 @@
<MyDescription>Windows File System Proxy</MyDescription>
<MyCompanyName>Navimatics Corporation</MyCompanyName>
<MyCopyright>2015-2016 Bill Zissimopoulos</MyCopyright>
<MyDevStage>Beta</MyDevStage>
<!-- build number: concat 2-digit year with 3-digit day of the year (16-bits until 2066) -->
<MyBuildNumber>$([System.DateTime]::Now.ToString(`yy`))$([System.DateTime]::Now.DayOfYear.ToString(`000`))</MyBuildNumber>
<MyVersion>0.16.$(MyBuildNumber)</MyVersion>
<MyVersion>0.17.$(MyBuildNumber)</MyVersion>
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
</PropertyGroup>
<ItemDefinitionGroup>

View File

@ -173,7 +173,8 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AdditionalOptions>/Gs16384 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -200,7 +201,8 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AdditionalOptions>/Gs16384 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -228,7 +230,8 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AdditionalOptions>/Gs16384 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -258,7 +261,8 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AdditionalOptions>/Gs16384 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>

View File

@ -1,6 +1,15 @@
= Changelog
v0.17::
This release brings support for named streams.
- Named streams (or alternate data streams) are additional streams of data within a file. When a file gets opened the main (default, unnamed) data stream of a file gets accessed. However NTFS (and now WinFsp) supports multiple data streams per file accessible using the `filename:streamname` syntax.
- WinFsp handles a lot of the hairy details regarding named streams, including sharing checks, pending delete checks, conflicts between the main and named streams, etc.
- User mode file systems that wish to support named streams must set the `FSP_FSCTL_VOLUME_PARAMS::NamedStreams` flag and must also be prepared to handle named streams on `Create`, `Cleanup`, etc. They must also implement the new `FSP_FILE_SYSTEM_INTERFACE::GetStreamInfo` operation. For more information on how to correctly handle named streams refer to the MEMFS sample.
v0.16::
This release brings support for reparse points and symbolic links as well as other minor changes.

View File

@ -1,12 +1,12 @@
The WinFsp project is Copyright (C) Bill Zissimopoulos. It is licensed
under the terms of the AGPLv3. The full text of this license follows
under the terms of the GPLv3. The full text of this license follows
below. Commercial licensing options are also available: Please contact
Bill Zissimopoulos <billziss at navimatics.com>.
-----------------------------------------------------------------------
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
@ -14,15 +14,17 @@ Bill Zissimopoulos <billziss at navimatics.com>.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
@ -31,34 +33,44 @@ them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
@ -67,7 +79,7 @@ modification follow.
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
@ -544,45 +556,35 @@ to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
@ -640,29 +642,40 @@ the "copyright" line and a pointer to where the full notice is found.
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
GNU General Public License for more details.
You should have received a copy of the GNU Affero General Public License
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -11,9 +11,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -11,9 +11,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -11,9 +11,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -7,9 +7,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -24,12 +24,17 @@
extern "C" {
#endif
/* static_assert is a C++11 feature, but seems to work with C on MSVC 2015 */
#if defined(WINFSP_SYS_INTERNAL) || defined(WINFSP_DLL_INTERNAL)
#define FSP_FSCTL_STATIC_ASSERT(e,m) static_assert(e,m)
#else
#define FSP_FSCTL_STATIC_ASSERT(e,m)
#endif
#define FSP_FSCTL_DRIVER_NAME "WinFsp"
#define FSP_FSCTL_DISK_DEVICE_NAME "WinFsp.Disk"
#define FSP_FSCTL_NET_DEVICE_NAME "WinFsp.Net"
#define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams="
// {6F9D25FA-6DEE-4A9D-80F5-E98E14F35E54}
extern const __declspec(selectany) GUID FspFsctlDeviceClassGuid =
{ 0x6f9d25fa, 0x6dee, 0x4a9d, { 0x80, 0xf5, 0xe9, 0x8e, 0x14, 0xf3, 0x5e, 0x54 } };
@ -55,19 +60,26 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
#define FSP_FSCTL_STOP \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'S', METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams="
#define FSP_FSCTL_VOLUME_NAME_SIZE (64 * sizeof(WCHAR))
#define FSP_FSCTL_VOLUME_PREFIX_SIZE (64 * sizeof(WCHAR))
#define FSP_FSCTL_VOLUME_PREFIX_SIZE (192 * sizeof(WCHAR))
#define FSP_FSCTL_VOLUME_FSNAME_SIZE (16 * sizeof(WCHAR))
#define FSP_FSCTL_VOLUME_NAME_SIZEMAX (FSP_FSCTL_VOLUME_NAME_SIZE + FSP_FSCTL_VOLUME_PREFIX_SIZE)
FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
"Max volume name size is greater than MAX_PATH.");
#define FSP_FSCTL_TRANSACT_PATH_SIZEMAX 2048
#define FSP_FSCTL_TRANSACT_PATH_SIZEMAX (1024 * sizeof(WCHAR))
#define FSP_FSCTL_TRANSACT_REQ_SIZEMAX (4096 - 64) /* 64: size for internal request header */
#define FSP_FSCTL_TRANSACT_RSP_SIZEMAX (4096 - 64) /* symmetry! */
#define FSP_FSCTL_TRANSACT_REQ_SIZEMAX (16 * 1024 - 64) /* 64: size for internal request header */
#define FSP_FSCTL_TRANSACT_RSP_SIZEMAX (16 * 1024)
#define FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMAX (FSP_FSCTL_TRANSACT_REQ_SIZEMAX - sizeof(FSP_FSCTL_TRANSACT_REQ))
#define FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX (FSP_FSCTL_TRANSACT_RSP_SIZEMAX - sizeof(FSP_FSCTL_TRANSACT_RSP))
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN 16384
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024)
#define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX
#define FSP_FSCTL_TRANSACT_USERCONTEXT(s,i) (((PUINT64)&(s).UserContext)[i])
/* marshalling */
#pragma warning(push)
#pragma warning(disable:4200) /* zero-sized array in struct/union */
@ -94,6 +106,7 @@ enum
FspFsctlTransactLockControlKind,
FspFsctlTransactQuerySecurityKind,
FspFsctlTransactSetSecurityKind,
FspFsctlTransactQueryStreamInformationKind,
FspFsctlTransactKindCount,
};
enum
@ -130,11 +143,18 @@ typedef struct
UINT32 PersistentAcls:1; /* file system preserves and enforces access control lists */
UINT32 ReparsePoints:1; /* file system supports reparse points */
UINT32 ReparsePointsAccessCheck:1; /* file system performs reparse point access checks */
UINT32 NamedStreams:1; /* file system supports named streams (!!!: unimplemented) */
UINT32 NamedStreams:1; /* file system supports named streams */
UINT32 HardLinks:1; /* unimplemented; set to 0 */
UINT32 ExtendedAttributes:1; /* unimplemented; set to 0 */
UINT32 ReadOnlyVolume:1;
/* kernel-mode flags */
UINT32 PostCleanupOnDeleteOnly:1; /* post Cleanup when deleting a file only */
UINT32 KmReservedFlags:5;
/* user-mode flags */
UINT32 UmFileNodeIsUserContext2:1; /* user mode: FileNode parameter is UserContext2 */
UINT32 UmReservedFlags:15;
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
} FSP_FSCTL_VOLUME_PARAMS;
typedef struct
{
@ -165,6 +185,13 @@ typedef struct
WCHAR FileNameBuf[];
} FSP_FSCTL_DIR_INFO;
typedef struct
{
UINT16 Size;
UINT64 StreamSize;
UINT64 StreamAllocationSize;
WCHAR StreamNameBuf[];
} FSP_FSCTL_STREAM_INFO;
typedef struct
{
UINT16 Offset;
UINT16 Size;
@ -191,6 +218,8 @@ typedef struct
UINT32 HasTraversePrivilege:1; /* requestor has TOKEN_HAS_TRAVERSE_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:28;
UINT16 NamedStream; /* request targets named stream; colon offset in FileName */
} Create;
struct
{
@ -313,6 +342,11 @@ typedef struct
UINT64 AccessToken; /* request access token (HANDLE) */
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
} SetSecurity;
struct
{
UINT64 UserContext;
UINT64 UserContext2;
} QueryStreamInformation;
} Req;
FSP_FSCTL_TRANSACT_BUF FileName; /* {Create,Cleanup,SetInformation/{...},QueryDirectory} */
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
@ -382,6 +416,10 @@ typedef struct
{
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* Size==0 means no security descriptor returned */
} SetSecurity;
struct
{
FSP_FSCTL_TRANSACT_BUF Buffer;
} QueryStreamInformation;
} Rsp;
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
} FSP_FSCTL_TRANSACT_RSP;

View File

@ -10,9 +10,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -318,6 +318,10 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* tested to see if the delete can proceed and if the answer is positive the file is then
* deleted during Cleanup.
*
* 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.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
@ -769,21 +773,39 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
PWSTR FileName, PVOID Buffer, SIZE_T Size);
/**
* Get named streams information.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file or directory to get stream information for.
* @param Buffer
* Pointer to a buffer that will receive the stream information.
* @param Length
* Length of buffer.
* @param PBytesTransferred [out]
* Pointer to a memory location that will receive the actual number of bytes stored.
* @return
* STATUS_SUCCESS or error code.
* @see
* FspFileSystemAddStreamInfo
*/
NTSTATUS (*GetStreamInfo)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PVOID Buffer, ULONG Length,
PULONG PBytesTransferred);
/*
* This ensures that this interface will always contain 64 function pointers.
* Please update when changing the interface as it is important for future compatibility.
*/
NTSTATUS (*Reserved[41])();
NTSTATUS (*Reserved[40])();
} FSP_FILE_SYSTEM_INTERFACE;
#if defined(WINFSP_DLL_INTERNAL)
/*
* Static_assert is a C++11 feature, but seems to work with C on MSVC 2015.
* Use it to verify that FSP_FILE_SYSTEM_INTERFACE has the right size.
*/
static_assert(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
#endif
typedef struct _FSP_FILE_SYSTEM
{
UINT16 Version;
@ -801,6 +823,7 @@ typedef struct _FSP_FILE_SYSTEM
UINT32 DebugLog;
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
SRWLOCK OpGuardLock;
BOOLEAN UmFileNodeIsUserContext2;
} FSP_FILE_SYSTEM;
/**
* Create a file system object.
@ -1011,6 +1034,8 @@ FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
FSP_API NTSTATUS FspFileSystemOpQueryStreamInformation(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
/*
* Helpers
@ -1151,6 +1176,30 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint(
PVOID CurrentReparseData, SIZE_T CurrentReparseDataSize,
PVOID ReplaceReparseData, SIZE_T ReplaceReparseDataSize);
/**
* Add named stream information to a buffer.
*
* This is a helper for implementing the GetStreamInfo operation.
*
* @param StreamInfo
* The stream information to add. A value of NULL acts as an EOF marker for a GetStreamInfo
* operation.
* @param Buffer
* Pointer to a buffer that will receive the stream information. This should contain
* the same value passed to the GetStreamInfo Buffer parameter.
* @param Length
* Length of buffer. This should contain the same value passed to the GetStreamInfo
* Length parameter.
* @param PBytesTransferred [out]
* Pointer to a memory location that will receive the actual number of bytes stored. This should
* contain the same value passed to the GetStreamInfo PBytesTransferred parameter.
* @return
* TRUE if the stream information was added, FALSE if there was not enough space to add it.
* @see
* GetStreamInfo
*/
FSP_API BOOLEAN FspFileSystemAddStreamInfo(FSP_FSCTL_STREAM_INFO *StreamInfo,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
/*
* Security
@ -1158,7 +1207,7 @@ FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint(
FSP_API PGENERIC_MAPPING FspGetFileGenericMapping(VOID);
FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
BOOLEAN CheckParentDirectory, BOOLEAN AllowTraverseCheck,
BOOLEAN CheckParentOrMain, BOOLEAN AllowTraverseCheck,
UINT32 DesiredAccess, PUINT32 PGrantedAccess/* or ReparsePointIndex */,
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
@ -1174,11 +1223,11 @@ FSP_API VOID FspDeleteSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor
static inline
NTSTATUS FspAccessCheck(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
BOOLEAN CheckParentDirectory, BOOLEAN AllowTraverseCheck,
BOOLEAN CheckParentOrMain, BOOLEAN AllowTraverseCheck,
UINT32 DesiredAccess, PUINT32 PGrantedAccess)
{
return FspAccessCheckEx(FileSystem, Request,
CheckParentDirectory, AllowTraverseCheck,
CheckParentOrMain, AllowTraverseCheck,
DesiredAccess, PGrantedAccess,
0);
}
@ -1420,9 +1469,10 @@ FSP_API NTSTATUS FspNtStatusFromWin32(DWORD Error);
FSP_API DWORD FspWin32FromNtStatus(NTSTATUS Status);
FSP_API VOID FspEventLog(ULONG Type, PWSTR Format, ...);
FSP_API VOID FspEventLogV(ULONG Type, PWSTR Format, va_list ap);
FSP_API VOID FspDebugLog(const char *format, ...);
FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDescriptor);
FSP_API VOID FspDebugLogFT(const char *format, PFILETIME FileTime);
FSP_API VOID FspDebugLogSetHandle(HANDLE Handle);
FSP_API VOID FspDebugLog(const char *Format, ...);
FSP_API VOID FspDebugLogSD(const char *Format, PSECURITY_DESCRIPTOR SecurityDescriptor);
FSP_API VOID FspDebugLogFT(const char *Format, PFILETIME FileTime);
FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request);
FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response);
FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -19,6 +19,13 @@
#include <sddl.h>
#include <stdarg.h>
static HANDLE FspDebugLogHandle = INVALID_HANDLE_VALUE;
FSP_API VOID FspDebugLogSetHandle(HANDLE Handle)
{
FspDebugLogHandle = Handle;
}
FSP_API VOID FspDebugLog(const char *format, ...)
{
char buf[1024];
@ -28,7 +35,13 @@ FSP_API VOID FspDebugLog(const char *format, ...)
wvsprintfA(buf, format, ap);
va_end(ap);
buf[sizeof buf - 1] = '\0';
OutputDebugStringA(buf);
if (INVALID_HANDLE_VALUE != FspDebugLogHandle)
{
DWORD bytes;
WriteFile(FspDebugLogHandle, buf, lstrlenA(buf), &bytes, 0);
}
else
OutputDebugStringA(buf);
}
FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDescriptor)

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -99,6 +99,7 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
FileSystem->Operations[FspFsctlTransactFileSystemControlKind] = FspFileSystemOpFileSystemControl;
FileSystem->Operations[FspFsctlTransactQuerySecurityKind] = FspFileSystemOpQuerySecurity;
FileSystem->Operations[FspFsctlTransactSetSecurityKind] = FspFileSystemOpSetSecurity;
FileSystem->Operations[FspFsctlTransactQueryStreamInformationKind] = FspFileSystemOpQueryStreamInformation;
FileSystem->Interface = Interface;
FileSystem->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE;
@ -106,6 +107,8 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
FileSystem->EnterOperation = FspFileSystemOpEnter;
FileSystem->LeaveOperation = FspFileSystemOpLeave;
FileSystem->UmFileNodeIsUserContext2 = !!VolumeParams->UmFileNodeIsUserContext2;
*PFileSystem = FileSystem;
return STATUS_SUCCESS;

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -32,7 +32,7 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
NTSTATUS Result;
PWSTR DeviceRoot;
SIZE_T DeviceRootSize, DevicePathSize;
WCHAR DevicePathBuf[MAX_PATH], *DevicePathPtr, *DevicePathEnd;
WCHAR DevicePathBuf[MAX_PATH + sizeof *VolumeParams], *DevicePathPtr, *DevicePathEnd;
HANDLE VolumeHandle = INVALID_HANDLE_VALUE;
DWORD Bytes;
@ -40,7 +40,7 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
VolumeNameBuf[0] = L'\0';
*PVolumeHandle = INVALID_HANDLE_VALUE;
/* check lengths; everything (including encoded volume params) must fit within MAX_PATH */
/* check lengths; everything (including encoded volume params) must fit within DevicePathBuf */
DeviceRoot = L'\\' == DevicePath[0] ? GLOBALROOT : GLOBALROOT "\\Device\\";
DeviceRootSize = lstrlenW(DeviceRoot) * sizeof(WCHAR);
DevicePathSize = lstrlenW(DevicePath) * sizeof(WCHAR);

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -17,6 +17,9 @@
#include <dll/library.h>
#define USERCONTEXT(s) \
FSP_FSCTL_TRANSACT_USERCONTEXT(s, FileSystem->UmFileNodeIsUserContext2)
FSP_API NTSTATUS FspFileSystemOpEnter(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{
@ -31,7 +34,8 @@ FSP_API NTSTATUS FspFileSystemOpEnter(FSP_FILE_SYSTEM *FileSystem,
10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass) ||
FspFsctlTransactSetVolumeInformationKind == Request->Kind ||
(FspFsctlTransactFlushBuffersKind == Request->Kind &&
0 == Request->Req.FlushBuffers.UserContext))
0 == Request->Req.FlushBuffers.UserContext &&
0 == Request->Req.FlushBuffers.UserContext2))
{
AcquireSRWLockExclusive(&FileSystem->OpGuardLock);
}
@ -68,7 +72,8 @@ FSP_API NTSTATUS FspFileSystemOpLeave(FSP_FILE_SYSTEM *FileSystem,
10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass) ||
FspFsctlTransactSetVolumeInformationKind == Request->Kind ||
(FspFsctlTransactFlushBuffersKind == Request->Kind &&
0 == Request->Req.FlushBuffers.UserContext))
0 == Request->Req.FlushBuffers.UserContext &&
0 == Request->Req.FlushBuffers.UserContext2))
{
ReleaseSRWLockExclusive(&FileSystem->OpGuardLock);
}
@ -135,24 +140,57 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
UINT32 GrantedAccess;
/*
* CreateCheck consists of checking the parent directory for the
* FILE_ADD_SUBDIRECTORY or FILE_ADD_FILE rights (depending on whether
* we are creating a file or directory).
* CreateCheck does different checks depending on whether we are
* creating a new file/directory or a new stream.
*
* If the access check succeeds and MAXIMUM_ALLOWED has been requested
* then we go ahead and grant all access to the creator.
* - CreateCheck for a new file consists of checking the parent directory
* for the FILE_ADD_SUBDIRECTORY or FILE_ADD_FILE rights (depending on
* whether we are creating a file or directory).
*
* If the access check succeeds and MAXIMUM_ALLOWED has been requested
* then we go ahead and grant all access to the creator.
*
* - CreateCheck for a new stream consists of checking the main file for
* FILE_WRITE_DATA access, unless FILE_DELETE_ON_CLOSE is requested in
* which case we also check for DELETE access.
*
* If the access check succeeds and MAXIMUM_ALLOWED was not requested
* then we reset the DELETE and FILE_WRITE_DATA accesses based on whether
* they were actually requested in DesiredAccess.
*/
Result = FspAccessCheckEx(FileSystem, Request, TRUE, AllowTraverseCheck,
(Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) ?
FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE,
&GrantedAccess, PSecurityDescriptor);
if (STATUS_REPARSE == Result)
Result = FspFileSystemCallResolveReparsePoints(FileSystem, Request, Response, GrantedAccess);
else if (NT_SUCCESS(Result))
if (!Request->Req.Create.NamedStream)
{
*PGrantedAccess = (MAXIMUM_ALLOWED & Request->Req.Create.DesiredAccess) ?
FspGetFileGenericMapping()->GenericAll : Request->Req.Create.DesiredAccess;
Result = FspAccessCheckEx(FileSystem, Request, TRUE, AllowTraverseCheck,
(Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) ?
FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE,
&GrantedAccess, PSecurityDescriptor);
if (STATUS_REPARSE == Result)
Result = FspFileSystemCallResolveReparsePoints(FileSystem, Request, Response, GrantedAccess);
else if (NT_SUCCESS(Result))
{
*PGrantedAccess = (MAXIMUM_ALLOWED & Request->Req.Create.DesiredAccess) ?
FspGetFileGenericMapping()->GenericAll : Request->Req.Create.DesiredAccess;
}
}
else
{
*PSecurityDescriptor = 0;
Result = FspAccessCheckEx(FileSystem, Request, TRUE, AllowTraverseCheck,
Request->Req.Create.DesiredAccess |
FILE_WRITE_DATA |
((Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE) ? DELETE : 0),
&GrantedAccess, 0);
if (STATUS_REPARSE == Result)
Result = FspFileSystemCallResolveReparsePoints(FileSystem, Request, Response, GrantedAccess);
else if (NT_SUCCESS(Result))
{
*PGrantedAccess = GrantedAccess;
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
*PGrantedAccess &= ~(DELETE | FILE_WRITE_DATA) |
(Request->Req.Create.DesiredAccess & (DELETE | FILE_WRITE_DATA));
}
}
return Result;
@ -338,7 +376,7 @@ static NTSTATUS FspFileSystemOpCreate_FileCreate(FSP_FILE_SYSTEM *FileSystem,
return Result;
Response->IoStatus.Information = FILE_CREATED;
Response->Rsp.Create.Opened.UserContext = (UINT_PTR)FileNode;
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
return STATUS_SUCCESS;
@ -365,7 +403,7 @@ static NTSTATUS FspFileSystemOpCreate_FileOpen(FSP_FILE_SYSTEM *FileSystem,
return Result;
Response->IoStatus.Information = FILE_OPENED;
Response->Rsp.Create.Opened.UserContext = (UINT_PTR)FileNode;
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
return STATUS_SUCCESS;
@ -428,7 +466,7 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem,
}
Response->IoStatus.Information = Create ? FILE_CREATED : FILE_OPENED;
Response->Rsp.Create.Opened.UserContext = (UINT_PTR)FileNode;
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
return STATUS_SUCCESS;
@ -456,7 +494,7 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwrite(FSP_FILE_SYSTEM *FileSystem,
return Result;
Response->IoStatus.Information = Supersede ? FILE_SUPERSEDED : FILE_OVERWRITTEN;
Response->Rsp.Create.Opened.UserContext = (UINT_PTR)FileNode;
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
return STATUS_SUCCESS;
@ -519,7 +557,7 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
}
Response->IoStatus.Information = Create ? FILE_CREATED : FILE_OVERWRITTEN;
Response->Rsp.Create.Opened.UserContext = (UINT_PTR)FileNode;
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
return STATUS_SUCCESS;
@ -558,7 +596,7 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenTargetDirectory(FSP_FILE_SYSTEM *F
}
Response->IoStatus.Information = Information;
Response->Rsp.Create.Opened.UserContext = (UINT_PTR)FileNode;
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
return STATUS_SUCCESS;
@ -604,7 +642,7 @@ FSP_API NTSTATUS FspFileSystemOpOverwrite(FSP_FILE_SYSTEM *FileSystem,
memset(&FileInfo, 0, sizeof FileInfo);
Result = FileSystem->Interface->Overwrite(FileSystem, Request,
(PVOID)Request->Req.Overwrite.UserContext,
(PVOID)USERCONTEXT(Request->Req.Overwrite),
Request->Req.Overwrite.FileAttributes,
Request->Req.Overwrite.Supersede,
&FileInfo);
@ -612,7 +650,7 @@ FSP_API NTSTATUS FspFileSystemOpOverwrite(FSP_FILE_SYSTEM *FileSystem,
{
if (0 != FileSystem->Interface->Close)
FileSystem->Interface->Close(FileSystem, Request,
(PVOID)Request->Req.Overwrite.UserContext);
(PVOID)USERCONTEXT(Request->Req.Overwrite));
return Result;
}
@ -625,7 +663,7 @@ FSP_API NTSTATUS FspFileSystemOpCleanup(FSP_FILE_SYSTEM *FileSystem,
{
if (0 != FileSystem->Interface->Cleanup)
FileSystem->Interface->Cleanup(FileSystem, Request,
(PVOID)Request->Req.Cleanup.UserContext,
(PVOID)USERCONTEXT(Request->Req.Cleanup),
0 != Request->FileName.Size ? (PWSTR)Request->Buffer : 0,
0 != Request->Req.Cleanup.Delete);
@ -637,7 +675,7 @@ FSP_API NTSTATUS FspFileSystemOpClose(FSP_FILE_SYSTEM *FileSystem,
{
if (0 != FileSystem->Interface->Close)
FileSystem->Interface->Close(FileSystem, Request,
(PVOID)Request->Req.Close.UserContext);
(PVOID)USERCONTEXT(Request->Req.Close));
return STATUS_SUCCESS;
}
@ -653,7 +691,7 @@ FSP_API NTSTATUS FspFileSystemOpRead(FSP_FILE_SYSTEM *FileSystem,
BytesTransferred = 0;
Result = FileSystem->Interface->Read(FileSystem, Request,
(PVOID)Request->Req.Read.UserContext,
(PVOID)USERCONTEXT(Request->Req.Read),
(PVOID)Request->Req.Read.Address,
Request->Req.Read.Offset,
Request->Req.Read.Length,
@ -679,7 +717,7 @@ FSP_API NTSTATUS FspFileSystemOpWrite(FSP_FILE_SYSTEM *FileSystem,
BytesTransferred = 0;
Result = FileSystem->Interface->Write(FileSystem, Request,
(PVOID)Request->Req.Write.UserContext,
(PVOID)USERCONTEXT(Request->Req.Write),
(PVOID)Request->Req.Write.Address,
Request->Req.Write.Offset,
Request->Req.Write.Length,
@ -706,7 +744,7 @@ FSP_API NTSTATUS FspFileSystemOpFlushBuffers(FSP_FILE_SYSTEM *FileSystem,
return STATUS_SUCCESS; /* liar! */
return FileSystem->Interface->Flush(FileSystem, Request,
(PVOID)Request->Req.FlushBuffers.UserContext);
(PVOID)USERCONTEXT(Request->Req.FlushBuffers));
}
FSP_API NTSTATUS FspFileSystemOpQueryInformation(FSP_FILE_SYSTEM *FileSystem,
@ -720,7 +758,7 @@ FSP_API NTSTATUS FspFileSystemOpQueryInformation(FSP_FILE_SYSTEM *FileSystem,
memset(&FileInfo, 0, sizeof FileInfo);
Result = FileSystem->Interface->GetFileInfo(FileSystem, Request,
(PVOID)Request->Req.QueryInformation.UserContext, &FileInfo);
(PVOID)USERCONTEXT(Request->Req.QueryInformation), &FileInfo);
if (!NT_SUCCESS(Result))
return Result;
@ -741,7 +779,7 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
case 4/*FileBasicInformation*/:
if (0 != FileSystem->Interface->SetBasicInfo)
Result = FileSystem->Interface->SetBasicInfo(FileSystem, Request,
(PVOID)Request->Req.SetInformation.UserContext,
(PVOID)USERCONTEXT(Request->Req.SetInformation),
Request->Req.SetInformation.Info.Basic.FileAttributes,
Request->Req.SetInformation.Info.Basic.CreationTime,
Request->Req.SetInformation.Info.Basic.LastAccessTime,
@ -751,14 +789,14 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
case 19/*FileAllocationInformation*/:
if (0 != FileSystem->Interface->SetFileSize)
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
(PVOID)Request->Req.SetInformation.UserContext,
(PVOID)USERCONTEXT(Request->Req.SetInformation),
Request->Req.SetInformation.Info.Allocation.AllocationSize, TRUE,
&FileInfo);
break;
case 20/*FileEndOfFileInformation*/:
if (0 != FileSystem->Interface->SetFileSize)
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
(PVOID)Request->Req.SetInformation.UserContext,
(PVOID)USERCONTEXT(Request->Req.SetInformation),
Request->Req.SetInformation.Info.EndOfFile.FileSize, FALSE,
&FileInfo);
break;
@ -766,7 +804,7 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
if (0 != FileSystem->Interface->GetFileInfo)
{
Result = FileSystem->Interface->GetFileInfo(FileSystem, Request,
(PVOID)Request->Req.SetInformation.UserContext, &FileInfo);
(PVOID)USERCONTEXT(Request->Req.SetInformation), &FileInfo);
if (NT_SUCCESS(Result) && 0 != (FileInfo.FileAttributes & FILE_ATTRIBUTE_READONLY))
{
Result = STATUS_CANNOT_DELETE;
@ -776,7 +814,7 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
if (0 != FileSystem->Interface->CanDelete)
if (Request->Req.SetInformation.Info.Disposition.Delete)
Result = FileSystem->Interface->CanDelete(FileSystem, Request,
(PVOID)Request->Req.SetInformation.UserContext,
(PVOID)USERCONTEXT(Request->Req.SetInformation),
(PWSTR)Request->Buffer);
else
Result = STATUS_SUCCESS;
@ -793,7 +831,7 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
break;
}
Result = FileSystem->Interface->Rename(FileSystem, Request,
(PVOID)Request->Req.SetInformation.UserContext,
(PVOID)USERCONTEXT(Request->Req.SetInformation),
(PWSTR)Request->Buffer,
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
0 != Request->Req.SetInformation.Info.Rename.AccessToken);
@ -862,7 +900,7 @@ FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
BytesTransferred = 0;
Result = FileSystem->Interface->ReadDirectory(FileSystem, Request,
(PVOID)Request->Req.QueryDirectory.UserContext,
(PVOID)USERCONTEXT(Request->Req.QueryDirectory),
(PVOID)Request->Req.QueryDirectory.Address,
Request->Req.QueryDirectory.Offset,
Request->Req.QueryDirectory.Length,
@ -896,7 +934,7 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
Size = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
Result = FileSystem->Interface->GetReparsePoint(FileSystem, Request,
(PVOID)Request->Req.FileSystemControl.UserContext,
(PVOID)USERCONTEXT(Request->Req.FileSystemControl),
(PWSTR)Request->Buffer, ReparseData, &Size);
if (NT_SUCCESS(Result))
{
@ -913,7 +951,7 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset);
Result = FileSystem->Interface->SetReparsePoint(FileSystem, Request,
(PVOID)Request->Req.FileSystemControl.UserContext,
(PVOID)USERCONTEXT(Request->Req.FileSystemControl),
(PWSTR)Request->Buffer,
ReparseData,
Request->Req.FileSystemControl.Buffer.Size);
@ -926,7 +964,7 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset);
Result = FileSystem->Interface->DeleteReparsePoint(FileSystem, Request,
(PVOID)Request->Req.FileSystemControl.UserContext,
(PVOID)USERCONTEXT(Request->Req.FileSystemControl),
(PWSTR)Request->Buffer,
ReparseData,
Request->Req.FileSystemControl.Buffer.Size);
@ -946,9 +984,9 @@ FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
if (0 == FileSystem->Interface->GetSecurity)
return STATUS_INVALID_DEVICE_REQUEST;
SecurityDescriptorSize = FSP_FSCTL_TRANSACT_RSP_SIZEMAX - sizeof *Response;
SecurityDescriptorSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
Result = FileSystem->Interface->GetSecurity(FileSystem, Request,
(PVOID)Request->Req.QuerySecurity.UserContext,
(PVOID)USERCONTEXT(Request->Req.QuerySecurity),
Response->Buffer, &SecurityDescriptorSize);
if (!NT_SUCCESS(Result))
return STATUS_BUFFER_OVERFLOW != Result ? Result : STATUS_INVALID_SECURITY_DESCR;
@ -966,23 +1004,51 @@ FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem,
return STATUS_INVALID_DEVICE_REQUEST;
return FileSystem->Interface->SetSecurity(FileSystem, Request,
(PVOID)Request->Req.SetSecurity.UserContext,
(PVOID)USERCONTEXT(Request->Req.SetSecurity),
Request->Req.SetSecurity.SecurityInformation,
(PSECURITY_DESCRIPTOR)Request->Buffer);
}
FSP_API BOOLEAN FspFileSystemAddDirInfo(FSP_FSCTL_DIR_INFO *DirInfo,
FSP_API NTSTATUS FspFileSystemOpQueryStreamInformation(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{
NTSTATUS Result;
ULONG BytesTransferred;
if (0 == FileSystem->Interface->GetStreamInfo)
return STATUS_INVALID_DEVICE_REQUEST;
BytesTransferred = 0;
Result = FileSystem->Interface->GetStreamInfo(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.QueryStreamInformation),
Response->Buffer,
FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX,
&BytesTransferred);
if (!NT_SUCCESS(Result))
return Result;
Response->Size = (UINT16)(sizeof *Response + BytesTransferred);
Response->Rsp.QueryStreamInformation.Buffer.Offset = 0;
Response->Rsp.QueryStreamInformation.Buffer.Size = (UINT16)BytesTransferred;
return STATUS_SUCCESS;
}
FSP_FSCTL_STATIC_ASSERT(
sizeof(UINT16) == sizeof ((FSP_FSCTL_DIR_INFO *)0)->Size &&
sizeof(UINT16) == sizeof ((FSP_FSCTL_STREAM_INFO *)0)->Size,
"FSP_FSCTL_DIR_INFO::Size and FSP_FSCTL_STREAM_INFO::Size: sizeof must be 2.");
static BOOLEAN FspFileSystemAddXxxInfo(PVOID Info,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
static UINT8 Zero[sizeof DirInfo->Size] = { 0 };
static UINT8 Zero[sizeof(UINT16)] = { 0 };
PVOID BufferEnd = (PUINT8)Buffer + Length;
PVOID SrcBuffer;
ULONG SrcLength, DstLength;
if (0 != DirInfo)
if (0 != Info)
{
SrcBuffer = DirInfo;
SrcLength = DirInfo->Size;
SrcBuffer = Info;
SrcLength = *(PUINT16)Info;
DstLength = FSP_FSCTL_DEFAULT_ALIGN_UP(SrcLength);
}
else
@ -1002,6 +1068,12 @@ FSP_API BOOLEAN FspFileSystemAddDirInfo(FSP_FSCTL_DIR_INFO *DirInfo,
return TRUE;
}
FSP_API BOOLEAN FspFileSystemAddDirInfo(FSP_FSCTL_DIR_INFO *DirInfo,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
return FspFileSystemAddXxxInfo(DirInfo, Buffer, Length, PBytesTransferred);
}
FSP_API BOOLEAN FspFileSystemFindReparsePoint(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS (*GetReparsePointByName)(
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
@ -1049,23 +1121,18 @@ FSP_API BOOLEAN FspFileSystemFindReparsePoint(FSP_FILE_SYSTEM *FileSystem,
return FALSE;
}
FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
FSP_API NTSTATUS FspFileSystemResolveReparsePointsInternal(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS (*GetReparsePointByName)(
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize),
PVOID Context,
PREPARSE_DATA_BUFFER ReparseData, SIZE_T ReparseDataSize0,
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent0,
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize)
{
PREPARSE_DATA_BUFFER OutputReparseData;
PWSTR TargetPath, RemainderPath, LastPathComponent, NewRemainderPath, ReparseTargetPath;
WCHAR RemainderChar;
union
{
REPARSE_DATA_BUFFER V;
UINT8 B[FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX];
} ReparseDataBuf;
PREPARSE_DATA_BUFFER ReparseData = &ReparseDataBuf.V;
SIZE_T ReparseDataSize, RemainderPathSize, ReparseTargetPathLength;
BOOLEAN ResolveLastPathComponent;
ULONG MaxTries = 32;
@ -1149,7 +1216,7 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
}
RemainderChar = *RemainderPath; *RemainderPath = L'\0';
ReparseDataSize = sizeof ReparseDataBuf;
ReparseDataSize = ReparseDataSize0;
Result = GetReparsePointByName(FileSystem, Context, TargetPath, '\0' != RemainderChar,
ReparseData, &ReparseDataSize);
*RemainderPath = RemainderChar;
@ -1238,6 +1305,32 @@ reparse_data_exit:
return STATUS_REPARSE;
}
FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS (*GetReparsePointByName)(
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize),
PVOID Context,
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent,
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize)
{
PREPARSE_DATA_BUFFER ReparseData;
NTSTATUS Result;
ReparseData = MemAlloc(FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX);
if (0 == ReparseData)
return STATUS_INSUFFICIENT_RESOURCES;
Result = FspFileSystemResolveReparsePointsInternal(FileSystem,
GetReparsePointByName, Context,
ReparseData, FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX,
FileName, ReparsePointIndex, ResolveLastPathComponent,
PIoStatus, Buffer, PSize);
MemFree(ReparseData);
return Result;
}
FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint(
PVOID CurrentReparseData, SIZE_T CurrentReparseDataSize,
PVOID ReplaceReparseData, SIZE_T ReplaceReparseDataSize)
@ -1262,3 +1355,9 @@ FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint(
else
return STATUS_SUCCESS;
}
FSP_API BOOLEAN FspFileSystemAddStreamInfo(FSP_FSCTL_STREAM_INFO *StreamInfo,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
return FspFileSystemAddXxxInfo(StreamInfo, Buffer, Length, PBytesTransferred);
}

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -41,7 +41,6 @@ struct fsp_fuse_core_opt_data
rellinks;
int set_FileInfoTimeout;
int CaseInsensitiveSearch,
NamedStreams,
ReadOnlyVolume;
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
};
@ -83,6 +82,8 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FSP_FUSE_CORE_OPT("rellinks", rellinks, 1),
FSP_FUSE_CORE_OPT("norellinks", rellinks, 0),
FUSE_OPT_KEY("fstypename=", 'F'),
FSP_FUSE_CORE_OPT("SectorSize=%hu", VolumeParams.SectorSize, 4096),
FSP_FUSE_CORE_OPT("SectorsPerAllocationUnit=%hu", VolumeParams.SectorsPerAllocationUnit, 1),
FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
@ -94,13 +95,14 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
FSP_FUSE_CORE_OPT("CaseInsensitiveSearch", CaseInsensitiveSearch, 1),
FSP_FUSE_CORE_OPT("NamedStreams", NamedStreams, 1),
FSP_FUSE_CORE_OPT("ReadOnlyVolume", ReadOnlyVolume, 1),
FUSE_OPT_KEY("ReparsePoints", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("NamedStreams", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("HardLinks", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("ExtendedAttributes", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("--UNC=", 'U'),
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
FUSE_OPT_KEY("--FileSystemName=", 'F'),
FUSE_OPT_END,
};
@ -454,9 +456,9 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
" -o VolumeSerialNumber=N 32-bit wide\n"
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n"
" -o CaseInsensitiveSearch file system supports case-insensitive file names\n"
//" -o NamedStreams file system supports named streams\n"
//" -o ReadOnlyVolume file system is read only\n"
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n");
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n"
" --FileSystemName=FSN Name of user mode file system\n");
opt_data->help = 1;
return 1;
case 'V':
@ -473,6 +475,21 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
opt_data->VolumeParams.Prefix, sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR)))
return -1;
opt_data->VolumeParams.Prefix
[sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR) - 1] = L'\0';
return 0;
case 'F':
if ('f' == arg[0])
arg += sizeof "fstypename=" - 1;
else if ('F' == arg[2])
arg += sizeof "--FileSystemName=" - 1;
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
opt_data->VolumeParams.FileSystemName + 5,
sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR)) - 5)
return -1;
opt_data->VolumeParams.FileSystemName
[sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0';
memcpy(opt_data->VolumeParams.FileSystemName, L"FUSE-", 5 * sizeof(WCHAR));
return 0;
}
}
@ -504,8 +521,12 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
opt_data.VolumeParams.PersistentAcls = TRUE;
opt_data.VolumeParams.ReparsePoints = TRUE;
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
opt_data.VolumeParams.NamedStreams = !!opt_data.NamedStreams;
opt_data.VolumeParams.NamedStreams = FALSE;
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
opt_data.VolumeParams.PostCleanupOnDeleteOnly = TRUE;
opt_data.VolumeParams.UmFileNodeIsUserContext2 = TRUE;
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
f = fsp_fuse_obj_alloc(env, sizeof *f);
if (0 == f)

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -32,7 +32,8 @@ VOID fsp_fuse_op_enter_lock(FSP_FILE_SYSTEM *FileSystem,
10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass) ||
FspFsctlTransactSetVolumeInformationKind == Request->Kind ||
(FspFsctlTransactFlushBuffersKind == Request->Kind &&
0 == Request->Req.FlushBuffers.UserContext) ||
0 == Request->Req.FlushBuffers.UserContext &&
0 == Request->Req.FlushBuffers.UserContext2) ||
/* FSCTL_SET_REPARSE_POINT manipulates namespace */
(FspFsctlTransactFileSystemControlKind == Request->Kind &&
FSCTL_SET_REPARSE_POINT == Request->Req.FileSystemControl.FsControlCode))
@ -74,7 +75,8 @@ VOID fsp_fuse_op_leave_unlock(FSP_FILE_SYSTEM *FileSystem,
10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass) ||
FspFsctlTransactSetVolumeInformationKind == Request->Kind ||
(FspFsctlTransactFlushBuffersKind == Request->Kind &&
0 == Request->Req.FlushBuffers.UserContext) ||
0 == Request->Req.FlushBuffers.UserContext &&
0 == Request->Req.FlushBuffers.UserContext2) ||
/* FSCTL_SET_REPARSE_POINT manipulates namespace */
(FspFsctlTransactFileSystemControlKind == Request->Kind &&
FSCTL_SET_REPARSE_POINT == Request->Req.FileSystemControl.FsControlCode))
@ -223,8 +225,6 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
context->gid = Gid;
contexthdr = FSP_FUSE_HDR_FROM_CONTEXT(context);
contexthdr->Request = Request;
contexthdr->Response = Response;
contexthdr->PosixPath = PosixPath;
Result = STATUS_SUCCESS;
@ -876,7 +876,7 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
if (!NT_SUCCESS(Result))
goto exit;
*PFileNode = 0;
*PFileNode = filedesc;
memcpy(FileInfo, &FileInfoBuf, sizeof FileInfoBuf);
filedesc->PosixPath = contexthdr->PosixPath;
@ -887,7 +887,6 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
filedesc->DirBuffer = 0;
filedesc->DirBufferSize = 0;
contexthdr->PosixPath = 0;
contexthdr->Response->Rsp.Create.Opened.UserContext2 = (UINT64)(UINT_PTR)filedesc;
Result = STATUS_SUCCESS;
@ -996,7 +995,7 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
* Ignore fuse_file_info::nonseekable.
*/
*PFileNode = 0;
*PFileNode = filedesc;
memcpy(FileInfo, &FileInfoBuf, sizeof FileInfoBuf);
filedesc->PosixPath = contexthdr->PosixPath;
@ -1007,7 +1006,6 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
filedesc->DirBuffer = 0;
filedesc->DirBufferSize = 0;
contexthdr->PosixPath = 0;
contexthdr->Response->Rsp.Create.Opened.UserContext2 = (UINT64)(UINT_PTR)filedesc;
Result = STATUS_SUCCESS;
@ -1024,8 +1022,7 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.Overwrite.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
UINT32 Uid, Gid, Mode;
struct fuse_file_info fi;
int err;
@ -1062,8 +1059,7 @@ static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, PWSTR FileName, BOOLEAN Delete)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.Cleanup.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
/*
* In Windows a DeleteFile/RemoveDirectory is the sequence of the following:
@ -1100,8 +1096,7 @@ static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.Close.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_file_info fi;
memset(&fi, 0, sizeof fi);
@ -1136,8 +1131,7 @@ static NTSTATUS fsp_fuse_intf_Read(FSP_FILE_SYSTEM *FileSystem,
PULONG PBytesTransferred)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.Read.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_file_info fi;
int bytes;
NTSTATUS Result;
@ -1173,8 +1167,7 @@ static NTSTATUS fsp_fuse_intf_Write(FSP_FILE_SYSTEM *FileSystem,
PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.Write.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
UINT32 Uid, Gid, Mode;
struct fuse_file_info fi;
FSP_FSCTL_FILE_INFO FileInfoBuf;
@ -1235,8 +1228,7 @@ static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.FlushBuffers.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_file_info fi;
int err;
NTSTATUS Result;
@ -1277,8 +1269,7 @@ static NTSTATUS fsp_fuse_intf_GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.QueryInformation.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
UINT32 Uid, Gid, Mode;
struct fuse_file_info fi;
@ -1297,8 +1288,7 @@ static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.SetInformation.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
UINT32 Uid, Gid, Mode;
struct fuse_file_info fi;
FSP_FSCTL_FILE_INFO FileInfoBuf;
@ -1376,8 +1366,7 @@ static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.SetInformation.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
UINT32 Uid, Gid, Mode;
struct fuse_file_info fi;
FSP_FSCTL_FILE_INFO FileInfoBuf;
@ -1460,8 +1449,7 @@ static NTSTATUS fsp_fuse_intf_CanDelete(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, PWSTR FileName)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.SetInformation.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_file_info fi;
struct fuse_dirhandle dh;
int err;
@ -1500,8 +1488,7 @@ static NTSTATUS fsp_fuse_intf_Rename(FSP_FILE_SYSTEM *FileSystem,
struct fsp_fuse_context_header *contexthdr = FSP_FUSE_HDR_FROM_CONTEXT(context);
UINT32 Uid, Gid, Mode;
FSP_FSCTL_FILE_INFO FileInfoBuf;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.SetInformation.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
int err;
NTSTATUS Result;
@ -1531,8 +1518,7 @@ static NTSTATUS fsp_fuse_intf_GetSecurity(FSP_FILE_SYSTEM *FileSystem,
PSECURITY_DESCRIPTOR SecurityDescriptorBuf, SIZE_T *PSecurityDescriptorSize)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.QuerySecurity.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_file_info fi;
UINT32 FileAttributes;
@ -1550,8 +1536,7 @@ static NTSTATUS fsp_fuse_intf_SetSecurity(FSP_FILE_SYSTEM *FileSystem,
SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR Ignored)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.SetSecurity.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_file_info fi;
UINT32 Uid, Gid, Mode, NewUid, NewGid, NewMode;
FSP_FSCTL_FILE_INFO FileInfo;
@ -1684,8 +1669,7 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
PULONG PBytesTransferred)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.QueryDirectory.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_file_info fi;
struct fuse_dirhandle dh;
struct fsp_fuse_dirinfo *di;
@ -1891,8 +1875,7 @@ static NTSTATUS fsp_fuse_intf_GetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode,
PWSTR FileName, PVOID Buffer, PSIZE_T PSize)
{
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.FileSystemControl.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_file_info fi;
memset(&fi, 0, sizeof fi);
@ -1909,8 +1892,7 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
{
struct fuse *f = FileSystem->UserContext;
struct fuse_context *context = fsp_fuse_get_context(f->env);
struct fsp_fuse_file_desc *filedesc =
(PVOID)(UINT_PTR)Request->Req.FileSystemControl.UserContext2;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_file_info fi;
UINT32 Uid, Gid, Mode, Dev;
FSP_FSCTL_FILE_INFO FileInfo;

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -51,8 +51,6 @@ struct fuse
struct fsp_fuse_context_header
{
FSP_FSCTL_TRANSACT_REQ *Request;
FSP_FSCTL_TRANSACT_RSP *Response;
char *PosixPath;
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ContextBuf[];
};

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -19,9 +19,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -63,10 +63,21 @@ static inline ULONG FspPathSuffixIndex(PWSTR FileName)
FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
BOOLEAN CheckParentDirectory, BOOLEAN AllowTraverseCheck,
BOOLEAN CheckParentOrMain, BOOLEAN AllowTraverseCheck,
UINT32 DesiredAccess, PUINT32 PGrantedAccess,
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
{
BOOLEAN CheckParentDirectory, CheckMainFile;
CheckParentDirectory = CheckMainFile = FALSE;
if (CheckParentOrMain)
{
if (!Request->Req.Create.NamedStream)
CheckParentDirectory = TRUE;
else
CheckMainFile = TRUE;
}
*PGrantedAccess = 0;
if (0 != PSecurityDescriptor)
*PSecurityDescriptor = 0;
@ -96,10 +107,16 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
PPRIVILEGE_SET PrivilegeSet = (PVOID)PrivilegeSetBuf;
DWORD PrivilegeSetLength = sizeof PrivilegeSetBuf;
UINT32 TraverseAccess, ParentAccess, DesiredAccess2;
UINT16 NamedStreamSave;
BOOL AccessStatus;
if (CheckParentDirectory)
FspPathSuffix((PWSTR)Request->Buffer, &FileName, &Suffix, Root);
else if (CheckMainFile)
{
((PWSTR)Request->Buffer)[Request->Req.Create.NamedStream / sizeof(WCHAR)] = L'\0';
FileName = (PWSTR)Request->Buffer;
}
else
FileName = (PWSTR)Request->Buffer;
@ -212,6 +229,8 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
0 == ((MAXIMUM_ALLOWED | DELETE | FILE_READ_ATTRIBUTES) & DesiredAccess))
goto exit;
NamedStreamSave = Request->Req.Create.NamedStream;
Request->Req.Create.NamedStream = 0;
Result = FspAccessCheck(FileSystem, Request, TRUE, FALSE,
(MAXIMUM_ALLOWED & DesiredAccess) ? (FILE_DELETE_CHILD | FILE_LIST_DIRECTORY) :
(
@ -219,6 +238,7 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
((FILE_READ_ATTRIBUTES & DesiredAccess) ? FILE_LIST_DIRECTORY : 0)
),
&ParentAccess);
Request->Req.Create.NamedStream = NamedStreamSave;
if (!NT_SUCCESS(Result))
{
/* any failure just becomes ACCESS DENIED at this point */
@ -269,6 +289,20 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
goto exit;
}
}
else if (CheckMainFile)
{
/*
* We check to see if this is a reparse point and FILE_OPEN_REPARSE_POINT
* was not specified, in which case we return STATUS_REPARSE.
*/
if (0 != (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
0 == (Request->Req.Create.CreateOptions & FILE_OPEN_REPARSE_POINT))
{
FileAttributes = FspPathSuffixIndex(FileName);
Result = STATUS_REPARSE;
goto exit;
}
}
else
{
/*
@ -344,6 +378,8 @@ exit:
if (STATUS_OBJECT_NAME_NOT_FOUND == Result)
Result = STATUS_OBJECT_PATH_NOT_FOUND;
}
else if (CheckMainFile)
((PWSTR)Request->Buffer)[Request->Req.Create.NamedStream / sizeof(WCHAR)] = L':';
return Result;
}
@ -358,6 +394,10 @@ FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
if (FspFsctlTransactCreateKind != Request->Kind)
return STATUS_INVALID_PARAMETER;
/* stream support: return NULL security descriptor when creating named stream */
if (Request->Req.Create.NamedStream)
return STATUS_SUCCESS;
if (!CreatePrivateObjectSecurity(
ParentDescriptor,
0 != Request->Req.Create.SecurityDescriptor.Offset ?
@ -438,6 +478,10 @@ FSP_API NTSTATUS FspSetSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
FSP_API VOID FspDeleteSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
NTSTATUS (*CreateFunc)())
{
/* stream support: allow NULL security descriptors */
if (0 == SecurityDescriptor)
return;
if ((NTSTATUS (*)())FspAccessCheckEx == CreateFunc ||
(NTSTATUS (*)())FspPosixMapPermissionsToSecurityDescriptor == CreateFunc)
MemFree(SecurityDescriptor);

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -26,11 +26,10 @@
* - "C/C++ > Code Generation > Basic Runtime Checks" must be set to "Default"
* - "C/C++ > Code Generation > Runtime Library" must be set to "Multi-threaded (/MT)".
* - "C/C++ > Code Generation > Security Check" must be disabled (/GS-).
* - "C/C++ > Command Line > Additional Options" add "/Gs16384" to disable __chkstk probes.
* - "Linker > Input > Ignore All Default Libraries" must be "Yes".
*
*
* Update:
* Update 1:
*
* It is possible to have the "Linker > Input > Ignore All Default Libraries"
* setting to "No" and still eliminate most dependencies on the MSVCRT libraries.
@ -44,6 +43,22 @@
* that are not required (or worse create a half-baked CRT). For example, the WinFsp
* DLL ensures this by setting the "Linker > Input > Ignore All Default Libraries"
* to "Yes" on 64-bit builds and "No" on 32-bit builds.
*
*
* Update 2:
*
* Using the /Gs[size] compiler option with a large size is a very bad idea.
* Turns out that the compiler uses the _chkstk call to ensure that enough
* stack space has been committed even when a function accesses locations in
* the stack below the guard page.
*
* The following links explain the problem very well:
* - http://stackoverflow.com/questions/8400118/what-is-the-purpose-of-the-chkstk-function#8400171
* - https://support.microsoft.com/en-us/kb/100775
*
* A library/program that does not wish to use the MSVCRT libraries (and hence
* does not have _chkstk available) must take care to not use more than a page
* (4096 bytes) of stack within a single function.
*/
#undef RtlFillMemory

View File

@ -7,9 +7,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -116,7 +116,9 @@ NTSTATUS FspAcquireForModWrite(
Success = FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, FALSE);
if (Success)
{
*ResourceToRelease = FileNode->Header.PagingIoResource;
*ResourceToRelease = 0 == FileNode->MainFileNode ?
FileNode->Header.PagingIoResource :
FileNode->MainFileNode->Header.PagingIoResource;
Result = STATUS_SUCCESS;
}
else

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -72,6 +72,7 @@ static NTSTATUS FspFsvolCleanup(
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
return STATUS_SUCCESS;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
@ -87,9 +88,6 @@ static NTSTATUS FspFsvolCleanup(
/* if this is a directory inform the FSRTL Notify mechanism */
if (FileNode->IsDirectory)
{
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FsvolDeviceObject);
if (DeletePending)
FspNotifyDeletePending(
FsvolDeviceExtension->NotifySync, &FsvolDeviceExtension->NotifyList, FileNode);
@ -114,14 +112,22 @@ static NTSTATUS FspFsvolCleanup(
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp;
return FSP_STATUS_IOQ_POST_BEST_EFFORT;
if (DeletePending || !FsvolDeviceExtension->VolumeParams.PostCleanupOnDeleteOnly)
/*
* 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
* from our perspective, because they mean that the file system is going
* away and should correctly tear things down.
*/
return FSP_STATUS_IOQ_POST_BEST_EFFORT;
else
{
/* if the file is being resized invalidate the volume info */
if (FileNode->TruncateOnClose)
FspFsvolDeviceInvalidateVolumeInfo(IrpSp->DeviceObject);
/*
* 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
* from our perspective, because they mean that the file system is going
* away and should correctly tear things down.
*/
return STATUS_SUCCESS; /* FspFsvolCleanupRequestFini will take care of the rest! */
}
}
NTSTATUS FspFsvolCleanupComplete(
@ -161,12 +167,21 @@ static VOID FspFsvolCleanupRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Co
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
HANDLE MainFileHandle;
ASSERT(FileNode == FileDesc->FileNode);
FspFileNodeReleaseOwner(FileNode, Pgio, Request);
FspFileNodeCleanupComplete(FileNode, FileObject);
MainFileHandle = FileDesc->MainFileHandle;
FileDesc->MainFileHandle = 0;
FspFileNodeReleaseOwner(FileNode, Main, Request);
FspMainFileClose(MainFileHandle, 0);
}
NTSTATUS FspCleanup(

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -77,7 +77,7 @@ static NTSTATUS FspFsvolClose(
FspFileNodeClose(FileNode, FileObject);
/* delete the FileDesc and deref the FileNode; order is important (FileDesc has FileNode ref) */
FspFileDescDelete(FileDesc);
FspFileDescDelete(FileDesc); /* this will also close the MainFileObject if any */
FspFileNodeDereference(FileNode);
/*

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -24,7 +24,8 @@ static NTSTATUS FspFsvrtCreate(
static NTSTATUS FspFsvolCreate(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolCreateNoLock(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN MainFileOpen);
FSP_IOPREP_DISPATCH FspFsvolCreatePrepare;
FSP_IOCMPL_DISPATCH FspFsvolCreateComplete;
static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
@ -109,23 +110,30 @@ static NTSTATUS FspFsvolCreate(
PAGED_CODE();
NTSTATUS Result = STATUS_SUCCESS;
BOOLEAN MainFileOpen = FspMainFileOpenCheck(Irp);
FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject);
try
if (!MainFileOpen)
{
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp);
}
finally
{
if (FSP_STATUS_IOQ_POST != Result)
FspFsvolDeviceFileRenameRelease(FsvolDeviceObject);
FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject);
try
{
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp, FALSE);
}
finally
{
if (FSP_STATUS_IOQ_POST != Result)
FspFsvolDeviceFileRenameRelease(FsvolDeviceObject);
}
}
else
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp, TRUE);
return Result;
}
static NTSTATUS FspFsvolCreateNoLock(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN MainFileOpen)
{
PAGED_CODE();
@ -162,10 +170,16 @@ static NTSTATUS FspFsvolCreateNoLock(
ULONG Flags = IrpSp->Flags;
KPROCESSOR_MODE RequestorMode =
FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode;
BOOLEAN CaseSensitiveRequested =
BooleanFlagOn(Flags, SL_CASE_SENSITIVE);
BOOLEAN CaseSensitive =
CaseSensitiveRequested || FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch;
BOOLEAN HasTraversePrivilege =
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE);
FSP_FILE_NODE *FileNode, *RelatedFileNode;
FSP_FILE_DESC *FileDesc;
UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 };
ULONG StreamType = FspUnicodePathStreamTypeNone;
FSP_FSCTL_TRANSACT_REQ *Request;
/* cannot open files by fileid */
@ -210,10 +224,6 @@ static NTSTATUS FspFsvolCreateNoLock(
FileName.Buffer++;
}
/* check filename validity */
if (!FspUnicodePathIsValid(&FileName, 0 != FsvolDeviceExtension->VolumeParams.NamedStreams))
return STATUS_OBJECT_NAME_INVALID;
/* is this a relative or absolute open? */
if (0 != RelatedFileObject)
{
@ -265,6 +275,28 @@ static NTSTATUS FspFsvolCreateNoLock(
Result = RtlAppendUnicodeStringToString(&FileNode->FileName, &FileName);
ASSERT(NT_SUCCESS(Result));
/* check filename validity */
if (!FspUnicodePathIsValid(&FileNode->FileName,
FsvolDeviceExtension->VolumeParams.NamedStreams ? &StreamPart : 0,
&StreamType))
{
FspFileNodeDereference(FileNode);
return STATUS_OBJECT_NAME_INVALID;
}
/* if we have a stream part (even non-empty), ensure that FileNode->FileName has single colon */
if (0 != StreamPart.Buffer)
{
ASSERT(
(PUINT8)FileNode->FileName.Buffer + sizeof(WCHAR) <= (PUINT8)StreamPart.Buffer &&
(PUINT8)StreamPart.Buffer + StreamPart.Length <=
(PUINT8)FileNode->FileName.Buffer + FileNode->FileName.Length);
FileNode->FileName.Length = (USHORT)
((PUINT8)StreamPart.Buffer - (PUINT8)FileNode->FileName.Buffer + StreamPart.Length -
(0 == StreamPart.Length) * sizeof(WCHAR));
}
/* check and remove any volume prefix */
if (0 == RelatedFileObject && 0 < FsvolDeviceExtension->VolumePrefix.Length)
{
@ -301,6 +333,16 @@ static NTSTATUS FspFsvolCreateNoLock(
FileNode->FileName.Length -= sizeof(WCHAR);
}
/* if a $DATA stream type, this cannot be a directory */
if (FspUnicodePathStreamTypeData == StreamType)
{
if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
{
FspFileNodeDereference(FileNode);
return STATUS_NOT_A_DIRECTORY;
}
}
/* not all operations allowed on the root directory */
if (sizeof(WCHAR) == FileNode->FileName.Length &&
(FILE_CREATE == CreateDisposition ||
@ -328,6 +370,71 @@ static NTSTATUS FspFsvolCreateNoLock(
return Result;
}
/* fix FileAttributes */
ClearFlag(FileAttributes,
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
if (CreateOptions & FILE_DIRECTORY_FILE)
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
/* if we have a non-empty stream part, open the main file */
if (0 != StreamPart.Length)
{
/* named streams can never be directories (even when attached to directories) */
if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
{
Result = STATUS_NOT_A_DIRECTORY;
goto main_stream_exit;
}
/* cannot open target directory of a named stream */
if (FlagOn(Flags, SL_OPEN_TARGET_DIRECTORY))
{
Result = STATUS_OBJECT_NAME_INVALID;
goto main_stream_exit;
}
MainFileName.Length = MainFileName.MaximumLength = (USHORT)
((PUINT8)StreamPart.Buffer - (PUINT8)FileNode->FileName.Buffer - sizeof(WCHAR));
MainFileName.Buffer = FileNode->FileName.Buffer;
Result = FspMainFileOpen(
FsvolDeviceObject,
FileObject->DeviceObject, /* use as device hint when using MUP */
&MainFileName, CaseSensitive,
SecurityDescriptor,
FileAttributes,
CreateDisposition,
&FileDesc->MainFileHandle,
&FileDesc->MainFileObject);
if (!NT_SUCCESS(Result))
goto main_stream_exit;
/* check that the main file is one we recognize */
if (!FspFileNodeIsValid(FileDesc->MainFileObject->FsContext))
{
Result = STATUS_OBJECT_NAME_NOT_FOUND;
goto main_stream_exit;
}
/* cannot set security descriptor or file attributes on named stream */
SecurityDescriptor = 0;
SecurityDescriptorSize = 0;
FileAttributes = 0;
/* remember the main file node */
FileNode->MainFileNode = FileDesc->MainFileObject->FsContext;
Result = STATUS_SUCCESS;
main_stream_exit:
if (!NT_SUCCESS(Result))
{
FspFileDescDelete(FileDesc);
FspFileNodeDereference(FileNode);
return Result;
}
}
/* create the user-mode file system request */
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, SecurityDescriptorSize,
FspFsvolCreateRequestFini, &Request);
@ -338,24 +445,19 @@ static NTSTATUS FspFsvolCreateNoLock(
return Result;
}
/* fix FileAttributes */
ClearFlag(FileAttributes,
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
if (CreateOptions & FILE_DIRECTORY_FILE)
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
/*
* The new request is associated with our IRP. Go ahead and associate our FileNode/FileDesc
* with the Request as well. After this is done completing our IRP will automatically
* delete the Request and any associated resources.
*/
FileDesc->FileNode = FileNode;
FileDesc->CaseSensitive =
0 != FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch ||
BooleanFlagOn(Flags, SL_CASE_SENSITIVE);
FileDesc->CaseSensitive = CaseSensitive;
FileDesc->HasTraversePrivilege = HasTraversePrivilege;
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
if (!MainFileOpen)
{
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
}
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
/* populate the Create request */
@ -374,7 +476,12 @@ static NTSTATUS FspFsvolCreateNoLock(
Request->Req.Create.UserMode = UserMode == RequestorMode;
Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege;
Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY);
Request->Req.Create.CaseSensitive = BooleanFlagOn(Flags, SL_CASE_SENSITIVE);
Request->Req.Create.CaseSensitive = CaseSensitiveRequested;
Request->Req.Create.NamedStream = MainFileName.Length;
ASSERT(
0 == StreamPart.Length && 0 == MainFileName.Length ||
0 != StreamPart.Length && 0 != MainFileName.Length);
/* copy the security descriptor (if any) into the request */
if (0 != SecurityDescriptorSize)
@ -724,6 +831,8 @@ NTSTATUS FspFsvolCreateComplete(
if (FileNode->IsDirectory)
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
PVOID RequestDeviceObjectValue = FspIopRequestContext(Request, RequestDeviceObject);
/* disassociate the FileDesc momentarily from the Request */
FspIopRequestContext(Request, RequestDeviceObject) = 0;
FspIopRequestContext(Request, RequestFileDesc) = 0;
@ -732,7 +841,7 @@ NTSTATUS FspFsvolCreateComplete(
Request->Kind = FspFsctlTransactOverwriteKind;
RtlZeroMemory(&Request->Req.Create, sizeof Request->Req.Create);
FspIopResetRequest(Request, FspFsvolCreateOverwriteRequestFini);
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
FspIopRequestContext(Request, RequestDeviceObject) = RequestDeviceObjectValue;
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
FspIopRequestContext(Request, RequestFileObject) = FileObject;
FspIopRequestContext(Request, RequestState) = (PVOID)RequestPending;
@ -815,7 +924,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
if (FspFsctlTransactCreateKind == Request->Kind)
{
PDEVICE_OBJECT FsvolDeviceObject = FspIopRequestContext(Request, RequestDeviceObject);
PVOID RequestDeviceObjectValue = FspIopRequestContext(Request, RequestDeviceObject);
/* disassociate the FileDesc momentarily from the Request */
Request = FspIrpRequest(Irp);
@ -825,7 +934,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
/* reset the Request and reassociate the FileDesc and FileObject with it */
Request->Kind = FspFsctlTransactReservedKind;
FspIopResetRequest(Request, FspFsvolCreateTryOpenRequestFini);
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
FspIopRequestContext(Request, RequestDeviceObject) = RequestDeviceObjectValue;
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
FspIopRequestContext(Request, RequestFileObject) = FileObject;
FspIopRequestContext(Request, RequestState) = (PVOID)(UINT_PTR)FlushImage;

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -295,7 +295,7 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
NTSTATUS Result;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
LARGE_INTEGER IrpTimeout;
LARGE_INTEGER SecurityTimeout, DirInfoTimeout;
LARGE_INTEGER SecurityTimeout, DirInfoTimeout, StreamInfoTimeout;
/*
* Volume device initialization is a mess, because of the different ways of
@ -347,6 +347,16 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
return Result;
FsvolDeviceExtension->InitDoneDir = 1;
/* create our stream info meta cache */
StreamInfoTimeout.QuadPart = FspTimeoutFromMillis(FsvolDeviceExtension->VolumeParams.FileInfoTimeout);
/* convert millis to nanos */
Result = FspMetaCacheCreate(
FspFsvolDeviceStreamInfoCacheCapacity, FspFsvolDeviceStreamInfoCacheItemSizeMax, &StreamInfoTimeout,
&FsvolDeviceExtension->StreamInfoCache);
if (!NT_SUCCESS(Result))
return Result;
FsvolDeviceExtension->InitDoneStrm = 1;
/* initialize the FSRTL Notify mechanism */
Result = FspNotifyInitializeSync(&FsvolDeviceExtension->NotifySync);
if (!NT_SUCCESS(Result))
@ -406,6 +416,10 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
FspNotifyUninitializeSync(&FsvolDeviceExtension->NotifySync);
}
/* delete the stream info meta cache */
if (FsvolDeviceExtension->InitDoneStrm)
FspMetaCacheDelete(FsvolDeviceExtension->StreamInfoCache);
/* delete the directory meta cache */
if (FsvolDeviceExtension->InitDoneDir)
FspMetaCacheDelete(FsvolDeviceExtension->DirInfoCache);
@ -484,6 +498,7 @@ static VOID FspFsvolDeviceExpirationRoutine(PVOID Context)
InterruptTime = KeQueryInterruptTime();
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->SecurityCache, InterruptTime);
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, InterruptTime);
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->StreamInfoCache, InterruptTime);
FspIoqRemoveExpired(FsvolDeviceExtension->Ioq, InterruptTime);
KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql);

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -100,7 +100,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
__VA_ARGS__\
Info = DestBuf;\
RtlCopyMemory(Info, &InfoStruct, FIELD_OFFSET(TYPE, FileName));\
RtlCopyMemory(Info->FileName, DirInfo->FileNameBuf, FileName.Length);\
RtlMoveMemory(Info->FileName, DirInfo->FileNameBuf, CopyLength);\
} while (0,0)
#define FILL_INFO(TYPE, ...)\
FILL_INFO_BASE(TYPE,\
@ -117,6 +117,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
PAGED_CODE();
NTSTATUS Result = STATUS_SUCCESS;
BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer;
BOOLEAN Loop = TRUE, DirectoryOffsetFound = FALSE;
FSP_FSCTL_DIR_INFO *DirInfo = *PDirInfo;
@ -124,7 +125,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
PUINT8 DestBufBgn = (PUINT8)DestBuf;
PUINT8 DestBufEnd = (PUINT8)DestBuf + *PDestLen;
PVOID PrevDestBuf = 0;
ULONG BaseInfoLen;
ULONG BaseInfoLen, CopyLength;
UNICODE_STRING FileName;
*PDestLen = 0;
@ -178,17 +179,27 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
FileName.MaximumLength = (USHORT)(DirInfoSize - sizeof(FSP_FSCTL_DIR_INFO));
FileName.Buffer = DirInfo->FileNameBuf;
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
CopyLength = FileName.Length;
if (MatchAll || FsRtlIsNameInExpression(DirectoryPattern, &FileName, CaseInsensitive, 0))
{
if ((PUINT8)DestBuf +
FSP_FSCTL_ALIGN_UP(BaseInfoLen + FileName.Length, sizeof(LONGLONG)) > DestBufEnd)
if ((PUINT8)DestBuf + BaseInfoLen + CopyLength > DestBufEnd)
{
if (0 == *PDestLen)
/* if we have already copied something exit the loop */
if (0 != *PDestLen)
break;
if ((PUINT8)DestBuf + BaseInfoLen > DestBufEnd)
/* buffer is too small, can't copy anything */
return STATUS_BUFFER_TOO_SMALL;
else
{
*PDestLen = BaseInfoLen + FileName.Length;
return STATUS_BUFFER_OVERFLOW;
/* copy as much of the file name as we can and return STATUS_BUFFER_OVERFLOW */
CopyLength = (USHORT)(DestBufEnd - ((PUINT8)DestBuf + BaseInfoLen));
Result = STATUS_BUFFER_OVERFLOW;
Loop = FALSE;
}
break;
}
if (0 != PrevDestBuf)
@ -196,7 +207,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
PrevDestBuf = DestBuf;
*PDirectoryOffset = DirInfo->NextOffset;
*PDestLen = (ULONG)((PUINT8)DestBuf + BaseInfoLen + FileName.Length - DestBufBgn);
*PDestLen = (ULONG)((PUINT8)DestBuf + BaseInfoLen + CopyLength - DestBufBgn);
switch (FileInformationClass)
{
@ -238,7 +249,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
}
DestBuf = (PVOID)((PUINT8)DestBuf +
FSP_FSCTL_ALIGN_UP(BaseInfoLen + FileName.Length, sizeof(LONGLONG)));
FSP_FSCTL_ALIGN_UP(BaseInfoLen + CopyLength, sizeof(LONGLONG)));
if (ReturnSingleEntry)
/* cannot just break, *PDirInfo must be advanced */
@ -250,15 +261,18 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
}
except (EXCEPTION_EXECUTE_HANDLER)
{
NTSTATUS Result = GetExceptionCode();
Result = GetExceptionCode();
if (STATUS_INSUFFICIENT_RESOURCES == Result)
return Result;
return FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
}
/* our code flow should allow only these two status codes here */
ASSERT(STATUS_SUCCESS == Result || STATUS_BUFFER_OVERFLOW == Result);
*PDirInfo = DirInfo;
return STATUS_SUCCESS;
return Result;
#undef FILL_INFO
#undef FILL_INFO_BASE
@ -604,7 +618,7 @@ static NTSTATUS FspFsvolQueryDirectory(
return STATUS_INVALID_PARAMETER;
/* check that FileName is valid (if supplied) */
if (0 != FileName && !FspUnicodePathIsValid(FileName, FALSE))
if (0 != FileName && !FspUnicodePathIsValidPattern(FileName))
return STATUS_INVALID_PARAMETER;
/* is this an allowed file information class? */
@ -857,7 +871,7 @@ NTSTATUS FspFsvolDirectoryControlComplete(
if (FspFsctlTransactQueryDirectoryKind == Request->Kind)
{
DirInfoChangeNumber = FileNode->DirInfoChangeNumber;
DirInfoChangeNumber = FspFileNodeDirInfoChangeNumber(FileNode);
Request->Kind = FspFsctlTransactReservedKind;
FspIopResetRequest(Request, 0);
FspIopRequestContext(Request, RequestDirInfoChangeNumber) = (PVOID)DirInfoChangeNumber;

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -417,15 +417,27 @@ BOOLEAN FspExpirationTimeValid(UINT64 ExpirationTime)
return 1 >= ExpirationTime + 1 ? (0 != ExpirationTime) : (KeQueryInterruptTime() < ExpirationTime);
}
static inline
BOOLEAN FspExpirationTimeValidEx(UINT64 ExpirationTime, UINT64 CurrentTime)
{
/* if ExpirationTime is 0 or -1 then ExpirationTime else CurrentTime < ExpirationTime */
return 1 >= ExpirationTime + 1 ? (0 != ExpirationTime) : (CurrentTime < ExpirationTime);
}
static inline
BOOLEAN FspExpirationTimeValid2(UINT64 ExpirationTime, UINT64 CurrentTime)
{
return CurrentTime < ExpirationTime;
}
/* utility */
enum
{
FspUnicodePathStreamTypeNone = 0,
FspUnicodePathStreamTypeData = 1,
};
PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag);
PVOID FspAllocateIrpMustSucceed(CCHAR StackSize);
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams);
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType);
BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Pattern);
VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
NTSTATUS FspCreateGuid(GUID *Guid);
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
@ -722,6 +734,8 @@ enum
FspFsvolDeviceSecurityCacheItemSizeMax = 4096,
FspFsvolDeviceDirInfoCacheCapacity = 100,
FspFsvolDeviceDirInfoCacheItemSizeMax = FSP_FSCTL_ALIGN_UP(16384, PAGE_SIZE),
FspFsvolDeviceStreamInfoCacheCapacity = 100,
FspFsvolDeviceStreamInfoCacheItemSizeMax = FSP_FSCTL_ALIGN_UP(16384, PAGE_SIZE),
};
typedef struct
{
@ -748,7 +762,7 @@ typedef struct
typedef struct
{
FSP_DEVICE_EXTENSION Base;
UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1,
UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, InitDoneStrm:1,
InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1;
PDEVICE_OBJECT FsctlDeviceObject;
PDEVICE_OBJECT FsvrtDeviceObject;
@ -760,6 +774,7 @@ typedef struct
FSP_IOQ *Ioq;
FSP_META_CACHE *SecurityCache;
FSP_META_CACHE *DirInfoCache;
FSP_META_CACHE *StreamInfoCache;
KSPIN_LOCK ExpirationLock;
WORK_QUEUE_ITEM ExpirationWorkItem;
BOOLEAN ExpirationInProgress;
@ -888,10 +903,11 @@ typedef struct
ERESOURCE PagingIoResource;
FAST_MUTEX HeaderFastMutex;
SECTION_OBJECT_POINTERS SectionObjectPointers;
KSPIN_LOCK DirInfoSpinLock;
UINT64 DirInfo; /* allows to invalidate DirInfo w/o resources acquired */
KSPIN_LOCK NpInfoSpinLock; /* allows to invalidate non-page Info w/o resources acquired */
UINT64 DirInfo;
UINT64 StreamInfo;
} FSP_FILE_NODE_NONPAGED;
typedef struct
typedef struct FSP_FILE_NODE
{
FSRTL_ADVANCED_FCB_HEADER Header;
FSP_FILE_NODE_NONPAGED *NonPaged;
@ -902,22 +918,25 @@ typedef struct
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 */
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT ContextByNameElementStorage;
/* locked under FSP_FSVOL_DEVICE_EXTENSION::FileRenameResource or Header.Resource */
UNICODE_STRING FileName;
PWSTR ExternalFileName;
/* locked under Header.Resource */
UINT64 InfoExpirationTime;
UINT64 FileInfoExpirationTime, BasicInfoExpirationTime;
UINT32 FileAttributes;
UINT32 ReparseTag;
UINT64 CreationTime;
UINT64 LastAccessTime;
UINT64 LastWriteTime;
UINT64 ChangeTime;
ULONG InfoChangeNumber;
ULONG FileInfoChangeNumber;
UINT64 Security;
ULONG SecurityChangeNumber;
ULONG DirInfoChangeNumber;
ULONG StreamInfoChangeNumber;
BOOLEAN TruncateOnClose;
FILE_LOCK FileLock;
struct
@ -935,6 +954,7 @@ typedef struct
UINT64 IndexNumber;
BOOLEAN IsDirectory;
BOOLEAN IsRootDirectory;
struct FSP_FILE_NODE *MainFileNode; /* this becomes invalid after our last desc close */
WCHAR FileNameBuf[];
} FSP_FILE_NODE;
typedef struct
@ -949,6 +969,9 @@ typedef struct
UINT64 DirectoryOffset;
UINT64 DirInfo;
ULONG DirInfoCacheHint;
/* stream support */
HANDLE MainFileHandle;
PFILE_OBJECT MainFileObject;
} FSP_FILE_DESC;
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
@ -993,20 +1016,86 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo);
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
static inline
ULONG FspFileNodeFileInfoChangeNumber(FSP_FILE_NODE *FileNode)
{
if (0 != FileNode->MainFileNode)
return (FileNode->MainFileNode->FileInfoChangeNumber & 0xfffff) |
((FileNode->FileInfoChangeNumber & 0xfff) << 20);
else
return FileNode->FileInfoChangeNumber & 0xfffff;
}
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,
ULONG SecurityChangeNumber);
static inline
ULONG FspFileNodeSecurityChangeNumber(FSP_FILE_NODE *FileNode)
{
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
return FileNode->SecurityChangeNumber;
}
BOOLEAN FspFileNodeReferenceDirInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG DirInfoChangeNumber);
static inline
ULONG FspFileNodeDirInfoChangeNumber(FSP_FILE_NODE *FileNode)
{
return FileNode->DirInfoChangeNumber;
}
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 inline
ULONG FspFileNodeStreamInfoChangeNumber(FSP_FILE_NODE *FileNode)
{
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
return FileNode->StreamInfoChangeNumber;
}
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action);
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN Reset);
NTSTATUS FspMainFileOpen(
PDEVICE_OBJECT FsvolDeviceObject,
PDEVICE_OBJECT DeviceObjectHint,
PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive,
PSECURITY_DESCRIPTOR SecurityDescriptor,
ULONG FileAttributes,
ULONG Disposition,
PHANDLE PMainFileHandle,
PFILE_OBJECT *PMainFileObject);
NTSTATUS FspMainFileClose(
HANDLE MainFileHandle,
PFILE_OBJECT MainFileObject);
static __forceinline
BOOLEAN FspMainFileOpenCheck(PIRP Irp)
{
extern const GUID FspMainFileOpenEcpGuid;
NTSTATUS Result;
PECP_LIST ExtraCreateParameters = 0;
PVOID ExtraCreateParameter = 0;
Result = FsRtlGetEcpListFromIrp(Irp, &ExtraCreateParameters);
if (!NT_SUCCESS(Result) || 0 == ExtraCreateParameters)
return FALSE;
Result = FsRtlFindExtraCreateParameter(ExtraCreateParameters,
&FspMainFileOpenEcpGuid, &ExtraCreateParameter, 0);
if (!NT_SUCCESS(Result) || 0 == ExtraCreateParameter)
return FALSE;
if (FsRtlIsEcpFromUserMode(ExtraCreateParameter))
return FALSE;
return TRUE;
}
#define FspFileNodeAcquireShared(N,F) FspFileNodeAcquireSharedF(N, FspFileNodeAcquire ## F)
#define FspFileNodeTryAcquireShared(N,F) FspFileNodeTryAcquireSharedF(N, FspFileNodeAcquire ## F, FALSE)
#define FspFileNodeAcquireExclusive(N,F) FspFileNodeAcquireExclusiveF(N, FspFileNodeAcquire ## F)
@ -1017,6 +1106,7 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
#define FspFileNodeReleaseOwner(N,F,P) FspFileNodeReleaseOwnerF(N, FspFileNodeAcquire ## F, P)
#define FspFileNodeDereferenceSecurity(P) FspMetaCacheDereferenceItemBuffer(P)
#define FspFileNodeDereferenceDirInfo(P) FspMetaCacheDereferenceItemBuffer(P)
#define FspFileNodeDereferenceStreamInfo(P) FspMetaCacheDereferenceItemBuffer(P)
#define FspFileNodeUnlockAll(N,F,P) FsRtlFastUnlockAll(&(N)->FileLock, F, P, N)
/* multiversion support */
@ -1041,6 +1131,7 @@ extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[];
extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[];
extern ERESOURCE FspDeviceGlobalResource;
extern WCHAR FspFileDescDirectoryPatternMatchAll[];
extern const GUID FspMainFileOpenEcpGuid;
extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;
extern ULONG FspMvMdlMappingNoWrite;

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -57,6 +57,11 @@ 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);
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);
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
@ -65,6 +70,18 @@ NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN Reset);
NTSTATUS FspMainFileOpen(
PDEVICE_OBJECT FsvolDeviceObject,
PDEVICE_OBJECT DeviceObjectHint,
PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive,
PSECURITY_DESCRIPTOR SecurityDescriptor,
ULONG FileAttributes,
ULONG Disposition,
PHANDLE PMainFileHandle,
PFILE_OBJECT *PMainFileObject);
NTSTATUS FspMainFileClose(
HANDLE MainFileHandle,
PFILE_OBJECT MainFileObject);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFileNodeCopyList)
@ -97,12 +114,18 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
// !#pragma alloc_text(PAGE, FspFileNodeSetDirInfo)
// !#pragma alloc_text(PAGE, FspFileNodeTrySetDirInfo)
// !#pragma alloc_text(PAGE, FspFileNodeInvalidateDirInfo)
// !#pragma alloc_text(PAGE, FspFileNodeReferenceStreamInfo)
// !#pragma alloc_text(PAGE, FspFileNodeSetStreamInfo)
// !#pragma alloc_text(PAGE, FspFileNodeTrySetStreamInfo)
// !#pragma alloc_text(PAGE, FspFileNodeInvalidateStreamInfo)
#pragma alloc_text(PAGE, FspFileNodeNotifyChange)
#pragma alloc_text(PAGE, FspFileNodeProcessLockIrp)
#pragma alloc_text(PAGE, FspFileNodeCompleteLockIrp)
#pragma alloc_text(PAGE, FspFileDescCreate)
#pragma alloc_text(PAGE, FspFileDescDelete)
#pragma alloc_text(PAGE, FspFileDescResetDirectoryPattern)
#pragma alloc_text(PAGE, FspMainFileOpen)
#pragma alloc_text(PAGE, FspMainFileClose)
#endif
#define FSP_FILE_NODE_GET_FLAGS() \
@ -176,7 +199,7 @@ NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
ExInitializeResourceLite(&NonPaged->Resource);
ExInitializeResourceLite(&NonPaged->PagingIoResource);
ExInitializeFastMutex(&NonPaged->HeaderFastMutex);
KeInitializeSpinLock(&NonPaged->DirInfoSpinLock);
KeInitializeSpinLock(&NonPaged->NpInfoSpinLock);
RtlZeroMemory(FileNode, sizeof *FileNode + ExtraSize);
FileNode->Header.NodeTypeCode = FspFileNodeFileKind;
@ -211,6 +234,7 @@ VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode)
FsRtlTeardownPerStreamContexts(&FileNode->Header);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->StreamInfoCache, FileNode->NonPaged->StreamInfo);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, FileNode->NonPaged->DirInfo);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->SecurityCache, FileNode->Security);
@ -230,6 +254,9 @@ VOID FspFileNodeAcquireSharedF(FSP_FILE_NODE *FileNode, ULONG Flags)
{
PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FILE_NODE_GET_FLAGS();
FSP_FILE_NODE_ASSERT_FLAGS_CLR();
@ -246,6 +273,9 @@ BOOLEAN FspFileNodeTryAcquireSharedF(FSP_FILE_NODE *FileNode, ULONG Flags, BOOLE
{
PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FILE_NODE_GET_FLAGS();
FSP_FILE_NODE_ASSERT_FLAGS_CLR();
@ -279,6 +309,9 @@ VOID FspFileNodeAcquireExclusiveF(FSP_FILE_NODE *FileNode, ULONG Flags)
{
PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FILE_NODE_GET_FLAGS();
FSP_FILE_NODE_ASSERT_FLAGS_CLR();
@ -295,6 +328,9 @@ BOOLEAN FspFileNodeTryAcquireExclusiveF(FSP_FILE_NODE *FileNode, ULONG Flags, BO
{
PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FILE_NODE_GET_FLAGS();
FSP_FILE_NODE_ASSERT_FLAGS_CLR();
@ -328,6 +364,9 @@ VOID FspFileNodeConvertExclusiveToSharedF(FSP_FILE_NODE *FileNode, ULONG Flags)
{
PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FILE_NODE_GET_FLAGS();
if (Flags & FspFileNodeAcquirePgio)
@ -341,6 +380,9 @@ VOID FspFileNodeSetOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
{
PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FILE_NODE_GET_FLAGS();
Owner = (PVOID)((UINT_PTR)Owner | 3);
@ -356,6 +398,9 @@ VOID FspFileNodeReleaseF(FSP_FILE_NODE *FileNode, ULONG Flags)
{
PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FILE_NODE_GET_FLAGS();
FSP_FILE_NODE_ASSERT_FLAGS_SET();
@ -372,6 +417,9 @@ VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
{
PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FILE_NODE_GET_FLAGS();
FSP_FILE_NODE_ASSERT_FLAGS_SET();
@ -410,12 +458,43 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PAGED_CODE();
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FILE_NODE *OpenedFileNode;
FSP_FILE_NODE *OpenedFileNode = 0;
BOOLEAN Inserted, DeletePending;
NTSTATUS Result;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
/*
* If this is a named stream we must also check with our main file.
* Note that FileNode->MainFileNode and OpenedFileNode->MainFileNode
* will always be the same.
*/
if (0 != FileNode->MainFileNode)
{
DeletePending = 0 != FileNode->MainFileNode->DeletePending;
MemoryBarrier();
if (DeletePending)
{
Result = STATUS_DELETE_PENDING;
goto exit;
}
/*
* Sharing violations between main file and streams were determined
* through experimentation with NTFS. They may be wrong!
*/
if (0 < FileNode->MainFileNode->MainFileDenyDeleteCount)
{
if (!FlagOn(ShareAccess, FILE_SHARE_DELETE) &&
FlagOn(GrantedAccess,
FILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE))
{
Result = STATUS_SHARING_VIOLATION;
goto exit;
}
}
}
OpenedFileNode = FspFsvolDeviceInsertContextByName(FsvolDeviceObject,
&FileNode->FileName, FileNode, &FileNode->ContextByNameElementStorage, &Inserted);
ASSERT(0 != OpenedFileNode);
@ -439,6 +518,7 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
* opening a prior FileNode that we found in the table.
*/
ASSERT(OpenedFileNode != FileNode);
ASSERT(OpenedFileNode->MainFileNode == FileNode->MainFileNode);
DeletePending = 0 != OpenedFileNode->DeletePending;
MemoryBarrier();
@ -448,6 +528,22 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
goto exit;
}
/*
* Sharing violations between main file and streams were determined
* through experimentation with NTFS. They may be wrong!
*/
if (0 < OpenedFileNode->StreamDenyDeleteCount)
{
/* we must be the main file! */
ASSERT(0 == OpenedFileNode->MainFileNode);
if (FlagOn(GrantedAccess, DELETE))
{
Result = STATUS_SHARING_VIOLATION;
goto exit;
}
}
/*
* FastFat says to do the following on Vista and above.
*
@ -468,15 +564,41 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
/* share access check */
Result = IoCheckShareAccess(GrantedAccess, ShareAccess, FileObject,
&OpenedFileNode->ShareAccess, TRUE);
exit:
if (!NT_SUCCESS(Result))
{
if (0 != PResult)
*PResult = Result;
goto exit;
}
OpenedFileNode = 0;
}
/*
* No more failures allowed at this point!
* This is because we have potentially inserted a new FileNode into the Context table.
* We also updated OpenedFileNode->ShareAccess in IoSetShareAccess/IoCheckShareAccess.
*/
/*
* Sharing violations between main file and streams were determined
* through experimentation with NTFS. They may be wrong!
*/
if (0 == OpenedFileNode->MainFileNode)
{
if (FileObject->DeleteAccess)
OpenedFileNode->MainFileDenyDeleteCount++;
}
else
{
if ((FileObject->ReadAccess || FileObject->WriteAccess || FileObject->DeleteAccess) &&
!FileObject->SharedDelete)
OpenedFileNode->MainFileNode->StreamDenyDeleteCount++;
}
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
{
if (0 != PResult)
*PResult = Result;
OpenedFileNode = 0;
}
if (0 != OpenedFileNode)
@ -546,6 +668,22 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
/*
* Sharing violations between main file and streams were determined
* through experimentation with NTFS. They may be wrong!
*/
if (0 == FileNode->MainFileNode)
{
if (FileObject->DeleteAccess)
FileNode->MainFileDenyDeleteCount--;
}
else
{
if ((FileObject->ReadAccess || FileObject->WriteAccess || FileObject->DeleteAccess) &&
!FileObject->SharedDelete)
FileNode->MainFileNode->StreamDenyDeleteCount--;
}
IoRemoveShareAccess(FileObject, &FileNode->ShareAccess);
if (0 == --FileNode->HandleCount)
@ -717,7 +855,14 @@ VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileIn
FileInfo->AllocationSize = FileNode->Header.AllocationSize.QuadPart;
FileInfo->FileSize = FileNode->Header.FileSize.QuadPart;
FileInfo->FileAttributes = FileNode->FileAttributes;
UINT32 FileAttributesMask = ~(UINT32)0;
if (0 != FileNode->MainFileNode)
{
FileAttributesMask = ~(UINT32)FILE_ATTRIBUTE_DIRECTORY;
FileNode = FileNode->MainFileNode;
}
FileInfo->FileAttributes = FileNode->FileAttributes & FileAttributesMask;
FileInfo->ReparseTag = FileNode->ReparseTag;
FileInfo->CreationTime = FileNode->CreationTime;
FileInfo->LastAccessTime = FileNode->LastAccessTime;
@ -729,25 +874,20 @@ BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *
{
PAGED_CODE();
BOOLEAN Result;
UINT64 CurrentTime = KeQueryInterruptTime();
if (FspExpirationTimeValid(FileNode->InfoExpirationTime))
if (0 != FileNode->MainFileNode)
{
FileInfo->AllocationSize = FileNode->Header.AllocationSize.QuadPart;
FileInfo->FileSize = FileNode->Header.FileSize.QuadPart;
FileInfo->FileAttributes = FileNode->FileAttributes;
FileInfo->ReparseTag = FileNode->ReparseTag;
FileInfo->CreationTime = FileNode->CreationTime;
FileInfo->LastAccessTime = FileNode->LastAccessTime;
FileInfo->LastWriteTime = FileNode->LastWriteTime;
FileInfo->ChangeTime = FileNode->ChangeTime;
Result = TRUE;
/* if this is a stream the main file basic info must have not expired as well! */
if (!FspExpirationTimeValidEx(FileNode->MainFileNode->BasicInfoExpirationTime, CurrentTime))
return FALSE;
}
else
Result = FALSE;
return Result;
if (!FspExpirationTimeValidEx(FileNode->FileInfoExpirationTime, CurrentTime))
return FALSE;
FspFileNodeGetFileInfo(FileNode, FileInfo);
return TRUE;
}
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
@ -768,15 +908,29 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
FileNode->Header.AllocationSize.QuadPart = AllocationSize;
FileNode->Header.FileSize.QuadPart = FileInfo->FileSize;
FileNode->FileAttributes = FileInfo->FileAttributes;
FileNode->ReparseTag = FileInfo->ReparseTag;
FileNode->CreationTime = FileInfo->CreationTime;
FileNode->LastAccessTime = FileInfo->LastAccessTime;
FileNode->LastWriteTime = FileInfo->LastWriteTime;
FileNode->ChangeTime = FileInfo->ChangeTime;
FileNode->InfoExpirationTime = FspExpirationTimeFromMillis(
FsvolDeviceExtension->VolumeParams.FileInfoTimeout);
FileNode->InfoChangeNumber++;
FileNode->FileInfoExpirationTime = FileNode->BasicInfoExpirationTime =
FspExpirationTimeFromMillis(FsvolDeviceExtension->VolumeParams.FileInfoTimeout);
FileNode->FileInfoChangeNumber++;
FSP_FILE_NODE *MainFileNode = FileNode;
UINT32 FileAttributesMask = ~(UINT32)0;
if (0 != FileNode->MainFileNode)
{
FileAttributesMask = ~(UINT32)FILE_ATTRIBUTE_DIRECTORY;
MainFileNode = FileNode->MainFileNode;
MainFileNode->BasicInfoExpirationTime = FileNode->BasicInfoExpirationTime;
MainFileNode->FileInfoChangeNumber++;
}
MainFileNode->FileAttributes =
(MainFileNode->FileAttributes & ~FileAttributesMask) |
(FileInfo->FileAttributes & FileAttributesMask);
MainFileNode->ReparseTag = FileInfo->ReparseTag;
MainFileNode->CreationTime = FileInfo->CreationTime;
MainFileNode->LastAccessTime = FileInfo->LastAccessTime;
MainFileNode->LastWriteTime = FileInfo->LastWriteTime;
MainFileNode->ChangeTime = FileInfo->ChangeTime;
if (0 != CcFileObject)
{
@ -796,7 +950,7 @@ BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileOb
{
PAGED_CODE();
if (FileNode->InfoChangeNumber != InfoChangeNumber)
if (FspFileNodeFileInfoChangeNumber(FileNode) != InfoChangeNumber)
return FALSE;
FspFileNodeSetFileInfo(FileNode, CcFileObject, FileInfo);
@ -807,6 +961,9 @@ BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, P
{
PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
@ -818,6 +975,9 @@ VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size)
{
PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
@ -832,7 +992,7 @@ BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG
{
PAGED_CODE();
if (FileNode->SecurityChangeNumber != SecurityChangeNumber)
if (FspFileNodeSecurityChangeNumber(FileNode) != SecurityChangeNumber)
return FALSE;
FspFileNodeSetSecurity(FileNode, Buffer, Size);
@ -848,7 +1008,7 @@ BOOLEAN FspFileNodeReferenceDirInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PU
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
UINT64 DirInfo;
/* no need to acquire the DirInfoSpinLock as the FileNode is acquired */
/* no need to acquire the NpInfoSpinLock as the FileNode is acquired */
DirInfo = NonPaged->DirInfo;
return FspMetaCacheReferenceItemBuffer(FsvolDeviceExtension->DirInfoCache,
@ -865,7 +1025,7 @@ VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size)
KIRQL Irql;
UINT64 DirInfo;
/* no need to acquire the DirInfoSpinLock as the FileNode is acquired */
/* no need to acquire the NpInfoSpinLock as the FileNode is acquired */
DirInfo = NonPaged->DirInfo;
FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, DirInfo);
@ -873,10 +1033,10 @@ VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size)
FspMetaCacheAddItem(FsvolDeviceExtension->DirInfoCache, Buffer, Size) : 0;
FileNode->DirInfoChangeNumber++;
/* acquire the DirInfoSpinLock to protect against concurrent FspFileNodeInvalidateDirInfo */
KeAcquireSpinLock(&NonPaged->DirInfoSpinLock, &Irql);
/* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeInvalidateDirInfo */
KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql);
NonPaged->DirInfo = DirInfo;
KeReleaseSpinLock(&NonPaged->DirInfoSpinLock, Irql);
KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql);
}
BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
@ -884,7 +1044,7 @@ BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG S
{
// !PAGED_CODE();
if (FileNode->DirInfoChangeNumber != DirInfoChangeNumber)
if (FspFileNodeDirInfoChangeNumber(FileNode) != DirInfoChangeNumber)
return FALSE;
FspFileNodeSetDirInfo(FileNode, Buffer, Size);
@ -901,14 +1061,93 @@ static VOID FspFileNodeInvalidateDirInfo(FSP_FILE_NODE *FileNode)
KIRQL Irql;
UINT64 DirInfo;
/* acquire the DirInfoSpinLock to protect against concurrent FspFileNodeSetDirInfo */
KeAcquireSpinLock(&NonPaged->DirInfoSpinLock, &Irql);
/* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeSetDirInfo */
KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql);
DirInfo = NonPaged->DirInfo;
KeReleaseSpinLock(&NonPaged->DirInfoSpinLock, Irql);
KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, DirInfo);
}
BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize)
{
// !PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
UINT64 StreamInfo;
/* no need to acquire the NpInfoSpinLock as the FileNode is acquired */
StreamInfo = NonPaged->StreamInfo;
return FspMetaCacheReferenceItemBuffer(FsvolDeviceExtension->StreamInfoCache,
StreamInfo, PBuffer, PSize);
}
VOID FspFileNodeSetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size)
{
// !PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
KIRQL Irql;
UINT64 StreamInfo;
/* no need to acquire the NpInfoSpinLock as the FileNode is acquired */
StreamInfo = NonPaged->StreamInfo;
FspMetaCacheInvalidateItem(FsvolDeviceExtension->StreamInfoCache, StreamInfo);
StreamInfo = 0 != Buffer ?
FspMetaCacheAddItem(FsvolDeviceExtension->StreamInfoCache, Buffer, Size) : 0;
FileNode->StreamInfoChangeNumber++;
/* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeInvalidateStreamInfo */
KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql);
NonPaged->StreamInfo = StreamInfo;
KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql);
}
BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG StreamInfoChangeNumber)
{
// !PAGED_CODE();
if (FspFileNodeStreamInfoChangeNumber(FileNode) != StreamInfoChangeNumber)
return FALSE;
FspFileNodeSetStreamInfo(FileNode, Buffer, Size);
return TRUE;
}
static VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode)
{
// !PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
KIRQL Irql;
UINT64 StreamInfo;
/* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeSetStreamInfo */
KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql);
StreamInfo = NonPaged->StreamInfo;
KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->StreamInfoCache, StreamInfo);
}
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
ULONG Filter, ULONG Action)
{
@ -946,11 +1185,38 @@ VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
break;
}
FspNotifyReportChange(
FsvolDeviceExtension->NotifySync, &FsvolDeviceExtension->NotifyList,
&FileNode->FileName,
(USHORT)((PUINT8)Suffix.Buffer - (PUINT8)FileNode->FileName.Buffer),
0, Filter, Action);
if (0 != FileNode->MainFileNode)
{
if (FlagOn(Filter, FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME))
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));
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)
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)
@ -1008,6 +1274,8 @@ VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc)
{
PAGED_CODE();
FspMainFileClose(FileDesc->MainFileHandle, FileDesc->MainFileObject);
if (0 != FileDesc->DirectoryPattern.Buffer &&
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer)
{
@ -1067,4 +1335,172 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
return STATUS_SUCCESS;
}
NTSTATUS FspMainFileOpen(
PDEVICE_OBJECT FsvolDeviceObject,
PDEVICE_OBJECT DeviceObjectHint,
PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive,
PSECURITY_DESCRIPTOR SecurityDescriptor,
ULONG FileAttributes,
ULONG Disposition,
PHANDLE PMainFileHandle,
PFILE_OBJECT *PMainFileObject)
{
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
UNICODE_STRING FullFileName = { 0 };
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatus;
IO_DRIVER_CREATE_CONTEXT DriverCreateContext = { 0 };
PVOID ExtraCreateParameter;
HANDLE MainFileHandle;
PFILE_OBJECT MainFileObject;
/* assert that the supplied name is actually a main file name */
ASSERT(FspUnicodePathIsValid(MainFileName, 0, 0));
*PMainFileHandle = 0;
*PMainFileObject = 0;
switch (Disposition)
{
case FILE_CREATE:
case FILE_OPEN_IF:
case FILE_OVERWRITE_IF:
Disposition = FILE_OPEN_IF;
break;
case FILE_OPEN:
case FILE_OVERWRITE:
case FILE_SUPERSEDE:
Disposition = FILE_OPEN;
break;
default:
IoStatus.Status = STATUS_INVALID_PARAMETER;
goto exit;
}
FullFileName.Length = 0;
FullFileName.MaximumLength =
FsvolDeviceExtension->VolumeName.Length +
FsvolDeviceExtension->VolumePrefix.Length +
MainFileName->Length;
FullFileName.Buffer = FspAlloc(FullFileName.MaximumLength);
if (0 == FullFileName.Buffer)
{
IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
RtlAppendUnicodeStringToString(&FullFileName, &FsvolDeviceExtension->VolumeName);
RtlAppendUnicodeStringToString(&FullFileName, &FsvolDeviceExtension->VolumePrefix);
RtlAppendUnicodeStringToString(&FullFileName, MainFileName);
InitializeObjectAttributes(
&ObjectAttributes,
&FullFileName,
OBJ_KERNEL_HANDLE | OBJ_FORCE_ACCESS_CHECK | (CaseSensitive ? 0 : OBJ_CASE_INSENSITIVE),
0/*RootDirectory*/,
SecurityDescriptor);
/* do not use SiloContext field as it is only available on Win10 v1607 and higher */
DriverCreateContext.Size =
FIELD_OFFSET(IO_DRIVER_CREATE_CONTEXT, TxnParameters) +
sizeof(((PIO_DRIVER_CREATE_CONTEXT)0)->TxnParameters);
DriverCreateContext.DeviceObjectHint = 0 != FsvolDeviceExtension->FsvrtDeviceObject ?
FsvolDeviceObject : DeviceObjectHint;
IoStatus.Status = FsRtlAllocateExtraCreateParameterList(0,
&DriverCreateContext.ExtraCreateParameter);
if (!NT_SUCCESS(IoStatus.Status))
goto exit;
IoStatus.Status = FsRtlAllocateExtraCreateParameter(&FspMainFileOpenEcpGuid,
sizeof(PVOID),
0/*Flags*/,
0/*CleanupCallback*/,
FSP_ALLOC_INTERNAL_TAG,
&ExtraCreateParameter);
if (!NT_SUCCESS(IoStatus.Status))
goto exit;
IoStatus.Status = FsRtlInsertExtraCreateParameter(DriverCreateContext.ExtraCreateParameter,
ExtraCreateParameter);
if (!NT_SUCCESS(IoStatus.Status))
{
FsRtlFreeExtraCreateParameter(ExtraCreateParameter);
goto exit;
}
IoStatus.Status = IoCreateFileEx(
&MainFileHandle,
FILE_READ_ATTRIBUTES,
&ObjectAttributes,
&IoStatus,
0/*AllocationSize*/,
FileAttributes,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
Disposition,
FILE_OPEN_REPARSE_POINT,
0/*EaBuffer*/,
0/*EaLength*/,
CreateFileTypeNone,
0/*InternalParameters*/,
IO_FORCE_ACCESS_CHECK,
&DriverCreateContext);
if (!NT_SUCCESS(IoStatus.Status))
goto exit;
IoStatus.Status = ObReferenceObjectByHandle(
MainFileHandle,
0/*DesiredAccess*/,
*IoFileObjectType,
KernelMode,
&MainFileObject,
0/*HandleInformation*/);
if (!NT_SUCCESS(IoStatus.Status))
{
ObCloseHandle(MainFileHandle, KernelMode);
goto exit;
}
*PMainFileHandle = MainFileHandle;
*PMainFileObject = MainFileObject;
IoStatus.Status = STATUS_SUCCESS;
exit:
if (0 != DriverCreateContext.ExtraCreateParameter)
FsRtlFreeExtraCreateParameterList(DriverCreateContext.ExtraCreateParameter);
if (0 != FullFileName.Buffer)
FspFree(FullFileName.Buffer);
return IoStatus.Status;
}
NTSTATUS FspMainFileClose(
HANDLE MainFileHandle,
PFILE_OBJECT MainFileObject)
{
PAGED_CODE();
NTSTATUS Result = STATUS_SUCCESS;
if (0 != MainFileObject)
ObDereferenceObject(MainFileObject);
if (0 != MainFileHandle)
{
Result = ObCloseHandle(MainFileHandle, KernelMode);
if (!NT_SUCCESS(Result))
DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result));
}
return Result;
}
WCHAR FspFileDescDirectoryPatternMatchAll[] = L"*";
// {904862B4-EB3F-461E-ACB2-4DF2B3FC898B}
const GUID FspMainFileOpenEcpGuid =
{ 0x904862b4, 0xeb3f, 0x461e, { 0xac, 0xb2, 0x4d, 0xf2, 0xb3, 0xfc, 0x89, 0x8b } };

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -38,6 +38,13 @@ static NTSTATUS FspFsvolQueryPositionInformation(PFILE_OBJECT FileObject,
static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd,
const FSP_FSCTL_FILE_INFO *FileInfo);
static NTSTATUS FspFsvolQueryStreamInformationCopy(
FSP_FSCTL_STREAM_INFO *StreamInfoBuffer, ULONG StreamInfoBufferSize,
PVOID DestBuf, PULONG PDestLen);
static NTSTATUS FspFsvolQueryStreamInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolQueryStreamInformationSuccess(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
static NTSTATUS FspFsvolQueryInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolQueryInformationComplete;
@ -78,6 +85,9 @@ FSP_DRIVER_DISPATCH FspSetInformation;
#pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation)
#pragma alloc_text(PAGE, FspFsvolQueryPositionInformation)
#pragma alloc_text(PAGE, FspFsvolQueryStandardInformation)
#pragma alloc_text(PAGE, FspFsvolQueryStreamInformationCopy)
#pragma alloc_text(PAGE, FspFsvolQueryStreamInformation)
#pragma alloc_text(PAGE, FspFsvolQueryStreamInformationSuccess)
#pragma alloc_text(PAGE, FspFsvolQueryInformation)
#pragma alloc_text(PAGE, FspFsvolQueryInformationComplete)
#pragma alloc_text(PAGE, FspFsvolQueryInformationRequestFini)
@ -349,6 +359,235 @@ static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject,
return STATUS_SUCCESS;
}
static NTSTATUS FspFsvolQueryStreamInformationCopy(
FSP_FSCTL_STREAM_INFO *StreamInfo, ULONG StreamInfoSize,
PVOID DestBuf, PULONG PDestLen)
{
#define STREAM_TYPE ":$DATA"
#define STREAM_TYPE_LENGTH (sizeof L"" STREAM_TYPE - sizeof(WCHAR))
#define STREAM_EXTRA_LENGTH (sizeof L":" STREAM_TYPE - sizeof(WCHAR))
#define FILL_INFO()\
do\
{\
FILE_STREAM_INFORMATION InfoStruct = { 0 }, *Info = &InfoStruct;\
Info->NextEntryOffset = 0;\
Info->StreamNameLength = StreamNameLength;\
Info->StreamSize.QuadPart = StreamInfo->StreamSize;\
Info->StreamAllocationSize.QuadPart = StreamInfo->StreamAllocationSize;\
Info = DestBuf;\
RtlCopyMemory(Info, &InfoStruct, FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName));\
{\
PWSTR StreamName = Info->StreamName;\
ULONG Length[3];\
Length[0] = 0 < CopyLength ? sizeof(WCHAR) : 0;\
Length[1] = Info->StreamNameLength - STREAM_EXTRA_LENGTH < CopyLength - Length[0] ?\
Info->StreamNameLength - STREAM_EXTRA_LENGTH : CopyLength - Length[0];\
Length[2] = CopyLength - Length[0] - Length[1];\
ASSERT(\
sizeof(WCHAR) >= Length[0] &&\
Info->StreamNameLength - STREAM_EXTRA_LENGTH >= Length[1] &&\
STREAM_TYPE_LENGTH >= Length[2]);\
RtlCopyMemory(StreamName, L":", Length[0]);\
StreamName += Length[0] / sizeof(WCHAR);\
RtlCopyMemory(StreamName, StreamInfo->StreamNameBuf, Length[1]);\
StreamName += Length[1] / sizeof(WCHAR);\
RtlCopyMemory(StreamName, L"" STREAM_TYPE, Length[2]);\
}\
} while (0,0)
PAGED_CODE();
NTSTATUS Result = STATUS_SUCCESS;
PUINT8 StreamInfoEnd = (PUINT8)StreamInfo + StreamInfoSize;
PUINT8 DestBufBgn = (PUINT8)DestBuf;
PUINT8 DestBufEnd = (PUINT8)DestBuf + *PDestLen;
PVOID PrevDestBuf = 0;
ULONG StreamNameLength, CopyLength;
ULONG BaseInfoLen = FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName);
*PDestLen = 0;
for (;
NT_SUCCESS(Result) && (PUINT8)StreamInfo + sizeof(StreamInfo->Size) <= StreamInfoEnd;
StreamInfo = (PVOID)((PUINT8)StreamInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(StreamInfoSize)))
{
StreamInfoSize = StreamInfo->Size;
if (sizeof(FSP_FSCTL_STREAM_INFO) > StreamInfoSize)
break;
StreamNameLength = StreamInfoSize - sizeof(FSP_FSCTL_STREAM_INFO) + STREAM_EXTRA_LENGTH;
/* CopyLength is the same as StreamNameLength except on STATUS_BUFFER_OVERFLOW */
CopyLength = StreamNameLength;
/* do we have enough space for this stream info? */
if ((PUINT8)DestBuf + BaseInfoLen + CopyLength > DestBufEnd)
{
/* can we even copy the base info? */
if ((PUINT8)DestBuf + BaseInfoLen > DestBufEnd)
{
if (0 == *PDestLen)
/* if we haven't copied anything yet, buffer is too small */
return STATUS_BUFFER_TOO_SMALL;
else
/* *PDestLen contains bytes copied so far */
return STATUS_BUFFER_OVERFLOW;
}
/* copy as much of the stream name as we can and return STATUS_BUFFER_OVERFLOW */
CopyLength = (ULONG)(DestBufEnd - ((PUINT8)DestBuf + BaseInfoLen));
Result = STATUS_BUFFER_OVERFLOW;
}
/* fill in NextEntryOffset */
if (0 != PrevDestBuf)
*(PULONG)PrevDestBuf = (ULONG)((PUINT8)DestBuf - (PUINT8)PrevDestBuf);
PrevDestBuf = DestBuf;
/* update bytes copied */
*PDestLen = (ULONG)((PUINT8)DestBuf + BaseInfoLen + CopyLength - DestBufBgn);
FILL_INFO();
/* advance DestBuf; make sure to align properly! */
DestBuf = (PVOID)((PUINT8)DestBuf +
FSP_FSCTL_ALIGN_UP(BaseInfoLen + CopyLength, sizeof(LONGLONG)));
}
/* our code flow should allow only these two status codes here */
ASSERT(STATUS_SUCCESS == Result || STATUS_BUFFER_OVERFLOW == Result);
return Result;
#undef FILL_INFO
#undef STREAM_EXTRA_LENGTH
#undef STREAM_TYPE_LENGTH
#undef STREAM_TYPE
}
static NTSTATUS FspFsvolQueryStreamInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
if (!FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.NamedStreams)
return STATUS_INVALID_PARAMETER;
NTSTATUS Result;
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
ULONG Length = IrpSp->Parameters.QueryFile.Length;
PVOID StreamInfoBuffer;
ULONG StreamInfoBufferSize;
FSP_FSCTL_TRANSACT_REQ *Request;
ASSERT(FileNode == FileDesc->FileNode);
FspFileNodeAcquireShared(FileNode, Main);
if (FspFileNodeReferenceStreamInfo(FileNode, &StreamInfoBuffer, &StreamInfoBufferSize))
{
FspFileNodeRelease(FileNode, Main);
Result = FspFsvolQueryStreamInformationCopy(
StreamInfoBuffer, StreamInfoBufferSize, Buffer, &Length);
FspFileNodeDereferenceStreamInfo(StreamInfoBuffer);
Irp->IoStatus.Information = Length;
return Result;
}
FspFileNodeAcquireShared(FileNode, Pgio);
Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolQueryInformationRequestFini, &Request);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
return Result;
}
Request->Kind = FspFsctlTransactQueryStreamInformationKind;
Request->Req.QueryStreamInformation.UserContext = FileNode->UserContext;
Request->Req.QueryStreamInformation.UserContext2 = FileDesc->UserContext2;
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
return FSP_STATUS_IOQ_POST;
}
static NTSTATUS FspFsvolQueryStreamInformationSuccess(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
{
PAGED_CODE();
if (!FspFsvolDeviceExtension(IoGetCurrentIrpStackLocation(Irp)->DeviceObject)->
VolumeParams.NamedStreams)
return STATUS_INVALID_PARAMETER;
NTSTATUS Result;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
ULONG Length = IrpSp->Parameters.QueryFile.Length;
PVOID StreamInfoBuffer = 0;
ULONG StreamInfoBufferSize = 0;
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
BOOLEAN Success;
if (0 != FspIopRequestContext(Request, RequestFileNode))
{
/* check that the stream info we got back is valid */
if (Response->Buffer + Response->Rsp.QueryStreamInformation.Buffer.Size >
(PUINT8)Response + Response->Size)
{
Irp->IoStatus.Information = 0;
return STATUS_INFO_LENGTH_MISMATCH; /* ???: what is the best code to return here? */
}
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)
FspFileNodeStreamInfoChangeNumber(FileNode);
FspIopRequestContext(Request, RequestFileNode) = 0;
FspFileNodeReleaseOwner(FileNode, Full, Request);
}
Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusive(FileNode, Main);
if (!Success)
{
FspIopRetryCompleteIrp(Irp, Response, &Result);
return Result;
}
Success = !FspFileNodeTrySetStreamInfo(FileNode,
Response->Buffer, Response->Rsp.QueryStreamInformation.Buffer.Size,
(ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestInfoChangeNumber));
Success = Success &&
FspFileNodeReferenceStreamInfo(FileNode, &StreamInfoBuffer, &StreamInfoBufferSize);
FspFileNodeRelease(FileNode, Main);
if (Success)
{
Result = FspFsvolQueryStreamInformationCopy(
StreamInfoBuffer, StreamInfoBufferSize, Buffer, &Length);
FspFileNodeDereferenceStreamInfo(StreamInfoBuffer);
}
else
{
StreamInfoBuffer = (PVOID)Response->Buffer;
StreamInfoBufferSize = Response->Rsp.QueryStreamInformation.Buffer.Size;
Result = FspFsvolQueryStreamInformationCopy(
StreamInfoBuffer, StreamInfoBufferSize, Buffer, &Length);
}
Irp->IoStatus.Information = Length;
return Result;
}
static NTSTATUS FspFsvolQueryInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
@ -358,8 +597,13 @@ static NTSTATUS FspFsvolQueryInformation(
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
return STATUS_INVALID_DEVICE_REQUEST;
NTSTATUS Result;
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
/* special case FileStreamInformation */
if (FileStreamInformation == FileInformationClass)
return FspFsvolQueryStreamInformation(FsvolDeviceObject, Irp, IrpSp);
NTSTATUS Result;
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
@ -415,9 +659,6 @@ static NTSTATUS FspFsvolQueryInformation(
case FileStandardInformation:
Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, 0);
break;
case FileStreamInformation:
Result = STATUS_INVALID_PARAMETER; /* !!!: no stream support yet! */
return Result;
default:
Result = STATUS_INVALID_PARAMETER;
return Result;
@ -496,6 +737,11 @@ NTSTATUS FspFsvolQueryInformationComplete(
}
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
/* special case FileStreamInformation */
if (FileStreamInformation == FileInformationClass)
FSP_RETURN(Result = FspFsvolQueryStreamInformationSuccess(Irp, Response));
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
@ -507,7 +753,8 @@ NTSTATUS FspFsvolQueryInformationComplete(
if (0 != FspIopRequestContext(Request, RequestFileNode))
{
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)FileNode->InfoChangeNumber;
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)
FspFileNodeFileInfoChangeNumber(FileNode);
FspIopRequestContext(Request, RequestFileNode) = 0;
FspFileNodeReleaseOwner(FileNode, Full, Request);
@ -869,7 +1116,7 @@ static NTSTATUS FspFsvolSetRenameInformation(
if (FileNode->IsRootDirectory)
/* cannot rename root directory */
return STATUS_INVALID_PARAMETER;
if (!FspUnicodePathIsValid(&FileNode->FileName, FALSE))
if (!FspUnicodePathIsValid(&FileNode->FileName, 0, 0))
/* cannot rename streams (WinFsp limitation) */
return STATUS_INVALID_PARAMETER;
@ -894,7 +1141,7 @@ static NTSTATUS FspFsvolSetRenameInformation(
if (L'\\' == Suffix.Buffer[0])
FspUnicodePathSuffix(&Suffix, &NewFileName, &Suffix);
if (!FspUnicodePathIsValid(&Remain, FALSE) || !FspUnicodePathIsValid(&Suffix, FALSE))
if (!FspUnicodePathIsValid(&Remain, 0, 0) || !FspUnicodePathIsValid(&Suffix, 0, 0))
{
/* cannot rename streams (WinFsp limitation) */
Result = STATUS_INVALID_PARAMETER;

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -146,7 +146,8 @@ NTSTATUS FspFsvolQuerySecurityComplete(
FSP_RETURN();
}
FspIopRequestContext(Request, RequestSecurityChangeNumber) = (PVOID)FileNode->SecurityChangeNumber;
FspIopRequestContext(Request, RequestSecurityChangeNumber) = (PVOID)
FspFileNodeSecurityChangeNumber(FileNode);
FspIopRequestContext(Request, RequestFileNode) = 0;
FspFileNodeReleaseOwner(FileNode, Full, Request);

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -17,7 +17,8 @@
#include <sys/driver.h>
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams);
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType);
BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Pattern);
VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
NTSTATUS FspCreateGuid(GUID *Guid);
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
@ -88,6 +89,7 @@ NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspUnicodePathIsValid)
#pragma alloc_text(PAGE, FspUnicodePathIsValidPattern)
#pragma alloc_text(PAGE, FspUnicodePathSuffix)
#pragma alloc_text(PAGE, FspCreateGuid)
#pragma alloc_text(PAGE, FspGetDeviceObjectPointer)
@ -169,32 +171,138 @@ PVOID FspAllocateIrpMustSucceed(CCHAR StackSize)
}
}
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams)
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType)
{
/* this does NOT check if the Path contains invalid file name chars (*, ?, etc.) */
PAGED_CODE();
/* if StreamPart is not NULL, StreamType must also be not NULL */
ASSERT(0 == StreamPart || 0 != StreamType);
if (0 != Path->Length % sizeof(WCHAR))
return FALSE;
PWSTR PathBgn, PathEnd, PathPtr;
PWSTR PathBgn, PathEnd, PathPtr, StreamTypeStr = 0;
UCHAR Flags = FSRTL_NTFS_LEGAL;
ULONG Colons = 0;
WCHAR Char;
PathBgn = Path->Buffer;
PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length);
PathPtr = PathBgn;
while (PathEnd > PathPtr)
if (L'\\' == *PathPtr)
{
Char = *PathPtr;
if (L'\\' == Char)
{
/* stream names can only appear as the last path component */
if (0 < Colons)
return FALSE;
PathPtr++;
/* don't like multiple backslashes */
if (PathEnd > PathPtr && L'\\' == *PathPtr)
return FALSE;
}
else if (!AllowStreams && L':' == *PathPtr)
else if (L':' == Char)
{
if (0 == StreamPart)
return FALSE;
/*
* Where are the docs on legal stream names?
*/
/* stream characters now allowed */
Flags = FSRTL_NTFS_STREAM_LEGAL;
PathPtr++;
Colons++;
if (1 == Colons)
{
/* first time through: set up StreamPart */
StreamPart->Length = StreamPart->MaximumLength = (USHORT)
((PUINT8)PathEnd - (PUINT8)PathPtr);
StreamPart->Buffer = PathPtr;
}
else if (2 == Colons)
{
/* second time through: fix StreamPart length to not include 2nd colon */
StreamPart->Length = (USHORT)
((PUINT8)PathPtr - (PUINT8)StreamPart->Buffer - sizeof(WCHAR));
StreamTypeStr = PathPtr;
}
}
else if (0x80 > Char && !FsRtlTestAnsiCharacter(Char, TRUE, FALSE, Flags))
return FALSE;
else
PathPtr++;
}
/* if we had no colons the path is valid */
if (0 == Colons)
return TRUE;
ASSERT(0 != StreamPart && 0 != StreamType);
*StreamType = FspUnicodePathStreamTypeNone;
/* if we had no stream type the path is valid if there was an actual stream name */
if (0 == StreamTypeStr)
return 0 != StreamPart->Length;
/* if we had a stream type the path is valid if the stream type was "$DATA" only */
if (StreamTypeStr + 5 == PathEnd &&
L'$' == StreamTypeStr[0] &&
L'D' == StreamTypeStr[1] &&
L'A' == StreamTypeStr[2] &&
L'T' == StreamTypeStr[3] &&
L'A' == StreamTypeStr[4])
{
*StreamType = FspUnicodePathStreamTypeData;
return TRUE;
}
return FALSE;
}
BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Path)
{
PAGED_CODE();
if (0 != Path->Length % sizeof(WCHAR))
return FALSE;
PWSTR PathBgn, PathEnd, PathPtr;
WCHAR Char;
PathBgn = Path->Buffer;
PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length);
PathPtr = PathBgn;
while (PathEnd > PathPtr)
{
Char = *PathPtr;
/*
* A pattern is allowed to have wildcards. It cannot consist of multiple
* path components (have a backslash) and it cannot reference a stream (have
* a colon).
*/
if (L'\\' == Char)
return FALSE;
else if (L':' == Char)
return FALSE;
else if (0x80 > Char && !FsRtlTestAnsiCharacter(Char, TRUE, TRUE, FSRTL_NTFS_LEGAL))
return FALSE;
else
PathPtr++;
}
return TRUE;
}

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -79,6 +79,10 @@ static NTSTATUS FspFsvolQueryFsAttributeInformation(
PFILE_FS_ATTRIBUTE_INFORMATION Info = (PFILE_FS_ATTRIBUTE_INFORMATION)*PBuffer;
PUINT8 Buffer = (PUINT8)Info->FileSystemName;
ULONG CopyLength;
UNICODE_STRING FileSystemName;
WCHAR FileSystemNameBuf[16 + FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
ASSERT(sizeof FileSystemNameBuf >= sizeof L"" DRIVER_NAME + FSP_FSCTL_VOLUME_FSNAME_SIZE);
Info->FileSystemAttributes =
(FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch ? FILE_CASE_SENSITIVE_SEARCH : 0) |
@ -91,15 +95,27 @@ static NTSTATUS FspFsvolQueryFsAttributeInformation(
//(FsvolDeviceExtension->VolumeParams.ExtendedAttributes ? FILE_SUPPORTS_EXTENDED_ATTRIBUTES : 0) |
(FsvolDeviceExtension->VolumeParams.ReadOnlyVolume ? FILE_READ_ONLY_VOLUME : 0);
Info->MaximumComponentNameLength = FsvolDeviceExtension->VolumeParams.MaxComponentLength;
Info->FileSystemNameLength = sizeof L"" DRIVER_NAME - sizeof(WCHAR);
CopyLength = Info->FileSystemNameLength;
RtlInitUnicodeString(&FileSystemName, FsvolDeviceExtension->VolumeParams.FileSystemName);
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;
}
Info->FileSystemNameLength = CopyLength;
if (Buffer + CopyLength > BufferEnd)
{
CopyLength = (ULONG)(BufferEnd - Buffer);
Result = STATUS_BUFFER_OVERFLOW;
}
RtlCopyMemory(Buffer, L"" DRIVER_NAME, CopyLength);
RtlCopyMemory(Buffer, FileSystemNameBuf, CopyLength);
Buffer += CopyLength;
*PBuffer = Buffer;

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -169,6 +169,7 @@ static NTSTATUS FspVolumeCreateNoLock(
if (I == PrefixLength)
return STATUS_INVALID_PARAMETER;
}
VolumeParams.FileSystemName[sizeof VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0';
/* create volume guid */
Result = FspCreateGuid(&Guid);

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

14
tools/ntstatus.bat Normal file
View File

@ -0,0 +1,14 @@
@echo off
setlocal
if X%1==X (echo usage: %~n0 VALUE >&2 & exit /b 1)
set RegKey="HKLM\SOFTWARE\Microsoft\Windows Kits\Installed Roots"
set RegVal="KitsRoot10"
reg query %RegKey% /v %RegVal% >nul 2>&1 || (echo Cannot find Windows Kit >&2 & exit /b 1)
for /f "tokens=2,*" %%i in ('reg query %RegKey% /v %RegVal% ^| findstr %RegVal%') do (
set KitRoot=%%j
)
findstr /R /I "\<0*[Xx]*%1[Ll]*\>" "%KitRoot%Include\10.0.10586.0\shared\%~n0.h"

View File

@ -75,34 +75,42 @@ exit /b 1
M:
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
if errorlevel 1 goto fail
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -f foo -N 5000 test xxxxxx
if errorlevel 1 goto fail
N:
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
if errorlevel 1 goto fail
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -f foo -N 5000 test xxxxxx
if errorlevel 1 goto fail
exit /b 0
:fsx-memfs-x86
O:
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
if errorlevel 1 goto fail
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -f foo -N 5000 test xxxxxx
if errorlevel 1 goto fail
P:
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
if errorlevel 1 goto fail
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -f foo -N 5000 test xxxxxx
if errorlevel 1 goto fail
exit /b 0
:winfstest-memfs-x64
M:
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" base reparse
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
if errorlevel 1 goto fail
N:
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" base reparse
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
if errorlevel 1 goto fail
exit /b 0
:winfstest-memfs-x86
O:
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" base reparse
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
if errorlevel 1 goto fail
P:
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" base reparse
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
if errorlevel 1 goto fail
exit /b 0

14
tools/winerror.bat Normal file
View File

@ -0,0 +1,14 @@
@echo off
setlocal
if X%1==X (echo usage: %~n0 VALUE >&2 & exit /b 1)
set RegKey="HKLM\SOFTWARE\Microsoft\Windows Kits\Installed Roots"
set RegVal="KitsRoot10"
reg query %RegKey% /v %RegVal% >nul 2>&1 || (echo Cannot find Windows Kit >&2 & exit /b 1)
for /f "tokens=2,*" %%i in ('reg query %RegKey% /v %RegVal% ^| findstr %RegVal%') do (
set KitRoot=%%j
)
findstr /R /I "\<0*[Xx]*%1[Ll]*\>" "%KitRoot%Include\10.0.10586.0\shared\%~n0.h"

View File

@ -11,9 +11,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -38,6 +38,7 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
{
wchar_t **argp, **arge;
ULONG DebugFlags = 0;
PWSTR DebugLogFile = 0;
ULONG Flags = MemfsDisk;
ULONG FileInfoTimeout = INFINITE;
ULONG MaxFileNodes = 1024;
@ -45,6 +46,7 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
PWSTR MountPoint = 0;
PWSTR VolumePrefix = 0;
PWSTR RootSddl = 0;
HANDLE DebugLogHandle = INVALID_HANDLE_VALUE;
MEMFS *Memfs = 0;
NTSTATUS Result;
@ -59,6 +61,9 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
case L'd':
argtol(DebugFlags);
break;
case L'D':
argtos(DebugLogFile);
break;
case L'm':
argtos(MountPoint);
break;
@ -90,6 +95,28 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
if (MemfsDisk == Flags && 0 == MountPoint)
goto usage;
if (0 != DebugLogFile)
{
if (0 == wcscmp(L"-", DebugLogFile))
DebugLogHandle = GetStdHandle(STD_OUTPUT_HANDLE);
else
DebugLogHandle = CreateFileW(
DebugLogFile,
FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
if (INVALID_HANDLE_VALUE == DebugLogHandle)
{
fail(L"cannot open debug log file");
goto usage;
}
FspDebugLogSetHandle(DebugLogHandle);
}
Result = MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl,
&Memfs);
if (!NT_SUCCESS(Result))
@ -142,6 +169,7 @@ usage:
"\n"
"options:\n"
" -d DebugFlags [-1: enable all debug logs]\n"
" -D DebugLogFile [file path; use - for stdout]\n"
" -t FileInfoTimeout [millis]\n"
" -n MaxFileNodes\n"
" -s MaxFileSize [bytes]\n"

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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
@ -22,6 +22,11 @@
#include <cassert>
#include <VersionHelpers.h>
/*
* Define the MEMFS_NAMED_STREAMS macro to include named streams support.
*/
#define MEMFS_NAMED_STREAMS
/*
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
* a check for the Write buffer to ensure that it is read-only.
@ -50,7 +55,16 @@ int MemfsFileNameCompare(PWSTR a, PWSTR b)
static inline
BOOLEAN MemfsFileNameHasPrefix(PWSTR a, PWSTR b)
{
return 0 == wcsncmp(a, b, wcslen(b));
size_t alen = wcslen(a);
size_t blen = wcslen(b);
return alen >= blen && 0 == memcmp(a, b, blen * sizeof(WCHAR)) &&
(alen == blen || (1 == blen && L'\\' == b[0]) ||
#if defined(MEMFS_NAMED_STREAMS)
(L'\\' == a[blen] || L':' == a[blen]));
#else
(L'\\' == a[blen]));
#endif
}
typedef struct _MEMFS_FILE_NODE
@ -63,6 +77,9 @@ typedef struct _MEMFS_FILE_NODE
SIZE_T ReparseDataSize;
PVOID ReparseData;
ULONG RefCount;
#if defined(MEMFS_NAMED_STREAMS)
struct _MEMFS_FILE_NODE *MainFileNode;
#endif
} MEMFS_FILE_NODE;
struct MEMFS_FILE_NODE_LESS
@ -121,6 +138,25 @@ VOID MemfsFileNodeDelete(MEMFS_FILE_NODE *FileNode)
free(FileNode);
}
static inline
VOID MemfsFileNodeGetFileInfo(MEMFS_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo)
{
#if defined(MEMFS_NAMED_STREAMS)
if (0 == FileNode->MainFileNode)
*FileInfo = FileNode->FileInfo;
else
{
*FileInfo = FileNode->MainFileNode->FileInfo;
FileInfo->FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
/* named streams cannot be directories */
FileInfo->AllocationSize = FileNode->FileInfo.AllocationSize;
FileInfo->FileSize = FileNode->FileInfo.FileSize;
}
#else
*FileInfo = FileNode->FileInfo;
#endif
}
static inline
VOID MemfsFileNodeMapDump(MEMFS_FILE_NODE_MAP *FileNodeMap)
{
@ -171,6 +207,23 @@ MEMFS_FILE_NODE *MemfsFileNodeMapGet(MEMFS_FILE_NODE_MAP *FileNodeMap, PWSTR Fil
return iter->second;
}
#if defined(MEMFS_NAMED_STREAMS)
static inline
MEMFS_FILE_NODE *MemfsFileNodeMapGetMain(MEMFS_FILE_NODE_MAP *FileNodeMap, PWSTR FileName0)
{
WCHAR FileName[MAX_PATH];
wcscpy_s(FileName, sizeof FileName / sizeof(WCHAR), FileName0);
PWSTR StreamName = wcschr(FileName, L':');
if (0 == StreamName)
return 0;
StreamName[0] = L'\0';
MEMFS_FILE_NODE_MAP::iterator iter = FileNodeMap->find(FileName);
if (iter == FileNodeMap->end())
return 0;
return iter->second;
}
#endif
static inline
MEMFS_FILE_NODE *MemfsFileNodeMapGetParent(MEMFS_FILE_NODE_MAP *FileNodeMap, PWSTR FileName0,
PNTSTATUS PResult)
@ -223,15 +276,21 @@ VOID MemfsFileNodeMapRemove(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMFS_FILE_NODE *F
static inline
BOOLEAN MemfsFileNodeMapHasChild(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMFS_FILE_NODE *FileNode)
{
BOOLEAN Result;
BOOLEAN Result = FALSE;
WCHAR Root[2] = L"\\";
PWSTR Remain, Suffix;
MEMFS_FILE_NODE_MAP::iterator iter = FileNodeMap->upper_bound(FileNode->FileName);
if (iter == FileNodeMap->end())
return FALSE;
FspPathSuffix(iter->second->FileName, &Remain, &Suffix, Root);
Result = 0 == MemfsFileNameCompare(Remain, FileNode->FileName);
FspPathCombine(iter->second->FileName, Suffix);
for (; FileNodeMap->end() != iter; ++iter)
{
#if defined(MEMFS_NAMED_STREAMS)
if (0 != wcschr(iter->second->FileName, L':'))
continue;
#endif
FspPathSuffix(iter->second->FileName, &Remain, &Suffix, Root);
Result = 0 == MemfsFileNameCompare(Remain, FileNode->FileName);
FspPathCombine(iter->second->FileName, Suffix);
break;
}
return Result;
}
@ -242,15 +301,18 @@ BOOLEAN MemfsFileNodeMapEnumerateChildren(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMF
WCHAR Root[2] = L"\\";
PWSTR Remain, Suffix;
MEMFS_FILE_NODE_MAP::iterator iter = FileNodeMap->upper_bound(FileNode->FileName);
BOOLEAN Equal;
BOOLEAN IsDirectoryChild;
for (; FileNodeMap->end() != iter; ++iter)
{
if (!MemfsFileNameHasPrefix(iter->second->FileName, FileNode->FileName))
break;
FspPathSuffix(iter->second->FileName, &Remain, &Suffix, Root);
Equal = 0 == MemfsFileNameCompare(Remain, FileNode->FileName);
IsDirectoryChild = 0 == MemfsFileNameCompare(Remain, FileNode->FileName);
#if defined(MEMFS_NAMED_STREAMS)
IsDirectoryChild = IsDirectoryChild && 0 == wcschr(Suffix, L':');
#endif
FspPathCombine(iter->second->FileName, Suffix);
if (Equal)
if (IsDirectoryChild)
{
if (!EnumFn(iter->second, Context))
return FALSE;
@ -259,6 +321,25 @@ BOOLEAN MemfsFileNodeMapEnumerateChildren(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMF
return TRUE;
}
#if defined(MEMFS_NAMED_STREAMS)
static inline
BOOLEAN MemfsFileNodeMapEnumerateNamedStreams(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMFS_FILE_NODE *FileNode,
BOOLEAN (*EnumFn)(MEMFS_FILE_NODE *, PVOID), PVOID Context)
{
MEMFS_FILE_NODE_MAP::iterator iter = FileNodeMap->upper_bound(FileNode->FileName);
for (; FileNodeMap->end() != iter; ++iter)
{
if (!MemfsFileNameHasPrefix(iter->second->FileName, FileNode->FileName))
break;
if (L':' != iter->second->FileName[wcslen(FileNode->FileName)])
break;
if (!EnumFn(iter->second, Context))
return FALSE;
}
return TRUE;
}
#endif
static inline
BOOLEAN MemfsFileNodeMapEnumerateDescendants(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMFS_FILE_NODE *FileNode,
BOOLEAN (*EnumFn)(MEMFS_FILE_NODE *, PVOID), PVOID Context)
@ -342,8 +423,20 @@ static NTSTATUS GetSecurityByName(FSP_FILE_SYSTEM *FileSystem,
return Result;
}
#if defined(MEMFS_NAMED_STREAMS)
UINT32 FileAttributesMask = ~(UINT32)0;
if (0 != FileNode->MainFileNode)
{
FileAttributesMask = ~(UINT32)FILE_ATTRIBUTE_DIRECTORY;
FileNode = FileNode->MainFileNode;
}
if (0 != PFileAttributes)
*PFileAttributes = FileNode->FileInfo.FileAttributes & FileAttributesMask;
#else
if (0 != PFileAttributes)
*PFileAttributes = FileNode->FileInfo.FileAttributes;
#endif
if (0 != PSecurityDescriptorSize)
{
@ -392,6 +485,10 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
if (!NT_SUCCESS(Result))
return Result;
#if defined(MEMFS_NAMED_STREAMS)
FileNode->MainFileNode = MemfsFileNodeMapGetMain(Memfs->FileNodeMap, FileName);
#endif
FileNode->FileInfo.FileAttributes = (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
FileAttributes : FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
@ -429,7 +526,7 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
FileNode->RefCount++;
*PFileNode = FileNode;
*FileInfo = FileNode->FileInfo;
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
return STATUS_SUCCESS;
}
@ -467,7 +564,7 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem,
FileNode->RefCount++;
*PFileNode = FileNode;
*FileInfo = FileNode->FileInfo;
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
return STATUS_SUCCESS;
}
@ -489,11 +586,28 @@ NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem,
FileNode->FileInfo.LastWriteTime =
FileNode->FileInfo.LastAccessTime = MemfsGetSystemTime();
*FileInfo = FileNode->FileInfo;
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
return STATUS_SUCCESS;
}
#if defined(MEMFS_NAMED_STREAMS)
typedef struct _MEMFS_CLEANUP_CONTEXT
{
MEMFS_FILE_NODE **FileNodes;
ULONG Count;
} MEMFS_CLEANUP_CONTEXT;
static BOOLEAN CleanupEnumFn(MEMFS_FILE_NODE *FileNode, PVOID Context0)
{
MEMFS_CLEANUP_CONTEXT *Context = (MEMFS_CLEANUP_CONTEXT *)Context0;
Context->FileNodes[Context->Count++] = FileNode;
return TRUE;
}
#endif
static VOID Cleanup(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode0, PWSTR FileName, BOOLEAN Delete)
@ -502,9 +616,26 @@ static VOID Cleanup(FSP_FILE_SYSTEM *FileSystem,
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
assert(0 == FileName || 0 == wcscmp(FileNode->FileName, FileName));
assert(Delete); /* the new FSP_FSCTL_VOLUME_PARAMS::PostCleanupOnDeleteOnly ensures this */
if (Delete && !MemfsFileNodeMapHasChild(Memfs->FileNodeMap, FileNode))
{
#if defined(MEMFS_NAMED_STREAMS)
MEMFS_CLEANUP_CONTEXT Context = { 0 };
ULONG Index;
Context.FileNodes = (MEMFS_FILE_NODE **)malloc(Memfs->MaxFileNodes * sizeof Context.FileNodes[0]);
if (0 != Context.FileNodes)
{
MemfsFileNodeMapEnumerateNamedStreams(Memfs->FileNodeMap, FileNode, CleanupEnumFn, &Context);
for (Index = 0; Context.Count > Index; Index++)
MemfsFileNodeMapRemove(Memfs->FileNodeMap, Context.FileNodes[Index]);
free(Context.FileNodes);
}
#endif
MemfsFileNodeMapRemove(Memfs->FileNodeMap, FileNode);
}
}
static VOID Close(FSP_FILE_SYSTEM *FileSystem,
@ -585,7 +716,7 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset));
*PBytesTransferred = (ULONG)(EndOffset - Offset);
*FileInfo = FileNode->FileInfo;
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
return STATUS_SUCCESS;
}
@ -605,7 +736,7 @@ static NTSTATUS GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
{
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
*FileInfo = FileNode->FileInfo;
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
return STATUS_SUCCESS;
}
@ -618,6 +749,11 @@ static NTSTATUS SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
{
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
#if defined(MEMFS_NAMED_STREAMS)
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
#endif
if (INVALID_FILE_ATTRIBUTES != FileAttributes)
FileNode->FileInfo.FileAttributes = FileAttributes;
if (0 != CreationTime)
@ -627,7 +763,7 @@ static NTSTATUS SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
if (0 != LastWriteTime)
FileNode->FileInfo.LastWriteTime = LastWriteTime;
*FileInfo = FileNode->FileInfo;
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
return STATUS_SUCCESS;
}
@ -680,7 +816,7 @@ static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
}
}
*FileInfo = FileNode->FileInfo;
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
return STATUS_SUCCESS;
}
@ -814,6 +950,11 @@ static NTSTATUS GetSecurity(FSP_FILE_SYSTEM *FileSystem,
{
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
#if defined(MEMFS_NAMED_STREAMS)
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
#endif
if (FileNode->FileSecuritySize > *PSecurityDescriptorSize)
{
*PSecurityDescriptorSize = FileNode->FileSecuritySize;
@ -837,6 +978,11 @@ static NTSTATUS SetSecurity(FSP_FILE_SYSTEM *FileSystem,
SIZE_T FileSecuritySize;
NTSTATUS Result;
#if defined(MEMFS_NAMED_STREAMS)
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
#endif
Result = FspSetSecurityDescriptor(FileSystem, Request, FileNode->FileSecurity,
&NewSecurityDescriptor);
if (!NT_SUCCESS(Result))
@ -1064,6 +1210,72 @@ static NTSTATUS DeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem,
return STATUS_SUCCESS;
}
#if defined(MEMFS_NAMED_STREAMS)
typedef struct _MEMFS_GET_STREAM_INFO_CONTEXT
{
PVOID Buffer;
ULONG Length;
PULONG PBytesTransferred;
} MEMFS_GET_STREAM_INFO_CONTEXT;
static BOOLEAN AddStreamInfo(MEMFS_FILE_NODE *FileNode,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
UINT8 StreamInfoBuf[sizeof(FSP_FSCTL_STREAM_INFO) + sizeof FileNode->FileName];
FSP_FSCTL_STREAM_INFO *StreamInfo = (FSP_FSCTL_STREAM_INFO *)StreamInfoBuf;
PWSTR StreamName;
StreamName = wcschr(FileNode->FileName, L':');
if (0 != StreamName)
StreamName++;
else
StreamName = L"";
StreamInfo->Size = (UINT16)(sizeof(FSP_FSCTL_STREAM_INFO) + wcslen(StreamName) * sizeof(WCHAR));
StreamInfo->StreamSize = FileNode->FileInfo.FileSize;
StreamInfo->StreamAllocationSize = FileNode->FileInfo.AllocationSize;
memcpy(StreamInfo->StreamNameBuf, StreamName, StreamInfo->Size - sizeof(FSP_FSCTL_STREAM_INFO));
return FspFileSystemAddStreamInfo(StreamInfo, Buffer, Length, PBytesTransferred);
}
static BOOLEAN GetStreamInfoEnumFn(MEMFS_FILE_NODE *FileNode, PVOID Context0)
{
MEMFS_GET_STREAM_INFO_CONTEXT *Context = (MEMFS_GET_STREAM_INFO_CONTEXT *)Context0;
return AddStreamInfo(FileNode,
Context->Buffer, Context->Length, Context->PBytesTransferred);
}
static NTSTATUS GetStreamInfo(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode0, PVOID Buffer, ULONG Length,
PULONG PBytesTransferred)
{
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
MEMFS_GET_STREAM_INFO_CONTEXT Context;
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
Context.Buffer = Buffer;
Context.Length = Length;
Context.PBytesTransferred = PBytesTransferred;
if (0 == (FileNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
!AddStreamInfo(FileNode, Buffer, Length, PBytesTransferred))
return STATUS_SUCCESS;
if (MemfsFileNodeMapEnumerateNamedStreams(Memfs->FileNodeMap, FileNode, GetStreamInfoEnumFn, &Context))
FspFileSystemAddStreamInfo(0, Buffer, Length, PBytesTransferred);
/* ???: how to handle out of response buffer condition? */
return STATUS_SUCCESS;
}
#endif
static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
{
GetVolumeInfo,
@ -1089,6 +1301,11 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
GetReparsePoint,
SetReparsePoint,
DeleteReparsePoint,
#if defined(MEMFS_NAMED_STREAMS)
GetStreamInfo,
#else
0,
#endif
};
NTSTATUS MemfsCreate(
@ -1151,8 +1368,13 @@ NTSTATUS MemfsCreate(
VolumeParams.PersistentAcls = 1;
VolumeParams.ReparsePoints = 1;
VolumeParams.ReparsePointsAccessCheck = 0;
#if defined(MEMFS_NAMED_STREAMS)
VolumeParams.NamedStreams = 1;
#endif
VolumeParams.PostCleanupOnDeleteOnly = 1;
if (0 != VolumePrefix)
wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix);
wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR), L"MEMFS");
Result = FspFileSystemCreate(DevicePath, &VolumeParams, &MemfsInterface, &Memfs->FileSystem);
if (!NT_SUCCESS(Result))

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* 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

View File

@ -68,6 +68,24 @@ void create_dotest(ULONG Flags, PWSTR Prefix)
ASSERT(ERROR_INVALID_NAME == GetLastError());
}
/* invalid chars (wildcards) not allowed */
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0*",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE == Handle);
ASSERT(ERROR_INVALID_NAME == GetLastError());
/* stream names can only appear as the last path component */
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\DOESNOTEXIST:foo\\file0*",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE == Handle);
ASSERT(ERROR_INVALID_NAME == GetLastError());
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));

View File

@ -226,10 +226,148 @@ void querydir_expire_cache_test(void)
}
}
typedef struct _FILE_DIRECTORY_INFORMATION {
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
NTSTATUS
NTAPI
NtQueryDirectoryFile (
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID FileInformation,
_In_ ULONG Length,
_In_ FILE_INFORMATION_CLASS FileInformationClass,
_In_ BOOLEAN ReturnSingleEntry,
_In_opt_ PUNICODE_STRING FileName,
_In_ BOOLEAN RestartScan
);
static void querydir_buffer_overflow_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
HANDLE Handle;
BOOL Success;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
WCHAR FilePath[MAX_PATH];
FILE_DIRECTORY_INFORMATION DirInfo;
UNICODE_STRING Pattern;
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Handle = CreateFileW(FilePath,
GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Pattern.Length = Pattern.MaximumLength = sizeof L"file0" - sizeof(WCHAR);
Pattern.Buffer = L"file0";
memset(&DirInfo, 0, sizeof DirInfo);
Status = NtQueryDirectoryFile(
Handle,
0, 0, 0,
&IoStatus,
&DirInfo,
0,
FileDirectoryInformation,
FALSE,
&Pattern,
FALSE);
ASSERT(STATUS_INFO_LENGTH_MISMATCH == Status);
memset(&DirInfo, 0, sizeof DirInfo);
Status = NtQueryDirectoryFile(
Handle,
0, 0, 0,
&IoStatus,
&DirInfo,
sizeof(FILE_DIRECTORY_INFORMATION),
FileDirectoryInformation,
FALSE,
&Pattern,
FALSE);
ASSERT(STATUS_BUFFER_OVERFLOW == Status);
ASSERT(sizeof(FILE_DIRECTORY_INFORMATION) == IoStatus.Information);
ASSERT(Pattern.Length == DirInfo.FileNameLength);
memset(&DirInfo, 0, sizeof DirInfo);
Status = NtQueryDirectoryFile(
Handle,
0, 0, 0,
&IoStatus,
&DirInfo,
sizeof(FILE_DIRECTORY_INFORMATION),
FileDirectoryInformation,
TRUE,
&Pattern,
FALSE);
ASSERT(STATUS_BUFFER_OVERFLOW == Status);
ASSERT(sizeof(FILE_DIRECTORY_INFORMATION) == IoStatus.Information);
ASSERT(Pattern.Length == DirInfo.FileNameLength);
CloseHandle(Handle);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = DeleteFileW(FilePath);
ASSERT(Success);
memfs_stop(memfs);
}
void querydir_buffer_overflow_test(void)
{
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH] = L"\\\\?\\";
GetCurrentDirectoryW(MAX_PATH - 4, DirBuf + 4);
querydir_buffer_overflow_dotest(-1, DirBuf, 0, 0);
}
if (WinFspDiskTests)
{
querydir_buffer_overflow_dotest(MemfsDisk, 0, 0, 0);
querydir_buffer_overflow_dotest(MemfsDisk, 0, 1000, 0);
}
if (WinFspNetTests)
{
querydir_buffer_overflow_dotest(MemfsNet, L"\\\\memfs\\share", 0, 0);
querydir_buffer_overflow_dotest(MemfsNet, L"\\\\memfs\\share", 1000, 0);
}
}
static unsigned __stdcall dirnotify_dotest_thread(void *FilePath)
{
FspDebugLog(__FUNCTION__ ": \"%S\"\n", FilePath);
Sleep(1000); /* wait for ReadDirectoryChangesW */
HANDLE Handle;
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
@ -330,5 +468,6 @@ void dirctl_tests(void)
{
TEST(querydir_test);
TEST(querydir_expire_cache_test);
TEST(querydir_buffer_overflow_test);
TEST(dirnotify_test);
}

View File

@ -496,7 +496,7 @@ void getvolinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
ASSERT(255 == MaxComponentLength);
ASSERT(0 != (FileSystemFlags &
(FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_PERSISTENT_ACLS)));
ASSERT(0 == wcscmp(FileSystemNameBuf, L"WinFsp"));
ASSERT(0 == wcscmp(FileSystemNameBuf, L"WinFsp-MEMFS"));
}
Success = GetDiskFreeSpaceW(FilePath, &SectorsPerCluster, &BytesPerSector, &FreeClusters, &TotalClusters);
@ -573,7 +573,7 @@ void setvolinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
ASSERT(255 == MaxComponentLength);
ASSERT(0 != (FileSystemFlags &
(FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_PERSISTENT_ACLS)));
ASSERT(0 == wcscmp(FileSystemNameBuf, L"WinFsp"));
ASSERT(0 == wcscmp(FileSystemNameBuf, L"WinFsp-MEMFS"));
}
Success = SetVolumeLabelW(FilePath, L"TestLabel");
@ -590,7 +590,7 @@ void setvolinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
ASSERT(255 == MaxComponentLength);
ASSERT(0 != (FileSystemFlags &
(FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_PERSISTENT_ACLS)));
ASSERT(0 == wcscmp(FileSystemNameBuf, L"WinFsp"));
ASSERT(0 == wcscmp(FileSystemNameBuf, L"WinFsp-MEMFS"));
}
Success = SetVolumeLabelW(FilePath, L"123456789012345678901234567890123");
@ -607,7 +607,7 @@ void setvolinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
ASSERT(255 == MaxComponentLength);
ASSERT(0 != (FileSystemFlags &
(FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_PERSISTENT_ACLS)));
ASSERT(0 == wcscmp(FileSystemNameBuf, L"WinFsp"));
ASSERT(0 == wcscmp(FileSystemNameBuf, L"WinFsp-MEMFS"));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@ int main(int argc, char *argv[])
TESTSUITE(lock_tests);
TESTSUITE(dirctl_tests);
TESTSUITE(reparse_tests);
TESTSUITE(stream_tests);
tlib_run_tests(argc, argv);
return 0;