Compare commits

..

256 Commits

Author SHA1 Message Date
637f461a65 sys: FspFileNodeTrySetFileInfoOnOpen 2017-07-11 15:23:03 -07:00
b35bf204db sys: FspFileNodeTrySetFileInfoOnOpen 2017-07-11 14:17:17 -07:00
3073646f29 doc: add link to queued events document 2017-06-21 14:32:18 -07:00
7f9f55de24 add queued events document 2017-06-21 14:19:56 -07:00
bb3f8d37f2 tools: run-tests: disable passthrough-cpp that is no longer included in installer 2017-06-13 11:13:04 -07:00
c72a9f2a05 build: update for release 1.1 2017-06-12 13:42:05 -07:00
9b4ab190e0 installer: do not install C++ layer 2017-06-12 13:33:45 -07:00
010ed909ec doc: update faq 2017-06-12 12:54:06 -07:00
2b4549a50d doc: update service arch doc with information about credentials 2017-06-12 12:40:50 -07:00
98a329e81b tst: memfs: atomically update FileNode::RefCount (issue #93) 2017-06-07 22:22:28 -07:00
8090b7c666 update Changelog 2017-05-22 17:42:55 -07:00
c7d720eaa0 dll: fuse: allows slashes in -o VolumePrefix=PREFIX 2017-05-22 17:02:40 -07:00
8320160d73 build: version.properties: update to v1.1B3 2017-05-22 13:49:59 -07:00
ce057b49b8 update Changelog 2017-05-22 13:30:16 -07:00
a60c989089 update Changelog 2017-05-22 21:25:44 +01:00
0f6371f0d8 tools: run-tests: add fsx and winfstest for memfs-dotnet 2017-05-17 21:07:37 -07:00
1a4bbbe09a cygfuse: fix tabs to spaces 2017-05-17 15:19:36 -07:00
4e891dc2a8 cygfuse: add fuse_exited 2017-05-17 15:13:05 -07:00
18a77d63c3 cygfuse: improve cygfuse initialization 2017-05-17 14:59:31 -07:00
4ea9c6e362 dll: fuse: added -o options for additional WinFsp-FUSE options 2017-05-17 12:11:45 -07:00
9d77c192a8 cygfuse: cygfuse_init_fail now prints message and exits 2017-05-17 10:58:04 -07:00
6d5401d911 cygfuse: add 32-bit package 2017-05-17 00:54:26 -07:00
330d6e79f8 opt: cygfuse: bump release number to 5 2017-05-17 00:05:41 -07:00
ed58b7a63c inc: fuse: fix missing-field-initializers warning 2017-05-16 23:41:02 -07:00
f6853114c1 dll: fuse: implement fuse_exited 2017-05-16 23:26:18 -07:00
8ec7285d32 doc: add rclone to known file systems 2017-05-15 15:12:26 -07:00
c183c0fe89 doc: add rar2fs to the known file systems 2017-05-13 16:37:26 -07:00
38ad8fd27d update README 2017-05-11 13:51:56 -07:00
de85070e73 tst: winfsp-tests: disable internal tests when running with --external 2017-05-11 11:17:57 -07:00
5b8ebd6e1d src: dotnet: minor documentation fixes 2017-05-11 10:38:12 -07:00
db530cb5e5 installer: add dotnet documentation 2017-05-10 23:32:43 -07:00
7cd4d4faab src: dotnet: add documentation 2017-05-10 23:11:42 -07:00
2560a513dc update changelog 2017-05-09 23:12:45 -07:00
1ee95be5d7 src: dotnet: FileSystemBase: GetStreamInfo: bug fix 2017-05-09 23:01:31 -07:00
bd7546559c tst: memfs-dotnet: Create: fix allocation size 2017-05-09 22:02:37 -07:00
d18a2c8b75 tst: memfs-dotnet: ReadDirectoryEntry: properly handle Marker 2017-05-09 17:49:43 -07:00
0ebae0adc1 src: dotnet: FileSystemHost.GetSecurityByName: handle STATUS_REPARSE 2017-05-09 16:58:16 -07:00
d70c49ccd0 tools: run-tests: add memfs-dotnet testing 2017-05-09 00:03:01 -07:00
5846939116 tools: run-tests: add memfs-dotnet testing 2017-05-08 23:11:45 -07:00
f124e74f01 installer: add memfs-dotnet 2017-05-08 22:56:06 -07:00
05abb93e4b tst: memfs-dotnet: fix stream_getstreaminfo_test 2017-05-08 22:17:17 -07:00
5839d46b7a tst: memfs-dotnet: fix stream_create_overwrite_test 2017-05-08 21:57:45 -07:00
bce0d63f7d tst: memfs-dotnet: fix read/write offset copy 2017-05-08 21:53:49 -07:00
14b9f5affc tst: memfs-dotnet: fix rename_caseins_test 2017-05-08 21:45:30 -07:00
035a430470 tst: dotnet: SetSecurity testing 2017-05-08 21:25:25 -07:00
0af9e46e76 src: dotnet: FileSystemBase.ModifySecurityDescriptor 2017-05-08 21:25:03 -07:00
c4530f1252 tst: memfs-dotnet: testing 2017-05-07 17:40:47 -07:00
9f78a17583 tst: memfs-dotnet: reparse points testing 2017-05-07 17:12:08 -07:00
eea0b1bc79 src: dotnet: GetReparseTag 2017-05-07 17:11:39 -07:00
8338a6e066 tst: memfs-dotnet: fix exceptions in SetFileSizeInternal 2017-05-07 16:29:28 -07:00
ddba49dbea tst: memfs-dotnet: remove unnecessary OpenNodeSet 2017-05-07 16:28:49 -07:00
a6ff8a87de tst: memfs-dotnet: ReadDirectory fixes 2017-05-07 15:45:01 -07:00
bf64bcf9ba dotnet: fix problems with FullContext and GCHandle 2017-05-07 15:13:22 -07:00
8c5d9bda20 tst: memfs-dotnet: testing 2017-05-06 23:40:46 -07:00
f1ac28b0aa dotnet: log exceptions 2017-05-06 23:39:58 -07:00
ff725f931d tst: memfs-dotnet: testing 2017-05-06 23:10:40 -07:00
31519ba416 dotnet: bug fixes 2017-05-06 17:01:55 -07:00
0bca8f851c tst: memfs-dotnet: remove dead code 2017-05-06 15:06:29 -07:00
acf175da60 tst: memfs-dotnet: WIP 2017-05-06 14:49:17 -07:00
23eac24c84 dotnet: FileSystemBase.GetStreamEntry 2017-05-06 14:48:56 -07:00
0f9ef3bd51 tst: memfs-dotnet: WIP 2017-05-05 20:30:07 -07:00
2bdd54536e dotnet: reparse point WIP 2017-05-05 20:29:47 -07:00
060ebcca0d tst: memfs-dotnet: WIP 2017-05-05 18:24:17 -07:00
b38a89e485 dotnet: reparse point changes 2017-05-05 18:23:52 -07:00
b5bfeee027 dotnet: FileSystemHost: fixes 2017-05-05 16:15:29 -07:00
f36cacaf84 tst: memfs-dotnet: WIP 2017-05-05 14:47:48 -07:00
4278cec465 tst: memfs-dotnet: WIP 2017-05-05 12:08:32 -07:00
151627091b tst: memfs-dotnet: WIP 2017-05-04 23:00:53 -07:00
2ee3f02928 tst: memfs-dotnet: WIP 2017-05-04 21:56:46 -07:00
d77d3ccccf tools: version-info.bat: toggle executable bit 2017-05-04 15:19:11 -07:00
1e0c91658e doc: add cgofuse to known file systems 2017-04-28 14:52:05 -07:00
568096b560 build: installer: mark as Beta 2017-04-17 16:57:06 -07:00
b2e175a991 build: installer: mark as Beta 2017-04-17 16:54:17 -07:00
757c4f151d Update README to point to latest release 2017-04-17 16:46:44 -07:00
8b71e18972 inc: winfsp.hpp: refactor FileSystem class into FileSystemHost and FileSystemBase 2017-04-17 14:30:07 -07:00
4e7f988371 inc: winfsp.hpp: refactor FileSystem class into FileSystemHost and FileSystemBase 2017-04-17 13:20:07 -07:00
eb04d7ab90 build: installer: add cygfuse 2017-04-16 15:44:55 -07:00
d6c3b7304d Update README with chocolatey linl 2017-04-16 13:03:51 -07:00
1ee563cd13 src: dotnet: refactor FileSystem class into FileSystemHost and FileSystemBase 2017-04-16 11:46:16 -07:00
8787f2c528 inc: winfsp.hpp: FileSystem: ReadDirectoryEntry and friends 2017-04-14 00:01:08 -07:00
4c102ab57c inc: winfsp.hpp: SetDebugLogFile 2017-04-13 22:19:17 -07:00
bf87c539fd inc: winfsp.hpp: Service class improvements 2017-04-13 21:57:07 -07:00
d5802f3a5f inc: winfsp.hpp: improve C++ layer 2017-04-13 18:23:55 -07:00
c144d4d303 src: dotnet: FileSystem: convert Set* methods to properties 2017-04-13 16:33:32 -07:00
9770efde14 build: dotnet: change assembly versioning scheme (fix to 1.0.0.0) 2017-04-13 16:04:13 -07:00
197ce7c30a src: dotnet: check dll version during assembly load 2017-04-12 15:37:19 -07:00
5d8384a508 src: dll: FspFsctlFixServiceSecurity
- fix GetEffectiveRightsFromAclW ERROR_CIRCULAR_DEPENDENCY
2017-04-12 10:50:27 -07:00
8bb46a5f86 doc: update FAQ 2017-04-12 10:02:16 -07:00
a3087cb696 update Changelog 2017-04-12 00:31:13 -07:00
92b1a8c00d update README 2017-04-12 00:11:26 -07:00
bbf641e721 build: installer: add .NET feature 2017-04-11 22:55:09 -07:00
539ab9ce63 tst: passthrough-dotnet: remove EnableRestoreBackupPrivileges 2017-04-11 19:56:47 -07:00
a29390412b tst: passthrough-dotnet: include in test suite 2017-04-11 18:23:56 -07:00
739eb80cfb tst: passthrough-dotnet: EnableBackupRestorePrivileges 2017-04-11 16:46:11 -07:00
f9a470a0f0 tools: run-tests: sample running improvements 2017-04-11 16:03:10 -07:00
44358e118c build: installer: add passthrough-dotnet 2017-04-11 15:13:07 -07:00
2a7ee146f1 update License with reference to winfsp-msil.dll 2017-04-11 14:47:49 -07:00
0ddeb02235 build: dotnet: use older Assembly Linker for publisher policy 2017-04-11 14:43:18 -07:00
26d8ea1c1c build: dotnet: improvements 2017-04-11 14:07:04 -07:00
fa4aaf2fb7 build: installer: add winfsp-msil.dll in installation bin directory 2017-04-11 13:29:31 -07:00
7645a0185b build: dotnet: add version info to publisher policy 2017-04-11 12:01:51 -07:00
dcf38cdf08 build: installer: add .NET assembly and GAC it 2017-04-11 00:39:57 -07:00
c7ca500dd5 build: dotnet: update publisher policy 2017-04-10 23:03:16 -07:00
d9fcc8ca1c build: dotnet: strong name assembly and add publisher policy 2017-04-10 22:51:15 -07:00
259f2bf1c1 tst: passthrough-dotnet: fix security 2017-04-10 21:33:49 -07:00
67711082b0 tst: passthrough-dotnet: testing 2017-04-10 20:08:14 -07:00
f2d98bbf25 tst: passthrough-dotnet: major refactoring and testing 2017-04-10 14:48:26 -07:00
e40505adb5 tst: passthrough-dotnet: minor fix 2017-04-10 10:34:31 -07:00
ac7b7f4a1b tst: passthrough-dotnet: testing 2017-04-10 10:03:59 -07:00
aa53b1e5ef src: dotnet: fix UnmanagedFunctionPointer delegate lifetime 2017-04-09 21:37:04 -07:00
c4b73c8eda tst: passthrough-dotnet: Cleanup: minor fix 2017-04-09 17:58:46 -07:00
332bce6322 src: dotnet: fix Boolean marshalling 2017-04-09 17:37:22 -07:00
5ef1de2647 src: dotnet: fix FspFileSystemMountPointF prototype 2017-04-09 17:01:18 -07:00
de60e76b1d tst: passthrough-dotnet: testing 2017-04-09 02:01:19 -07:00
8f8e8fe086 src: dotnet: testing 2017-04-09 02:01:03 -07:00
0ac9a83026 build: version.properties: update version number 2017-04-08 22:15:49 -07:00
b8c97caec0 tst: passthrough-dotnet: update .gitignore 2017-04-08 22:08:24 -07:00
f9b8bfc020 src: dll,dotnet: add out-of-line API's 2017-04-08 21:13:21 -07:00
f938bf5e3f tst: passthrough-dotnet: ReadDirectory 2017-04-08 18:42:20 -07:00
a0df9babf9 src: dotnet: ReadDirectory helpers 2017-04-08 18:41:00 -07:00
0d9d8ef5a2 tst: passthrough-dotnet: WIP 2017-04-08 11:29:56 -07:00
668948ebc1 src: dll: SetDebugLogFile and other fixes 2017-04-08 11:29:32 -07:00
83c9351d38 tst: passthrough-dotnet: WIP 2017-04-07 22:28:57 -07:00
aa1e32494c src: dotnet: add FspDebugLogSetHandle 2017-04-07 22:28:24 -07:00
6365a553dc src: dotnet: WIP 2017-04-07 22:11:57 -07:00
1245a29be6 src: dotnet: WIP 2017-04-07 16:23:56 -07:00
c79785c2db src: dotnet: WIP 2017-04-07 13:52:26 -07:00
f117a89697 src: dotnet: WIP 2017-04-07 12:35:20 -07:00
33f5b8c05b src: dotnet: WIP 2017-04-07 12:31:51 -07:00
9a02a46cf4 tst: passthrough-dotnet: fix problem with vshost ignore Main return value 2017-04-07 11:03:58 -07:00
4d6fc3c848 src: dotnet: testing 2017-04-07 10:52:52 -07:00
964f2eed69 src: dotnet: Service testing 2017-04-07 10:29:50 -07:00
b45cff2881 tst: passthrough-dotnet: initial commit 2017-04-06 23:49:55 -07:00
f219885939 src: dotnet: testing 2017-04-06 23:48:58 -07:00
0cfc730745 tools: version-info.bat 2017-04-06 15:56:01 -07:00
a3643f8b02 build: reorganize winfsp.net project 2017-04-06 14:12:33 -07:00
de61eaf6b8 src: dotnet: Service improvements 2017-04-06 13:05:31 -07:00
075a2b6e4c build: version.properties: AssemblyVersion 2017-04-05 17:31:11 -07:00
37affbf572 build: version.properties: AssemblyVersion 2017-04-05 17:18:49 -07:00
20b3ecd0cd src: dotnet: WIP 2017-04-05 16:31:38 -07:00
c782c4d668 src: dotnet: add Service class 2017-04-05 16:25:38 -07:00
d545b8df26 src: dotnet: WIP 2017-04-03 17:21:54 -07:00
08e520e0ec src: dotnet: WIP 2017-04-03 17:07:32 -07:00
a5db7a2cca src: dotnet: WIP 2017-04-03 15:27:33 -07:00
74c2494bbd src: dotnet: WIP 2017-04-03 15:15:13 -07:00
858f77cdf7 src: dotnet: WIP 2017-04-03 14:54:26 -07:00
30dae34700 src: dotnet: WIP 2017-04-03 13:52:35 -07:00
36d50facd7 src: dotnet: WIP 2017-04-03 13:42:59 -07:00
55dd8797d8 src: dotnet: WIP 2017-04-03 12:55:08 -07:00
27114184d2 src: dotnet: WIP 2017-04-03 12:06:45 -07:00
1980f511ce src: dotnet: WIP 2017-04-03 11:42:39 -07:00
4cbee05849 src: dotnet: WIP 2017-04-03 10:45:41 -07:00
f2391d99d5 src: dotnet: WIP 2017-04-02 22:40:43 -07:00
fa9ff37de9 src: dotnet: WIP 2017-04-02 16:37:21 -07:00
39b60c1348 src: dotnet: WIP 2017-04-02 16:36:10 -07:00
5bc15a7e54 src: dotnet: FileSystem+NtStatus 2017-04-02 15:38:25 -07:00
81bc200fe7 src: dotnet: WIP 2017-04-02 15:20:31 -07:00
89324d2327 src: dotnet: WIP 2017-04-02 15:13:05 -07:00
47b81a8025 src: dotnet: WIP 2017-04-02 12:43:49 -07:00
02cec420e7 src: dotnet: WIP 2017-04-02 11:44:25 -07:00
8e7e959d8a src: dotnet: WIP 2017-04-02 11:31:06 -07:00
fc51b7cc22 src: dotnet: WIP 2017-04-01 18:00:34 -07:00
ff5850847f src: dotnet: WIP 2017-04-01 16:43:30 -07:00
ab462fb546 src: dotnet: WIP 2017-04-01 16:13:09 -07:00
a5eadc50a7 add .net dll and project 2017-04-01 01:06:40 -07:00
afe7f8d728 inc: winfsp.hpp: add convenience functions in Fsp namespace 2017-03-30 12:16:01 -07:00
c137d49dcd tst: passthrough-cpp: minor fix 2017-03-30 12:08:11 -07:00
b70337bac3 inc: winfsp.hpp: default VolumeParams are same as in C API 2017-03-30 11:50:51 -07:00
c9b5f25ffc tst: passthrough-cpp: minor improvements 2017-03-29 14:40:37 -07:00
96f6c28885 inc: winfsp.hpp: FSP_CPP_EXCEPTION_GUARD 2017-03-29 14:37:19 -07:00
deb8aed91f inc: winfsp.hpp: FSP_CPP_EXCEPTION_GUARD 2017-03-29 14:36:25 -07:00
fac270e596 inc: winfsp: add Service class 2017-03-28 17:32:19 -07:00
0189adac8f src: dll: Service: minor fix 2017-03-28 16:06:52 -07:00
af772d7a86 tools: run-tests: add passthrough-cpp 2017-03-28 10:10:21 -07:00
96554cc0ca tools: run-tests: add passthrough-cpp 2017-03-27 20:55:56 -07:00
ddb3698c89 installer: add winfsp.hpp and passthrough-cpp 2017-03-27 20:15:52 -07:00
9657ae31c3 tst: passthrough-cpp: FspLoad 2017-03-27 17:39:24 -07:00
0795774e9e inc: winfsp.hpp: testing 2017-03-27 17:38:52 -07:00
763f256e1f inc: winfsp.hpp: catch exceptions from file system operations 2017-03-27 16:25:35 -07:00
367f450e30 tst: passthrough-cpp: initial implementation 2017-03-27 13:44:41 -07:00
7afdee7c01 inc: winfsp.hpp: improvements 2017-03-27 13:43:43 -07:00
87c5f19ce1 inc: winfsp.hpp: Fsp::FileSystem::Mount 2017-03-26 23:19:33 -07:00
00d1a3176e inc: winfsp.hpp: initial implementation of a C++ layer 2017-03-26 23:10:22 -07:00
6318e7b0ef doc: update known file systems document 2017-03-24 17:10:23 -07:00
5d23b1fef8 doc: add known file systems document 2017-03-24 17:04:03 -07:00
44fe02d2fd doc: update Home 2017-03-24 16:41:01 -07:00
1f0de20b7f build: choco: update package description 2017-03-20 17:20:40 -07:00
bfd2e106ac build: choco: update package as per chocolatey review instructions 2017-03-20 15:30:33 -07:00
b1848e963f Merge branch 'DuroSoft-fuse-volume-label' 2017-03-19 21:33:53 -07:00
a29611fa2a dll: fuse: improve volname option handling 2017-03-19 18:06:21 -07:00
8a369bd48a Merge branch 'fuse-volume-label' of https://github.com/DuroSoft/winfsp into DuroSoft-fuse-volume-label 2017-03-19 16:59:50 -07:00
9ca7424d27 Revert "appveyor: disable windows defender"
This reverts commit 4f640755bc.
2017-03-19 11:53:44 -07:00
4f640755bc appveyor: disable windows defender 2017-03-19 11:52:14 -07:00
c085a91991 add FUSE support for VolumeLabel via "volname" option
* closes #64
2017-03-19 00:40:45 -04:00
83cd3cab99 add name to CONTRIBUTORS list 2017-03-19 00:21:39 -04:00
67dff84a13 doc: update faq 2017-03-18 16:04:58 -07:00
c702a86fbf doc: add faq 2017-03-18 16:02:39 -07:00
f335a990af doc: add wiki home 2017-03-18 14:56:49 -07:00
ba68ab845b update Changelog 2017-03-13 15:28:16 -07:00
db0566701e dll: fuse: add fuse_* symbols for programs using FFI 2017-03-13 12:30:25 -07:00
433e62f813 dll: do not export FspFileSystemResolveReparsePointsInternal 2017-03-13 11:46:36 -07:00
6777de6569 update Changelog for v1.0 2017-03-11 16:45:40 -08:00
63ee24235b update Changelog for v1.0 2017-03-11 16:37:55 -08:00
c3eb46813e update Changelog for v1.0 2017-03-11 16:21:46 -08:00
bee0fa79b2 build: choco: rename chocolateyUninstall.ps1 to chocolateyBeforeModify.ps1 to properly handle upgrades 2017-03-11 15:06:48 -08:00
d907bf2769 inc: winfsp: RegGetValueW prototype and disable macro redef warnings 2017-03-11 14:32:12 -08:00
38bcece5ce build: choco: remove MSI after installation 2017-03-10 22:14:16 -08:00
193de36301 dll: fuse: debug output goes to stderr; configurable with -oDebugLog=FILE 2017-03-10 21:57:27 -08:00
c080e86f11 build: choco: add admin tag as per chocolatey validator 2017-03-10 15:23:54 -08:00
79811a2faa appveyor: add -y switch for chocolatey 2017-03-10 10:56:21 -08:00
b1e287727d appveyor: test chocolatey uninstall 2017-03-10 10:54:22 -08:00
2def18e271 build: choco: add chocolateyUninstall.ps1 2017-03-10 10:44:56 -08:00
3ddc2249f6 build: choco: add chocolateyUninstall.ps1 2017-03-10 10:37:19 -08:00
709ead9e06 build: choco: initial chocolatey package implementation 2017-03-09 22:14:50 -08:00
7c574da261 build: version.properties: 2017 Gold 2017-03-09 15:54:46 -08:00
0980365082 dll: fuse: fuse_intf_GetVolumeInfo: return default info when statfs unimplemented 2017-03-09 14:59:01 -08:00
ba46d9fef8 update Changelog, README, etc. 2017-02-25 17:59:37 -08:00
4c0386bf8d sys: hardcode AlwaysUseDoubleBuffering for Reads 2017-02-25 11:22:22 -08:00
6774c34422 sys: FspProcessBufferAcquire: fix silly mistake when using ZwAllocateVirtualMemory 2017-02-23 22:24:32 -08:00
3215d8e26a sys: ProcessBuffer: DEBUGTEST 2017-02-23 20:26:14 -08:00
7911f1354f sys: ProcessBuffer: improvements 2017-02-23 17:39:28 -08:00
28f97c2619 sys: ProcessBuffer: conditional usage 2017-02-23 16:36:21 -08:00
4b43cc590f sys: initial ProcessBuffer implementation 2017-02-23 16:06:55 -08:00
441c45c77f sys: fix a couple of static analysis issues 2017-02-21 15:07:06 -08:00
c246acb2d3 dll: FspVersion 2017-02-17 15:22:31 -08:00
50ed020e16 dll: FspVersion 2017-02-17 15:20:57 -08:00
12704a3a4a dll: FspFileSystemSetMountPointEx and related refactoring 2017-02-16 20:30:39 -08:00
186f7cd9ee dll: fuse: minor fix 2017-02-16 17:26:07 -08:00
50830f0bf2 bump version to 2017 RC3 2017-02-16 17:25:54 -08:00
86025aa30b dll: fuse: fuse_mount: now also accepts cygwin paths 2017-02-16 16:53:06 -08:00
31e6f15eaf tst: passthrough-fuse: FSP_FUSE_CAP_*: testing 2017-02-15 18:07:25 -08:00
5ce6d74e90 tst: passthrough-fuse: FSP_FUSE_CAP_*: testing 2017-02-15 17:26:37 -08:00
02ffa6afb2 tst: passthrough-fuse: ptfs_init 2017-02-13 22:03:39 -08:00
712870ddd9 tst: passthrough-fuse: FSP_FUSE_CAP_* 2017-02-13 21:53:37 -08:00
35d1adb360 dll: fuse: improve SectorSize: handling 2017-02-13 16:21:26 -08:00
3b9f9ce93b dll: fuse: discard unused options 2017-02-13 15:11:09 -08:00
a7c5e4f80c dll: fuse: default FileInfoTimeout is now 1000ms 2017-02-12 13:25:43 -08:00
0b826f04c2 tst: winfsp-tests: exec-test: disable test that fails under shares 2017-02-12 11:49:46 -08:00
69d53b7a28 tst: winfsp-tests: exec-test: disable test that fails under shares 2017-02-12 11:33:56 -08:00
877bd97ba8 tst: winfsp-tests: exec-test 2017-02-12 10:42:14 -08:00
559b7e80a3 tst: winfsp-tests: exec-test 2017-02-12 10:29:30 -08:00
495c78eb25 tst: winfsp-tests: exec-test 2017-02-12 00:26:20 -08:00
cf69d6a08d tst: winfsp-tests: delete_standby_test 2017-02-11 10:07:03 -08:00
0d95bb9b14 tst: winfsp-tests: delete_standby_test: disable parts that fail with shares and passthrough 2017-02-10 23:24:05 -08:00
cf48d19759 tst: winfsp-tests: delete_standby_test: disable portion that fails under a share 2017-02-10 22:19:25 -08:00
14c602ccd8 tst: winfsp-tests: delete_standby_test 2017-02-10 21:31:55 -08:00
2d45082d80 tst: winfsp-tests: delete_standby_test 2017-02-10 19:50:16 -08:00
25cf527af4 tst: winfsp-tests: rename_standby_test 2017-02-10 15:47:44 -08:00
76d081937e tst: winfsp-tests: rename_standby_test 2017-02-10 15:25:36 -08:00
ccd4bb869c Experimental fix for github issue #45 2017-02-10 12:39:53 -08:00
46d5c98926 tst: winfsp-tests: rename_standby_test 2017-02-09 17:38:24 -08:00
1726ca8ccb Update README as per issue #48 2017-02-09 12:06:54 -08:00
b8c257f996 Update README as per issue #48 2017-02-09 12:04:51 -08:00
53e6894298 doc: use asciidoc for winfsp.h reference 2017-02-08 17:36:17 -08:00
10d1ba707e Update README.md 2017-02-08 13:42:49 -08:00
c234e2af2a Update README.md 2017-02-08 13:42:30 -08:00
113 changed files with 15824 additions and 2299 deletions

View File

@ -1,6 +1,55 @@
= Changelog = Changelog
v1.1 (2017.1)::
This release brings some major new components and improvements.
- A .NET layer that allows the creation of file systems in managed mode. This is contained in the new `winfsp-msil.dll`. The new .NET layer is being tested with the WinFsp test suites and Microsoft's ifstest.
- FUSE for Cygwin is now included with the installer.
- FUSE now has a `-ovolname=VOLNAME` parameter that allows setting the volume label. Thanks @samkelly.
- A number of other FUSE improvements have been made (see issue #85).
NOTE: The C++ layer included in the v1.1 beta releases is not part of this release as it is still work in progress. It can be found in `inc/winfsp/winfsp.hpp` in the WinFsp source repository.
v1.1B3 (2017.1 B3)::
v1.1B2 (2017.1 B2)::
v1.1B1 (2017.1 BETA)::
This release brings some major new components and improvements.
- A .NET layer that allows the creation of file systems in managed mode. This is contained in the new `winfsp-msil.dll`. The new .NET layer is being tested with the WinFsp test suites and Microsoft's ifstest.
- A simple C++ layer can be found in `inc/winfsp/winfsp.hpp`.
- FUSE for Cygwin is now included with the installer.
- FUSE now has a `-ovolname=VOLNAME` parameter that allows setting the volume label. Thanks @samkelly.
v1.0::
This is the WinFsp 2017 release! :tada:
- The API is now *FROZEN*. Breaking API changes will receive a major version update (`2.0`). Incremental API changes will receive a minor version update (`1.x`).
- Adds chocolatey package. Try `choco install winfsp` (note: pending approval from chocolatey.org).
- FUSE `-d` output now always goes to stderr. There is also a new `-oDebugLog=FILE` switch to specify a debug output file.
- FUSE now provides a default `statfs` implementation if a file system does not provide one.
- The WinFsp DLL now exports `fuse_*` symbols in addition to the `fsp_fuse_*` symbols. These symbols are for use with programs that use FFI technology such as jnr-fuse and fusepy *ONLY*. They are not supposed to be used by native C/C++ programs. Such programs are supposed to include the `<fuse.h>` headers.
v1.0RC3::
This is the WinFsp 2017 Release Candidate 3, which should be the last Release Candidate according to the current plan. This release fixes a major issue with some file systems and includes a few smaller changes:
- Fixes GitHub issue #55. Prior to this fix it was possible for a rogue process (or faulty file system) to crash Windows using WinFsp. For full details read http://www.osronline.com/showthread.cfm?link=282037[this thread].
- Introduces the `FspFileSystemSetMountPointEx` API, which allows the specification of a security descriptor when mounting over a directory.
- Introduces the `FspVersion` API, which allows the retrieval of the WinFsp DLL version. Currently this reports `0x00010000` (version `1.0`).
- Introduces the `FSP_FUSE_CAP_CASE_INSENSITIVE` and `FSP_FUSE_CAP_READDIR_PLUS` WinFsp-FUSE flags. The `FSP_FUSE_CAP_CASE_INSENSITIVE` flag allows a file system to mark itself as case-insensitive. The `FSP_FUSE_CAP_READDIR_PLUS` flag allows a file system to include full `stat` details when responding to the `readdir` operation (thus avoiding extraneous `getattr` calls).
- When using WinFsp-FUSE over Cygwin, POSIX paths can be used as mountpoints.
- Fixes GitHub issue #45. Prior to this fix, file systems that do not properly implement `Cleanup` (including FUSE file systems) would at times disallow renaming of directories.
v1.0RC2:: v1.0RC2::
This is the WinFsp 2017 Release Candidate 2. Some important changes included below: This is the WinFsp 2017 Release Candidate 2. Some important changes included below:

View File

@ -54,5 +54,6 @@ This CONTRIBUTOR AGREEMENT applies to any contribution that you make to the WinF
CONTRIBUTOR LIST CONTRIBUTOR LIST
---------------- ----------------
|=== |===
|Bill Zissimopoulos |billziss at navimatics.com |Bill Zissimopoulos |billziss at navimatics.com
|Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com
|=== |===

View File

@ -6,7 +6,7 @@ permissions to Free/Libre and Open Source Software ("FLOSS") without requiring
that such software is covered by the GPLv3. that such software is covered by the GPLv3.
1. Permission to link with a platform specific version of the WinFsp DLL 1. Permission to link with a platform specific version of the WinFsp DLL
(currently winfsp-x64.dll or winfsp-x86.dll). (one of: winfsp-x64.dll, winfsp-x86.dll, winfsp-msil.dll).
2. Permission to distribute unmodified binary releases of the WinFsp 2. Permission to distribute unmodified binary releases of the WinFsp
installer (as released by the WinFsp project). installer (as released by the WinFsp project).

View File

@ -3,7 +3,9 @@
![WinFsp Demo](http://www.secfs.net/winfsp/files/cap.gif) ![WinFsp Demo](http://www.secfs.net/winfsp/files/cap.gif)
<a href="https://github.com/billziss-gh/winfsp/releases/download/v1.0RC1/winfsp-1.0.17009.msi"><img src="http://www.secfs.net/winfsp/resources/Download-WinFsp.png" alt="Download WinFsp Installer" width="244" height="34"></a> <a href="https://github.com/billziss-gh/winfsp/releases/latest"><img src="http://www.secfs.net/winfsp/resources/Download-WinFsp.png" alt="Download WinFsp Installer" width="244" height="34"></a>
&emsp;
<a href="https://chocolatey.org/packages/winfsp"><img src="http://www.secfs.net/winfsp/resources/Choco-WinFsp.png" alt="choco install winfsp" width="244" height="34"></a>
@ -16,6 +18,7 @@ Some of the benefits of using WinFsp are listed below:
* Strives for compatibility with NTFS. Read about its [Compatibility](doc/NTFS-Compatibility.asciidoc ). * Strives for compatibility with NTFS. Read about its [Compatibility](doc/NTFS-Compatibility.asciidoc ).
* Easy to understand but comprehensive API. Consult the [API Reference](http://www.secfs.net/winfsp/apiref/). There is also a simple [Tutorial](doc/WinFsp-Tutorial.asciidoc). * Easy to understand but comprehensive API. Consult the [API Reference](http://www.secfs.net/winfsp/apiref/). There is also a simple [Tutorial](doc/WinFsp-Tutorial.asciidoc).
* FUSE compatibility layer for native Windows and Cygwin. See [fuse.h](inc/fuse/fuse.h). * FUSE compatibility layer for native Windows and Cygwin. See [fuse.h](inc/fuse/fuse.h).
* .NET layer for managed development. See [src/dotnet](src/dotnet).
* Signed drivers provided on every release. * Signed drivers provided on every release.
* Available under the [GPLv3](License.txt) license with a special exception for Free/Libre and Open Source Software. * Available under the [GPLv3](License.txt) license with a special exception for Free/Libre and Open Source Software.
@ -35,29 +38,34 @@ The project source code is organized as follows:
* inc/fuse: Public headers for the FUSE compatibility layer. * inc/fuse: Public headers for the FUSE compatibility layer.
* src/dll: Source code to the WinFsp DLL. * src/dll: Source code to the WinFsp DLL.
* src/dll/fuse: Source code to the FUSE compatibility layer. * src/dll/fuse: Source code to the FUSE compatibility layer.
* src/dotnet: Source code to the .NET layer.
* src/launcher: Source code to the launcher service and the launchctl utility. * src/launcher: Source code to the launcher service and the launchctl utility.
* src/sys: Source code to the WinFsp FSD. * src/sys: Source code to the WinFsp FSD.
* opt/cygfuse: Source code for the Cygwin FUSE package. * opt/cygfuse: Source code for the Cygwin FUSE package.
* tst/memfs: Source code to an example file system written in C++ (memfs). * tst/memfs*: Source code to an example file system written in C/C++ (memfs) or C# (memfs-dotnet).
* tst/passthrough*: Source code to additional example file systems.
* tst/winfsp-tests: WinFsp test suite. * tst/winfsp-tests: WinFsp test suite.
## Building and Running ## Building and Running
In order to build WinFsp you will need the following: In order to build WinFsp you will need the following:
* Windows 10
* Visual Studio 2015 * Visual Studio 2015
* Windows Driver Kit (WDK) 10 * Windows Driver Kit (WDK) 10
* [Wix toolset](http://wixtoolset.org) * [Wix toolset](http://wixtoolset.org)
If you build the driver yourself it will not be signed and Windows will refuse to load it unless you enable "testsigning". You can enable "testsigning" using the command `bcdedit.exe -set testsigning`. For more information see this [document](http://www.secfs.net/winfsp/develop/debug/). To fully build WinFsp (including the installer) you must use `tools\build.bat`. By default it builds a Release build, but you can choose either the Debug or Release configuration by using the syntax:
WinFsp is designed to run on Vista and above. It has been tested on the following platforms so far: tools\build.bat CONFIGURATION
If you build the driver yourself it will not be signed and Windows will refuse to load it unless you enable "testsigning". You can enable "testsigning" using the command `bcdedit.exe -set testsigning on`. For more information see this [document](http://www.secfs.net/winfsp/develop/debug/).
WinFsp is designed to run on Windows 7 and above. It has been tested on the following platforms:
* Windows 7 Enterprise * Windows 7 Enterprise
* Windows 8 Pro * Windows 8 Pro
* Windows 10 Pro
* Windows Server 2012 * Windows Server 2012
* Windows 10 Pro
* Windows Server 2016 * Windows Server 2016
## How to Help ## How to Help
@ -65,7 +73,7 @@ WinFsp is designed to run on Vista and above. It has been tested on the followin
I am looking for help in the following areas: I am looking for help in the following areas:
* If you have a file system that runs on FUSE please consider porting it to WinFsp. WinFsp has a native API, but it also has a FUSE (high-level) API. * If you have a file system that runs on FUSE please consider porting it to WinFsp. WinFsp has a native API, but it also has a FUSE (high-level) API.
* If you are working with a language other than C/C++ (e.g. Delphi, C#, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you. * If you are working with a language other than C/C++ (e.g. Delphi, Java, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you.
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues). Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart. * There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues). Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart.
In all cases I can provide ideas and/or support. In all cases I can provide ideas and/or support.

View File

@ -23,7 +23,7 @@ build_script:
- tools\build.bat %CONFIGURATION% - tools\build.bat %CONFIGURATION%
test_script: test_script:
- for %%f in ("build\VStudio\build\%CONFIGURATION%\winfsp-*.msi") do start /wait msiexec /i %%f /qn INSTALLLEVEL=1000 - choco install winfsp -s build\VStudio\build\%CONFIGURATION% -y
- if %TESTING%==Func appveyor DownloadFile http://www.secfs.net/winfsp/resources/Test.Filter.Driver.zip && 7z x Test.Filter.Driver.zip - if %TESTING%==Func appveyor DownloadFile http://www.secfs.net/winfsp/resources/Test.Filter.Driver.zip && 7z x Test.Filter.Driver.zip
- if %TESTING%==Func start /wait msiexec /i "Test.Filter.Driver\HCK Filter.Driver Content-x86_en-us.msi" /qn - if %TESTING%==Func start /wait msiexec /i "Test.Filter.Driver\HCK Filter.Driver Content-x86_en-us.msi" /qn
- if %TESTING%==Func tools\nmake-ext-test.bat %CONFIGURATION% - if %TESTING%==Func tools\nmake-ext-test.bat %CONFIGURATION%
@ -31,6 +31,7 @@ test_script:
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% ifstest - if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% ifstest
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% sample - if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% sample
- if %TESTING%==Perf tools\run-perf-tests.bat %CONFIGURATION% baseline > perf-tests.csv && type perf-tests.csv & appveyor PushArtifact perf-tests.csv - if %TESTING%==Perf tools\run-perf-tests.bat %CONFIGURATION% baseline > perf-tests.csv && type perf-tests.csv & appveyor PushArtifact perf-tests.csv
- choco uninstall winfsp -y
- if exist %SystemRoot%\memory.dmp exit 1 - if exist %SystemRoot%\memory.dmp exit 1
on_finish: on_finish:

View File

@ -3,3 +3,4 @@ build
*.suo *.suo
*.vcproj.* *.vcproj.*
*.vcxproj.user *.vcxproj.user
*.csproj.user

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\version.properties" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{94580219-CC8D-4FE5-A3BE-437B0B3481E1}</ProjectGuid>
<OutputType>Library</OutputType>
<ProjectName>winfsp.net</ProjectName>
<RootNamespace>Fsp</RootNamespace>
<AssemblyName>winfsp-msil</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>$(BaseIntermediateOutputPath)$(Configuration)\winfsp-msil.xml</DocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>$(BaseIntermediateOutputPath)$(Configuration)\winfsp-msil.xml</DocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>winfsp.net.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\src\dotnet\FileSystemBase+Const.cs">
<Link>FileSystemBase+Const.cs</Link>
</Compile>
<Compile Include="..\..\..\src\dotnet\FileSystemBase.cs">
<Link>FileSystemBase.cs</Link>
</Compile>
<Compile Include="..\..\..\src\dotnet\FileSystemHost.cs">
<Link>FileSystemHost.cs</Link>
</Compile>
<Compile Include="..\..\..\src\dotnet\Interop.cs">
<Link>Interop.cs</Link>
</Compile>
<Compile Include="..\..\..\src\dotnet\Service.cs">
<Link>Service.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="winfsp.net.snk" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="AfterBuild">
</Target>
-->
<Target Name="BeforeBuild">
<ItemGroup>
<AssemblyInfo Include="using System.Reflection%3b" />
<AssemblyInfo Include="[assembly: AssemblyProduct(&quot;$(MyProductName)&quot;)]" />
<AssemblyInfo Include="[assembly: AssemblyTitle(&quot;$(MyDescription)&quot;)]" />
<AssemblyInfo Include="[assembly: AssemblyCompany(&quot;$(MyCompanyName)&quot;)]" />
<AssemblyInfo Include="[assembly: AssemblyCopyright(&quot;$(MyCopyright)&quot;)]" />
<AssemblyInfo Include="[assembly: AssemblyVersion(&quot;$(MyAssemblyVersion)&quot;)]" />
<AssemblyInfo Include="[assembly: AssemblyFileVersion(&quot;$(MyVersion)&quot;)]" />
</ItemGroup>
<MakeDir Directories="$(IntermediateOutputPath)" />
<WriteLinesToFile File="$(IntermediateOutputPath)AssemblyInfo.cs" Lines="@(AssemblyInfo)" Overwrite="true" />
<ItemGroup>
<Compile Include="$(IntermediateOutputPath)AssemblyInfo.cs" />
<FileWrites Include="$(IntermediateOutputPath)AssemblyInfo.cs" />
</ItemGroup>
</Target>
<PropertyGroup>
<PostBuildEvent>exit /b 0
set TargetName=$(TargetName)
set MyAssemblyPolicyVersion=$(MyAssemblyPolicyVersion)
set MyAssemblyVersion=$(MyAssemblyVersion)
setlocal EnableDelayedExpansion
if exist $(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).config del $(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).config
for /f "delims=" %25%25l in ($(ProjectDir)winfsp.net.policy.config) do (
set line=%25%25l
echo !line! &gt;&gt;$(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).config
)
"$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.0A\Bin\al.exe" /product:"$(MyProductName)" /title:"$(MyDescription)" /company:"$(MyCompanyName)" /copyright:"$(MyCopyright)" /version:"$(MyAssemblyPolicyVersion)" /fileversion:"$(MyVersion)" /link:$(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).config /out:$(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).dll /keyfile:$(ProjectDir)$(ProjectName).snk
</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,10 @@
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="!TargetName!" publicKeyToken="b099876d8fa9b1f3" culture="neutral" />
<bindingRedirect oldVersion="!MyAssemblyPolicyVersion!.0.0-!MyAssemblyVersion!" newVersion="!MyAssemblyVersion!" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

Binary file not shown.

View File

@ -39,6 +39,7 @@
<Directory Id="BINDIR" Name="bin" /> <Directory Id="BINDIR" Name="bin" />
<Directory Id="INCDIR" Name="inc" /> <Directory Id="INCDIR" Name="inc" />
<Directory Id="LIBDIR" Name="lib" /> <Directory Id="LIBDIR" Name="lib" />
<Directory Id="OPTDIR" Name="opt" />
<Directory Id="SMPDIR" Name="samples" /> <Directory Id="SMPDIR" Name="samples" />
<Directory Id="SYMDIR" Name="sym" /> <Directory Id="SYMDIR" Name="sym" />
</Directory> </Directory>
@ -87,6 +88,23 @@
<Condition>NOT VersionNT64</Condition> <Condition>NOT VersionNT64</Condition>
</Component> </Component>
<!-- install assembly -->
<Component Id="C.winfsp_msil.dll" Guid="0D8BA6AE-9F87-402B-AE1A-95B0AE3BE179">
<File Id="FILE.winfsp_msil.dll" Name="winfsp-msil.dll" KeyPath="yes" />
</Component>
<Component Id="C.winfsp_msil.xml" Guid="1657F707-C112-454C-91AE-0FDEBBF454AB">
<File Id="FILE.winfsp_msil.xml" Name="winfsp-msil.xml" KeyPath="yes" />
</Component>
<!--
<Component Id="C.winfsp_msil.dll.GAC" Guid="6469467D-8C90-4889-8138-4028F9DA6E85">
<File Id="FILE.winfsp_msil.dll.GAC" Name="winfsp-msil.dll" KeyPath="yes" Assembly=".net" />
</Component>
<Component Id="C.policy.winfsp_msil.dll.GAC">
<File Name="policy.1.0.winfsp-msil.dll" KeyPath="yes" Assembly=".net" />
<File Name="policy.1.0.winfsp-msil.config" KeyPath="no" />
</Component>
-->
<!-- On Win64 ServiceInstall launcher-x64.exe --> <!-- On Win64 ServiceInstall launcher-x64.exe -->
<Component Id="C.launcher_x64.exe.svcinst"> <Component Id="C.launcher_x64.exe.svcinst">
<File Id="launcher_x64.exe.svcinst" Name="launcher-x64.exe" KeyPath="yes" /> <File Id="launcher_x64.exe.svcinst" Name="launcher-x64.exe" KeyPath="yes" />
@ -199,6 +217,32 @@
</RegistryKey> </RegistryKey>
</RegistryKey> </RegistryKey>
</Component> </Component>
<Component Id="C.memfs_dotnet_msil.exe">
<File Name="memfs-dotnet-msil.exe" KeyPath="yes" />
<RegistryKey
Root="HKLM"
Key="[P.LauncherRegistryKey]">
<RegistryKey
Key="memfs-dotnet">
<RegistryValue
Type="string"
Name="Executable"
Value="[BINDIR]memfs-dotnet-msil.exe" />
<RegistryValue
Type="string"
Name="CommandLine"
Value="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2" />
<RegistryValue
Type="string"
Name="Security"
Value="D:P(A;;RPWPLC;;;WD)" />
<RegistryValue
Type="integer"
Name="JobControl"
Value="1" />
</RegistryKey>
</RegistryKey>
</Component>
</DirectoryRef> </DirectoryRef>
<DirectoryRef Id="INCDIR" FileSource="..\..\..\inc"> <DirectoryRef Id="INCDIR" FileSource="..\..\..\inc">
<Directory Id="INCDIR.winfsp" Name="winfsp"> <Directory Id="INCDIR.winfsp" Name="winfsp">
@ -208,6 +252,9 @@
<Component Id="C.winfsp.h"> <Component Id="C.winfsp.h">
<File Name="winfsp.h" KeyPath="yes" /> <File Name="winfsp.h" KeyPath="yes" />
</Component> </Component>
<!--Component Id="C.winfsp.hpp">
<File Name="winfsp.hpp" KeyPath="yes" />
</Component-->
</Directory> </Directory>
<Directory Id="INCDIR.fuse" Name="fuse"> <Directory Id="INCDIR.fuse" Name="fuse">
<Component Id="C.fuse.h"> <Component Id="C.fuse.h">
@ -252,6 +299,26 @@
<Condition>NOT VersionNT64</Condition> <Condition>NOT VersionNT64</Condition>
</Component> </Component>
</DirectoryRef> </DirectoryRef>
<DirectoryRef Id="OPTDIR">
<Directory Id="OPTDIR.cygfuse" Name="cygfuse" FileSource="..\..\..\opt\cygfuse\dist">
<Directory Id="OPTDIR.cygfuse.x64" Name="x64">
<Component Id="C.fuse.tar.xz.x64">
<File Id="FILE.fuse.tar.xz.x64" Name="fuse-2.8-5.tar.xz" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="OPTDIR.cygfuse.x86" Name="x86">
<Component Id="C.fuse.tar.xz.x86">
<File Id="FILE.fuse.tar.xz.x86" Name="fuse-2.8-5.tar.xz" KeyPath="yes" />
</Component>
</Directory>
<Component Id="C.fuse.install.sh">
<File Name="install.sh" KeyPath="yes" />
</Component>
<Component Id="C.fuse.uninstall.sh">
<File Name="uninstall.sh" KeyPath="yes" />
</Component>
</Directory>
</DirectoryRef>
<DirectoryRef Id="SMPDIR" FileSource="..\..\..\tst"> <DirectoryRef Id="SMPDIR" FileSource="..\..\..\tst">
<Directory Id="SMPDIR.memfs" Name="memfs"> <Directory Id="SMPDIR.memfs" Name="memfs">
<Component Id="C.memfs.h"> <Component Id="C.memfs.h">
@ -264,6 +331,11 @@
<File Name="memfs-main.c" KeyPath="yes" /> <File Name="memfs-main.c" KeyPath="yes" />
</Component> </Component>
</Directory> </Directory>
<Directory Id="SMPDIR.memfs_dotnet" Name="memfs-dotnet">
<Component Id="C.memfs_dotnet.Program.cs">
<File Id="FILE.memfs_dotnet.Program.cs" Name="Program.cs" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="SMPDIR.passthrough" Name="passthrough"> <Directory Id="SMPDIR.passthrough" Name="passthrough">
<Component Id="C.passthrough.c"> <Component Id="C.passthrough.c">
<File Name="passthrough.c" KeyPath="yes" /> <File Name="passthrough.c" KeyPath="yes" />
@ -278,6 +350,20 @@
<File Name="passthrough.vcxproj.filters" KeyPath="yes" /> <File Name="passthrough.vcxproj.filters" KeyPath="yes" />
</Component> </Component>
</Directory> </Directory>
<!--Directory Id="SMPDIR.passthrough_cpp" Name="passthrough-cpp">
<Component Id="C.passthrough_cpp.cpp">
<File Name="passthrough-cpp.cpp" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_cpp.sln">
<File Name="passthrough-cpp.sln" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_cpp.vcxproj">
<File Name="passthrough-cpp.vcxproj" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_cpp.vcxproj.filters">
<File Name="passthrough-cpp.vcxproj.filters" KeyPath="yes" />
</Component>
</Directory-->
<Directory Id="SMPDIR.passthrough_fuse" Name="passthrough-fuse"> <Directory Id="SMPDIR.passthrough_fuse" Name="passthrough-fuse">
<Component Id="C.passthrough_fuse.c"> <Component Id="C.passthrough_fuse.c">
<File Name="passthrough-fuse.c" KeyPath="yes" /> <File Name="passthrough-fuse.c" KeyPath="yes" />
@ -304,6 +390,17 @@
<File Name="README.md" KeyPath="yes" /> <File Name="README.md" KeyPath="yes" />
</Component> </Component>
</Directory> </Directory>
<Directory Id="SMPDIR.passthrough_dotnet" Name="passthrough-dotnet">
<Component Id="C.passthrough_dotnet.Program.cs">
<File Id="FILE.passthrough_dotnet.Program.cs" Name="Program.cs" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_dotnet.sln">
<File Name="passthrough-dotnet.sln" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_dotnet.csproj">
<File Name="passthrough-dotnet.csproj" KeyPath="yes" />
</Component>
</Directory>
</DirectoryRef> </DirectoryRef>
<DirectoryRef Id="SYMDIR"> <DirectoryRef Id="SYMDIR">
<Component Id="C.winfsp_x64.sys.pdb"> <Component Id="C.winfsp_x64.sys.pdb">
@ -357,6 +454,7 @@
<ComponentGroup Id="C.WinFsp.inc"> <ComponentGroup Id="C.WinFsp.inc">
<ComponentRef Id="C.fsctl.h" /> <ComponentRef Id="C.fsctl.h" />
<ComponentRef Id="C.winfsp.h" /> <ComponentRef Id="C.winfsp.h" />
<!--ComponentRef Id="C.winfsp.hpp" /-->
<ComponentRef Id="C.fuse.h" /> <ComponentRef Id="C.fuse.h" />
<ComponentRef Id="C.fuse_common.h" /> <ComponentRef Id="C.fuse_common.h" />
<ComponentRef Id="C.fuse_opt.h" /> <ComponentRef Id="C.fuse_opt.h" />
@ -368,6 +466,12 @@
<ComponentRef Id="C.fuse_x64.pc" /> <ComponentRef Id="C.fuse_x64.pc" />
<ComponentRef Id="C.fuse_x86.pc" /> <ComponentRef Id="C.fuse_x86.pc" />
</ComponentGroup> </ComponentGroup>
<ComponentGroup Id="C.WinFsp.opt.fuse">
<ComponentRef Id="C.fuse.tar.xz.x64" />
<ComponentRef Id="C.fuse.tar.xz.x86" />
<ComponentRef Id="C.fuse.install.sh" />
<ComponentRef Id="C.fuse.uninstall.sh" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.smp"> <ComponentGroup Id="C.WinFsp.smp">
<ComponentRef Id="C.memfs_x64.exe" /> <ComponentRef Id="C.memfs_x64.exe" />
<ComponentRef Id="C.memfs_x86.exe" /> <ComponentRef Id="C.memfs_x86.exe" />
@ -378,6 +482,10 @@
<ComponentRef Id="C.passthrough.sln" /> <ComponentRef Id="C.passthrough.sln" />
<ComponentRef Id="C.passthrough.vcxproj" /> <ComponentRef Id="C.passthrough.vcxproj" />
<ComponentRef Id="C.passthrough.vcxproj.filters" /> <ComponentRef Id="C.passthrough.vcxproj.filters" />
<!--ComponentRef Id="C.passthrough_cpp.cpp" /-->
<!--ComponentRef Id="C.passthrough_cpp.sln" /-->
<!--ComponentRef Id="C.passthrough_cpp.vcxproj" /-->
<!--ComponentRef Id="C.passthrough_cpp.vcxproj.filters" /-->
<ComponentRef Id="C.passthrough_fuse.c" /> <ComponentRef Id="C.passthrough_fuse.c" />
<ComponentRef Id="C.passthrough_fuse.winposix.c" /> <ComponentRef Id="C.passthrough_fuse.winposix.c" />
<ComponentRef Id="C.passthrough_fuse.winposix.h" /> <ComponentRef Id="C.passthrough_fuse.winposix.h" />
@ -399,6 +507,21 @@
<ComponentRef Id="C.memfs_x64.pdb" /> <ComponentRef Id="C.memfs_x64.pdb" />
<ComponentRef Id="C.memfs_x86.pdb" /> <ComponentRef Id="C.memfs_x86.pdb" />
</ComponentGroup> </ComponentGroup>
<ComponentGroup Id="C.WinFsp.net">
<ComponentRef Id="C.winfsp_msil.dll" />
<ComponentRef Id="C.winfsp_msil.xml" />
<!--
<ComponentRef Id="C.winfsp_msil.dll.GAC" />
<ComponentRef Id="C.policy.winfsp_msil.dll.GAC" />
-->
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.smp.net">
<ComponentRef Id="C.memfs_dotnet_msil.exe" />
<ComponentRef Id="C.memfs_dotnet.Program.cs" />
<ComponentRef Id="C.passthrough_dotnet.Program.cs" />
<ComponentRef Id="C.passthrough_dotnet.sln" />
<ComponentRef Id="C.passthrough_dotnet.csproj" />
</ComponentGroup>
<Feature <Feature
Id="F.Main" Id="F.Main"
@ -421,7 +544,20 @@
InstallDefault="local" InstallDefault="local"
Absent="disallow"> Absent="disallow">
<ComponentGroupRef Id="C.WinFsp.bin" /> <ComponentGroupRef Id="C.WinFsp.bin" />
<ComponentGroupRef Id="C.WinFsp.net" />
</Feature> </Feature>
<!--
<Feature
Id="F.Net"
Level="10"
Title=".NET"
Description="The managed $(var.MyProductName) files."
AllowAdvertise="no"
InstallDefault="local"
Absent="allow">
<ComponentGroupRef Id="C.WinFsp.net" />
</Feature>
-->
<Feature <Feature
Id="F.Developer" Id="F.Developer"
Level="1000" Level="1000"
@ -433,8 +569,19 @@
<ComponentGroupRef Id="C.WinFsp.inc" /> <ComponentGroupRef Id="C.WinFsp.inc" />
<ComponentGroupRef Id="C.WinFsp.lib" /> <ComponentGroupRef Id="C.WinFsp.lib" />
<ComponentGroupRef Id="C.WinFsp.smp" /> <ComponentGroupRef Id="C.WinFsp.smp" />
<ComponentGroupRef Id="C.WinFsp.smp.net" />
<ComponentGroupRef Id="C.WinFsp.sym" /> <ComponentGroupRef Id="C.WinFsp.sym" />
</Feature> </Feature>
<Feature
Id="F.Cygfuse"
Level="1000"
Title="FUSE for Cygwin"
Description="From a Cygwin prompt change to &lt;InstallDir&gt;/opt/cygfuse and run install.sh."
AllowAdvertise="no"
InstallDefault="local"
Absent="allow">
<ComponentGroupRef Id="C.WinFsp.opt.fuse" />
</Feature>
</Feature> </Feature>
<WixVariable Id="WixUIBannerBmp" Value="wixbanner.bmp" /> <WixVariable Id="WixUIBannerBmp" Value="wixbanner.bmp" />

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4920E350-D496-4652-AE98-6C4208AEC1D8}</ProjectGuid>
<OutputType>Exe</OutputType>
<ProjectName>memfs-dotnet</ProjectName>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>memfs</RootNamespace>
<AssemblyName>memfs-dotnet-msil</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\tst\memfs-dotnet\Program.cs">
<Link>Program.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\dotnet\winfsp.net.csproj">
<Project>{94580219-cc8d-4fe5-a3be-437b0b3481e1}</Project>
<Name>winfsp.net</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

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

View File

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

View File

@ -15,14 +15,17 @@
<MyCompanyName>Navimatics Corporation</MyCompanyName> <MyCompanyName>Navimatics Corporation</MyCompanyName>
<MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright> <MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
<MyCanonicalVersion>1.0</MyCanonicalVersion> <MyCanonicalVersion>1.1</MyCanonicalVersion>
<MyProductVersion>2017 RC2</MyProductVersion> <MyProductVersion>2017.1</MyProductVersion>
<MyProductStage>RC</MyProductStage> <MyProductStage>Gold</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion> <MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas> <MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
<MyFullVersion>$(MyCanonicalVersion).$(MyBuildNumber).$(MyGitRevision)</MyFullVersion> <MyFullVersion>$(MyCanonicalVersion).$(MyBuildNumber).$(MyGitRevision)</MyFullVersion>
<MyAssemblyPolicyVersion>$(MyCanonicalVersion.Substring(0,$(MyVersion.IndexOf('.')))).0</MyAssemblyPolicyVersion>
<MyAssemblyVersion>$(MyAssemblyPolicyVersion).0.0</MyAssemblyVersion>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup> <ItemDefinitionGroup>

View File

@ -53,146 +53,238 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fscrash", "testing\fscrash.
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fsbench", "testing\fsbench.vcxproj", "{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fsbench", "testing\fsbench.vcxproj", "{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winfsp.net", "dotnet\winfsp.net.csproj", "{94580219-CC8D-4FE5-A3BE-437B0B3481E1}"
ProjectSection(ProjectDependencies) = postProject
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}
{C85C26BA-8C22-4D30-83DA-46C3548E6332} = {C85C26BA-8C22-4D30-83DA-46C3548E6332}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dotnet", "dotnet", "{A998CEC4-4B34-43DC-8457-F7761228BA67}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "memfs-dotnet", "testing\memfs-dotnet.csproj", "{4920E350-D496-4652-AE98-6C4208AEC1D8}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64
Debug|x86 = Debug|x86 Debug|x86 = Debug|x86
Installer.Debug|Any CPU = Installer.Debug|Any CPU
Installer.Debug|x64 = Installer.Debug|x64 Installer.Debug|x64 = Installer.Debug|x64
Installer.Debug|x86 = Installer.Debug|x86 Installer.Debug|x86 = Installer.Debug|x86
Installer.Release|Any CPU = Installer.Release|Any CPU
Installer.Release|x64 = Installer.Release|x64 Installer.Release|x64 = Installer.Release|x64
Installer.Release|x86 = Installer.Release|x86 Installer.Release|x86 = Installer.Release|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64 Release|x64 = Release|x64
Release|x86 = Release|x86 Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|Any CPU.ActiveCfg = Debug|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x64.ActiveCfg = Debug|x64 {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x64.ActiveCfg = Debug|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x64.Build.0 = Debug|x64 {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x64.Build.0 = Debug|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x86.ActiveCfg = Debug|Win32 {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x86.ActiveCfg = Debug|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x86.Build.0 = Debug|Win32 {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x86.Build.0 = Debug|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Debug|x64.ActiveCfg = Debug|x64 {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Debug|x64.ActiveCfg = Debug|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Debug|x86.ActiveCfg = Debug|Win32 {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Release|x64.ActiveCfg = Release|x64 {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Release|x64.ActiveCfg = Release|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Release|x86.ActiveCfg = Release|Win32 {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Release|x86.ActiveCfg = Release|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|Any CPU.ActiveCfg = Release|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x64.ActiveCfg = Release|x64 {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x64.ActiveCfg = Release|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x64.Build.0 = Release|x64 {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x64.Build.0 = Release|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x86.ActiveCfg = Release|Win32 {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x86.ActiveCfg = Release|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x86.Build.0 = Release|Win32 {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x86.Build.0 = Release|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|Any CPU.ActiveCfg = Debug|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x64.ActiveCfg = Debug|x64 {C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x64.ActiveCfg = Debug|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x64.Build.0 = Debug|x64 {C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x64.Build.0 = Debug|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x86.ActiveCfg = Debug|Win32 {C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x86.ActiveCfg = Debug|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x86.Build.0 = Debug|Win32 {C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x86.Build.0 = Debug|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Debug|x64.ActiveCfg = Debug|x64 {C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Debug|x64.ActiveCfg = Debug|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Debug|x86.ActiveCfg = Debug|Win32 {C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Release|x64.ActiveCfg = Release|x64 {C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Release|x64.ActiveCfg = Release|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Release|x86.ActiveCfg = Release|Win32 {C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Release|x86.ActiveCfg = Release|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|Any CPU.ActiveCfg = Release|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x64.ActiveCfg = Release|x64 {C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x64.ActiveCfg = Release|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x64.Build.0 = Release|x64 {C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x64.Build.0 = Release|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x86.ActiveCfg = Release|Win32 {C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x86.ActiveCfg = Release|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x86.Build.0 = Release|Win32 {C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x86.Build.0 = Release|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|Any CPU.ActiveCfg = Debug|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x64.ActiveCfg = Debug|x64 {262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x64.ActiveCfg = Debug|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x64.Build.0 = Debug|x64 {262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x64.Build.0 = Debug|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x86.ActiveCfg = Debug|Win32 {262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x86.ActiveCfg = Debug|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x86.Build.0 = Debug|Win32 {262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x86.Build.0 = Debug|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Debug|x64.ActiveCfg = Debug|x64 {262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Debug|x64.ActiveCfg = Debug|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Debug|x86.ActiveCfg = Debug|Win32 {262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Release|x64.ActiveCfg = Release|x64 {262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Release|x64.ActiveCfg = Release|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Release|x86.ActiveCfg = Release|Win32 {262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Release|x86.ActiveCfg = Release|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|Any CPU.ActiveCfg = Release|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x64.ActiveCfg = Release|x64 {262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x64.ActiveCfg = Release|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x64.Build.0 = Release|x64 {262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x64.Build.0 = Release|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x86.ActiveCfg = Release|Win32 {262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x86.ActiveCfg = Release|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x86.Build.0 = Release|Win32 {262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x86.Build.0 = Release|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|Any CPU.ActiveCfg = Debug|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x64.ActiveCfg = Debug|x64 {AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x64.ActiveCfg = Debug|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x64.Build.0 = Debug|x64 {AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x64.Build.0 = Debug|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x86.ActiveCfg = Debug|Win32 {AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x86.ActiveCfg = Debug|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x86.Build.0 = Debug|Win32 {AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x86.Build.0 = Debug|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Debug|x64.ActiveCfg = Debug|x64 {AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Debug|x64.ActiveCfg = Debug|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Debug|x86.ActiveCfg = Debug|Win32 {AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Release|x64.ActiveCfg = Release|x64 {AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Release|x64.ActiveCfg = Release|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Release|x86.ActiveCfg = Release|Win32 {AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Release|x86.ActiveCfg = Release|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|Any CPU.ActiveCfg = Release|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x64.ActiveCfg = Release|x64 {AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x64.ActiveCfg = Release|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x64.Build.0 = Release|x64 {AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x64.Build.0 = Release|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x86.ActiveCfg = Release|Win32 {AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x86.ActiveCfg = Release|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x86.Build.0 = Release|Win32 {AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x86.Build.0 = Release|Win32
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Debug|Any CPU.ActiveCfg = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Debug|x64.ActiveCfg = Debug|x86 {D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Debug|x64.ActiveCfg = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Debug|x86.ActiveCfg = Debug|x86 {D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Debug|x86.ActiveCfg = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|Any CPU.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|Any CPU.Build.0 = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x64.ActiveCfg = Release|x86 {D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x64.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x64.Build.0 = Release|x86 {D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x64.Build.0 = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x86.ActiveCfg = Debug|x86 {D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x86.ActiveCfg = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x86.Build.0 = Debug|x86 {D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x86.Build.0 = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|Any CPU.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|Any CPU.Build.0 = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x64.ActiveCfg = Release|x86 {D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x64.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x64.Build.0 = Release|x86 {D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x64.Build.0 = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x86.ActiveCfg = Release|x86 {D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x86.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x86.Build.0 = Release|x86 {D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x86.Build.0 = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Release|Any CPU.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Release|x64.ActiveCfg = Release|x86 {D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Release|x64.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Release|x86.ActiveCfg = Release|x86 {D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Release|x86.ActiveCfg = Release|x86
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Debug|Any CPU.ActiveCfg = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Debug|x64.ActiveCfg = Debug|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Debug|x64.ActiveCfg = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Debug|x86.ActiveCfg = Debug|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Debug|x86.ActiveCfg = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|Any CPU.Build.0 = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x64.ActiveCfg = Release|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x64.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x64.Build.0 = Release|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x64.Build.0 = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x86.ActiveCfg = Debug|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x86.Build.0 = Debug|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x86.Build.0 = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|Any CPU.Build.0 = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x64.ActiveCfg = Release|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x64.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x64.Build.0 = Release|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x64.Build.0 = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x86.ActiveCfg = Release|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x86.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x86.Build.0 = Release|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x86.Build.0 = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|Any CPU.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x64.ActiveCfg = Release|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x64.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x86.ActiveCfg = Release|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x86.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|Any CPU.ActiveCfg = Debug|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.ActiveCfg = Debug|x64 {A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.ActiveCfg = Debug|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.Build.0 = Debug|x64 {A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.Build.0 = Debug|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x86.ActiveCfg = Debug|Win32 {A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x86.ActiveCfg = Debug|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x86.Build.0 = Debug|Win32 {A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x86.Build.0 = Debug|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|x64.ActiveCfg = Debug|x64 {A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|x64.ActiveCfg = Debug|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|x86.ActiveCfg = Debug|Win32 {A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|x64.ActiveCfg = Release|x64 {A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|x64.ActiveCfg = Release|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|x86.ActiveCfg = Release|Win32 {A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|x86.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|Any CPU.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x64.ActiveCfg = Release|x64 {A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x64.ActiveCfg = Release|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x64.Build.0 = Release|x64 {A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x64.Build.0 = Release|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x86.ActiveCfg = Release|Win32 {A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x86.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x86.Build.0 = Release|Win32 {A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x86.Build.0 = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|Any CPU.ActiveCfg = Debug|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x64.ActiveCfg = Debug|x64 {73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x64.ActiveCfg = Debug|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x64.Build.0 = Debug|x64 {73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x64.Build.0 = Debug|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x86.ActiveCfg = Debug|Win32 {73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x86.ActiveCfg = Debug|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x86.Build.0 = Debug|Win32 {73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x86.Build.0 = Debug|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|x64.ActiveCfg = Debug|x64 {73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|x64.ActiveCfg = Debug|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|x86.ActiveCfg = Debug|Win32 {73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|x64.ActiveCfg = Release|x64 {73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|x64.ActiveCfg = Release|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|x86.ActiveCfg = Release|Win32 {73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|x86.ActiveCfg = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|Any CPU.ActiveCfg = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.ActiveCfg = Release|x64 {73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.ActiveCfg = Release|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.Build.0 = Release|x64 {73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.Build.0 = Release|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.ActiveCfg = Release|Win32 {73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.ActiveCfg = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.Build.0 = Release|Win32 {73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.Build.0 = Release|Win32
{10757011-749D-4954-873B-AE38D8145472}.Debug|Any CPU.ActiveCfg = Debug|Win32
{10757011-749D-4954-873B-AE38D8145472}.Debug|x64.ActiveCfg = Debug|x64 {10757011-749D-4954-873B-AE38D8145472}.Debug|x64.ActiveCfg = Debug|x64
{10757011-749D-4954-873B-AE38D8145472}.Debug|x64.Build.0 = Debug|x64 {10757011-749D-4954-873B-AE38D8145472}.Debug|x64.Build.0 = Debug|x64
{10757011-749D-4954-873B-AE38D8145472}.Debug|x86.ActiveCfg = Debug|Win32 {10757011-749D-4954-873B-AE38D8145472}.Debug|x86.ActiveCfg = Debug|Win32
{10757011-749D-4954-873B-AE38D8145472}.Debug|x86.Build.0 = Debug|Win32 {10757011-749D-4954-873B-AE38D8145472}.Debug|x86.Build.0 = Debug|Win32
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.ActiveCfg = Debug|x64 {10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.ActiveCfg = Debug|x64
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.Build.0 = Debug|x64
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.ActiveCfg = Debug|Win32 {10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.Build.0 = Debug|Win32 {10757011-749D-4954-873B-AE38D8145472}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.ActiveCfg = Release|x64 {10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.ActiveCfg = Release|x64
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.Build.0 = Release|x64
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.ActiveCfg = Release|Win32 {10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.ActiveCfg = Release|Win32
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.Build.0 = Release|Win32 {10757011-749D-4954-873B-AE38D8145472}.Release|Any CPU.ActiveCfg = Release|Win32
{10757011-749D-4954-873B-AE38D8145472}.Release|x64.ActiveCfg = Release|x64 {10757011-749D-4954-873B-AE38D8145472}.Release|x64.ActiveCfg = Release|x64
{10757011-749D-4954-873B-AE38D8145472}.Release|x64.Build.0 = Release|x64 {10757011-749D-4954-873B-AE38D8145472}.Release|x64.Build.0 = Release|x64
{10757011-749D-4954-873B-AE38D8145472}.Release|x86.ActiveCfg = Release|Win32 {10757011-749D-4954-873B-AE38D8145472}.Release|x86.ActiveCfg = Release|Win32
{10757011-749D-4954-873B-AE38D8145472}.Release|x86.Build.0 = Release|Win32 {10757011-749D-4954-873B-AE38D8145472}.Release|x86.Build.0 = Release|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|Any CPU.ActiveCfg = Debug|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x64.ActiveCfg = Debug|x64 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x64.ActiveCfg = Debug|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x64.Build.0 = Debug|x64 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x64.Build.0 = Debug|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x86.ActiveCfg = Debug|Win32 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x86.ActiveCfg = Debug|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x86.Build.0 = Debug|Win32 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x86.Build.0 = Debug|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x64.ActiveCfg = Debug|x64 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x64.ActiveCfg = Debug|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x64.Build.0 = Debug|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x86.ActiveCfg = Debug|Win32 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x86.Build.0 = Debug|Win32 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x64.ActiveCfg = Release|x64 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x64.ActiveCfg = Release|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x64.Build.0 = Release|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x86.ActiveCfg = Release|Win32 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x86.ActiveCfg = Release|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x86.Build.0 = Release|Win32 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|Any CPU.ActiveCfg = Release|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x64.ActiveCfg = Release|x64 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x64.ActiveCfg = Release|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x64.Build.0 = Release|x64 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x64.Build.0 = Release|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x86.ActiveCfg = Release|Win32 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x86.ActiveCfg = Release|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x86.Build.0 = Release|Win32 {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x86.Build.0 = Release|Win32
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Debug|x64.ActiveCfg = Debug|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Debug|x64.Build.0 = Debug|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Debug|x86.ActiveCfg = Debug|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Debug|x86.Build.0 = Debug|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Installer.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Installer.Debug|x64.ActiveCfg = Debug|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Installer.Debug|x86.ActiveCfg = Debug|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Installer.Release|Any CPU.ActiveCfg = Release|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Installer.Release|x64.ActiveCfg = Release|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Installer.Release|x86.ActiveCfg = Release|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|Any CPU.Build.0 = Release|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|x64.ActiveCfg = Release|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|x64.Build.0 = Release|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|x86.ActiveCfg = Release|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|x86.Build.0 = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x64.ActiveCfg = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x64.Build.0 = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x86.ActiveCfg = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x86.Build.0 = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|Any CPU.Build.0 = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x64.ActiveCfg = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x64.Build.0 = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x86.ActiveCfg = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x86.Build.0 = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|Any CPU.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|Any CPU.Build.0 = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x64.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x64.Build.0 = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x86.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x86.Build.0 = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|Any CPU.Build.0 = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x64.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x64.Build.0 = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -206,5 +298,7 @@ Global
{73EAAEDA-557B-48D5-A137-328934720FB4} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66} {73EAAEDA-557B-48D5-A137-328934720FB4} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
{10757011-749D-4954-873B-AE38D8145472} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49} {10757011-749D-4954-873B-AE38D8145472} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49} {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
{94580219-CC8D-4FE5-A3BE-437B0B3481E1} = {A998CEC4-4B34-43DC-8457-F7761228BA67}
{4920E350-D496-4652-AE98-6C4208AEC1D8} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@ -26,6 +26,7 @@
<ClInclude Include="..\..\inc\fuse\winfsp_fuse.h" /> <ClInclude Include="..\..\inc\fuse\winfsp_fuse.h" />
<ClInclude Include="..\..\inc\winfsp\fsctl.h" /> <ClInclude Include="..\..\inc\winfsp\fsctl.h" />
<ClInclude Include="..\..\inc\winfsp\winfsp.h" /> <ClInclude Include="..\..\inc\winfsp\winfsp.h" />
<ClInclude Include="..\..\inc\winfsp\winfsp.hpp" />
<ClInclude Include="..\..\src\dll\fuse\library.h" /> <ClInclude Include="..\..\src\dll\fuse\library.h" />
<ClInclude Include="..\..\src\dll\library.h" /> <ClInclude Include="..\..\src\dll\library.h" />
<ClInclude Include="..\..\src\shared\minimal.h" /> <ClInclude Include="..\..\src\shared\minimal.h" />
@ -34,6 +35,7 @@
<ClCompile Include="..\..\src\dll\dirbuf.c" /> <ClCompile Include="..\..\src\dll\dirbuf.c" />
<ClCompile Include="..\..\src\dll\eventlog.c" /> <ClCompile Include="..\..\src\dll\eventlog.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse.c" /> <ClCompile Include="..\..\src\dll\fuse\fuse.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_compat.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c" /> <ClCompile Include="..\..\src\dll\fuse\fuse_intf.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_main.c" /> <ClCompile Include="..\..\src\dll\fuse\fuse_main.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_opt.c" /> <ClCompile Include="..\..\src\dll\fuse\fuse_opt.c" />

View File

@ -50,6 +50,9 @@
<ClInclude Include="..\..\src\dll\fuse\library.h"> <ClInclude Include="..\..\src\dll\fuse\library.h">
<Filter>Source\fuse</Filter> <Filter>Source\fuse</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\inc\winfsp\winfsp.hpp">
<Filter>Include\winfsp</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\src\dll\library.c"> <ClCompile Include="..\..\src\dll\library.c">
@ -106,6 +109,9 @@
<ClCompile Include="..\..\src\dll\dirbuf.c"> <ClCompile Include="..\..\src\dll\dirbuf.c">
<Filter>Source</Filter> <Filter>Source</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\dll\fuse\fuse_compat.c">
<Filter>Source\fuse</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\..\src\dll\library.def"> <None Include="..\..\src\dll\library.def">

View File

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

View File

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

4
build/choco/LICENSE.txt Normal file
View File

@ -0,0 +1,4 @@
From: https://github.com/billziss-gh/winfsp/blob/master/License.txt
LICENSE

View File

@ -0,0 +1,15 @@
VERIFICATION
Verification is intended to assist the Chocolatey moderators and community
in verifying that this package's contents are trustworthy.
WinFsp GitHub repository: https://github.com/billziss-gh/winfsp
WinFsp MSI releases : https://github.com/billziss-gh/winfsp/releases
You may use the Windows certutil utility to confirm the hash of the MSI
included in this package against the WinFsp MSI release of the same version.
For example, for WinFsp version 1.0.17072 the command line to use is:
certutil -hashfile winfsp-1.0.17072.msi SHA256
The certutil output of the MSI in this package is included below.

View File

@ -0,0 +1,36 @@
$ErrorActionPreference = 'Stop';
$packageName = 'winfsp'
$softwareName = 'WinFsp*'
$installerType = 'msi'
$silentArgs = '/qn /norestart'
$validExitCodes = @(0, 3010, 1605, 1614, 1641)
[array]$key = Get-UninstallRegistryKey -SoftwareName $softwareName
if ($key.Count -eq 1) {
$key | % {
# The Product Code GUID is all that should be passed for MSI, and very
# FIRST, because it comes directly after /x, which is already set in the
# Uninstall-ChocolateyPackage msiargs (facepalm).
$silentArgs = "$($_.PSChildName) $silentArgs"
# Don't pass anything for file, it is ignored for msi (facepalm number 2)
# Alternatively if you need to pass a path to an msi, determine that and
# use it instead of the above in silentArgs, still very first
$file = ''
Uninstall-ChocolateyPackage `
-PackageName $packageName `
-FileType $installerType `
-SilentArgs "$silentArgs" `
-ValidExitCodes $validExitCodes `
-File "$file"
}
} elseif ($key.Count -eq 0) {
Write-Warning "$packageName has already been uninstalled by other means."
} elseif ($key.Count -gt 1) {
Write-Warning "Too many matching packages found! Package may not be uninstalled."
Write-Warning "Please alert package maintainer the following packages were matched:"
$key | % {Write-Warning "- $_"}
}

View File

@ -0,0 +1,16 @@
$ErrorActionPreference = 'Stop';
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
$fileLocation = @(Get-ChildItem $toolsDir -filter winfsp-*.msi)[0].FullName
$packageArgs = @{
packageName = 'winfsp'
fileType = 'msi'
file = $fileLocation
silentArgs = "/qn /norestart INSTALLLEVEL=1000"
validExitCodes = @(0, 3010, 1641)
}
Install-ChocolateyInstallPackage @packageArgs
Remove-Item -Force $packageArgs.file

56
build/choco/winfsp.nuspec Normal file
View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
<metadata>
<id>winfsp</id>
<version>$version$</version>
<packageSourceUrl>https://github.com/billziss-gh/winfsp/tree/master/build/choco</packageSourceUrl>
<owners>Bill Zissimopoulos</owners>
<title>WinFsp</title>
<authors>Bill Zissimopoulos</authors>
<projectUrl>https://github.com/billziss-gh/winfsp</projectUrl>
<iconUrl>https://github.com/billziss-gh/winfsp/raw/master/art/winfsp-solid.png</iconUrl>
<copyright>Bill Zissimopoulos</copyright>
<licenseUrl>https://github.com/billziss-gh/winfsp/blob/master/License.txt</licenseUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<projectSourceUrl>https://github.com/billziss-gh/winfsp</projectSourceUrl>
<docsUrl>https://github.com/billziss-gh/winfsp/tree/master/doc</docsUrl>
<mailingListUrl>https://groups.google.com/forum/#!forum/winfsp</mailingListUrl>
<bugTrackerUrl>https://github.com/billziss-gh/winfsp/issues</bugTrackerUrl>
<tags>driver filesystem fuse gplv3 windows-kernel admin</tags>
<summary>Windows File System Proxy - FUSE for Windows</summary>
<description>
WinFsp is a set of software components for Windows computers that allows the creation of user mode file systems. In this sense it is similar to FUSE (Filesystem in Userspace), which provides the same functionality on UNIX-like computers.
Some of the benefits of using WinFsp are listed below:
* Very well-tested and stable.
* Very fast.
* Strives for compatibility with NTFS.
* Easy to understand but comprehensive API.
* FUSE compatibility layer for native Windows and Cygwin.
* Signed drivers provided on every release.
* Available under the GPLv3 license with a special exception for Free/Libre and Open Source Software.
To verify installation:
* For 64-bit Windows: `net use m: \\memfs64\share` from the command prompt.
* For 32-bit Windows: `net use m: \\memfs32\share`
* For Cygwin: `net use m: '\\memfs64\share'`
* To delete the drive: `net use m: /delete`
</description>
<releaseNotes>https://github.com/billziss-gh/winfsp/blob/master/Changelog.asciidoc</releaseNotes>
<!--<dependencies>
<dependency id="chocolatey-uninstall.extension" />
</dependencies>-->
</metadata>
<files>
<file src="LICENSE.txt" target="tools" />
<file src="VERIFICATION.txt" target="tools" />
<file src="chocolateyInstall.ps1" target="tools" />
<file src="chocolateyBeforeModify.ps1" target="tools" />
<file src="winfsp-$version$.msi" target="tools" />
</files>
</package>

View File

@ -0,0 +1,56 @@
= Frequently Asked Questions
== General
[qanda]
I am running Windows 7 and I am finding that the installed driver is not signed. [@efeat]::
Your Windows 7 OS is missing SHA-2 Code Signing Support. You need to install the following security advisory that will rectify the problem:
https://technet.microsoft.com/en-us/library/security/3033929.aspx
Disconnecting (unmapping) a network drive does not work. [@carlreinke]::
You may have Dokany installed. Dokany installs its own Network Provider DLL that unfortunately interferes with the WinFsp handling of network drives. The solution is to change your system's Network Provider order and ensure that the WinFsp Network Provider runs before the Dokany one. Instructions on how to change the Network Provider order can be found in this http://blogs.interfacett.com/changing-the-network-provider-order-in-windows-10[article].
Why is the DLL not installed in the Windows system directories? [@netheril96]::
It is true that this would make it convenient to load the DLL, because the Windows loader looks into the Windows system directories when it loads DLL's. However, in the opinion of the WinFsp author, software that does not ship with the OS should not be installing components in the system directories.
+
There are a few alternative methods to overcome this problem. WinFsp recommends marking the WinFsp DLL as "delay load" and then using `FspLoad` to dynamically load the DLL during process initialization. For more information see the WinFsp Tutorial.
Does WinFsp provide debugging symbols? [@netheril96]::
Public debugging symbols are already included in the installer. You need to install the "Developer" feature; the symbols can be found in the `sym` directory under the WinFsp installation directory.
Is there a maximum number of concurrent file systems? [@efeat]::
WinFsp does not have a hard limit of how many file systems can be created or how many processes can create file systems.
+
As of the commits required to fix issue #55, there is however a hash table inside the FSD that uses PID's (Process ID's) as keys. This hash table currently expects that in general there will not be more than 50 processes creating file systems. However this is not a hard limit.
== FUSE
[qanda]
Which version of FUSE does WinFsp-FUSE support?::
Currently it supports FUSE 2.8.
FUSE on UNIX systems mounts file systems over an existing directory. When mounting a WinFsp-FUSE file system on a directory, the directory is created and later deleted when the file system goes away. What is the reason for this incompatibility? [@efeat]::
It would be preferrable if WinFsp-FUSE behaved like FUSE on UNIX in this instance. However there are a number of reasons that this is not the case.
+
When mounting over directories in Windows, WinFsp-FUSE uses a special construct called a reparse point. Reparse points are a general mechanism for adding special behavior to files and directories. One of the possible reparse points is the "mountpoint" reparse point (often called "junction"), which converts a directory into a mount point.
+
With this in mind here are the reasons for the current WinFsp-FUSE behavior:
+
- Symmetry with mounting on a drive. On Windows drives are created when the file system comes into existence and deleted when it is gone.
- Inability to mount over a non-empty directory on Windows. On FUSE/UNIX this is possible, but not on Windows because NTFS disallows the creation of (mountpoint) reparse points on non-empty directories.
- Most importantly: inability to guarantee that the mount point will cease to exist if the file system crashes. WinFsp attempts to guarantee that all resources used by a file system will get cleaned up. This is certainly true for the kernel-mode FSD, but an attempt is made to do so also in user mode. For this reason, drive symbolic links are marked as temporary and (importantly for our discussion) mount directories are opened with `FILE_FLAG_DELETE_ON_CLOSE`. There is no way to guarantee the removal of a reparse point in the same way.

33
doc/Home.md Normal file
View File

@ -0,0 +1,33 @@
# WinFsp - Windows File System Proxy
[[WinFsp-Icon.png]]
Developing file systems is a challenging proposition. Developing file systems for Windows is an order of magnitude more difficult. WinFsp eases the task of writing a new file system for Windows. WinFsp file systems are user mode programs and they can be written in a variety of languages and frameworks.
The documentation available here discusses various aspects of WinFsp.
## Programming
- The [[Tutorial|WinFsp-Tutorial]] describes how to create a simple, but complete file system in C/C++.
- The [[API Reference|winfsp.h]] describes the native WinFsp API. This external [[link|http://www.secfs.net/winfsp/apiref/]] may be easier to browse for some people.
- There is also a FUSE compatibility layer for native Windows and Cygwin. See fuse.h in the source repository.
- This [[document|Native-API-vs-FUSE]] discusses the need for both a native API and FUSE and gives some pointers on which one to choose.
## Design
- The [[Design|WinFsp-Design]] document describes the high-level design of WinFsp.
- The [[IPC|WinFsp-as-an-IPC-Mechanism]] document offers insights into the WinFsp Inter-Process Communication mechanism.
- The [[Queued Events|Queued-Events]] document discusses a low-level synchronization primitive that is largely responsible for the excellent performance of the WinFsp IPC mechanism.
- The [[Service Architecture|WinFsp-Service-Architecture]] document discusses how to intergrate a file system into Windows as a service and the reasons to do so.
- The [[SSHFS Port Case Study|SSHFS-Port-Case-Study]] document chronicles the creation of the WinFsp-FUSE compatibility layer and the decisions that led to its design.
## Testing
- The [[Testing|WinFsp-Testing]] document discusses the WinFsp testing strategy and how WinFsp achieves correctness and stability.
- The [[Performance|WinFsp-Performance-Testing]] document compares WinFsp performance against other file systems.
## Compatibility
- The [[Compatibility|NTFS-Compatibility]] document discusses current WinFsp compatibility with NTFS.
WinFsp is available under the GPLv3 license with a special exception for Free/Libre and Open Source Software.

View File

@ -0,0 +1,20 @@
= Known File Systems and File System Libraries
This document contains a list of known file systems and file system libraries that run on WinFsp. Please contact the WinFsp project to have your file system solution added to this list.
== File Systems
- https://github.com/billziss-gh/nfs-win[nfs-win] - NFS for Windows
- https://github.com/ncw/rclone[rclone] - rsync for cloud storage
- https://github.com/hasse69/rar2fs[rar2fs] - FUSE file system for reading RAR archives
- https://github.com/billziss-gh/redditfs[redditfs] - ls -l /r/programming
- https://github.com/netheril96/securefs[securefs] - Filesystem in userspace (FUSE) with transparent authenticated encryption
- https://github.com/billziss-gh/sshfs-win[sshfs-win] - SSHFS for Windows
== File System Libraries
- https://github.com/billziss-gh/cgofuse[cgofuse] - Cross-platform FUSE library for Go
- https://github.com/DuroSoft/fuse-bindings[fuse-bindings] - Fully maintained FUSE bindings for Node that aims to cover the entire FUSE api
- https://github.com/ui4j/fuse-jna[fuse-jna] - No-nonsense, actually-working Java bindings to FUSE using JNA
- https://github.com/billziss-gh/fusepy[fusepy] - Simple ctypes bindings for FUSE
- https://github.com/yogendersolanki91/winfsp[WinFsp fork with .NET Layer] - by @yogendersolanki91

105
doc/Queued-Events.asciidoc Normal file
View File

@ -0,0 +1,105 @@
= Queued Events - Windows kernel events with IOCP scheduling characteristics
In this article I am discussing _Queued Events_. _Queued Events_ are a Windows kernel synchronization mechanism that I invented for https://github.com/billziss-gh/winfsp[WinFsp - FUSE for Windows]. _Queued Events_ behave like kernel Synchronization Events (i.e. Win32 auto-reset events), but provide scheduling characteristics similar to those of I/O Completion Ports.
== The Problem
During the later stages of WinFsp development I decided to do some performance testing to understand its behavior and find opportunities for optimization. I found out that WinFsp performed very well in most tested scenarios, but there was one test that seemed to have bad performance for no particular reason.
I ended up profiling this issue using xperf (included in the https://docs.microsoft.com/en-us/windows-hardware/test/wpt/[Windows Performance Toolkit]), which allows for kernel-level profiling. I spent considerable time looking at the profiling results, but could identify no obvious issue with my code.
After a day or two of doing this and being stumped I finally had a lightbulb moment: what if the issue is not with my code, but with how the OS schedules threads? Sure enough I had xperf trace context switches and found that on good runs the OS would context switch my file system threads relatively rarely; on bad runs the OS would context switch my threads excessively.
After contemplating this issue I realized that this was happening because the OS was trying to schedule my threads in a "fair" manner. Windows in general tries to give every thread a chance to run. This can be counter-productive in server-like programs (such as file systems), where all server threads are equivalent and it is actually better to reuse the same thread (if possible) to avoid context switching and other negative effects.
== The Solution
One way of looking at WinFsp is as an IPC (Inter-Process Communication) mechanism. The Windows kernel packages file system operations (open, close, read, write) as IRP's (I/O Request Packets) which it sends to WinFsp. WinFsp places them in an _I/O Queue_; at a later time the threads in a user mode file system retrieve the IRP's from the _I/O Queue_ and service them.
The _I/O Queue_ had gone through multiple iterations, but at the time I was looking at this issue it was using Windows kernel Synchronization Event's (Win32 auto-reset events) for managing threads. The problem was that a wait on a Synchronization Event would be satisfied in a "fair" manner, thus resulting to excessive context switching and bad performance in some circumstances. I needed to find a way to convince Windows to schedule my threads in an "unfair" manner, giving preference to the same thread as much as possible.
I started considering different schemes where I would associate a different event per thread thus being able to wake up the "correct" thread myself and effectively writing my own mini-scheduler. Luckily I had another lightbulb moment: I/O completion ports already do this better than I would ever be able to!
The kernel portion of an I/O Completion Port is called a https://msdn.microsoft.com/en-us/library/windows/hardware/ff549547(v=vs.85).aspx[KQUEUE]. KQUEUE's are (unfortunately) not directly exposed to user mode, however they are at the core of the user mode I/O Completion Ports. KQUEUE's are the main reason I/O Completion Ports are so fast as they provide the following scheduling characteristics:
- They have a Last-In First-Out (LIFO) wait discipline.
- They limit the number of threads that can be satisfied concurrently.
I briefly considered the idea of building _I/O Queues_ directly on top of KQUEUE's, but soon dismissed this idea because _I/O Queues_ are not simple queues but provide additional services, such as IRP cancelation, IRP expiration, etc.
== Queued Events
In an ideal scenario I wanted to continue using my implementation of _I/O Queues_ which had undergone considerable testing and I knew it worked. But somehow I had to convince the Windows kernel to change the scheduling characteristics of Synchronization Events to mirror those of a KQUEUE.
Then I had lightbulb no 3: _Queued Events_ or how to make a queue behave like a Synchronization Event.
Here is how _Queued Events_ work. A _Queued Event_ consists of a KQUEUE and a spin lock. There is also a single dummy item that can be placed in the KQUEUE.
The KQUEUE is guaranteed to contain either 0 or 1 items. When the KQUEUE contains 0 items the _Queued Event_ is considered non-signaled. When the KQUEUE contains 1 items the _Queued Event_ is considered signaled.
ifdef::env-browser[]
[ditaa,file="Queued-Events/states.png"]
--
Non signaled Signaled
+---------------------------+ +---------------------------+
| Queued Event | | Queued Event |
+---------------------------+ +---------------------------+
| | | +---------+ |
| KQUEUE (empty) | | KQUEUE | DUMMY | |
| | | +---------+ |
+---------------------------+ +---------------------------+
--
endif::env-browser[]
ifndef::env-browser[image::Queued-Events/states.png[]]
To transition from the non-signaled to the signaled state, we acquire the spin lock and then insert the dummy item in the KQUEUE using https://msdn.microsoft.com/en-us/library/windows/hardware/ff549570(v=vs.85).aspx[KeInsertQueue]. To transition from the signaled to the non-signaled state, we simply (wait and) remove the dummy item from the KQUEUE using https://msdn.microsoft.com/en-us/library/windows/hardware/ff549605(v=vs.85).aspx[KeRemoveQueue] (without the use of the spin lock).
----
EventSet:
AcquireSpinLock
if (0 == KeReadState()) // if KQUEUE is empty
KeInsertQueue(DUMMY);
ReleaseSpinLock
EventWait:
KeRemoveQueue(); // (wait and) remove item
----
First notice that EventSet is serialized by the use of the spin lock. This guarantees that the dummy item can be only inserted ONCE in the KQUEUE and that the only possible signaled state transitions for EventSet are 0->1 and 1->1. This is how https://msdn.microsoft.com/en-us/library/windows/hardware/ff553253(v=vs.85).aspx[KeSetEvent] works for a Synchronization Event.
Second notice that EventWait is not protected by the spin lock, which means that it can happen at any time including concurrently with EventSet or another EventWait. Notice also that for EventWait the only possible transitions are 1->0 or 0->0 (0->block->0). This is how https://msdn.microsoft.com/en-us/library/windows/hardware/ff553350(v=vs.85).aspx[KeWaitForSingleObject] works for a Synchronization Event.
ifdef::env-browser[]
[ditaa,file="Queued-Events/transitions.png"]
--
Non signaled Signaled
+---------------------------+ +---------------------------+
| Queued Event | | Queued Event |
+---------------------------+ +---------------------------+
| | ---EventSet --> | +---------+ |
| KQUEUE (empty) | | KQUEUE | DUMMY | |
| | <--EventWait--- | +---------+ |
+---------------------------+ +---------------------------+
--
endif::env-browser[]
ifndef::env-browser[image::Queued-Events/transitions.png[]]
We now have to consider what happens when we have one EventSet concurrently with one or more EventWait's:
1. The EventWait(s) happen before https://msdn.microsoft.com/en-us/library/windows/hardware/ff549591(v=vs.85).aspx[KeReadState]. If the KQUEUE has an item one EventWait gets satisfied, otherwise it blocks. In this case KeReadState will read the KQUEUE's state as 0 and KeInsertQueue will insert the dummy item, which will unblock the EventWait.
2. The EventWait(s) happen after KeReadState, but before KeInsertQueue. If the dummy item was already in the KQUEUE the KeReadState test will fail and KeInsertQueue will not be executed, but EventWait will be satisfied immediately. If the dummy item was not in the KQUEUE the KeReadState will succeed and EventWait will momentarily block until KeInsertQueue releases it.
3. The EventWait(s) happen after KeInsertQueue. In this case the dummy item in is the KQUEUE already and one EventWait will be satisfied immediately.
NOTE: _Queued Events_ cannot cleanly support an EventClear operation. The obvious choice of using KeRemoveQueue with a 0 timeout is insufficient because it would associate the current thread with the KQUEUE and that is not desirable. KeRundownQueue cannot be used either because it disassociates all threads from the KQUEUE.
The complete implementation of _Queued Events_ within WinFsp can be found here: https://github.com/billziss-gh/winfsp/blob/v1.1/src/sys/driver.h#L655-L795
== Queued Events Scheduling Characteristics
Queued Events encapsulate KQUEUE's and therefore inherit their scheduling characteristics:
- They have a Last-In First-Out (LIFO) wait discipline.
- They limit the number of threads that can be satisfied concurrently.
These characteristics are desirable because they reduce the number of context switches thus speeding up the WinFsp IPC implementation. Performance testing immediately after the incorporation of _Queued Events_ into WinFsp showed significant performance improvements; profiling with xperf showed that context switches among file system threads were now a relatively rare event!

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
doc/WinFsp-Icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -38,7 +38,7 @@ For example, the MEMFS sample adds the following registry entries in a 64-bit sy
"Security"="D:P(A;;RPWPLC;;;WD)" "Security"="D:P(A;;RPWPLC;;;WD)"
"JobControl"=dword:00000001 "JobControl"=dword:00000001
When the WinFsp.Launcher starts up it creates a named pipe that applications can use to start, stop, get information about and list service instances. A small command line utility (`launchctl`) can be used to issue those commands. The CallNamedPipeW API can be used as well. When the WinFsp.Launcher starts up it creates a named pipe that applications can use to start, stop, get information about and list service instances. A small command line utility (`launchctl`) can be used to issue those commands. The `CallNamedPipeW` API can be used as well.
One final note regarding security. Notice the `Security` registry value in the example above. This registry value uses SDDL syntax to instruct WinFsp.Launcher to allow Everyone (`WD`) to start (`RP`), stop (`WP`) and get information (`LC`) about the service instance. If the `Security` registry value is missing the default is to allow only LocalSystem and Administrators to control the service instance. One final note regarding security. Notice the `Security` registry value in the example above. This registry value uses SDDL syntax to instruct WinFsp.Launcher to allow Everyone (`WD`) to start (`RP`), stop (`WP`) and get information (`LC`) about the service instance. If the `Security` registry value is missing the default is to allow only LocalSystem and Administrators to control the service instance.
@ -47,3 +47,13 @@ One final note regarding security. Notice the `Security` registry value in the e
WinFsp includes a Network Provider that integrates with Windows and can be used to start and stop user mode file systems from the Windows shell. To achieve this the Network Provider (implemented as part of the WinFsp DLL) works closely with the WinFsp.Launcher service. WinFsp includes a Network Provider that integrates with Windows and can be used to start and stop user mode file systems from the Windows shell. To achieve this the Network Provider (implemented as part of the WinFsp DLL) works closely with the WinFsp.Launcher service.
For example, if a user uses the Windows Explorer to map `\\memfs64\share` to the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to start an instance of the memfs64 service with command line `-i -F NTFS -n 65536 -s 67108864 -u \\memfs64\share -m Z:`. When the user disconnects the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to stop the previously started instance of the memfs64 service. For example, if a user uses the Windows Explorer to map `\\memfs64\share` to the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to start an instance of the memfs64 service with command line `-i -F NTFS -n 65536 -s 67108864 -u \\memfs64\share -m Z:`. When the user disconnects the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to stop the previously started instance of the memfs64 service.
== File System Credential Support
Some file systems require credentials in order to allow access and be mounted. Such file systems must add a registry value `Credentials`:
"Credentials"=dword:00000001
This will instruct the WinFsp Network Provider to request a password from the user prior to starting the file system. This password will then be securely passed to the WinFsp Launcher which in turn will pass it to the user mode file system on its standard input. The user mode file system must respond `OK` if the password is correct and allows access to the user mode file system. Any other response from the user mode file system (including a timeout without a response) is interpreted as an authentication failure.
NOTE: During password entry the user may also choose to "remember" the password in which case it will be saved in the Windows Credential Manager.

View File

@ -112,7 +112,7 @@ usage: passthrough OPTIONS
options: options:
-d DebugFlags [-1: enable all debug logs] -d DebugFlags [-1: enable all debug logs]
-D DebugLogFile [file path; use - for stdout] -D DebugLogFile [file path; use - for stderr]
-u \Server\Share [UNC prefix (single backslash)] -u \Server\Share [UNC prefix (single backslash)]
-p Directory [directory to expose as pass through file system] -p Directory [directory to expose as pass through file system]
-m MountPoint [X:|*|directory] -m MountPoint [X:|*|directory]
@ -138,7 +138,7 @@ The variable `DebugLogFile` is used to control the WinFsp debug logging mechanis
if (0 != DebugLogFile) if (0 != DebugLogFile)
{ {
if (0 == wcscmp(L"-", DebugLogFile)) if (0 == wcscmp(L"-", DebugLogFile))
DebugLogHandle = GetStdHandle(STD_OUTPUT_HANDLE); DebugLogHandle = GetStdHandle(STD_ERROR_HANDLE);
else else
DebugLogHandle = CreateFileW( DebugLogHandle = CreateFileW(
DebugLogFile, DebugLogFile,

1741
doc/winfsp.h.asciidoc Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -118,6 +118,8 @@ FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_loop_mt)(struct fsp_fuse_env *env,
struct fuse *f); struct fuse *f);
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_exit)(struct fsp_fuse_env *env, FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_exit)(struct fsp_fuse_env *env,
struct fuse *f); struct fuse *f);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_exited)(struct fsp_fuse_env *env,
struct fuse *f);
FSP_FUSE_API struct fuse_context *FSP_FUSE_API_NAME(fsp_fuse_get_context)(struct fsp_fuse_env *env); FSP_FUSE_API struct fuse_context *FSP_FUSE_API_NAME(fsp_fuse_get_context)(struct fsp_fuse_env *env);
FSP_FUSE_SYM( FSP_FUSE_SYM(
@ -171,6 +173,13 @@ void fuse_exit(struct fuse *f),
(fsp_fuse_env(), f); (fsp_fuse_env(), f);
}) })
FSP_FUSE_SYM(
int fuse_exited(struct fuse *f),
{
return FSP_FUSE_API_CALL(fsp_fuse_exited)
(fsp_fuse_env(), f);
})
FSP_FUSE_SYM( FSP_FUSE_SYM(
struct fuse_context *fuse_get_context(void), struct fuse_context *fuse_get_context(void),
{ {

View File

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

View File

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

View File

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

View File

@ -26,7 +26,10 @@
#include <windows.h> #include <windows.h>
#undef WIN32_NO_STATUS #undef WIN32_NO_STATUS
#include <winternl.h> #include <winternl.h>
#pragma warning(push)
#pragma warning(disable:4005) /* macro redefinition */
#include <ntstatus.h> #include <ntstatus.h>
#pragma warning(pop)
#if defined(WINFSP_DLL_INTERNAL) #if defined(WINFSP_DLL_INTERNAL)
#define FSP_API __declspec(dllexport) #define FSP_API __declspec(dllexport)
@ -893,6 +896,8 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem);
* STATUS_SUCCESS or error code. * STATUS_SUCCESS or error code.
*/ */
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint); FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint);
FSP_API NTSTATUS FspFileSystemSetMountPointEx(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint,
PSECURITY_DESCRIPTOR SecurityDescriptor);
/** /**
* Remove the mount point for a file system. * Remove the mount point for a file system.
* *
@ -956,11 +961,14 @@ FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
* The current operation context. * The current operation context.
*/ */
FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID); FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID);
FSP_API PWSTR FspFileSystemMountPointF(FSP_FILE_SYSTEM *FileSystem);
static inline static inline
PWSTR FspFileSystemMountPoint(FSP_FILE_SYSTEM *FileSystem) PWSTR FspFileSystemMountPoint(FSP_FILE_SYSTEM *FileSystem)
{ {
return FileSystem->MountPoint; return FileSystem->MountPoint;
} }
FSP_API NTSTATUS FspFileSystemEnterOperationF(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
static inline static inline
NTSTATUS FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem, NTSTATUS FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response) FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
@ -970,6 +978,8 @@ NTSTATUS FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem,
return FileSystem->EnterOperation(FileSystem, Request, Response); return FileSystem->EnterOperation(FileSystem, Request, Response);
} }
FSP_API NTSTATUS FspFileSystemLeaveOperationF(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
static inline static inline
NTSTATUS FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem, NTSTATUS FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response) FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
@ -979,6 +989,9 @@ NTSTATUS FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem,
return FileSystem->LeaveOperation(FileSystem, Request, Response); return FileSystem->LeaveOperation(FileSystem, Request, Response);
} }
FSP_API VOID FspFileSystemSetOperationGuardF(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation,
FSP_FILE_SYSTEM_OPERATION_GUARD *LeaveOperation);
static inline static inline
VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation, FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation,
@ -997,12 +1010,17 @@ VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
* @see * @see
* FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY * FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY
*/ */
FSP_API VOID FspFileSystemSetOperationGuardStrategyF(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy);
static inline static inline
VOID FspFileSystemSetOperationGuardStrategy(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetOperationGuardStrategy(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy) FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy)
{ {
FileSystem->OpGuardStrategy = GuardStrategy; FileSystem->OpGuardStrategy = GuardStrategy;
} }
FSP_API VOID FspFileSystemSetOperationF(FSP_FILE_SYSTEM *FileSystem,
ULONG Index,
FSP_FILE_SYSTEM_OPERATION *Operation);
static inline static inline
VOID FspFileSystemSetOperation(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetOperation(FSP_FILE_SYSTEM *FileSystem,
ULONG Index, ULONG Index,
@ -1010,6 +1028,8 @@ VOID FspFileSystemSetOperation(FSP_FILE_SYSTEM *FileSystem,
{ {
FileSystem->Operations[Index] = Operation; FileSystem->Operations[Index] = Operation;
} }
FSP_API VOID FspFileSystemGetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS *PDispatcherResult);
static inline static inline
VOID FspFileSystemGetDispatcherResult(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemGetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS *PDispatcherResult) NTSTATUS *PDispatcherResult)
@ -1018,6 +1038,8 @@ VOID FspFileSystemGetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
*PDispatcherResult = FileSystem->DispatcherResult; *PDispatcherResult = FileSystem->DispatcherResult;
MemoryBarrier(); MemoryBarrier();
} }
FSP_API VOID FspFileSystemSetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS DispatcherResult);
static inline static inline
VOID FspFileSystemSetDispatcherResult(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS DispatcherResult) NTSTATUS DispatcherResult)
@ -1026,12 +1048,15 @@ VOID FspFileSystemSetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
return; return;
InterlockedCompareExchange(&FileSystem->DispatcherResult, DispatcherResult, 0); InterlockedCompareExchange(&FileSystem->DispatcherResult, DispatcherResult, 0);
} }
FSP_API VOID FspFileSystemSetDebugLogF(FSP_FILE_SYSTEM *FileSystem,
UINT32 DebugLog);
static inline static inline
VOID FspFileSystemSetDebugLog(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetDebugLog(FSP_FILE_SYSTEM *FileSystem,
UINT32 DebugLog) UINT32 DebugLog)
{ {
FileSystem->DebugLog = DebugLog; FileSystem->DebugLog = DebugLog;
} }
FSP_API BOOLEAN FspFileSystemIsOperationCaseSensitiveF(VOID);
static inline static inline
BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID) BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID)
{ {
@ -1625,6 +1650,7 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize, PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout, PULONG PBytesTransferred, ULONG Timeout,
PSID Sid); PSID Sid);
FSP_API NTSTATUS FspVersion(PUINT32 PVersion);
/* /*
* Delay load * Delay load
@ -1639,6 +1665,18 @@ NTSTATUS FspLoad(PVOID *PModule)
#endif #endif
#define FSP_DLLPATH "bin\\" FSP_DLLNAME #define FSP_DLLPATH "bin\\" FSP_DLLNAME
WINADVAPI
LSTATUS
APIENTRY
RegGetValueW(
HKEY hkey,
LPCWSTR lpSubKey,
LPCWSTR lpValue,
DWORD dwFlags,
LPDWORD pdwType,
PVOID pvData,
LPDWORD pcbData);
WCHAR PathBuf[MAX_PATH]; WCHAR PathBuf[MAX_PATH];
DWORD Size; DWORD Size;
HKEY RegKey; HKEY RegKey;

1308
inc/winfsp/winfsp.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -18,3 +18,11 @@ cygport:
> opt/cygfuse/winfsp-work.tar.gz\ > opt/cygfuse/winfsp-work.tar.gz\
) )
CYGPORT_SRC_URI=winfsp-work.tar.gz CYGPORT_SRC_DIR=winfsp-work cygport fuse.cygport download prep compile install package CYGPORT_SRC_URI=winfsp-work.tar.gz CYGPORT_SRC_DIR=winfsp-work cygport fuse.cygport download prep compile install package
dist: cygport
case $(shell uname -m) in \
x86_64)\
cp fuse-*/dist/fuse/fuse-*[0-9].tar.xz dist/x64 ;;\
*)\
cp fuse-*/dist/fuse/fuse-*[0-9].tar.xz dist/x86 ;;\
esac

View File

@ -17,22 +17,39 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <pthread.h> #include <pthread.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/cygwin.h> #include <sys/cygwin.h>
static void *cygfuse_init_slow(int force);
static void *cygfuse_init_winfsp(); static void *cygfuse_init_winfsp();
static void *cygfuse_init_fail();
static pthread_mutex_t cygfuse_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t cygfuse_mutex = PTHREAD_MUTEX_INITIALIZER;
static void *cygfuse_handle = 0; static void *cygfuse_handle = 0;
static inline void cygfuse_init(int force) static inline void *cygfuse_init_fast(void)
{ {
void *handle = cygfuse_handle;
__sync_synchronize(); /* memory barrier */
if (0 == handle)
handle = cygfuse_init_slow(0);
return handle;
}
static void *cygfuse_init_slow(int force)
{
void *handle;
pthread_mutex_lock(&cygfuse_mutex); pthread_mutex_lock(&cygfuse_mutex);
if (force || 0 == cygfuse_handle) handle = cygfuse_handle;
cygfuse_handle = cygfuse_init_winfsp(); if (force || 0 == handle)
{
handle = cygfuse_init_winfsp();
__sync_synchronize(); /* memory barrier */
cygfuse_handle = handle;
}
pthread_mutex_unlock(&cygfuse_mutex); pthread_mutex_unlock(&cygfuse_mutex);
return handle;
} }
/* /*
@ -50,7 +67,7 @@ static inline int cygfuse_daemon(int nochdir, int noclose)
return -1; return -1;
/* force reload of WinFsp DLL to workaround fork() problems */ /* force reload of WinFsp DLL to workaround fork() problems */
cygfuse_init(1); cygfuse_init_slow(1);
return 0; return 0;
} }
@ -58,7 +75,7 @@ static inline int cygfuse_daemon(int nochdir, int noclose)
#define FSP_FUSE_API static #define FSP_FUSE_API static
#define FSP_FUSE_API_NAME(api) (* pfn_ ## api) #define FSP_FUSE_API_NAME(api) (* pfn_ ## api)
#define FSP_FUSE_API_CALL(api) (cygfuse_init(0), pfn_ ## api) #define FSP_FUSE_API_CALL(api) (cygfuse_init_fast(), pfn_ ## api)
#define FSP_FUSE_SYM(proto, ...) __attribute__ ((visibility("default"))) proto { __VA_ARGS__ } #define FSP_FUSE_SYM(proto, ...) __attribute__ ((visibility("default"))) proto { __VA_ARGS__ }
#include <fuse_common.h> #include <fuse_common.h>
#include <fuse.h> #include <fuse.h>
@ -74,6 +91,7 @@ static inline int cygfuse_daemon(int nochdir, int noclose)
if (0 == (*(void **)&(pfn_ ## n) = dlsym(h, #n)))\ if (0 == (*(void **)&(pfn_ ## n) = dlsym(h, #n)))\
return cygfuse_init_fail(); return cygfuse_init_fail();
static void *cygfuse_init_fail();
static void *cygfuse_init_winfsp() static void *cygfuse_init_winfsp()
{ {
void *h; void *h;
@ -125,6 +143,7 @@ static void *cygfuse_init_winfsp()
CYGFUSE_GET_API(h, fsp_fuse_loop); CYGFUSE_GET_API(h, fsp_fuse_loop);
CYGFUSE_GET_API(h, fsp_fuse_loop_mt); CYGFUSE_GET_API(h, fsp_fuse_loop_mt);
CYGFUSE_GET_API(h, fsp_fuse_exit); CYGFUSE_GET_API(h, fsp_fuse_exit);
CYGFUSE_GET_API(h, fsp_fuse_exited);
CYGFUSE_GET_API(h, fsp_fuse_get_context); CYGFUSE_GET_API(h, fsp_fuse_get_context);
/* fuse_opt.h */ /* fuse_opt.h */
@ -141,6 +160,7 @@ static void *cygfuse_init_winfsp()
static void *cygfuse_init_fail() static void *cygfuse_init_fail()
{ {
abort(); fprintf(stderr, "cygfuse: initialization failed: " CYGFUSE_WINFSP_NAME " not found\n");
exit(1);
return 0; return 0;
} }

8
opt/cygfuse/dist/install.sh vendored Normal file
View File

@ -0,0 +1,8 @@
cd "$(dirname "$0")"
case $(uname -m) in
x86_64)
tar -C/ -xaf x64/fuse-2.8-*.tar.xz ;;
*)
tar -C/ -xaf x86/fuse-2.8-*.tar.xz ;;
esac
echo FUSE for Cygwin installed.

8
opt/cygfuse/dist/uninstall.sh vendored Normal file
View File

@ -0,0 +1,8 @@
cd "$(dirname "$0")"
case $(uname -m) in
x86_64)
tar -taf x64/fuse-2.8-*.tar.xz | sed -e '/\/$/d' -e 's/.*/\/&/' | xargs rm -f ;;
*)
tar -taf x86/fuse-2.8-*.tar.xz | sed -e '/\/$/d' -e 's/.*/\/&/' | xargs rm -f ;;
esac
echo FUSE for Cygwin uninstalled.

BIN
opt/cygfuse/dist/x64/fuse-2.8-5.tar.xz vendored Normal file

Binary file not shown.

BIN
opt/cygfuse/dist/x86/fuse-2.8-5.tar.xz vendored Normal file

Binary file not shown.

View File

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

View File

@ -187,20 +187,63 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem)
MemFree(FileSystem); MemFree(FileSystem);
} }
static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWSTR VolumeName) static NTSTATUS FspFileSystemSetMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName,
PHANDLE PMountHandle)
{
*PMountHandle = 0;
if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, VolumeName))
return FspNtStatusFromWin32(GetLastError());
if (0 != FspNtOpenSymbolicLinkObject)
{
NTSTATUS Result;
WCHAR SymlinkBuf[6];
UNICODE_STRING Symlink;
OBJECT_ATTRIBUTES Obja;
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
SymlinkBuf[4] = MountPoint[0];
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
Symlink.Buffer = SymlinkBuf;
memset(&Obja, 0, sizeof Obja);
Obja.Length = sizeof Obja;
Obja.ObjectName = &Symlink;
Obja.Attributes = OBJ_CASE_INSENSITIVE;
Result = FspNtOpenSymbolicLinkObject(PMountHandle, DELETE, &Obja);
if (NT_SUCCESS(Result))
{
Result = FspNtMakeTemporaryObject(*PMountHandle);
if (!NT_SUCCESS(Result))
{
FspNtClose(*PMountHandle);
*PMountHandle = 0;
}
}
}
return STATUS_SUCCESS;
}
static NTSTATUS FspFileSystemSetMountPoint_Directory(PWSTR MountPoint, PWSTR VolumeName,
PSECURITY_DESCRIPTOR SecurityDescriptor, PHANDLE PMountHandle)
{ {
NTSTATUS Result; NTSTATUS Result;
HANDLE DirHandle; SECURITY_ATTRIBUTES SecurityAttributes;
BOOL Success; HANDLE MountHandle = INVALID_HANDLE_VALUE;
DWORD Backslashes, Bytes; DWORD Backslashes, Bytes;
USHORT VolumeNameLength, BackslashLength, ReparseDataLength; USHORT VolumeNameLength, BackslashLength, ReparseDataLength;
PREPARSE_DATA_BUFFER ReparseData = 0; PREPARSE_DATA_BUFFER ReparseData = 0;
PWSTR P, PathBuffer; PWSTR P, PathBuffer;
*PMountHandle = 0;
/* /*
* Windows does not allow mount points (junctions) to point to network file systems. * Windows does not allow mount points (junctions) to point to network file systems.
* *
* Count how many backslashes our VolumeName. If it is 3 or more this is a network * Count how many backslashes our VolumeName has. If it is 3 or more this is a network
* file system. Preemptively return STATUS_NETWORK_ACCESS_DENIED. * file system. Preemptively return STATUS_NETWORK_ACCESS_DENIED.
*/ */
for (P = VolumeName, Backslashes = 0; *P; P++) for (P = VolumeName, Backslashes = 0; *P; P++)
@ -211,25 +254,24 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
goto exit; goto exit;
} }
if (!CreateDirectoryW(MountPoint, 0)) memset(&SecurityAttributes, 0, sizeof SecurityAttributes);
SecurityAttributes.nLength = sizeof SecurityAttributes;
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
MountHandle = CreateFileW(MountPoint,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
&SecurityAttributes,
CREATE_NEW,
FILE_ATTRIBUTE_DIRECTORY |
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE,
0);
if (INVALID_HANDLE_VALUE == MountHandle)
{ {
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());
goto exit; goto exit;
} }
DirHandle = CreateFileW(MountPoint,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
0);
if (INVALID_HANDLE_VALUE == DirHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto rmdir_and_exit;
}
VolumeNameLength = (USHORT)lstrlenW(VolumeName); VolumeNameLength = (USHORT)lstrlenW(VolumeName);
BackslashLength = 0 == VolumeNameLength || L'\\' != VolumeName[VolumeNameLength - 1]; BackslashLength = 0 == VolumeNameLength || L'\\' != VolumeName[VolumeNameLength - 1];
VolumeNameLength *= sizeof(WCHAR); VolumeNameLength *= sizeof(WCHAR);
@ -243,7 +285,7 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
if (0 == ReparseData) if (0 == ReparseData)
{ {
Result = STATUS_INSUFFICIENT_RESOURCES; Result = STATUS_INSUFFICIENT_RESOURCES;
goto rmdir_and_exit; goto exit;
} }
ReparseData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; ReparseData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
@ -270,86 +312,35 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\'; PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\';
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0'; PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
Success = DeviceIoControl(DirHandle, FSCTL_SET_REPARSE_POINT, if (!DeviceIoControl(MountHandle, FSCTL_SET_REPARSE_POINT,
ReparseData, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseData->ReparseDataLength, ReparseData, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseData->ReparseDataLength,
0, 0, 0, 0,
&Bytes, 0); &Bytes, 0))
CloseHandle(DirHandle);
if (!Success)
{ {
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());
goto rmdir_and_exit; goto exit;
} }
*PMountHandle = MountHandle;
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
exit: exit:
if (!NT_SUCCESS(Result) && INVALID_HANDLE_VALUE != MountHandle)
CloseHandle(MountHandle);
MemFree(ReparseData); MemFree(ReparseData);
return Result;
rmdir_and_exit:
RemoveDirectoryW(MountPoint);
goto exit;
}
static NTSTATUS FspFileSystemSetMountPoint_MakeTemporary(PWSTR MountPoint, PHANDLE PMountHandle)
{
NTSTATUS Result = STATUS_SUCCESS;
HANDLE MountHandle = 0;
if (FspPathIsDrive(MountPoint))
{
if (0 != FspNtOpenSymbolicLinkObject)
{
WCHAR SymlinkBuf[6];
UNICODE_STRING Symlink;
OBJECT_ATTRIBUTES Obja;
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
SymlinkBuf[4] = MountPoint[0];
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
Symlink.Buffer = SymlinkBuf;
memset(&Obja, 0, sizeof Obja);
Obja.Length = sizeof Obja;
Obja.ObjectName = &Symlink;
Obja.Attributes = OBJ_CASE_INSENSITIVE;
Result = FspNtOpenSymbolicLinkObject(&MountHandle, DELETE, &Obja);
if (NT_SUCCESS(Result))
{
Result = FspNtMakeTemporaryObject(MountHandle);
if (!NT_SUCCESS(Result))
{
FspNtClose(MountHandle);
MountHandle = 0;
}
}
}
}
else
{
/* open the directory for DELETE_ON_CLOSE; closing it will remove the directory */
MountHandle = CreateFileW(MountPoint,
FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_DELETE_ON_CLOSE,
0);
if (INVALID_HANDLE_VALUE == MountHandle)
{
MountHandle = 0;
Result = FspNtStatusFromWin32(GetLastError());
}
}
*PMountHandle = MountHandle;
return Result; return Result;
} }
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint) FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint)
{
return FspFileSystemSetMountPointEx(FileSystem, MountPoint, 0);
}
FSP_API NTSTATUS FspFileSystemSetMountPointEx(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint,
PSECURITY_DESCRIPTOR SecurityDescriptor)
{ {
if (0 != FileSystem->MountPoint) if (0 != FileSystem->MountPoint)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
@ -375,11 +366,10 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
if (0 == (Drives & (1 << (Drive - 'A')))) if (0 == (Drives & (1 << (Drive - 'A'))))
{ {
MountPoint[0] = Drive; MountPoint[0] = Drive;
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName)) Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
{ &MountHandle);
Result = STATUS_SUCCESS; if (NT_SUCCESS(Result))
goto exit; goto exit;
}
} }
Result = STATUS_NO_SUCH_DEVICE; Result = STATUS_NO_SUCH_DEVICE;
} }
@ -400,22 +390,16 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
MountPoint = P; MountPoint = P;
if (FspPathIsDrive(MountPoint)) if (FspPathIsDrive(MountPoint))
{ Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName)) &MountHandle);
Result = STATUS_SUCCESS;
else
Result = FspNtStatusFromWin32(GetLastError());
}
else else
Result = FspFileSystemSetMountPoint_CreateDirectory(MountPoint, FileSystem->VolumeName); Result = FspFileSystemSetMountPoint_Directory(MountPoint, FileSystem->VolumeName,
SecurityDescriptor, &MountHandle);
} }
exit: exit:
if (NT_SUCCESS(Result)) if (NT_SUCCESS(Result))
{ {
FspFileSystemSetMountPoint_MakeTemporary(MountPoint, &MountHandle);
/* ignore result; this path always considered successful */
FileSystem->MountPoint = MountPoint; FileSystem->MountPoint = MountPoint;
FileSystem->MountHandle = MountHandle; FileSystem->MountHandle = MountHandle;
} }
@ -425,33 +409,35 @@ exit:
return Result; return Result;
} }
static VOID FspFileSystemRemoveMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName, HANDLE MountHandle)
{
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
MountPoint, VolumeName);
if (0 != MountHandle)
FspNtClose(MountHandle);
}
static VOID FspFileSystemRemoveMountPoint_Directory(HANDLE MountHandle)
{
/* directory is marked DELETE_ON_CLOSE */
CloseHandle(MountHandle);
}
FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem) FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
{ {
BOOLEAN IsDrive;
if (0 == FileSystem->MountPoint) if (0 == FileSystem->MountPoint)
return; return;
IsDrive = FspPathIsDrive(FileSystem->MountPoint); if (FspPathIsDrive(FileSystem->MountPoint))
if (IsDrive) FspFileSystemRemoveMountPoint_Drive(FileSystem->MountPoint, FileSystem->VolumeName,
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, FileSystem->MountHandle);
FileSystem->MountPoint, FileSystem->VolumeName);
else else
/* nothing to do! directory will be deleted when the MountHandle is closed */; FspFileSystemRemoveMountPoint_Directory(FileSystem->MountHandle);
MemFree(FileSystem->MountPoint); MemFree(FileSystem->MountPoint);
FileSystem->MountPoint = 0; FileSystem->MountPoint = 0;
FileSystem->MountHandle = 0;
if (0 != FileSystem->MountHandle)
{
if (IsDrive)
FspNtClose(FileSystem->MountHandle);
else
/* CloseHandle really calls NtClose, but I like being defensive when programming */
CloseHandle(FileSystem->MountHandle);
FileSystem->MountHandle = 0;
}
} }
static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0) static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
@ -633,3 +619,67 @@ FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID
{ {
return (FSP_FILE_SYSTEM_OPERATION_CONTEXT *)TlsGetValue(FspFileSystemTlsKey); return (FSP_FILE_SYSTEM_OPERATION_CONTEXT *)TlsGetValue(FspFileSystemTlsKey);
} }
/*
* Out-of-Line
*/
FSP_API PWSTR FspFileSystemMountPointF(FSP_FILE_SYSTEM *FileSystem)
{
return FspFileSystemMountPoint(FileSystem);
}
FSP_API NTSTATUS FspFileSystemEnterOperationF(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{
return FspFileSystemEnterOperation(FileSystem, Request, Response);
}
FSP_API NTSTATUS FspFileSystemLeaveOperationF(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{
return FspFileSystemLeaveOperation(FileSystem, Request, Response);
}
FSP_API VOID FspFileSystemSetOperationGuardF(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation,
FSP_FILE_SYSTEM_OPERATION_GUARD *LeaveOperation)
{
FspFileSystemSetOperationGuard(FileSystem, EnterOperation, LeaveOperation);
}
FSP_API VOID FspFileSystemSetOperationGuardStrategyF(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy)
{
FspFileSystemSetOperationGuardStrategy(FileSystem, GuardStrategy);
}
FSP_API VOID FspFileSystemSetOperationF(FSP_FILE_SYSTEM *FileSystem,
ULONG Index,
FSP_FILE_SYSTEM_OPERATION *Operation)
{
FspFileSystemSetOperation(FileSystem, Index, Operation);
}
FSP_API VOID FspFileSystemGetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS *PDispatcherResult)
{
FspFileSystemGetDispatcherResult(FileSystem, PDispatcherResult);
}
FSP_API VOID FspFileSystemSetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS DispatcherResult)
{
FspFileSystemSetDispatcherResult(FileSystem, DispatcherResult);
}
FSP_API VOID FspFileSystemSetDebugLogF(FSP_FILE_SYSTEM *FileSystem,
UINT32 DebugLog)
{
FspFileSystemSetDebugLog(FileSystem, DebugLog);
}
FSP_API BOOLEAN FspFileSystemIsOperationCaseSensitiveF(VOID)
{
return FspFileSystemIsOperationCaseSensitive();
}

View File

@ -355,10 +355,18 @@ static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
{ {
LastError = GetEffectiveRightsFromAclW(Dacl, &AccessEntry.Trustee, &AccessRights); LastError = GetEffectiveRightsFromAclW(Dacl, &AccessEntry.Trustee, &AccessRights);
if (0 != LastError) if (0 != LastError)
{ /*
Result = FspNtStatusFromWin32(LastError); * Apparently GetEffectiveRightsFromAclW can fail with ERROR_CIRCULAR_DEPENDENCY
goto exit; * in some rare circumstances. Calling GetEffectiveRightsFromAclW is not essential
} * in this instance. It is only done to check whether the "Everyone/World" SID
* already has the access required to start the FSD; if it does not have those
* rights already they are added. It is probably safe to just assume that the
* required rights are not there if GetEffectiveRightsFromAclW fails; the worst
* that can happen is that the rights get added twice (which is benign).
*
* See https://github.com/billziss-gh/winfsp/issues/62
*/
AccessRights = 0;
} }
/* do we have the required access rights? */ /* do we have the required access rights? */

View File

@ -1354,7 +1354,7 @@ FSP_API BOOLEAN FspFileSystemFindReparsePoint(FSP_FILE_SYSTEM *FileSystem,
return FALSE; return FALSE;
} }
FSP_API NTSTATUS FspFileSystemResolveReparsePointsInternal(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS FspFileSystemResolveReparsePointsInternal(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS (*GetReparsePointByName)( NTSTATUS (*GetReparsePointByName)(
FSP_FILE_SYSTEM *FileSystem, PVOID Context, FSP_FILE_SYSTEM *FileSystem, PVOID Context,
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize), PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize),

View File

@ -32,18 +32,20 @@ struct fsp_fuse_core_opt_data
{ {
struct fsp_fuse_env *env; struct fsp_fuse_env *env;
int help, debug; int help, debug;
int hard_remove, HANDLE DebugLogHandle;
use_ino, readdir_ino, int set_umask, umask,
set_umask, umask,
set_uid, uid, set_uid, uid,
set_gid, gid, set_gid, gid,
set_attr_timeout, attr_timeout, set_attr_timeout, attr_timeout,
rellinks; rellinks;
int set_FileInfoTimeout; int set_FileInfoTimeout;
int CaseInsensitiveSearch,
ReadOnlyVolume;
FSP_FSCTL_VOLUME_PARAMS VolumeParams; FSP_FSCTL_VOLUME_PARAMS VolumeParams;
UINT16 VolumeLabelLength;
WCHAR VolumeLabel[sizeof ((FSP_FSCTL_VOLUME_INFO *)0)->VolumeLabel / sizeof(WCHAR)];
}; };
FSP_FSCTL_STATIC_ASSERT(
sizeof ((struct fuse *)0)->VolumeLabel == sizeof ((struct fsp_fuse_core_opt_data *)0)->VolumeLabel,
"fuse::VolumeLabel and fsp_fuse_core_opt_data::VolumeLabel: sizeof must be same.");
static struct fuse_opt fsp_fuse_core_opts[] = static struct fuse_opt fsp_fuse_core_opts[] =
{ {
@ -56,9 +58,11 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FSP_FUSE_CORE_OPT("-d", debug, 1), FSP_FUSE_CORE_OPT("-d", debug, 1),
FSP_FUSE_CORE_OPT("debug", debug, 1), FSP_FUSE_CORE_OPT("debug", debug, 1),
FSP_FUSE_CORE_OPT("hard_remove", hard_remove, 1), FUSE_OPT_KEY("DebugLog=", 'D'),
FSP_FUSE_CORE_OPT("use_ino", use_ino, 1),
FSP_FUSE_CORE_OPT("readdir_ino", readdir_ino, 1), FUSE_OPT_KEY("hard_remove", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("use_ino", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("readdir_ino", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("direct_io", FUSE_OPT_KEY_DISCARD), FUSE_OPT_KEY("direct_io", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("kernel_cache", FUSE_OPT_KEY_DISCARD), FUSE_OPT_KEY("kernel_cache", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("auto_cache", FUSE_OPT_KEY_DISCARD), FUSE_OPT_KEY("auto_cache", FUSE_OPT_KEY_DISCARD),
@ -83,25 +87,20 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FSP_FUSE_CORE_OPT("norellinks", rellinks, 0), FSP_FUSE_CORE_OPT("norellinks", rellinks, 0),
FUSE_OPT_KEY("fstypename=", 'F'), FUSE_OPT_KEY("fstypename=", 'F'),
FUSE_OPT_KEY("volname=", 'v'),
FSP_FUSE_CORE_OPT("SectorSize=%hu", VolumeParams.SectorSize, 4096), FSP_FUSE_CORE_OPT("SectorSize=%hu", VolumeParams.SectorSize, 4096),
FSP_FUSE_CORE_OPT("SectorsPerAllocationUnit=%hu", VolumeParams.SectorsPerAllocationUnit, 1), FSP_FUSE_CORE_OPT("SectorsPerAllocationUnit=%hu", VolumeParams.SectorsPerAllocationUnit, 1),
FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0), FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
FSP_FUSE_CORE_OPT("VolumeCreationTime=%lli", VolumeParams.VolumeCreationTime, 0), FSP_FUSE_CORE_OPT("VolumeCreationTime=%lli", VolumeParams.VolumeCreationTime, 0),
FSP_FUSE_CORE_OPT("VolumeSerialNumber=%lx", VolumeParams.VolumeSerialNumber, 0), FSP_FUSE_CORE_OPT("VolumeSerialNumber=%lx", VolumeParams.VolumeSerialNumber, 0),
FSP_FUSE_CORE_OPT("TransactTimeout=%u", VolumeParams.TransactTimeout, 0),
FSP_FUSE_CORE_OPT("IrpTimeout=%u", VolumeParams.IrpTimeout, 0),
FSP_FUSE_CORE_OPT("IrpCapacity=%u", VolumeParams.IrpCapacity, 0),
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1), FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0), FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
FSP_FUSE_CORE_OPT("CaseInsensitiveSearch", CaseInsensitiveSearch, 1), FUSE_OPT_KEY("UNC=", 'U'),
FSP_FUSE_CORE_OPT("ReadOnlyVolume", ReadOnlyVolume, 1),
FUSE_OPT_KEY("ReparsePoints", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("NamedStreams", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("HardLinks", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("ExtendedAttributes", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("--UNC=", 'U'), FUSE_OPT_KEY("--UNC=", 'U'),
FUSE_OPT_KEY("VolumePrefix=", 'U'),
FUSE_OPT_KEY("--VolumePrefix=", 'U'), FUSE_OPT_KEY("--VolumePrefix=", 'U'),
FUSE_OPT_KEY("FileSystemName=", 'F'),
FUSE_OPT_KEY("--FileSystemName=", 'F'), FUSE_OPT_KEY("--FileSystemName=", 'F'),
FUSE_OPT_END, FUSE_OPT_END,
@ -131,6 +130,9 @@ static inline void *fsp_fuse_obj_alloc(struct fsp_fuse_env *env, size_t size)
static inline void fsp_fuse_obj_free(void *obj) static inline void fsp_fuse_obj_free(void *obj)
{ {
if (0 == obj)
return;
struct fsp_fuse_obj_hdr *hdr = (PVOID)((PUINT8)obj - sizeof(struct fsp_fuse_obj_hdr)); struct fsp_fuse_obj_hdr *hdr = (PVOID)((PUINT8)obj - sizeof(struct fsp_fuse_obj_hdr));
hdr->dtor(hdr); hdr->dtor(hdr);
@ -190,23 +192,55 @@ FSP_FUSE_API struct fuse_chan *fsp_fuse_mount(struct fsp_fuse_env *env,
const char *mountpoint, struct fuse_args *args) const char *mountpoint, struct fuse_args *args)
{ {
struct fuse_chan *ch = 0; struct fuse_chan *ch = 0;
WCHAR TempMountPointBuf[MAX_PATH], MountPointBuf[MAX_PATH];
int Size; int Size;
if (0 == mountpoint) if (0 == mountpoint || '\0' == mountpoint[0] ||
mountpoint = ""; ('*' == mountpoint[0] && '\0' == mountpoint[1]))
{
MountPointBuf[0] = L'*';
MountPointBuf[1] = L'\0';
Size = 2 * sizeof(WCHAR);
}
else if (
(
('A' <= mountpoint[0] && mountpoint[0] <= 'Z') ||
('a' <= mountpoint[0] && mountpoint[0] <= 'z')
) &&
':' == mountpoint[1] && '\0' == mountpoint[2])
{
MountPointBuf[0] = mountpoint[0];
MountPointBuf[1] = ':';
MountPointBuf[2] = '\0';
Size = 3 * sizeof(WCHAR);
}
else
{
char *win_mountpoint = 0;
Size = MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, 0, 0); if (0 != env->conv_to_win_path)
if (0 == Size) mountpoint = win_mountpoint = env->conv_to_win_path(mountpoint);
goto fail;
ch = fsp_fuse_obj_alloc(env, sizeof *ch + Size * sizeof(WCHAR)); Size = 0;
if (0 != mountpoint &&
0 != MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, TempMountPointBuf, MAX_PATH))
Size = GetFullPathNameW(TempMountPointBuf, MAX_PATH, MountPointBuf, 0);
env->memfree(win_mountpoint);
if (0 == Size || MAX_PATH <= Size)
goto fail;
mountpoint = 0;
Size = (Size + 1) * sizeof(WCHAR);
}
ch = fsp_fuse_obj_alloc(env, sizeof *ch + Size);
if (0 == ch) if (0 == ch)
goto fail; goto fail;
ch->MountPoint = (PVOID)ch->Buffer; ch->MountPoint = (PVOID)ch->Buffer;
Size = MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, ch->MountPoint, Size); memcpy(ch->MountPoint, MountPointBuf, Size);
if (0 == Size)
goto fail;
return ch; return ch;
@ -261,9 +295,17 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
//FUSE_CAP_ATOMIC_O_TRUNC | /* due to Windows/WinFsp design, no support */ //FUSE_CAP_ATOMIC_O_TRUNC | /* due to Windows/WinFsp design, no support */
//FUSE_CAP_EXPORT_SUPPORT | /* not needed in Windows/WinFsp */ //FUSE_CAP_EXPORT_SUPPORT | /* not needed in Windows/WinFsp */
FUSE_CAP_BIG_WRITES | FUSE_CAP_BIG_WRITES |
FUSE_CAP_DONT_MASK; FUSE_CAP_DONT_MASK |
FSP_FUSE_CAP_READDIR_PLUS |
FSP_FUSE_CAP_READ_ONLY |
FSP_FUSE_CAP_CASE_INSENSITIVE;
if (0 != f->ops.init) if (0 != f->ops.init)
{
context->private_data = f->data = f->ops.init(&conn); context->private_data = f->data = f->ops.init(&conn);
f->VolumeParams.ReadOnlyVolume = 0 != (conn.want & FSP_FUSE_CAP_READ_ONLY);
f->VolumeParams.CaseSensitiveSearch = 0 == (conn.want & FSP_FUSE_CAP_CASE_INSENSITIVE);
f->conn_want = conn.want;
}
f->fsinit = TRUE; f->fsinit = TRUE;
if (0 != f->ops.statfs) if (0 != f->ops.statfs)
{ {
@ -278,10 +320,12 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
goto fail; goto fail;
} }
if (stbuf.f_frsize > FSP_FUSE_SECTORSIZE_MAX) if (0 == f->VolumeParams.SectorSize && 0 != stbuf.f_frsize)
stbuf.f_frsize = FSP_FUSE_SECTORSIZE_MAX;
if (0 == f->VolumeParams.SectorSize)
f->VolumeParams.SectorSize = (UINT16)stbuf.f_frsize; f->VolumeParams.SectorSize = (UINT16)stbuf.f_frsize;
#if 0
if (0 == f->VolumeParams.SectorsPerAllocationUnit && 0 != stbuf.f_frsize)
f->VolumeParams.SectorsPerAllocationUnit = (UINT16)(stbuf.f_bsize / stbuf.f_frsize);
#endif
if (0 == f->VolumeParams.MaxComponentLength) if (0 == f->VolumeParams.MaxComponentLength)
f->VolumeParams.MaxComponentLength = (UINT16)stbuf.f_namemax; f->VolumeParams.MaxComponentLength = (UINT16)stbuf.f_namemax;
} }
@ -313,9 +357,8 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
} }
/* the FSD does not currently limit these VolumeParams fields; do so here! */ /* the FSD does not currently limit these VolumeParams fields; do so here! */
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN) if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN ||
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MIN; f->VolumeParams.SectorSize > FSP_FUSE_SECTORSIZE_MAX)
if (f->VolumeParams.SectorSize > FSP_FUSE_SECTORSIZE_MAX)
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MAX; f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MAX;
if (f->VolumeParams.SectorsPerAllocationUnit == 0) if (f->VolumeParams.SectorsPerAllocationUnit == 0)
f->VolumeParams.SectorsPerAllocationUnit = 1; f->VolumeParams.SectorsPerAllocationUnit = 1;
@ -417,18 +460,27 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
default: default:
return 1; return 1;
case 'h': case 'h':
/* Note: The limit on FspServiceLog messages is 1024 bytes. This is getting close. */
FspServiceLog(EVENTLOG_ERROR_TYPE, L"" FspServiceLog(EVENTLOG_ERROR_TYPE, L""
FSP_FUSE_LIBRARY_NAME " options:\n" FSP_FUSE_LIBRARY_NAME " options:\n"
" -o SectorSize=N sector size for Windows (512-4096, deflt: 512)\n" " -o umask=MASK set file permissions (octal)\n"
" -o SectorsPerAllocationUnit=N allocation unit size (deflt: 1*SectorSize)\n" " -o uid=N set file owner (-1 for mounting user id)\n"
" -o MaxComponentLength=N max file name component length (deflt: 255)\n" " -o gid=N set file group (-1 for mounting user group)\n"
" -o VolumeCreationTime=T volume creation time (FILETIME hex format)\n" " -o rellinks interpret absolute symlinks as volume relative\n"
" -o VolumeSerialNumber=N 32-bit wide\n" " -o volname=NAME set volume label\n"
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n" " -o VolumePrefix=UNC set UNC prefix (/Server/Share)\n"
" -o CaseInsensitiveSearch file system supports case-insensitive file names\n" " --VolumePrefix=UNC set UNC prefix (\\Server\\Share)\n"
//" -o ReadOnlyVolume file system is read only\n" " -o FileSystemName=NAME set file system name\n"
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n" " -o DebugLog=FILE debug log file (requires -d)\n"
" --FileSystemName=FSN Name of user mode file system\n"); "\n"
FSP_FUSE_LIBRARY_NAME " advanced options:\n"
" -o FileInfoTimeout=N metadata timeout (millis, -1 for data caching)\n"
" -o SectorSize=N (512-4096, deflt: 4096)\n"
" -o SectorsPerAllocationUnit=N (deflt: 1)\n"
" -o MaxComponentLength=N (deflt: 255)\n"
" -o VolumeCreationTime=T (FILETIME hex format)\n"
" -o VolumeSerialNumber=N (32-bit wide)\n"
);
opt_data->help = 1; opt_data->help = 1;
return 1; return 1;
case 'V': case 'V':
@ -437,9 +489,24 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION); FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION);
opt_data->help = 1; opt_data->help = 1;
return 1; return 1;
case 'D':
arg += sizeof "DebugLog=" - 1;
opt_data->DebugLogHandle = CreateFileA(
arg,
FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
return 0;
case 'U': case 'U':
if ('U' == arg[2]) if ('U' == arg[0])
arg += sizeof "UNC=" - 1;
else if ('U' == arg[2])
arg += sizeof "--UNC=" - 1; arg += sizeof "--UNC=" - 1;
else if ('V' == arg[0])
arg += sizeof "VolumePrefix=" - 1;
else if ('V' == arg[2]) else if ('V' == arg[2])
arg += sizeof "--VolumePrefix=" - 1; arg += sizeof "--VolumePrefix=" - 1;
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1, if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
@ -447,20 +514,33 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
return -1; return -1;
opt_data->VolumeParams.Prefix opt_data->VolumeParams.Prefix
[sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR) - 1] = L'\0'; [sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR) - 1] = L'\0';
for (PWSTR P = opt_data->VolumeParams.Prefix; *P; P++)
if (L'/' == *P)
*P = '\\';
return 0; return 0;
case 'F': case 'F':
if ('f' == arg[0]) if ('f' == arg[0])
arg += sizeof "fstypename=" - 1; arg += sizeof "fstypename=" - 1;
else if ('F' == arg[0])
arg += sizeof "FileSystemName=" - 1;
else if ('F' == arg[2]) else if ('F' == arg[2])
arg += sizeof "--FileSystemName=" - 1; arg += sizeof "--FileSystemName=" - 1;
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1, if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
opt_data->VolumeParams.FileSystemName + 5, opt_data->VolumeParams.FileSystemName + 5,
sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR)) - 5) sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR) - 5))
return -1; return -1;
opt_data->VolumeParams.FileSystemName opt_data->VolumeParams.FileSystemName
[sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0'; [sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0';
memcpy(opt_data->VolumeParams.FileSystemName, L"FUSE-", 5 * sizeof(WCHAR)); memcpy(opt_data->VolumeParams.FileSystemName, L"FUSE-", 5 * sizeof(WCHAR));
return 0; return 0;
case 'v':
arg += sizeof "volname=" - 1;
opt_data->VolumeLabelLength = (UINT16)(sizeof(WCHAR) *
MultiByteToWideChar(CP_UTF8, 0, arg, lstrlenA(arg),
opt_data->VolumeLabel, sizeof opt_data->VolumeLabel / sizeof(WCHAR)));
if (0 == opt_data->VolumeLabelLength)
return -1;
return 0;
} }
} }
@ -479,12 +559,24 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
memset(&opt_data, 0, sizeof opt_data); memset(&opt_data, 0, sizeof opt_data);
opt_data.env = env; opt_data.env = env;
opt_data.DebugLogHandle = GetStdHandle(STD_ERROR_HANDLE);
opt_data.VolumeParams.FileInfoTimeout = 1000; /* default FileInfoTimeout for FUSE file systems */
if (-1 == fsp_fuse_opt_parse(env, args, &opt_data, fsp_fuse_core_opts, fsp_fuse_core_opt_proc)) if (-1 == fsp_fuse_opt_parse(env, args, &opt_data, fsp_fuse_core_opts, fsp_fuse_core_opt_proc))
return 0; return 0;
if (opt_data.help) if (opt_data.help)
return 0; return 0;
if (opt_data.debug)
{
if (INVALID_HANDLE_VALUE == opt_data.DebugLogHandle)
{
ErrorMessage = L": cannot open debug log file.";
goto fail;
}
FspDebugLogSetHandle(opt_data.DebugLogHandle);
}
if ((opt_data.set_uid && -1 == opt_data.uid) || if ((opt_data.set_uid && -1 == opt_data.uid) ||
(opt_data.set_gid && -1 == opt_data.gid)) (opt_data.set_gid && -1 == opt_data.gid))
{ {
@ -509,12 +601,12 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout) if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout)
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000; opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
opt_data.VolumeParams.CaseSensitiveSearch = !opt_data.CaseInsensitiveSearch; opt_data.VolumeParams.CaseSensitiveSearch = TRUE;
opt_data.VolumeParams.PersistentAcls = TRUE; opt_data.VolumeParams.PersistentAcls = TRUE;
opt_data.VolumeParams.ReparsePoints = TRUE; opt_data.VolumeParams.ReparsePoints = TRUE;
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE; opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
opt_data.VolumeParams.NamedStreams = FALSE; opt_data.VolumeParams.NamedStreams = FALSE;
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume; opt_data.VolumeParams.ReadOnlyVolume = FALSE;
opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE; opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE; opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
if (L'\0' == opt_data.VolumeParams.FileSystemName[0]) if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
@ -533,6 +625,8 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
f->data = data; f->data = data;
f->DebugLog = opt_data.debug ? -1 : 0; f->DebugLog = opt_data.debug ? -1 : 0;
memcpy(&f->VolumeParams, &opt_data.VolumeParams, sizeof opt_data.VolumeParams); memcpy(&f->VolumeParams, &opt_data.VolumeParams, sizeof opt_data.VolumeParams);
f->VolumeLabelLength = opt_data.VolumeLabelLength;
memcpy(&f->VolumeLabel, &opt_data.VolumeLabel, opt_data.VolumeLabelLength);
Size = (lstrlenW(ch->MountPoint) + 1) * sizeof(WCHAR); Size = (lstrlenW(ch->MountPoint) + 1) * sizeof(WCHAR);
f->MountPoint = fsp_fuse_obj_alloc(env, Size); f->MountPoint = fsp_fuse_obj_alloc(env, Size);
@ -615,6 +709,13 @@ FSP_FUSE_API void fsp_fuse_exit(struct fsp_fuse_env *env,
{ {
if (0 != f->Service) if (0 != f->Service)
FspServiceStop(f->Service); FspServiceStop(f->Service);
f->exited = 1;
}
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_exited)(struct fsp_fuse_env *env,
struct fuse *f)
{
return f->exited;
} }
FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env) FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env)

View File

@ -0,0 +1,35 @@
/**
* @file dll/fuse/fuse_compat.c
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dll/library.h>
/*
* This file provides an implementation of the `fuse_*` symbols. This
* implementation is a simple shim that forwards `fuse_*` calls to the
* equivalent `fsp_fuse_*` ones using a default `fsp_fuse_env`.
*
* These symbols should *not* be used by C/C++ programs. For this reason
* the `fuse.h` headers only expose the `fsp_fuse_*` symbols, wrapped
* with macros. These symbols are for use only from programs using FFI
* technology to access FUSE symbols (e.g. fusepy, jnr-fuse).
*/
#define FSP_FUSE_API
#define FSP_FUSE_SYM(proto, ...) __declspec(dllexport) proto { __VA_ARGS__ }
#include <fuse/fuse_common.h>
#include <fuse/fuse.h>
#include <fuse/fuse_opt.h>

View File

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

View File

@ -40,13 +40,17 @@ struct fuse
int rellinks; int rellinks;
struct fuse_operations ops; struct fuse_operations ops;
void *data; void *data;
unsigned conn_want;
BOOLEAN fsinit;
UINT32 DebugLog; UINT32 DebugLog;
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy; FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
FSP_FSCTL_VOLUME_PARAMS VolumeParams; FSP_FSCTL_VOLUME_PARAMS VolumeParams;
UINT16 VolumeLabelLength;
WCHAR VolumeLabel[sizeof ((FSP_FSCTL_VOLUME_INFO *)0)->VolumeLabel / sizeof(WCHAR)];
PWSTR MountPoint; PWSTR MountPoint;
FSP_FILE_SYSTEM *FileSystem; FSP_FILE_SYSTEM *FileSystem;
BOOLEAN fsinit;
FSP_SERVICE *Service; /* weak */ FSP_SERVICE *Service; /* weak */
volatile int exited;
}; };
struct fsp_fuse_context_header struct fsp_fuse_context_header
@ -66,8 +70,12 @@ struct fsp_fuse_file_desc
struct fuse_dirhandle struct fuse_dirhandle
{ {
/* ReadDirectory */
struct fsp_fuse_file_desc *filedesc; struct fsp_fuse_file_desc *filedesc;
FSP_FILE_SYSTEM *FileSystem;
BOOLEAN ReaddirPlus;
NTSTATUS Result; NTSTATUS Result;
/* CanDelete */
BOOLEAN DotFiles, HasChild; BOOLEAN DotFiles, HasChild;
}; };

View File

@ -79,7 +79,7 @@ FSP_API ULONG FspServiceRunEx(PWSTR ServiceName,
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
{ {
FspServiceLog(EVENTLOG_ERROR_TYPE, FspServiceLog(EVENTLOG_ERROR_TYPE,
L"The service %s cannot be created (Status=%lx).", Service->ServiceName, Result); L"The service %s cannot be created (Status=%lx).", ServiceName, Result);
return FspWin32FromNtStatus(Result); return FspWin32FromNtStatus(Result);
} }
Service->UserContext = UserContext; Service->UserContext = UserContext;
@ -92,7 +92,7 @@ FSP_API ULONG FspServiceRunEx(PWSTR ServiceName,
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
{ {
FspServiceLog(EVENTLOG_ERROR_TYPE, FspServiceLog(EVENTLOG_ERROR_TYPE,
L"The service %s has failed to run (Status=%lx).", Service->ServiceName, Result); L"The service %s has failed to run (Status=%lx).", ServiceName, Result);
return FspWin32FromNtStatus(Result); return FspWin32FromNtStatus(Result);
} }

View File

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

File diff suppressed because it is too large Load Diff

1153
src/dotnet/FileSystemBase.cs Normal file

File diff suppressed because it is too large Load Diff

1029
src/dotnet/FileSystemHost.cs Normal file

File diff suppressed because it is too large Load Diff

1081
src/dotnet/Interop.cs Normal file

File diff suppressed because it is too large Load Diff

187
src/dotnet/Service.cs Normal file
View File

@ -0,0 +1,187 @@
/*
* dotnet/Service.cs
*
* Copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
using System;
using Fsp.Interop;
namespace Fsp
{
/// <summary>
/// Provides the base class for a process that can be run as a service,
/// command line application or under the control of the WinFsp launcher.
/// </summary>
public class Service
{
/* const */
public const UInt32 EVENTLOG_ERROR_TYPE = 0x0001;
public const UInt32 EVENTLOG_WARNING_TYPE = 0x0002;
public const UInt32 EVENTLOG_INFORMATION_TYPE = 0x0004;
/* ctor/dtor */
/// <summary>
/// Creates an instance of the Service class.
/// </summary>
/// <param name="ServiceName">The name of the service.</param>
public Service(String ServiceName)
{
Api.FspServiceCreate(ServiceName, _OnStart, _OnStop, null, out _ServicePtr);
if (IntPtr.Zero != _ServicePtr)
Api.SetUserContext(_ServicePtr, this);
}
~Service()
{
if (IntPtr.Zero != _ServicePtr)
{
Api.DisposeUserContext(_ServicePtr);
Api.FspServiceDelete(_ServicePtr);
}
}
/* control */
/// <summary>
/// Runs a service.
/// </summary>
/// <returns>Service process exit code.</returns>
public int Run()
{
if (IntPtr.Zero == _ServicePtr)
{
const Int32 STATUS_INSUFFICIENT_RESOURCES = unchecked((Int32)0xc000009a);
Log(EVENTLOG_ERROR_TYPE,
String.Format("The service {0} cannot be created (Status={1:X}).",
GetType().FullName, STATUS_INSUFFICIENT_RESOURCES));
return (int)Api.FspWin32FromNtStatus(STATUS_INSUFFICIENT_RESOURCES);
}
Api.FspServiceAllowConsoleMode(_ServicePtr);
Int32 Result = Api.FspServiceLoop(_ServicePtr);
int ExitCode = (int)Api.FspServiceGetExitCode(_ServicePtr);
if (0 > Result)
{
Log(EVENTLOG_ERROR_TYPE,
String.Format("The service {0} has failed to run (Status={1:X}).",
GetType().FullName, Result));
return (int)Api.FspWin32FromNtStatus(Result);
}
return ExitCode;
}
/// <summary>
/// Stops a running service.
/// </summary>
public void Stop()
{
if (IntPtr.Zero == _ServicePtr)
throw new InvalidOperationException();
Api.FspServiceStop(_ServicePtr);
}
public void RequestTime(UInt32 Time)
{
if (IntPtr.Zero == _ServicePtr)
throw new InvalidOperationException();
Api.FspServiceRequestTime(_ServicePtr, Time);
}
/// <summary>
/// Gets or sets the service process exit code.
/// </summary>
public int ExitCode
{
get
{
if (IntPtr.Zero == _ServicePtr)
throw new InvalidOperationException();
return (int)Api.FspServiceGetExitCode(_ServicePtr);
}
set
{
if (IntPtr.Zero == _ServicePtr)
throw new InvalidOperationException();
Api.FspServiceSetExitCode(_ServicePtr, (UInt32)value);
}
}
public IntPtr ServiceHandle
{
get { return _ServicePtr; }
}
public static void Log(UInt32 Type, String Message)
{
Api.FspServiceLog(Type, "%s", Message);
}
/* start/stop */
/// <summary>
/// Provides a means to customize the returned status code when an exception happens.
/// </summary>
/// <param name="ex"></param>
/// <returns>STATUS_SUCCESS or error code.</returns>
protected virtual Int32 ExceptionHandler(Exception ex)
{
return unchecked((Int32)0xE0434f4D)/*STATUS_CLR_EXCEPTION*/;
}
/// <summary>
/// Occurs when the service starts.
/// </summary>
/// <param name="Args">Command line arguments passed to the service.</param>
protected virtual void OnStart(String[] Args)
{
}
/// <summary>
/// Occurs when the service stops.
/// </summary>
protected virtual void OnStop()
{
}
/* callbacks */
private static Int32 OnStart(
IntPtr Service,
UInt32 Argc,
String[] Argv)
{
Service self = (Service)Api.GetUserContext(Service);
try
{
self.OnStart(
Argv);
return 0/*STATUS_SUCCESS*/;
}
catch (Exception ex)
{
return self.ExceptionHandler(ex);
}
}
private static Int32 OnStop(
IntPtr Service)
{
Service self = (Service)Api.GetUserContext(Service);
try
{
self.OnStop();
return 0/*STATUS_SUCCESS*/;
}
catch (Exception ex)
{
return self.ExceptionHandler(ex);
}
}
private static Api.Proto.ServiceStart _OnStart = OnStart;
private static Api.Proto.ServiceStop _OnStop = OnStop;
private IntPtr _ServicePtr;
}
}

View File

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

View File

@ -1098,7 +1098,44 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
return Result; return Result;
} }
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Create.Opened.FileInfo, /*
* FspFileNodeTrySetFileInfoOnOpen sets the FileNode's metadata to values reported
* by the user mode file system. It does so only if the file is not already open; the
* reason is that there is a subtle race condition otherwise.
*
* Consider that a file is already open and (for example) being appended to. The appends
* appear as WRITE IRP's and they are all synchronized by acquiring the FileNode resources
* exclusive. Part of the WRITE protocol involves returning an updated FileInfo for the
* written FileNode, which the FSD uses to update its view of the file metadata.
*
* Now consider that a file OPEN comes in. Because the FSD does not know yet which FileNode
* will be opened it does not acquire any FileNode. [Note that while it is possible to
* uniquely identify a FileNode by FileName currently, this would no longer be the case
* when we implement hard links.] The FSD posts the OPEN request to the user mode file system.
* The user mode file system processes the OPEN request successfully and responds with the
* opened file and its FileInfo.
*
* Prior to the FSD processing the OPEN response additional WRITE IRP's come through the
* original file handle. These WRITE's update the FileSize as understood by the user mode
* file system and the corresponding FileInfo gets reported back to the FSD. Eventually the
* delayed OPEN response gets processed, which now clobbers the FileInfo as understood by
* the FSD.
*
* The problem here is that OPEN requests have no way of locking the FileNode while the OPEN
* request is in transit to the user mode file system. In all other cases the user mode file
* system and the FSD update their view of the file's metadata in an atomic fashion. Not so
* in the case of OPEN.
*
* While this is a subtle race condition it can nevertheless creates a real problem. For
* example, Explorer often opens files to get information about them and may inappropriately
* update the FSD view of the file size during WRITE's.
*
* FspFileNodeTrySetFileInfoOnOpen attempts to mitigate this problem by only updating the
* FileInfo if the file is not already open. This avoids placing stale information in the
* FileNode.
*/
FspFileNodeTrySetFileInfoOnOpen(FileNode, FileObject, &Response->Rsp.Create.Opened.FileInfo,
FILE_CREATED == Response->IoStatus.Information); FILE_CREATED == Response->IoStatus.Information);
if (FlushImage) if (FlushImage)

View File

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

View File

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

View File

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

View File

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

View File

@ -58,6 +58,8 @@ VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileIn
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject, VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose); const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
BOOLEAN FspFileNodeTrySetFileInfoOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject, BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber); const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode); VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
@ -129,6 +131,7 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
#pragma alloc_text(PAGE, FspFileNodeGetFileInfo) #pragma alloc_text(PAGE, FspFileNodeGetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo) #pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeSetFileInfo) #pragma alloc_text(PAGE, FspFileNodeSetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfoOnOpen)
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfo) #pragma alloc_text(PAGE, FspFileNodeTrySetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeInvalidateFileInfo) #pragma alloc_text(PAGE, FspFileNodeInvalidateFileInfo)
#pragma alloc_text(PAGE, FspFileNodeReferenceSecurity) #pragma alloc_text(PAGE, FspFileNodeReferenceSecurity)
@ -1243,6 +1246,50 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp
} }
} }
/* flush and purge cleaned up but still open files affected by rename (github issue #45) */
{
PIRP TopLevelIrp;
IO_STATUS_BLOCK IoStatus;
/* reset the top-level IRP to avoid deadlock on the FileNodes' resources */
TopLevelIrp = IoGetTopLevelIrp();
IoSetTopLevelIrp(0);
/* enumerate in reverse order so that files are flushed before containing directories */
for (
DescendantFileNodeIndex = DescendantFileNodeCount - 1;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex--)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
HasHandles = (UINT_PTR)DescendantFileNode & 1;
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
if (HasHandles)
continue;
if (CheckingOldName &&
(DescendantFileNode->FileName.Length <= FileName->Length ||
L'\\' != DescendantFileNode->FileName.Buffer[FileName->Length / sizeof(WCHAR)]))
continue;
if (MmDoesFileHaveUserWritableReferences(&DescendantFileNode->NonPaged->SectionObjectPointers))
continue;
/*
* There are no handles and no writable user mappings. [Ideally we would want to know
* that there are no handles and no user mappings, period. Is there an DDI/method to
* do that?] There may be a read-only user mapping, but in this case CcFlushCache
* should be a no-op and MmForceSectionClosed will fail (which is fine).
*/
ASSERT(DescendantFileNode != FileNode && DescendantFileNode->MainFileNode != FileNode);
FspCcFlushCache(&DescendantFileNode->NonPaged->SectionObjectPointers, 0, 0, &IoStatus);
MmForceSectionClosed(&DescendantFileNode->NonPaged->SectionObjectPointers, FALSE);
}
IoSetTopLevelIrp(TopLevelIrp);
}
/* break any Batch or Handle oplocks on descendants */ /* break any Batch or Handle oplocks on descendants */
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
for ( for (
@ -1616,6 +1663,43 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
} }
} }
BOOLEAN FspFileNodeTrySetFileInfoOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose)
{
PAGED_CODE();
BOOLEAN EarlyExit;
FspFsvolDeviceLockContextTable(FileNode->FsvolDeviceObject);
EarlyExit = 1 < FileNode->OpenCount;
FspFsvolDeviceUnlockContextTable(FileNode->FsvolDeviceObject);
if (EarlyExit)
{
if (TruncateOnClose)
{
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
UINT64 AllocationSize = FileInfo->AllocationSize > FileInfo->FileSize ?
FileInfo->AllocationSize : FileInfo->FileSize;
UINT64 AllocationUnit;
AllocationUnit = FsvolDeviceExtension->VolumeParams.SectorSize *
FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit;
AllocationSize = (AllocationSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
if ((UINT64)FileNode->Header.AllocationSize.QuadPart != AllocationSize ||
(UINT64)FileNode->Header.FileSize.QuadPart != FileInfo->FileSize)
FileNode->TruncateOnClose = TRUE;
}
return FALSE;
}
FspFileNodeSetFileInfo(FileNode, CcFileObject, FileInfo, TruncateOnClose);
return TRUE;
}
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject, BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber) const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber)
{ {
@ -2073,6 +2157,8 @@ NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc, NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName) PUNICODE_STRING FileName)
{ {
PAGED_CODE();
if (&FileDesc->DirectoryMarker == FileName) if (&FileDesc->DirectoryMarker == FileName)
return STATUS_SUCCESS; return STATUS_SUCCESS;

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,20 +12,26 @@ if X!ProjDir!==X (echo usage: build-sample Config Arch Sample ProjDir >&2 & goto
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64 call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
set RegKey="HKLM\SOFTWARE\WinFsp" if X!FSP_SAMPLE_DIR!==X (
set RegVal="InstallDir" set RegKey="HKLM\SOFTWARE\WinFsp"
reg query !RegKey! /v !RegVal! /reg:32 >nul 2>&1 set RegVal="InstallDir"
if !ERRORLEVEL! equ 0 ( reg query !RegKey! /v !RegVal! /reg:32 >nul 2>&1
for /f "tokens=2,*" %%i in ('reg query !RegKey! /v !RegVal! /reg:32 ^| findstr !RegVal!') do ( if !ERRORLEVEL! equ 0 (
set InstallDir=%%j for /f "tokens=2,*" %%i in ('reg query !RegKey! /v !RegVal! /reg:32 ^| findstr !RegVal!') do (
) set InstallDir=%%j
)
)
if not exist "!InstallDir!" (echo cannot find WinFsp installation >&2 & goto fail)
if not exist "!InstallDir!samples\!Sample!" (echo cannot find WinFsp sample !Sample! >&2 & goto fail)
set SampleDir=!InstallDir!samples
) else (
set SampleDir=!FSP_SAMPLE_DIR!
) )
if not exist "!InstallDir!" (echo cannot find WinFsp installation >&2 & goto fail)
if not exist "!InstallDir!samples\!Sample!" (echo cannot find WinFsp sample !Sample! >&2 & goto fail)
if exist "!ProjDir!" rmdir /s/q "!ProjDir!" if exist "!ProjDir!" rmdir /s/q "!ProjDir!"
mkdir "!ProjDir!" mkdir "!ProjDir!"
xcopy /s/e/q/y "!InstallDir!samples\!Sample!" "!ProjDir!" xcopy /s/e/q/y "!SampleDir!\!Sample!" "!ProjDir!"
devenv "!ProjDir!\!Sample!.sln" /build "!Config!|!Arch!" devenv "!ProjDir!\!Sample!.sln" /build "!Config!|!Arch!"
if !ERRORLEVEL! neq 0 goto :fail if !ERRORLEVEL! neq 0 goto :fail

View File

@ -1,6 +1,7 @@
@echo off @echo off
setlocal setlocal
setlocal EnableDelayedExpansion
set MsiName="WinFsp - Windows File System Proxy" set MsiName="WinFsp - Windows File System Proxy"
set CrossCert="%~dp0DigiCert High Assurance EV Root CA.crt" set CrossCert="%~dp0DigiCert High Assurance EV Root CA.crt"
@ -19,6 +20,7 @@ if not X%SignedPackage%==X (
if not exist "%~dp0..\build\VStudio\build\%Configuration%\winfsp-*.msi" (echo previous build not found >&2 & exit /b 1) if not exist "%~dp0..\build\VStudio\build\%Configuration%\winfsp-*.msi" (echo previous build not found >&2 & exit /b 1)
if not exist "%SignedPackage%" (echo signed package not found >&2 & exit /b 1) if not exist "%SignedPackage%" (echo signed package not found >&2 & exit /b 1)
del "%~dp0..\build\VStudio\build\%Configuration%\winfsp-*.msi" del "%~dp0..\build\VStudio\build\%Configuration%\winfsp-*.msi"
if exist "%~dp0..\build\VStudio\build\%Configuration%\winfsp.*.nupkg" del "%~dp0..\build\VStudio\build\%Configuration%\winfsp.*.nupkg"
for /R "%SignedPackage%" %%f in (*.sys) do ( for /R "%SignedPackage%" %%f in (*.sys) do (
copy "%%f" "%~dp0..\build\VStudio\build\%Configuration%" >nul copy "%%f" "%~dp0..\build\VStudio\build\%Configuration%" >nul
) )
@ -81,6 +83,18 @@ for %%f in (build\%Configuration%\winfsp-*.msi) do (
if not %signfail%==0 echo SIGNING FAILED! The product has been successfully built, but not signed. if not %signfail%==0 echo SIGNING FAILED! The product has been successfully built, but not signed.
where /q choco.exe
if %ERRORLEVEL% equ 0 (
for %%f in (build\%Configuration%\winfsp-*.msi) do set Version=%%~nf
set Version=!Version:winfsp-=!
copy ..\choco\* build\%Configuration%
copy ..\choco\LICENSE.TXT /B + ..\..\License.txt /B build\%Configuration%\LICENSE.txt /B
certutil -hashfile build\%Configuration%\winfsp-!Version!.msi SHA256 >>build\%Configuration%\VERIFICATION.txt
choco pack build\%Configuration%\winfsp.nuspec --version=!Version! --outputdirectory=build\%Configuration%
if errorlevel 1 goto fail
)
exit /b 0 exit /b 0
:fail :fail

View File

@ -17,12 +17,16 @@ launchctl-x64 start memfs64 testdsk "" M: >nul
launchctl-x64 start memfs64 testnet \memfs64\test N: >nul launchctl-x64 start memfs64 testnet \memfs64\test N: >nul
launchctl-x64 start memfs32 testdsk "" O: >nul launchctl-x64 start memfs32 testdsk "" O: >nul
launchctl-x64 start memfs32 testnet \memfs32\test P: >nul launchctl-x64 start memfs32 testnet \memfs32\test P: >nul
launchctl-x64 start memfs-dotnet testdsk "" Q: >nul
launchctl-x64 start memfs-dotnet testnet \memfs-dotnet\test R: >nul
rem Cannot use timeout under cygwin/mintty: "Input redirection is not supported" rem Cannot use timeout under cygwin/mintty: "Input redirection is not supported"
waitfor 7BF47D72F6664550B03248ECFE77C7DD /t 3 2>nul waitfor 7BF47D72F6664550B03248ECFE77C7DD /t 3 2>nul
cd M: >nul 2>nul || (echo === Unable to find drive M: >&2 & goto fail) cd M: >nul 2>nul || (echo === Unable to find drive M: >&2 & goto fail)
cd N: >nul 2>nul || (echo === Unable to find drive N: >&2 & goto fail) cd N: >nul 2>nul || (echo === Unable to find drive N: >&2 & goto fail)
cd O: >nul 2>nul || (echo === Unable to find drive O: >&2 & goto fail) cd O: >nul 2>nul || (echo === Unable to find drive O: >&2 & goto fail)
cd P: >nul 2>nul || (echo === Unable to find drive P: >&2 & goto fail) cd P: >nul 2>nul || (echo === Unable to find drive P: >&2 & goto fail)
cd Q: >nul 2>nul || (echo === Unable to find drive Q: >&2 & goto fail)
cd R: >nul 2>nul || (echo === Unable to find drive R: >&2 & goto fail)
set dfl_tests=^ set dfl_tests=^
winfsp-tests-x64 ^ winfsp-tests-x64 ^
@ -31,6 +35,7 @@ set dfl_tests=^
winfsp-tests-x64-mountpoint-dir ^ winfsp-tests-x64-mountpoint-dir ^
winfsp-tests-x64-no-traverse ^ winfsp-tests-x64-no-traverse ^
winfsp-tests-x64-oplock ^ winfsp-tests-x64-oplock ^
winfsp-tests-x64-external ^
winfsp-tests-x64-external-share ^ winfsp-tests-x64-external-share ^
fsx-memfs-x64-disk ^ fsx-memfs-x64-disk ^
fsx-memfs-x64-net ^ fsx-memfs-x64-net ^
@ -46,6 +51,7 @@ set dfl_tests=^
winfsp-tests-x86-mountpoint-dir ^ winfsp-tests-x86-mountpoint-dir ^
winfsp-tests-x86-no-traverse ^ winfsp-tests-x86-no-traverse ^
winfsp-tests-x86-oplock ^ winfsp-tests-x86-oplock ^
winfsp-tests-x86-external ^
winfsp-tests-x86-external-share ^ winfsp-tests-x86-external-share ^
fsx-memfs-x86-disk ^ fsx-memfs-x86-disk ^
fsx-memfs-x86-net ^ fsx-memfs-x86-net ^
@ -54,14 +60,22 @@ set dfl_tests=^
net-use-memfs-x86 ^ net-use-memfs-x86 ^
winfstest-memfs-x86-disk ^ winfstest-memfs-x86-disk ^
winfstest-memfs-x86-net ^ winfstest-memfs-x86-net ^
fscrash-x86 fscrash-x86 ^
winfsp-tests-dotnet-external ^
winfsp-tests-dotnet-external-share ^
fsx-memfs-dotnet-disk ^
fsx-memfs-dotnet-net ^
winfstest-memfs-dotnet-disk ^
winfstest-memfs-dotnet-net
set opt_tests=^ set opt_tests=^
ifstest-memfs-x64-disk ^ ifstest-memfs-x64-disk ^
ifstest-memfs-x86-disk ^ ifstest-memfs-x86-disk ^
ifstest-memfs-dotnet-disk ^
sample-passthrough-x64 ^ sample-passthrough-x64 ^
sample-passthrough-x86 ^ sample-passthrough-x86 ^
sample-passthrough-fuse-x64 ^ sample-passthrough-fuse-x64 ^
sample-passthrough-fuse-x86 sample-passthrough-fuse-x86 ^
sample-passthrough-dotnet
set tests= set tests=
for %%f in (%dfl_tests%) do ( for %%f in (%dfl_tests%) do (
@ -118,6 +132,8 @@ launchctl-x64 stop memfs64 testdsk >nul
launchctl-x64 stop memfs64 testnet >nul launchctl-x64 stop memfs64 testnet >nul
launchctl-x64 stop memfs32 testdsk >nul launchctl-x64 stop memfs32 testdsk >nul
launchctl-x64 stop memfs32 testnet >nul launchctl-x64 stop memfs32 testnet >nul
launchctl-x64 stop memfs-dotnet testdsk >nul
launchctl-x64 stop memfs-dotnet testnet >nul
rem Cannot use timeout under cygwin/mintty: "Input redirection is not supported" rem Cannot use timeout under cygwin/mintty: "Input redirection is not supported"
waitfor 7BF47D72F6664550B03248ECFE77C7DD /t 3 2>nul waitfor 7BF47D72F6664550B03248ECFE77C7DD /t 3 2>nul
@ -192,6 +208,12 @@ winfsp-tests-x86 --oplock=filter --resilient
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:winfsp-tests-x64-external
M:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --resilient
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-x64-external-share :winfsp-tests-x64-external-share
M: M:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --share=winfsp-tests-share=M:\ --resilient ^ "%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --share=winfsp-tests-share=M:\ --resilient ^
@ -239,6 +261,12 @@ net use L: /delete
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:winfsp-tests-x86-external
O:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" --external --resilient
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-x86-external-share :winfsp-tests-x86-external-share
O: O:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" --external --share=winfsp-tests-share=O:\ --resilient ^ "%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" --external --share=winfsp-tests-share=O:\ --resilient ^
@ -348,6 +376,47 @@ fscrash-x86 --huge-alloc-size --cached >nul 2>&1
if !ERRORLEVEL! neq 1 goto fail if !ERRORLEVEL! neq 1 goto fail
exit /b 0 exit /b 0
:winfsp-tests-dotnet-external
Q:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --resilient
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-dotnet-external-share
Q:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --share=winfsp-tests-share=Q:\ --resilient ^
-reparse_symlink*
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:fsx-memfs-dotnet-disk
Q:
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
if !ERRORLEVEL! neq 0 goto fail
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -f foo -N 5000 test xxxxxx
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:fsx-memfs-dotnet-net
R:
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
if !ERRORLEVEL! neq 0 goto fail
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -f foo -N 5000 test xxxxxx
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfstest-memfs-dotnet-disk
Q:
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfstest-memfs-dotnet-net
R:
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:ifstest-memfs-x64-disk :ifstest-memfs-x64-disk
call :__ifstest-memfs M: \Device\WinFsp.Disk C: call :__ifstest-memfs M: \Device\WinFsp.Disk C:
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
@ -358,23 +427,28 @@ call :__ifstest-memfs O: \Device\WinFsp.Disk C:
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:ifstest-memfs-dotnet-disk
call :__ifstest-memfs Q: \Device\WinFsp.Disk C:
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:__ifstest-memfs :__ifstest-memfs
%1 %1
set IfsTestDirectories=^ set IfsTestDirectories=^
securit^ securit^
opcreatg^ opcreatg^
opcreatp^ opcreatp^
closedel^ closedel^
volinfo^ volinfo^
fileinfo^ fileinfo^
dirinfo^ dirinfo^
filelock^ filelock^
oplocks^ oplocks^
chgnotif^ chgnotif^
readwr^ readwr^
seccache^ seccache^
reparspt^ reparspt^
estream estream
set IfsTestMemfsExit=0 set IfsTestMemfsExit=0
call :__ifstest %1 /g Security call :__ifstest %1 /g Security
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1 if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
@ -418,7 +492,7 @@ rem StreamEnhancements.StreamNotifyNameTest: WinFsp does not notify when streams
call :__ifstest %1 /g StreamEnhancements -t StreamRenameTest -t StreamNotifyNameTest call :__ifstest %1 /g StreamEnhancements -t StreamRenameTest -t StreamNotifyNameTest
if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1 if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1
for %%d in (!IfsTestDirectories!) do ( for %%d in (!IfsTestDirectories!) do (
if exist %%d (echo :ifstest directory %%d still exists & set IfsTestMemfsExit=1) if exist %%d (echo :ifstest directory %%d still exists & set IfsTestMemfsExit=1)
) )
exit /b !IfsTestMemfsExit! exit /b !IfsTestMemfsExit!
@ -482,81 +556,94 @@ if not X!IfsTestFound!==XYES set IfsTestExit=1
exit /b !IfsTestExit! exit /b !IfsTestExit!
:sample-passthrough-x64 :sample-passthrough-x64
call :__sample-passthrough x64 call :__run_sample_test passthrough x64 passthrough-x64 winfsp-tests-x64
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:sample-passthrough-x86 :sample-passthrough-x86
call :__sample-passthrough x86 call :__run_sample_test passthrough x86 passthrough-x86 winfsp-tests-x86
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:__sample-passthrough :sample-passthrough-cpp-x64
set SamplePassthroughExit=0 call :__run_sample_test passthrough-cpp x64 passthrough-cpp-x64 winfsp-tests-x64
call %ProjRoot%\tools\build-sample %Configuration% %1 passthrough "%TMP%\passthrough-%1"
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
mkdir "%TMP%\passthrough-%1\test" exit /b 0
call "%ProjRoot%\tools\fsreg" passthrough "%TMP%\passthrough-%1\build\%Configuration%\passthrough-%1.exe" "-u %%%%1 -m %%%%2" "D:P(A;;RPWPLC;;;WD)"
echo net use L: "\\passthrough\%TMP::=$%\passthrough-%1\test" :sample-passthrough-cpp-x86
net use L: "\\passthrough\%TMP::=$%\passthrough-%1\test" call :__run_sample_test passthrough-cpp x86 passthrough-cpp-x86 winfsp-tests-x86
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
echo net use ^| findstr L: exit /b 0
net use | findstr L:
pushd >nul
cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail)
L:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-%1.exe" ^ :sample-passthrough-dotnet
--external --resilient --case-insensitive-cmp --share-prefix="\passthrough\%TMP::=$%\passthrough-%1\test" ^ call :__run_sample_test passthrough-dotnet anycpu passthrough-dotnet winfsp-tests-x64 ^
-create_allocation_test -getfileinfo_name_test -rename_flipflop_test -rename_mmap_test -reparse* -stream* "-create_backup_test -create_restore_test -create_namelen_test -delete_access_test"
if !ERRORLEVEL! neq 0 set SamplePassthroughExit=1 if !ERRORLEVEL! neq 0 goto fail
exit /b 0
popd
echo net use L: /delete
net use L: /delete
call "%ProjRoot%\tools\fsreg" -u passthrough
rmdir /s/q "%TMP%\passthrough-%1"
exit /b !SamplePassthroughExit!
:sample-passthrough-fuse-x64 :sample-passthrough-fuse-x64
call :__sample-passthrough-fuse x64 call :__run_sample_fuse_test passthrough-fuse x64 passthrough-fuse-x64 winfsp-tests-x64
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:sample-passthrough-fuse-x86 :sample-passthrough-fuse-x86
call :__sample-passthrough-fuse x86 call :__run_sample_fuse_test passthrough-fuse x86 passthrough-fuse-x86 winfsp-tests-x86
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:__sample-passthrough-fuse :__run_sample_test
set SamplePassthroughExit=0 set RunSampleTestExit=0
call %ProjRoot%\tools\build-sample %Configuration% %1 passthrough-fuse "%TMP%\passthrough-fuse-%1" call %ProjRoot%\tools\build-sample %Configuration% %2 %1 "%TMP%\%1"
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
mkdir "%TMP%\passthrough-fuse-%1\test" mkdir "%TMP%\%1\test"
call "%ProjRoot%\tools\fsreg" passthrough-fuse "%TMP%\passthrough-fuse-%1\build\%Configuration%\passthrough-fuse-%1.exe" ^ call "%ProjRoot%\tools\fsreg" %1 "%TMP%\%1\build\%Configuration%\%3.exe" "-u %%%%1 -m %%%%2" "D:P(A;;RPWPLC;;;WD)"
"-ouid=65792,gid=65792 -oCaseInsensitiveSearch --VolumePrefix=%%%%1 %%%%2" "D:P(A;;RPWPLC;;;WD)" echo net use L: "\\%1\%TMP::=$%\%1\test"
echo net use L: "\\passthrough-fuse\%TMP::=$%\passthrough-fuse-%1\test" net use L: "\\%1\%TMP::=$%\%1\test"
net use L: "\\passthrough-fuse\%TMP::=$%\passthrough-fuse-%1\test"
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
echo net use ^| findstr L: echo net use ^| findstr L:
net use | findstr L: net use | findstr L:
pushd >nul pushd >nul
cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail) cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail)
L: L:
"%ProjRoot%\build\VStudio\build\%Configuration%\%4.exe" ^
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-%1.exe" ^ --external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^
--external --resilient --case-insensitive-cmp --share-prefix="\passthrough-fuse\%TMP::=$%\passthrough-fuse-%1\test" ^ -create_allocation_test -getfileinfo_name_test -rename_flipflop_test -rename_mmap_test -exec_rename_dir_test ^
-create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^ -reparse* -stream* %~5
-getfileinfo_name_test -setfileinfo_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test ^ if !ERRORLEVEL! neq 0 set RunSampleTestExit=1
-reparse* -stream*
if !ERRORLEVEL! neq 0 set SamplePassthroughExit=1
popd popd
echo net use L: /delete echo net use L: /delete
net use L: /delete net use L: /delete
call "%ProjRoot%\tools\fsreg" -u passthrough-fuse call "%ProjRoot%\tools\fsreg" -u %1
rmdir /s/q "%TMP%\passthrough-fuse-%1" rmdir /s/q "%TMP%\%1"
exit /b !SamplePassthroughExit! exit /b !RunSampleTestExit!
:__run_sample_fuse_test
set RunSampleTestExit=0
call %ProjRoot%\tools\build-sample %Configuration% %2 %1 "%TMP%\%1"
if !ERRORLEVEL! neq 0 goto fail
mkdir "%TMP%\%1\test"
call "%ProjRoot%\tools\fsreg" %1 "%TMP%\%1\build\%Configuration%\%3.exe" ^
"-ouid=11,gid=65792 --VolumePrefix=%%%%1 %%%%2" "D:P(A;;RPWPLC;;;WD)"
echo net use L: "\\%1\%TMP::=$%\%1\test"
net use L: "\\%1\%TMP::=$%\%1\test"
if !ERRORLEVEL! neq 0 goto fail
echo net use ^| findstr L:
net use | findstr L:
pushd >nul
cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail)
L:
"%ProjRoot%\build\VStudio\build\%Configuration%\%4.exe" ^
--external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^
-create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^
-getfileinfo_name_test -setfileinfo_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test -exec_rename_dir_test ^
-reparse* -stream*
if !ERRORLEVEL! neq 0 set RunSampleTestExit=1
popd
echo net use L: /delete
net use L: /delete
call "%ProjRoot%\tools\fsreg" -u %1
rmdir /s/q "%TMP%\%1"
exit /b !RunSampleTestExit!
:leak-test :leak-test
for /F "tokens=1,2 delims=:" %%i in ('verifier /query ^| findstr ^ for /F "tokens=1,2 delims=:" %%i in ('verifier /query ^| findstr ^

15
tools/version-info.bat Executable file
View File

@ -0,0 +1,15 @@
@echo off
setlocal
setlocal EnableDelayedExpansion
for %%f in (%*) do (
set file="%%~f"
if exist !file! (
echo version-info: !file!
powershell -command "[System.Diagnostics.FileVersionInfo]::GetVersionInfo(""!file!"") | fl -property ProductName, ProductVersion, ProductVersionRaw, LegalCopyright, CompanyName, FileDescription, FileVersionRaw, FileVersion"
powershell -command "try { [System.Reflection.AssemblyName]::GetAssemblyName(""!file!"") | fl -property FullName, Version } catch {}"
) else (
echo version-info: file !file! not found
)
)

1156
tst/memfs-dotnet/Program.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -106,7 +106,7 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
if (0 != DebugLogFile) if (0 != DebugLogFile)
{ {
if (0 == wcscmp(L"-", DebugLogFile)) if (0 == wcscmp(L"-", DebugLogFile))
DebugLogHandle = GetStdHandle(STD_OUTPUT_HANDLE); DebugLogHandle = GetStdHandle(STD_ERROR_HANDLE);
else else
DebugLogHandle = CreateFileW( DebugLogHandle = CreateFileW(
DebugLogFile, DebugLogFile,
@ -184,7 +184,7 @@ usage:
"\n" "\n"
"options:\n" "options:\n"
" -d DebugFlags [-1: enable all debug logs]\n" " -d DebugFlags [-1: enable all debug logs]\n"
" -D DebugLogFile [file path; use - for stdout]\n" " -D DebugLogFile [file path; use - for stderr]\n"
" -i [case insensitive file system]\n" " -i [case insensitive file system]\n"
" -t FileInfoTimeout [millis]\n" " -t FileInfoTimeout [millis]\n"
" -n MaxFileNodes\n" " -n MaxFileNodes\n"

View File

@ -45,9 +45,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
/* /*
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes * Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
* a check for the Write buffer to ensure that it is read-only. * a check for the Write buffer to ensure that it is read-only.
*
* Since ProcessBuffer support in the FSD, this is no longer a guarantee.
*/ */
#if !defined(NDEBUG) #if !defined(NDEBUG)
#define DEBUG_BUFFER_CHECK //#define DEBUG_BUFFER_CHECK
#endif #endif
#define MEMFS_SECTOR_SIZE 512 #define MEMFS_SECTOR_SIZE 512
@ -190,7 +192,7 @@ typedef struct _MEMFS_FILE_NODE
SIZE_T ReparseDataSize; SIZE_T ReparseDataSize;
PVOID ReparseData; PVOID ReparseData;
#endif #endif
ULONG RefCount; volatile LONG RefCount;
#if defined(MEMFS_NAMED_STREAMS) #if defined(MEMFS_NAMED_STREAMS)
struct _MEMFS_FILE_NODE *MainFileNode; struct _MEMFS_FILE_NODE *MainFileNode;
#endif #endif
@ -258,13 +260,13 @@ VOID MemfsFileNodeDelete(MEMFS_FILE_NODE *FileNode)
static inline static inline
VOID MemfsFileNodeReference(MEMFS_FILE_NODE *FileNode) VOID MemfsFileNodeReference(MEMFS_FILE_NODE *FileNode)
{ {
FileNode->RefCount++; InterlockedIncrement(&FileNode->RefCount);
} }
static inline static inline
VOID MemfsFileNodeDereference(MEMFS_FILE_NODE *FileNode) VOID MemfsFileNodeDereference(MEMFS_FILE_NODE *FileNode)
{ {
if (0 == --FileNode->RefCount) if (0 == InterlockedDecrement(&FileNode->RefCount))
MemfsFileNodeDelete(FileNode); MemfsFileNodeDelete(FileNode);
} }
@ -848,14 +850,18 @@ static NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS Result; NTSTATUS Result;
#if defined(MEMFS_NAMED_STREAMS) #if defined(MEMFS_NAMED_STREAMS)
MEMFS_FILE_NODE_MAP_ENUM_CONTEXT Context = { FALSE }; MEMFS_FILE_NODE_MAP_ENUM_CONTEXT Context = { TRUE };
ULONG Index; ULONG Index;
MemfsFileNodeMapEnumerateNamedStreams(Memfs->FileNodeMap, FileNode, MemfsFileNodeMapEnumerateNamedStreams(Memfs->FileNodeMap, FileNode,
MemfsFileNodeMapEnumerateFn, &Context); MemfsFileNodeMapEnumerateFn, &Context);
for (Index = 0; Context.Count > Index; Index++) for (Index = 0; Context.Count > Index; Index++)
if (1 >= Context.FileNodes[Index]->RefCount) {
LONG RefCount = Context.FileNodes[Index]->RefCount;
MemoryBarrier();
if (2 >= RefCount)
MemfsFileNodeMapRemove(Memfs->FileNodeMap, Context.FileNodes[Index]); MemfsFileNodeMapRemove(Memfs->FileNodeMap, Context.FileNodes[Index]);
}
MemfsFileNodeMapEnumerateFree(&Context); MemfsFileNodeMapEnumerateFree(&Context);
#endif #endif

5
tst/passthrough-cpp/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
build
*.ncb
*.suo
*.vcproj.*
*.vcxproj.user

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "passthrough-cpp", "passthrough-cpp.vcxproj", "{E8A4060D-E6A4-42CC-9BCA-DC82E6EDB2C5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E8A4060D-E6A4-42CC-9BCA-DC82E6EDB2C5}.Debug|x64.ActiveCfg = Debug|x64
{E8A4060D-E6A4-42CC-9BCA-DC82E6EDB2C5}.Debug|x64.Build.0 = Debug|x64
{E8A4060D-E6A4-42CC-9BCA-DC82E6EDB2C5}.Debug|x86.ActiveCfg = Debug|Win32
{E8A4060D-E6A4-42CC-9BCA-DC82E6EDB2C5}.Debug|x86.Build.0 = Debug|Win32
{E8A4060D-E6A4-42CC-9BCA-DC82E6EDB2C5}.Release|x64.ActiveCfg = Release|x64
{E8A4060D-E6A4-42CC-9BCA-DC82E6EDB2C5}.Release|x64.Build.0 = Release|x64
{E8A4060D-E6A4-42CC-9BCA-DC82E6EDB2C5}.Release|x86.ActiveCfg = Release|Win32
{E8A4060D-E6A4-42CC-9BCA-DC82E6EDB2C5}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,178 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{E8A4060D-E6A4-42CC-9BCA-DC82E6EDB2C5}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>passthroughcpp</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="passthrough-cpp.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="passthrough-cpp.cpp">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
</Project>

6
tst/passthrough-dotnet/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
build
*.ncb
*.suo
*.vcproj.*
*.vcxproj.user
*.csproj.user

View File

@ -0,0 +1,845 @@
/**
* @file Program.cs
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
using System;
using System.Collections;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using Fsp;
using VolumeInfo = Fsp.Interop.VolumeInfo;
using FileInfo = Fsp.Interop.FileInfo;
namespace passthrough
{
class Ptfs : FileSystemBase
{
protected const int ALLOCATION_UNIT = 4096;
protected static void ThrowIoExceptionWithHResult(Int32 HResult)
{
throw new IOException(null, HResult);
}
protected static void ThrowIoExceptionWithWin32(Int32 Error)
{
ThrowIoExceptionWithHResult(unchecked((Int32)(0x80070000 | Error)));
}
protected static void ThrowIoExceptionWithNtStatus(Int32 Status)
{
ThrowIoExceptionWithWin32((Int32)Win32FromNtStatus(Status));
}
protected class FileDesc
{
public FileStream Stream;
public DirectoryInfo DirInfo;
public DictionaryEntry[] FileSystemInfos;
public FileDesc(FileStream Stream)
{
this.Stream = Stream;
}
public FileDesc(DirectoryInfo DirInfo)
{
this.DirInfo = DirInfo;
}
public static void GetFileInfoFromFileSystemInfo(
FileSystemInfo Info,
out FileInfo FileInfo)
{
FileInfo.FileAttributes = (UInt32)Info.Attributes;
FileInfo.ReparseTag = 0;
FileInfo.FileSize = Info is System.IO.FileInfo ?
(UInt64)((System.IO.FileInfo)Info).Length : 0;
FileInfo.AllocationSize = (FileInfo.FileSize + ALLOCATION_UNIT - 1)
/ ALLOCATION_UNIT * ALLOCATION_UNIT;
FileInfo.CreationTime = (UInt64)Info.CreationTimeUtc.ToFileTimeUtc();
FileInfo.LastAccessTime = (UInt64)Info.LastAccessTimeUtc.ToFileTimeUtc();
FileInfo.LastWriteTime = (UInt64)Info.LastWriteTimeUtc.ToFileTimeUtc();
FileInfo.ChangeTime = FileInfo.LastWriteTime;
FileInfo.IndexNumber = 0;
FileInfo.HardLinks = 0;
}
public Int32 GetFileInfo(out FileInfo FileInfo)
{
if (null != Stream)
{
BY_HANDLE_FILE_INFORMATION Info;
if (!GetFileInformationByHandle(Stream.SafeFileHandle.DangerousGetHandle(),
out Info))
ThrowIoExceptionWithWin32(Marshal.GetLastWin32Error());
FileInfo.FileAttributes = Info.dwFileAttributes;
FileInfo.ReparseTag = 0;
FileInfo.FileSize = (UInt64)Stream.Length;
FileInfo.AllocationSize = (FileInfo.FileSize + ALLOCATION_UNIT - 1)
/ ALLOCATION_UNIT * ALLOCATION_UNIT;
FileInfo.CreationTime = Info.ftCreationTime;
FileInfo.LastAccessTime = Info.ftLastAccessTime;
FileInfo.LastWriteTime = Info.ftLastWriteTime;
FileInfo.ChangeTime = FileInfo.LastWriteTime;
FileInfo.IndexNumber = 0;
FileInfo.HardLinks = 0;
}
else
GetFileInfoFromFileSystemInfo(DirInfo, out FileInfo);
return STATUS_SUCCESS;
}
public void SetBasicInfo(
UInt32 FileAttributes,
UInt64 CreationTime,
UInt64 LastAccessTime,
UInt64 LastWriteTime)
{
if (0 == FileAttributes)
FileAttributes = (UInt32)System.IO.FileAttributes.Normal;
if (null != Stream)
{
FILE_BASIC_INFO Info = default(FILE_BASIC_INFO);
if (unchecked((UInt32)(-1)) != FileAttributes)
Info.FileAttributes = FileAttributes;
if (0 != CreationTime)
Info.CreationTime = CreationTime;
if (0 != LastAccessTime)
Info.LastAccessTime = LastAccessTime;
if (0 != LastWriteTime)
Info.LastWriteTime = LastWriteTime;
if (!SetFileInformationByHandle(Stream.SafeFileHandle.DangerousGetHandle(),
0/*FileBasicInfo*/, ref Info, (UInt32)Marshal.SizeOf(Info)))
ThrowIoExceptionWithWin32(Marshal.GetLastWin32Error());
}
else
{
if (unchecked((UInt32)(-1)) != FileAttributes)
DirInfo.Attributes = (System.IO.FileAttributes)FileAttributes;
if (0 != CreationTime)
DirInfo.CreationTimeUtc = DateTime.FromFileTimeUtc((Int64)CreationTime);
if (0 != LastAccessTime)
DirInfo.LastAccessTimeUtc = DateTime.FromFileTimeUtc((Int64)LastAccessTime);
if (0 != LastWriteTime)
DirInfo.LastWriteTimeUtc = DateTime.FromFileTimeUtc((Int64)LastWriteTime);
}
}
public UInt32 GetFileAttributes()
{
FileInfo FileInfo;
GetFileInfo(out FileInfo);
return FileInfo.FileAttributes;
}
public void SetFileAttributes(UInt32 FileAttributes)
{
SetBasicInfo(FileAttributes, 0, 0, 0);
}
public Byte[] GetSecurityDescriptor()
{
if (null != Stream)
return Stream.GetAccessControl().GetSecurityDescriptorBinaryForm();
else
return DirInfo.GetAccessControl().GetSecurityDescriptorBinaryForm();
}
public void SetSecurityDescriptor(AccessControlSections Sections, Byte[] SecurityDescriptor)
{
Int32 SecurityInformation = 0;
if (0 != (Sections & AccessControlSections.Owner))
SecurityInformation |= 1/*OWNER_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Group))
SecurityInformation |= 2/*GROUP_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Access))
SecurityInformation |= 4/*DACL_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Audit))
SecurityInformation |= 8/*SACL_SECURITY_INFORMATION*/;
if (null != Stream)
{
if (!SetKernelObjectSecurity(Stream.SafeFileHandle.DangerousGetHandle(),
SecurityInformation, SecurityDescriptor))
ThrowIoExceptionWithWin32(Marshal.GetLastWin32Error());
}
else
{
if (!SetFileSecurityW(DirInfo.FullName,
SecurityInformation, SecurityDescriptor))
ThrowIoExceptionWithWin32(Marshal.GetLastWin32Error());
}
}
public void SetDisposition(Boolean Safe)
{
if (null != Stream)
{
FILE_DISPOSITION_INFO Info;
Info.DeleteFile = true;
if (!SetFileInformationByHandle(Stream.SafeFileHandle.DangerousGetHandle(),
4/*FileDispositionInfo*/, ref Info, (UInt32)Marshal.SizeOf(Info)))
if (!Safe)
ThrowIoExceptionWithWin32(Marshal.GetLastWin32Error());
}
else
try
{
DirInfo.Delete();
}
catch (Exception ex)
{
if (!Safe)
ThrowIoExceptionWithHResult(ex.HResult);
}
}
public static void Rename(String FileName, String NewFileName, Boolean ReplaceIfExists)
{
if (!MoveFileExW(FileName, NewFileName, ReplaceIfExists ? 1U/*MOVEFILE_REPLACE_EXISTING*/ : 0))
ThrowIoExceptionWithWin32(Marshal.GetLastWin32Error());
}
/* interop */
[StructLayout(LayoutKind.Sequential, Pack = 4)]
private struct BY_HANDLE_FILE_INFORMATION
{
public UInt32 dwFileAttributes;
public UInt64 ftCreationTime;
public UInt64 ftLastAccessTime;
public UInt64 ftLastWriteTime;
public UInt32 dwVolumeSerialNumber;
public UInt32 nFileSizeHigh;
public UInt32 nFileSizeLow;
public UInt32 nNumberOfLinks;
public UInt32 nFileIndexHigh;
public UInt32 nFileIndexLow;
}
[StructLayout(LayoutKind.Sequential)]
private struct FILE_BASIC_INFO
{
public UInt64 CreationTime;
public UInt64 LastAccessTime;
public UInt64 LastWriteTime;
public UInt64 ChangeTime;
public UInt32 FileAttributes;
}
[StructLayout(LayoutKind.Sequential)]
private struct FILE_DISPOSITION_INFO
{
public Boolean DeleteFile;
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern Boolean GetFileInformationByHandle(
IntPtr hFile,
out BY_HANDLE_FILE_INFORMATION lpFileInformation);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern Boolean SetFileInformationByHandle(
IntPtr hFile,
Int32 FileInformationClass,
ref FILE_BASIC_INFO lpFileInformation,
UInt32 dwBufferSize);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern Boolean SetFileInformationByHandle(
IntPtr hFile,
Int32 FileInformationClass,
ref FILE_DISPOSITION_INFO lpFileInformation,
UInt32 dwBufferSize);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern Boolean MoveFileExW(
[MarshalAs(UnmanagedType.LPWStr)] String lpExistingFileName,
[MarshalAs(UnmanagedType.LPWStr)] String lpNewFileName,
UInt32 dwFlags);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern Boolean SetFileSecurityW(
[MarshalAs(UnmanagedType.LPWStr)] String FileName,
Int32 SecurityInformation,
Byte[] SecurityDescriptor);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern Boolean SetKernelObjectSecurity(
IntPtr Handle,
Int32 SecurityInformation,
Byte[] SecurityDescriptor);
}
private class DirectoryEntryComparer : IComparer
{
public int Compare(object x, object y)
{
return String.Compare(
(String)((DictionaryEntry)x).Key,
(String)((DictionaryEntry)y).Key);
}
}
private static DirectoryEntryComparer _DirectoryEntryComparer =
new DirectoryEntryComparer();
public Ptfs(String Path0)
{
_Path = Path.GetFullPath(Path0);
if (_Path.EndsWith("\\"))
_Path = _Path.Substring(0, _Path.Length - 1);
}
public String ConcatPath(String FileName)
{
return _Path + FileName;
}
public override Int32 ExceptionHandler(Exception ex)
{
Int32 HResult = ex.HResult; /* needs Framework 4.5 */
if (0x80070000 == (HResult & 0xFFFF0000))
return NtStatusFromWin32((UInt32)HResult & 0xFFFF);
return STATUS_UNEXPECTED_IO_ERROR;
}
public override Int32 Init(Object Host0)
{
FileSystemHost Host = (FileSystemHost)Host0;
Host.SectorSize = ALLOCATION_UNIT;
Host.SectorsPerAllocationUnit = 1;
Host.MaxComponentLength = 255;
Host.FileInfoTimeout = 1000;
Host.CaseSensitiveSearch = false;
Host.CasePreservedNames = true;
Host.UnicodeOnDisk = true;
Host.PersistentAcls = true;
Host.PostCleanupWhenModifiedOnly = true;
Host.PassQueryDirectoryPattern = true;
Host.VolumeCreationTime = (UInt64)File.GetCreationTimeUtc(_Path).ToFileTimeUtc();
Host.VolumeSerialNumber = 0;
return STATUS_SUCCESS;
}
public override Int32 GetVolumeInfo(
out VolumeInfo VolumeInfo)
{
VolumeInfo = default(VolumeInfo);
try
{
DriveInfo Info = new DriveInfo(_Path);
VolumeInfo.TotalSize = (UInt64)Info.TotalSize;
VolumeInfo.FreeSize = (UInt64)Info.TotalFreeSpace;
}
catch (ArgumentException)
{
/*
* DriveInfo only supports drives and does not support UNC paths.
* It would be better to use GetDiskFreeSpaceEx here.
*/
}
return STATUS_SUCCESS;
}
public override Int32 GetSecurityByName(
String FileName,
out UInt32 FileAttributes/* or ReparsePointIndex */,
ref Byte[] SecurityDescriptor)
{
FileName = ConcatPath(FileName);
System.IO.FileInfo Info = new System.IO.FileInfo(FileName);
FileAttributes = (UInt32)Info.Attributes;
if (null != SecurityDescriptor)
SecurityDescriptor = Info.GetAccessControl().GetSecurityDescriptorBinaryForm();
return STATUS_SUCCESS;
}
public override Int32 Create(
String FileName,
UInt32 CreateOptions,
UInt32 GrantedAccess,
UInt32 FileAttributes,
Byte[] SecurityDescriptor,
UInt64 AllocationSize,
out Object FileNode,
out Object FileDesc0,
out FileInfo FileInfo,
out String NormalizedName)
{
FileDesc FileDesc = null;
try
{
FileName = ConcatPath(FileName);
if (0 == (CreateOptions & FILE_DIRECTORY_FILE))
{
FileSecurity Security = null;
if (null != SecurityDescriptor)
{
Security = new FileSecurity();
Security.SetSecurityDescriptorBinaryForm(SecurityDescriptor);
}
FileDesc = new FileDesc(
new FileStream(
FileName,
FileMode.CreateNew,
(FileSystemRights)GrantedAccess | FileSystemRights.WriteAttributes,
FileShare.Read | FileShare.Write | FileShare.Delete,
4096,
0,
Security));
}
else
{
if (Directory.Exists(FileName))
ThrowIoExceptionWithNtStatus(STATUS_OBJECT_NAME_COLLISION);
DirectorySecurity Security = null;
if (null != SecurityDescriptor)
{
Security = new DirectorySecurity();
Security.SetSecurityDescriptorBinaryForm(SecurityDescriptor);
}
FileDesc = new FileDesc(
Directory.CreateDirectory(FileName, Security));
}
FileDesc.SetFileAttributes(FileAttributes);
FileNode = default(Object);
FileDesc0 = FileDesc;
NormalizedName = default(String);
return FileDesc.GetFileInfo(out FileInfo);
}
catch
{
if (null != FileDesc && null != FileDesc.Stream)
FileDesc.Stream.Dispose();
throw;
}
}
public override Int32 Open(
String FileName,
UInt32 CreateOptions,
UInt32 GrantedAccess,
out Object FileNode,
out Object FileDesc0,
out FileInfo FileInfo,
out String NormalizedName)
{
FileDesc FileDesc = null;
try
{
FileName = ConcatPath(FileName);
if (!Directory.Exists(FileName))
{
FileDesc = new FileDesc(
new FileStream(
FileName,
FileMode.Open,
(FileSystemRights)GrantedAccess,
FileShare.Read | FileShare.Write | FileShare.Delete,
4096,
0));
}
else
{
FileDesc = new FileDesc(
new DirectoryInfo(FileName));
}
FileNode = default(Object);
FileDesc0 = FileDesc;
NormalizedName = default(String);
return FileDesc.GetFileInfo(out FileInfo);
}
catch
{
if (null != FileDesc && null != FileDesc.Stream)
FileDesc.Stream.Dispose();
throw;
}
}
public override Int32 Overwrite(
Object FileNode,
Object FileDesc0,
UInt32 FileAttributes,
Boolean ReplaceFileAttributes,
UInt64 AllocationSize,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (ReplaceFileAttributes)
FileDesc.SetFileAttributes(FileAttributes);
else if (0 != FileAttributes)
FileDesc.SetFileAttributes(FileDesc.GetFileAttributes() | FileAttributes);
FileDesc.Stream.SetLength(0);
return FileDesc.GetFileInfo(out FileInfo);
}
public override void Cleanup(
Object FileNode,
Object FileDesc0,
String FileName,
UInt32 Flags)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (0 != (Flags & CleanupDelete))
{
FileDesc.SetDisposition(true);
if (null != FileDesc.Stream)
FileDesc.Stream.Dispose();
}
}
public override void Close(
Object FileNode,
Object FileDesc0)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (null != FileDesc.Stream)
FileDesc.Stream.Dispose();
}
public override Int32 Read(
Object FileNode,
Object FileDesc0,
IntPtr Buffer,
UInt64 Offset,
UInt32 Length,
out UInt32 PBytesTransferred)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (Offset >= (UInt64)FileDesc.Stream.Length)
ThrowIoExceptionWithNtStatus(STATUS_END_OF_FILE);
Byte[] Bytes = new byte[Length];
FileDesc.Stream.Seek((Int64)Offset, SeekOrigin.Begin);
PBytesTransferred = (UInt32)FileDesc.Stream.Read(Bytes, 0, Bytes.Length);
Marshal.Copy(Bytes, 0, Buffer, Bytes.Length);
return STATUS_SUCCESS;
}
public override Int32 Write(
Object FileNode,
Object FileDesc0,
IntPtr Buffer,
UInt64 Offset,
UInt32 Length,
Boolean WriteToEndOfFile,
Boolean ConstrainedIo,
out UInt32 PBytesTransferred,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (ConstrainedIo)
{
if (Offset >= (UInt64)FileDesc.Stream.Length)
{
PBytesTransferred = default(UInt32);
FileInfo = default(FileInfo);
return STATUS_SUCCESS;
}
if (Offset + Length > (UInt64)FileDesc.Stream.Length)
Length = (UInt32)((UInt64)FileDesc.Stream.Length - Offset);
}
Byte[] Bytes = new byte[Length];
Marshal.Copy(Buffer, Bytes, 0, Bytes.Length);
if (!WriteToEndOfFile)
FileDesc.Stream.Seek((Int64)Offset, SeekOrigin.Begin);
FileDesc.Stream.Write(Bytes, 0, Bytes.Length);
PBytesTransferred = (UInt32)Bytes.Length;
return FileDesc.GetFileInfo(out FileInfo);
}
public override Int32 Flush(
Object FileNode,
Object FileDesc0,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (null == FileDesc)
{
/* we do not flush the whole volume, so just return SUCCESS */
FileInfo = default(FileInfo);
return STATUS_SUCCESS;
}
FileDesc.Stream.Flush(true);
return FileDesc.GetFileInfo(out FileInfo);
}
public override Int32 GetFileInfo(
Object FileNode,
Object FileDesc0,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
return FileDesc.GetFileInfo(out FileInfo);
}
public override Int32 SetBasicInfo(
Object FileNode,
Object FileDesc0,
UInt32 FileAttributes,
UInt64 CreationTime,
UInt64 LastAccessTime,
UInt64 LastWriteTime,
UInt64 ChangeTime,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
FileDesc.SetBasicInfo(FileAttributes, CreationTime, LastAccessTime, LastWriteTime);
return FileDesc.GetFileInfo(out FileInfo);
}
public override Int32 SetFileSize(
Object FileNode,
Object FileDesc0,
UInt64 NewSize,
Boolean SetAllocationSize,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (!SetAllocationSize || (UInt64)FileDesc.Stream.Length > NewSize)
{
/*
* "FileInfo.FileSize > NewSize" explanation:
* Ptfs does not support allocation size. However if the new AllocationSize
* is less than the current FileSize we must truncate the file.
*/
FileDesc.Stream.SetLength((Int64)NewSize);
}
return FileDesc.GetFileInfo(out FileInfo);
}
public override Int32 CanDelete(
Object FileNode,
Object FileDesc0,
String FileName)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
FileDesc.SetDisposition(false);
return STATUS_SUCCESS;
}
public override Int32 Rename(
Object FileNode,
Object FileDesc0,
String FileName,
String NewFileName,
Boolean ReplaceIfExists)
{
FileName = ConcatPath(FileName);
NewFileName = ConcatPath(NewFileName);
FileDesc.Rename(FileName, NewFileName, ReplaceIfExists);
return STATUS_SUCCESS;
}
public override Int32 GetSecurity(
Object FileNode,
Object FileDesc0,
ref Byte[] SecurityDescriptor)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
SecurityDescriptor = FileDesc.GetSecurityDescriptor();
return STATUS_SUCCESS;
}
public override Int32 SetSecurity(
Object FileNode,
Object FileDesc0,
AccessControlSections Sections,
Byte[] SecurityDescriptor)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
FileDesc.SetSecurityDescriptor(Sections, SecurityDescriptor);
return STATUS_SUCCESS;
}
public override Boolean ReadDirectoryEntry(
Object FileNode,
Object FileDesc0,
String Pattern,
String Marker,
ref Object Context,
out String FileName,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (null == FileDesc.FileSystemInfos)
{
IEnumerable Enum = FileDesc.DirInfo.EnumerateFileSystemInfos(
null != Pattern ? Pattern : "*");
SortedList List = new SortedList();
List.Add(".", FileDesc.DirInfo);
List.Add("..", FileDesc.DirInfo.Parent);
foreach (FileSystemInfo Info in Enum)
List.Add(Info.Name, Info);
FileDesc.FileSystemInfos = new DictionaryEntry[List.Count];
List.CopyTo(FileDesc.FileSystemInfos, 0);
}
int Index;
if (null == Context)
{
Index = 0;
if (null != Marker)
{
Index = Array.BinarySearch(FileDesc.FileSystemInfos,
new DictionaryEntry(Marker, null),
_DirectoryEntryComparer);
if (0 <= Index)
Index++;
else
Index = ~Index;
}
}
else
Index = (int)Context;
if (FileDesc.FileSystemInfos.Length > Index)
{
Context = Index + 1;
FileName = (String)FileDesc.FileSystemInfos[Index].Key;
FileDesc.GetFileInfoFromFileSystemInfo(
(FileSystemInfo)FileDesc.FileSystemInfos[Index].Value,
out FileInfo);
return true;
}
else
{
FileName = default(String);
FileInfo = default(FileInfo);
return false;
}
}
private String _Path;
}
class PtfsService : Service
{
private class CommandLineUsageException : Exception
{
public CommandLineUsageException(String Message = null) : base(Message)
{
HasMessage = null != Message;
}
public bool HasMessage;
}
private const String PROGNAME = "passthrough-dotnet";
public PtfsService() : base("PtfsService")
{
}
protected override void OnStart(String[] Args)
{
try
{
String DebugLogFile = null;
UInt32 DebugFlags = 0;
String VolumePrefix = null;
String PassThrough = null;
String MountPoint = null;
IntPtr DebugLogHandle = (IntPtr)(-1);
FileSystemHost Host = null;
Ptfs Ptfs = null;
int I;
for (I = 1; Args.Length > I; I++)
{
String Arg = Args[I];
if ('-' != Arg[0])
break;
switch (Arg[1])
{
case '?':
throw new CommandLineUsageException();
case 'd':
argtol(Args, ref I, ref DebugFlags);
break;
case 'D':
argtos(Args, ref I, ref DebugLogFile);
break;
case 'm':
argtos(Args, ref I, ref MountPoint);
break;
case 'p':
argtos(Args, ref I, ref PassThrough);
break;
case 'u':
argtos(Args, ref I, ref VolumePrefix);
break;
default:
throw new CommandLineUsageException();
}
}
if (Args.Length > I)
throw new CommandLineUsageException();
if (null == PassThrough && null != VolumePrefix)
{
I = VolumePrefix.IndexOf('\\');
if (-1 != I && VolumePrefix.Length > I && '\\' != VolumePrefix[I + 1])
{
I = VolumePrefix.IndexOf('\\', I + 1);
if (-1 != I &&
VolumePrefix.Length > I + 1 &&
(
('A' <= VolumePrefix[I + 1] && VolumePrefix[I + 1] <= 'Z') ||
('a' <= VolumePrefix[I + 1] && VolumePrefix[I + 1] <= 'z')
) &&
'$' == VolumePrefix[I + 2])
{
PassThrough = String.Format("{0}:{1}", VolumePrefix[I + 1], VolumePrefix.Substring(I + 3));
}
}
}
if (null == PassThrough || null == MountPoint)
throw new CommandLineUsageException();
if (null != DebugLogFile)
if (0 > FileSystemHost.SetDebugLogFile(DebugLogFile))
throw new CommandLineUsageException("cannot open debug log file");
Host = new FileSystemHost(Ptfs = new Ptfs(PassThrough));
Host.Prefix = VolumePrefix;
if (0 > Host.Mount(MountPoint, null, true, DebugFlags))
throw new IOException("cannot mount file system");
MountPoint = Host.MountPoint();
_Host = Host;
Log(EVENTLOG_INFORMATION_TYPE, String.Format("{0}{1}{2} -p {3} -m {4}",
PROGNAME,
null != VolumePrefix && 0 < VolumePrefix.Length ? " -u " : "",
null != VolumePrefix && 0 < VolumePrefix.Length ? VolumePrefix : "",
PassThrough,
MountPoint));
}
catch (CommandLineUsageException ex)
{
Log(EVENTLOG_ERROR_TYPE, String.Format(
"{0}" +
"usage: {1} OPTIONS\n" +
"\n" +
"options:\n" +
" -d DebugFlags [-1: enable all debug logs]\n" +
" -D DebugLogFile [file path; use - for stderr]\n" +
" -u \\Server\\Share [UNC prefix (single backslash)]\n" +
" -p Directory [directory to expose as pass through file system]\n" +
" -m MountPoint [X:|*|directory]\n",
ex.HasMessage ? ex.Message + "\n" : "",
PROGNAME));
throw;
}
catch (Exception ex)
{
Log(EVENTLOG_ERROR_TYPE, String.Format("{0}", ex.Message));
throw;
}
}
protected override void OnStop()
{
_Host.Unmount();
_Host = null;
}
private static void argtos(String[] Args, ref int I, ref String V)
{
if (Args.Length > ++I)
V = Args[I];
else
throw new CommandLineUsageException();
}
private static void argtol(String[] Args, ref int I, ref UInt32 V)
{
Int32 R;
if (Args.Length > ++I)
V = Int32.TryParse(Args[I], out R) ? (UInt32)R : V;
else
throw new CommandLineUsageException();
}
private FileSystemHost _Host;
}
class Program
{
static void Main(string[] args)
{
Environment.ExitCode = new PtfsService().Run();
}
}
}

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6EC13EBC-BD7E-4997-9B29-49D5F06103A6}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>passthrough</RootNamespace>
<AssemblyName>passthrough-dotnet</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="winfsp-msil, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b099876d8fa9b1f3, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>$(MSBuildProgramFiles32)\WinFsp\bin\winfsp-msil.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.5.2">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.5.2 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "passthrough-dotnet", "passthrough-dotnet.csproj", "{6EC13EBC-BD7E-4997-9B29-49D5F06103A6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6EC13EBC-BD7E-4997-9B29-49D5F06103A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6EC13EBC-BD7E-4997-9B29-49D5F06103A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6EC13EBC-BD7E-4997-9B29-49D5F06103A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6EC13EBC-BD7E-4997-9B29-49D5F06103A6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

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

View File

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

View File

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

View File

@ -846,7 +846,7 @@ static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
if (0 != DebugLogFile) if (0 != DebugLogFile)
{ {
if (0 == wcscmp(L"-", DebugLogFile)) if (0 == wcscmp(L"-", DebugLogFile))
DebugLogHandle = GetStdHandle(STD_OUTPUT_HANDLE); DebugLogHandle = GetStdHandle(STD_ERROR_HANDLE);
else else
DebugLogHandle = CreateFileW( DebugLogHandle = CreateFileW(
DebugLogFile, DebugLogFile,
@ -903,7 +903,7 @@ usage:
"\n" "\n"
"options:\n" "options:\n"
" -d DebugFlags [-1: enable all debug logs]\n" " -d DebugFlags [-1: enable all debug logs]\n"
" -D DebugLogFile [file path; use - for stdout]\n" " -D DebugLogFile [file path; use - for stderr]\n"
" -u \\Server\\Share [UNC prefix (single backslash)]\n" " -u \\Server\\Share [UNC prefix (single backslash)]\n"
" -p Directory [directory to expose as pass through file system]\n" " -p Directory [directory to expose as pass through file system]\n"
" -m MountPoint [X:|*|directory]\n"; " -m MountPoint [X:|*|directory]\n";

View File

@ -316,6 +316,9 @@ static void dirbuf_fill_test(void)
void dirbuf_tests(void) void dirbuf_tests(void)
{ {
if (OptExternal)
return;
TEST(dirbuf_empty_test); TEST(dirbuf_empty_test);
TEST(dirbuf_dots_test); TEST(dirbuf_dots_test);
TEST(dirbuf_fill_test); TEST(dirbuf_fill_test);

View File

@ -31,5 +31,8 @@ void eventlog_test(void)
void eventlog_tests(void) void eventlog_tests(void)
{ {
if (OptExternal)
return;
TEST_OPT(eventlog_test); TEST_OPT(eventlog_test);
} }

View File

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

View File

@ -370,5 +370,8 @@ void fuse_opt_parse_test(void)
void fuse_opt_tests(void) void fuse_opt_tests(void)
{ {
if (OptExternal)
return;
TEST(fuse_opt_parse_test); TEST(fuse_opt_parse_test);
} }

View File

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

Binary file not shown.

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