Compare commits

...

262 Commits

Author SHA1 Message Date
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
fa652cdb56 launcher: change registry location 2017-02-07 17:15:41 -08:00
aeaeba0dd6 launcher: change registry location 2017-02-07 14:53:27 -08:00
b299027f6e Update Changelog 2017-02-07 12:48:40 -08:00
5edd9eb548 Update Changelog 2017-02-07 12:45:32 -08:00
fbc24bcca9 Update Changelog 2017-02-07 12:44:59 -08:00
4ef6dcb71d Update README.md 2017-02-07 12:35:14 -08:00
b8f0d08672 Update README.md 2017-02-07 12:32:29 -08:00
5c82044295 Update README.md 2017-02-07 12:26:11 -08:00
e3b5426e45 Update README.md 2017-02-07 12:25:27 -08:00
d34f262c02 Merge branch 'pvt-license-change' into release/1.0 2017-02-07 12:21:48 -08:00
ede72e4c5f tst: passthrough: fix missed FspFileSystemReleaseDirectoryBuffer in case of error 2017-02-06 12:05:30 -08:00
9c4b73dac1 add FLOSS exception to License 2017-02-06 11:51:29 -08:00
9ecfc64178 doc: update tutorial 2017-02-04 15:22:42 -08:00
fbe46d8c81 doc: update tutorial 2017-02-04 14:56:01 -08:00
2a12ed490d tools: run-tests: run mountpoint-drive tests with --resilient 2017-02-03 18:50:39 -08:00
c6d9e68c3f Revert "tst: winfsp-tests: getfileinfo_dotest: CREATE_ALWAYS instead of CREATE_NEW"
This reverts commit dca3cb93f3.
2017-02-03 18:48:55 -08:00
bfc41127d0 sys: FspFsvolCreateSharingViolationOplock: fix problem with missed FspFsvolCreatePostClose 2017-02-03 18:08:11 -08:00
6e70500afc sys: FspFsvolCreateComplete: populate FileNode and FileDesc before name normalization 2017-02-03 17:36:16 -08:00
dca3cb93f3 tst: winfsp-tests: getfileinfo_dotest: CREATE_ALWAYS instead of CREATE_NEW 2017-02-02 22:12:49 -08:00
2f0061b4ba tools: run-tests: sample-passthrough-fuse 2017-02-02 21:44:36 -08:00
3fcef3b0fa tools: run-tests: sample-passthrough-fuse 2017-02-02 21:39:13 -08:00
6a0574e309 tools: run-tests: sample-passthrough-fuse 2017-02-02 17:51:08 -08:00
0c945b67f3 dll: fuse: use -ouid=-1,gid=-1 to specify user/group who mounted file system 2017-02-02 17:06:10 -08:00
25b3e111fa dll: fuse: fuse.pc file renamed to fuse.pc.in 2017-02-02 15:01:22 -08:00
09101129a3 tst: passthrough: EnableBackupRestorePrivileges: minor fix 2017-02-02 14:51:45 -08:00
3700b375a7 tst: passthrough-fuse: on Windows allow the --VolumePrefix option to specify path 2017-02-01 21:37:53 -08:00
22fccdb575 build: bump version to RC2 and files to installer 2017-02-01 16:10:13 -08:00
c4932f7c7e tools: run-tests: include passthrough-fuse sample test 2017-02-01 15:38:46 -08:00
303cadb55d tst: passthrough-fuse: update Makefile to link with CYGFUSE or WinFsp-FUSE 2017-02-01 15:30:51 -08:00
5617d09edc tst: passthrough-fuse:
- When building for Windows (rather than Cygwin or POSIX OS)
allow the syntax C$\Path as an alternative to C:\Path.
2017-02-01 13:35:13 -08:00
eefaad241d doc: update tutorial 2017-01-31 17:29:03 -08:00
11dce32baa doc: update tutorial 2017-01-31 17:21:55 -08:00
3b8396dc27 tst: passthrough: minor fix 2017-01-31 16:53:27 -08:00
da7082030a doc: update tutorial 2017-01-31 16:36:30 -08:00
7425eba8af inc: winfsp.h: FspLoad 2017-01-31 16:07:50 -08:00
acf6ce1008 inc: winfsp.h: FspLoad 2017-01-31 15:56:00 -08:00
06f6c192ed tst: passthrough, passthrough-fuse: WinFspLoad: eliminate RRF_SUBKEY_WOW6432KEY 2017-01-31 15:27:15 -08:00
b7a06c7046 tools: run-tests 2017-01-31 14:52:20 -08:00
edb675d2d4 tools: run-tests 2017-01-31 12:21:46 -08:00
9533815931 update Changelog 2017-01-31 12:19:54 -08:00
fe74fc4013 tools: run-tests: sample testing fix 2017-01-31 11:31:00 -08:00
5bd6c1a122 dll: np: NPAddConnection: check volume access and report success/failure 2017-01-31 11:29:24 -08:00
7b15d32c33 appveyor: sample testing 2017-01-30 23:33:50 -08:00
c186289672 tools: run-tests: sample-passthrough-fuse: add but keep disabled 2017-01-30 23:32:22 -08:00
ff649e05c5 tools: run-tests: sample-passthrough* 2017-01-30 23:10:34 -08:00
9a9d3cd4e8 installer: add passthrough-fuse and fsreg.bat 2017-01-30 16:23:45 -08:00
d1bb65a998 tst: winfsp-tests: add --share-prefix option:
- this accommodates network file systems that have mapped drives
2017-01-30 16:07:44 -08:00
178200fd63 doc: update tutorial 2017-01-30 15:32:48 -08:00
396d9d97d2 tst: passthrough: enable backup/restore privileges if able 2017-01-30 15:22:20 -08:00
1d35069aab doc: update tutorial 2017-01-30 14:41:33 -08:00
4421c82ce0 doc: update tutorial 2017-01-30 14:34:44 -08:00
36f0978971 dll: fuse: allow rename for filenames that differ only in case 2017-01-30 11:59:21 -08:00
dae4bad732 tst: passthrough-fuse: testing 2017-01-29 21:25:50 -08:00
75744571ff dll: debug: fix problem with debug logs under 32-bits 2017-01-29 21:23:44 -08:00
0494726f52 tst: passthrough-fuse: testing 2017-01-29 18:06:56 -08:00
a964ab1b73 dll: fuse: CanDelete bug fix 2017-01-29 17:38:13 -08:00
796010c9fe tst: passthrough-fuse: testing 2017-01-29 17:28:40 -08:00
dc343ecbe5 tst: passthrough-fuse: testing 2017-01-29 17:07:22 -08:00
706fa2cc07 tst: passthrough-fuse: fi_fd, fi_setfd, etc. macros 2017-01-29 16:45:21 -08:00
c0aaebd0a5 tst: passthrough-fuse: windows-posix layer: dirfd 2017-01-29 15:45:36 -08:00
9c2b4e5631 tst: passthrough-fuse: testing 2017-01-29 13:59:29 -08:00
206b85c278 tst: passthrough-fuse: testing 2017-01-29 13:48:29 -08:00
075d1821a2 tst: passthrough-fuse: windows-posix layer 2017-01-29 12:44:18 -08:00
c252382204 tst: passthrough-fuse: windows-posix layer 2017-01-29 12:34:28 -08:00
a91e5b01ab tst: passthrough-fuse: windows-posix layer 2017-01-29 10:29:37 -08:00
473914d45f tst: passthrough-fuse: initial checkin 2017-01-28 22:47:46 -08:00
e12e3630bb doc: update tutorial document 2017-01-28 12:40:42 -08:00
960c627924 tst: passthrough: reorg project 2017-01-28 12:34:10 -08:00
f97ef5704f dll: fuse: reimplement ReadDirectory 2017-01-28 11:49:57 -08:00
41605a3d5a doc: update tutorial 2017-01-27 15:40:04 -08:00
e4f0406c4f tools: fsreg
tst: passthrough: support passing passthrough directory using -u
2017-01-27 13:38:45 -08:00
b5bf84b618 installer: add passthrough sample 2017-01-27 11:10:20 -08:00
3c340345c0 tst: passthrough: PassQueryDirectoryPattern 2017-01-26 23:22:59 -08:00
63c23f382b inc: fsctl: PassQueryDirectoryPattern 2017-01-26 23:09:58 -08:00
de5ef0c81d tst: winfsp-tests: --case-insensitive-cmp 2017-01-26 22:58:49 -08:00
7288605f65 tst: passthrough: use FspFileSystem*DirectoryBuffer API's 2017-01-26 16:39:06 -08:00
55a7864173 dll: FspFileSystem*DirectoryBuffer API's 2017-01-26 16:30:33 -08:00
4fe72ab332 sys,dll: ReadDirectory: add Marker, remove Offset 2017-01-25 10:51:37 -08:00
76a2926116 sys,dll: ReadDirectory: add Marker, remove Offset 2017-01-24 20:20:02 -08:00
7843c73d34 sys,dll: ReadDirectory: add Marker, remove Offset 2017-01-24 18:10:13 -08:00
ebad86387c tst: passthrough: testing 2017-01-23 14:33:07 -08:00
5475c414b3 doc: tutorial: minor fixes 2017-01-23 11:23:19 -08:00
e3e111ab27 doc: add tutorial document 2017-01-23 10:52:26 -08:00
9cd6710438 tst: passthrough: minor fix 2017-01-22 16:47:50 -08:00
a5f8736b1e tst: passthrough: ReadDirectory improvements 2017-01-20 20:47:55 -08:00
2ced698256 tst: passthrough: testing 2017-01-20 17:46:43 -08:00
53a4bdc478 tst: passthrough file system: WIP 2017-01-20 13:16:11 -08:00
eea92e89ef tst: passthrough file system: WIP 2017-01-20 13:05:22 -08:00
d519145f61 tst: passthrough file system: WIP 2017-01-20 12:38:25 -08:00
2809f56217 tst: passthrough file system: WIP 2017-01-20 12:03:06 -08:00
8cb76783ad tst: passthrough file system: WIP 2017-01-20 11:07:39 -08:00
117ab9c3e4 tst: passthrough file system: WIP 2017-01-20 10:38:31 -08:00
61a001baf1 tst: passthrough file system: WIP 2017-01-20 00:28:18 -08:00
d0c700eb0f tst: passthrough file system: WIP 2017-01-20 00:13:54 -08:00
b774aea4f4 tst: passthrough file system: WIP 2017-01-19 23:58:36 -08:00
f8e4c1bbc4 tst: passthrough file system: WIP 2017-01-19 22:44:31 -08:00
3bbff30f14 tst: passthrough file system: skeleton 2017-01-19 17:09:02 -08:00
2fe4e18d9c dll: FspFileSystemPreflight 2017-01-16 18:48:05 -08:00
b65322c2ac dll: FspPathIsDrive: bug fix 2017-01-16 18:21:56 -08:00
7764663386 dll: FspFileSystemPreflight 2017-01-16 14:54:10 -08:00
c6ae62f301 Update README - add installer link 2017-01-09 15:34:17 -08:00
6f22828060 tools: build: ensure that driver.cab is properly signed 2017-01-09 12:56:13 -08:00
7c2de68892 tools: build: create single driver.cab file 2017-01-09 12:37:39 -08:00
4656e8ed26 tools: build: incorporate sysdev signed drivers in build 2017-01-08 00:07:03 -08:00
be98326bbb tools: build: create driver.cab for sysdev 2017-01-07 20:59:36 -08:00
52acc3bc48 update Changelog 2017-01-06 12:47:11 -08:00
f68bc75255 build: include git short hash when versioning 2017-01-06 11:35:10 -08:00
029942bbac Update README 2017-01-05 16:54:46 -08:00
cb0c7def54 update README 2017-01-05 16:45:07 -08:00
5fbd75926b update README 2017-01-05 16:11:49 -08:00
bc9bcefc62 doc: add NTFS compatibility document 2017-01-05 15:56:15 -08:00
a57325e8af update source copyright notices for 2017 2017-01-05 13:56:18 -08:00
466922787d doc: update winfsp.h reference 2017-01-05 13:48:50 -08:00
9dc8aca710 inc: winfsp.h: update source documentation 2017-01-05 13:45:30 -08:00
88aeb83211 doc: fix file name case 2017-01-05 12:54:40 -08:00
a7cee1eafe doc: update testing document 2017-01-05 12:34:06 -08:00
eb0816db56 sys: create: do FspFsvolCreatePostClose when normalized name check fails 2017-01-04 16:26:12 -08:00
51833751d0 appveyor: reenable all jobs 2017-01-04 15:15:14 -08:00
155344ea61 appveyor: memory.dmp test 2017-01-04 15:03:03 -08:00
3874e2a6b5 appveyor: upload perf-tests results as artifact 2017-01-04 14:53:45 -08:00
c5740029f7 appveyor: optimize yml file 2017-01-04 14:41:15 -08:00
9973c4c963 appveyor: optimize yml file 2017-01-04 14:39:12 -08:00
6cfda75447 tools: run-perf-tests: 'self' option changed to 'baseline' 2017-01-04 14:28:52 -08:00
c7d6fc355b tools: run-perf-tests: specialized testing using the self option 2017-01-04 14:26:02 -08:00
b062f8683c appveyor: temporary change 2017-01-04 13:47:50 -08:00
cec5f0be08 appveyor: temporary change 2017-01-04 13:45:23 -08:00
40b61f7667 tools: run-perf-tests: fix 2017-01-04 13:44:22 -08:00
7c383654bd appveyor: perf tests job 2017-01-04 13:07:51 -08:00
9e4e7d4bcf tools: run-tests: ifstest: disable StreamNotifyNameTest 2017-01-03 23:40:49 -08:00
638e5a20b6 sys: FspFileNodeCopyActiveList, FspFileNodeCopyOpenList 2017-01-03 23:14:33 -08:00
95bbb584eb sys: FspFileNodeOpen,FspFileNode: maintain active list 2017-01-03 18:57:00 -08:00
1d8241cba7 sys: FspFileNodeNotifyChange: FILE_NOTIFY_CHANGE_STREAM_WRITE 2017-01-03 12:17:52 -08:00
460726df83 tst: memfs: Cleanup now properly update metadata on MainFileNode 2017-01-03 12:07:52 -08:00
b5cefc59e9 tools: run-tests.bat 2017-01-03 10:43:57 -08:00
e9ca1a8996 tools: run-tests 2017-01-03 10:12:44 -08:00
8c0f609a93 tools: run-tests: ifstest 2017-01-03 00:56:58 -08:00
23eabe5939 sys: FspFsvolFileSystemControlReparsePoint: FSCL_DELETE_REPARSE_POINT 2017-01-03 00:48:12 -08:00
eecca688bc sys: FspFileNodeInvalidateFileInfo: use after setting/deleting reparse point 2017-01-01 12:53:58 -08:00
23d2083d8f sys: FspFsvolFileSystemControlReparsePoint 2017-01-01 11:23:38 -08:00
8d379a4c8b tools: run-tests: ifstest: enable ReparsePoints tests 2016-12-31 23:36:45 -08:00
830985d331 sys: FspFsvolFileSystemControlReparsePoint: STATUS_ACCESS_DENIED 2016-12-31 23:01:40 -08:00
6b37e2ef12 sys: FspFsvolFileSystemControlReparsePointComplete 2016-12-31 21:26:12 -08:00
62dbaf56e3 sys: FspFsvolFileSystemControlReparsePointComplete 2016-12-31 20:50:03 -08:00
d301164609 sys: FspFsvolFileSystemControlReparsePointComplete: STATUS_INVALID_PARAMETER 2016-12-31 16:56:02 -08:00
ada3e1b0e5 tools: run-tests: ifstest: do not output unnamed tests 2016-12-31 16:32:33 -08:00
13d6ec3638 sys: FspFileNodeRenameCheck: allow multiple handles open on the file being renamed 2016-12-31 15:28:26 -08:00
2210561b65 sys: FspIopDispatchComplete: check user mode file system response 2016-12-31 11:22:27 -08:00
1713ce9c9e sys: FSP_STATUS_IGNORE_BIT 2016-12-30 19:48:19 -08:00
8f25dd6cab sys: FspIopCompleteIrpEx:
- only update statistics if we actually have a reference to the DeviceObject
2016-12-30 15:36:06 -08:00
c9485ff214 tools: run-tests: ifstest: add information about disabled tests 2016-12-30 15:03:42 -08:00
5ce1a722b3 tools: run-tests: ifstest: FileInformation tests 2016-12-30 14:43:15 -08:00
27315c1111 sys: FspFsvolQueryInformation,FspFsvolSetInformation:
- return STATUS_INVALID_PARAMETER on volume handles
2016-12-30 14:40:28 -08:00
bd38a39dbd sys: FileHardLinkInformation,FileLinkInformation: return STATUS_NOT_SUPPORTED 2016-12-30 14:14:54 -08:00
766734a8e3 sys: FileAlternateNameInformation: return STATUS_OBJECT_NAME_NOT_FOUND 2016-12-30 13:59:56 -08:00
b242a449b8 tools: run-tests: ifstest: enable FileInformation (not all tests pass yet) 2016-12-30 13:43:17 -08:00
c6a6fdfc36 sys: FSCTL_GET_RETRIEVAL_POINTERS 2016-12-30 13:42:46 -08:00
843d3f0362 sys: FspFsvolSetBasicInformation: invalidate dir caches 2016-12-30 11:01:52 -08:00
5190923c9a sys: FspFsvolQueryDirectoryRetry: on RestartScan do not always reset DirectoryPattern 2016-12-29 15:57:02 -08:00
2f8ac3765d sys: FspFileNodeCleanup:
- Handle the scenario where there are cleaned up, but unclosed streams in the context table.
2016-12-29 14:18:04 -08:00
e4b4e6a1f9 sys: FSP_FILE_NODE::MainFileNode: reference/dereference on create/delete 2016-12-29 13:16:11 -08:00
fa54898c64 appveyor: improvements 2016-12-28 21:50:22 -08:00
2f82d91e1f appveyor: save memory.dmp 2016-12-28 21:30:24 -08:00
7574c39ffb tools: run-tests: check whether ifstest could remove its directories 2016-12-28 17:41:35 -08:00
bdc02c8ab5 tst: memfs: ReadDirectory fix with concurrent deletes 2016-12-28 16:49:21 -08:00
15c16d7070 tools: run-tests: ifstest: enable ChangeNotification 2016-12-27 22:27:13 -08:00
ba312de59b sys: security: change notification 2016-12-27 22:24:42 -08:00
5824a24bf4 sys: FspFileNodeNotifyChange: significant improvements 2016-12-27 21:30:56 -08:00
f0a0787f6b update submodules 2016-12-27 17:07:58 -08:00
c17b84cff2 sys: statistics: fix stupid mistake when having multiple processors 2016-12-27 16:43:53 -08:00
168acb1a1f sys: statistics: implement FSCTL_FILESYSTEM_GET_STATISTICS 2016-12-26 22:45:48 -08:00
c8206751d2 sys,dll: Flush now takes FileInfo parameter 2016-12-26 13:59:53 -08:00
bec91873fe inc: fsctl: HasTrailingBackslash: allows for better checking user mode 2016-12-24 11:28:59 -08:00
9bf0d5d46d tools: run-tests: ifstest: enable CloseCleanupDelete (-UpdateOnCloseTest) 2016-12-23 17:16:07 -08:00
2d85c7bf73 tst: memfs: update parent timestamp on create/delete 2016-12-23 17:12:23 -08:00
ff3436718c sys: FSP_FILE_DESC::DidSetMetadata 2016-12-23 16:26:16 -08:00
69f6f661ba sys,dll: Cleanup, file times overhaul 2016-12-23 15:30:39 -08:00
6e52def53c tools: run-tests: ifstest: enable all tests that pass 2016-12-22 15:59:26 -08:00
2212d021e1 appveyor: run ifstest 2016-12-22 13:23:03 -08:00
7b94f2bebf sys: FspFileNodeSetFileInfo: TruncateOnClose 2016-12-21 16:45:01 -08:00
c897ddd864 sys,dll: Cleanup/TruncateOnClose overhaul 2016-12-21 16:09:24 -08:00
8d6314e2db tst: winfsp-tests: create_allocation_test 2016-12-20 10:56:35 -08:00
eec63332e0 sys: fileinfo: correctly set AllInformation and StandardInformation DeletePending flag 2016-12-19 13:36:11 -08:00
04186ea834 installer: change product name to WinFsp 2017 2016-12-19 10:46:32 -08:00
3adcf70748 sys: disallow creating a ReadOnly and DeleteOnClose file 2016-12-18 21:50:11 -08:00
33e8b5df04 sys,dll: create: correctly handle FILE_SUPERSEDE 2016-12-18 16:56:11 -08:00
154933ecab sys: overwrite: check hidde/system attributes (IFSTEST) 2016-12-18 16:02:32 -08:00
c760cf9563 tst: winfsp-tests: create_namelen_test: disable test in cases that it cannot work 2016-12-18 14:15:08 -08:00
245bba0a17 sys: name: fix warning on x86 builds 2016-12-18 13:35:25 -08:00
3008575bdf tst: winfsp-tests: create_namelen_test 2016-12-18 12:51:57 -08:00
2ce434efbd tst: run-tests: ifstest 2016-12-18 12:04:20 -08:00
94ea4f65f7 sys: FspFileNameIsValid, FspFileNameIsValidPattern: check path component length
tst: memfs: allow filenames to be 512 chars long
2016-12-18 11:51:23 -08:00
c780912810 sys: create: fix status return (IFSTEST) 2016-12-17 12:43:00 -08:00
299605b8fc sys: FILE_ATTRIBUTE_DIRECTORY support 2016-12-17 12:13:53 -08:00
86bccd763c tools: run-tests: ifstest 2016-12-16 23:55:19 -08:00
856d3bdefe tools: run-tests: ifstest 2016-12-16 23:10:13 -08:00
104c830437 tools: run-tests: ifstest 2016-12-16 22:54:40 -08:00
f35a93d1f7 tools: run-tests: ifstest 2016-12-16 20:20:49 -08:00
2d9b1b80fa sys: lockctl: fix hang uncovered by IFSTEST 2016-12-16 16:31:00 -08:00
f1ee19d8dc tst: winfsp-tests: getvolinfo_test: do not do short name testing with shares 2016-12-15 16:52:36 -08:00
671c0c12ab sys: FSCTL_QUERY_PERSISTENT_VOLUME_STATE 2016-12-15 16:15:22 -08:00
6eb2879374 tst: memfs: check FileName length in Create/Open 2016-12-15 14:54:15 -08:00
1e03c1a465 sys: FspFsvolQueryFsAttributeInformation: allow file system to fully specify file system name
tst: memfs: add -F FileSystemName option
2016-12-15 14:26:36 -08:00
b55c20b393 tools: deploy ifstest.bat 2016-12-15 13:08:25 -08:00
406af6901f tools: ifstest 2016-12-15 11:58:38 -08:00
173 changed files with 11909 additions and 3257 deletions

View File

@ -1,11 +1,50 @@
= Changelog
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::
This is the WinFsp 2017 Release Candidate 2. Some important changes included below:
- WinFsp is now available under the GPLv3 with a special exception for Free/Libre and Open Source Software.
- The location of the WinFsp launcher registry entries is now `HKEY_LOCAL_MACHINE\Software\WinFsp\Services`. [On Win64 the actual location is `HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\WinFsp\Services`.] This change was necessary to avoid loss of third party file system registry entries during WinFsp uninstallation. [See GitHub issue #31.]
- Despite stating in the previous release that the API has been finalized the `ReadDirectory` `FSP_FILE_SYSTEM_INTERFACE` operation has been changed. Extensive testing with multiple file systems has shown that `ReadDirectory` was hard to implement correctly. The new definition should make implementation easier for most file systems. [See GitHub issue #34.]
- Some API's to facilitate `ReadDirectory` implementation have been added. Look for `FspFileSystem*DirectoryBuffer` symbols.
- The installer now (optionally) installs a sample file system called "passthrough". This is a simple file system that passes all operations to an underlying file system. There is also a tutorial for this file system (in the doc directory).
- The installer now (optionally) installs a sample file system called "passthrough-fuse". This file system performs the same function as the "passthrough" file system, but uses the FUSE compatibility layer. It builds and runs on both Windows and Cygwin.
v1.0RC1::
This is the first Release Candidate. It has been tested for robustness and correct file system semantics in a variety of scenarios. Some of the more important changes:
This is the WinFsp 2017 Release Candidate 1. It has been tested extensively in a variety of scenarios for stability and correct file system semantics. Some of the more important changes:
- API has been polished and finalized.
- Extensively tested against multiple test suites including Microsoft's IfsTest.
- WinFsp I/O Queues (the fundamental WinFsp IPC mechanism) have been improved to work similar to I/O Completion Ports.
- Opportunistic locks have been implemented.
- File system statistics have been implemented.
- Sharing a (disk) file system over the network is supported.
- Case insensitive file systems are supported.
- Directories are supported as mount points.

View File

@ -1,8 +1,35 @@
The WinFsp project is Copyright (C) Bill Zissimopoulos. It is licensed
under the terms of the GPLv3. The full text of this license follows
below. Commercial licensing options are also available: Please contact
under the terms of the GPLv3.
As a special exception to GPLv3, Bill Zissimopoulos grants additional
permissions to Free/Libre and Open Source Software ("FLOSS") without requiring
that such software is covered by the GPLv3.
1. Permission to link with a platform specific version of the WinFsp DLL
(currently winfsp-x64.dll or winfsp-x86.dll).
2. Permission to distribute unmodified binary releases of the WinFsp
installer (as released by the WinFsp project).
These permissions (and no other) are granted provided that the software:
1. Is distributed under a license that satisfies the Free Software
Definition Version 1.141 (https://www.gnu.org/philosophy/free-sw.en.html)
or the Open Source Definition Version 1.9 (https://opensource.org/osd).
2. Includes the copyright notice "WinFsp - Windows File System Proxy,
Copyright (C) Bill Zissimopoulos" and a link to the WinFsp repository in
its user-interface and any user-facing documentation.
3. Is not linked or distributed with proprietary (non-FLOSS) software.
[You cannot mix FLOSS and proprietary software while using WinFsp under
this special exception.]
Commercial licensing options are also available: Please contact
Bill Zissimopoulos <billziss at navimatics.com>.
The full text of the GPLv3 license follows below.
-----------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE

View File

@ -2,17 +2,22 @@
![WinFsp Demo](http://www.secfs.net/winfsp/files/cap.gif)
<a href="https://github.com/billziss-gh/winfsp/releases"><img src="http://www.secfs.net/winfsp/resources/Download-WinFsp.png" alt="Download WinFsp Installer" width="244" height="34"></a>
WinFsp is a set of software components for Windows computers that allows the creation of user mode file systems. In this sense it is similar to FUSE (Filesystem in Userspace), which provides the same functionality on UNIX-like computers.
Some of the benefits and features of using WinFsp are listed below:
Some of the benefits of using WinFsp are listed below:
* Allows for easy development of file systems in user mode. There are no restrictions on what a process can do in order to implement a file system (other than respond in a timely manner to file system requests).
* Support for disk and network based file systems.
* Support for NTFS level security and access control.
* Support for memory mapped files, cached files and the NT cache manager.
* Support for file change notifications.
* Support for file locking.
* Correct NT semantics with respect to file sharing, file deletion and renaming.
* Very well-tested and stable. Read about its [Testing Strategy](doc/WinFsp-Testing.asciidoc).
* Very fast. Read about its [Performance](doc/WinFsp-Performance-Testing.asciidoc).
* Strives for compatibility with NTFS. Read about its [Compatibility](doc/NTFS-Compatibility.asciidoc ).
* Easy to understand but comprehensive API. Consult the [API Reference](http://www.secfs.net/winfsp/apiref/). There is also a simple [Tutorial](doc/WinFsp-Tutorial.asciidoc).
* FUSE compatibility layer for native Windows and Cygwin. See [fuse.h](inc/fuse/fuse.h).
* Signed drivers provided on every release.
* Available under the [GPLv3](License.txt) license with a special exception for Free/Libre and Open Source Software.
To learn more about WinFsp, please visit its website: http://www.secfs.net/winfsp/
@ -40,19 +45,23 @@ The project source code is organized as follows:
In order to build WinFsp you will need the following:
* Windows 10
* Visual Studio 2015
* Windows Driver Kit (WDK) 10
* [Wix toolset](http://wixtoolset.org)
If you build the driver yourself it will not be signed and Windows will refuse to load it unless you enable "testsigning". You can enable "testsigning" using the command `bcdedit.exe -set testsigning`. For more information see this [document](http://www.secfs.net/winfsp/develop/debug/).
To fully build WinFsp (including the installer) you must use `tools\build.bat`. By default it builds a Release build, but you can choose either the Debug or Release configuration by using the syntax:
WinFsp is designed to run on Vista and above. It has been tested on the following platforms so far:
tools\build.bat CONFIGURATION
If you build the driver yourself it will not be signed and Windows will refuse to load it unless you enable "testsigning". You can enable "testsigning" using the command `bcdedit.exe -set testsigning on`. For more information see this [document](http://www.secfs.net/winfsp/develop/debug/).
WinFsp is designed to run on Windows 7 and above. It has been tested on the following platforms:
* Windows 7 Enterprise
* Windows 8 Pro
* Windows 10 Pro
* Windows Server 2012
* Windows 10 Pro
* Windows Server 2016
## How to Help
@ -60,7 +69,7 @@ I am looking for help in the following areas:
* If you have a file system that runs on FUSE please consider porting it to WinFsp. WinFsp has a native API, but it also has a FUSE (high-level) API.
* If you are working with a language other than C/C++ (e.g. Delphi, C#, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you.
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues) ~~[BitBucket repository](https://bitbucket.org/billziss/winfsp/issues?status=new&status=open)~~. Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart. If you decide to tackle any of those please coordinate with me as I am actively working on that issue list.
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues). Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart.
In all cases I can provide ideas and/or support.
@ -73,4 +82,4 @@ If you wish to discuss WinFsp there are now two options:
## License
WinFsp is available under the [GPLv3](http://www.gnu.org/licenses/gpl-3.0.html) license. If you find the constraints of the GPLv3 too onerous, a commercial license is also available. Please contact Bill Zissimopoulos <billziss at navimatics.com> for more details.
WinFsp is available under the [GPLv3](License.txt) license with a special exception for Free/Libre and Open Source Software. A commercial license is also available. Please contact Bill Zissimopoulos \<billziss at navimatics.com> for more details.

View File

@ -1,27 +1,39 @@
version: '{build}'
environment:
matrix:
- CONFIGURATION: Debug
- CONFIGURATION: Release
install:
- git submodule update --init --recursive
- appveyor AddMessage "Change boot configuration and reboot" -Category Information
- verifier /standard /driver winfsp-x64.sys
- bcdedit /set testsigning on
- ps: Restart-Computer -Force
- ps: Start-Sleep -s 10
build_script:
- appveyor AddMessage "Reboot complete" -Category Information
- bcdedit | findstr /i "testsigning"
- tools\build.bat %CONFIGURATION%
test_script:
- for %%f in ("build\VStudio\build\%CONFIGURATION%\winfsp-*.msi") do start /wait msiexec /i %%f /qn INSTALLLEVEL=1000
- tools\nmake-ext-test.bat %CONFIGURATION%
- tools\run-tests.bat %CONFIGURATION%
on_finish:
- verifier /query
version: '{build}'
environment:
matrix:
- CONFIGURATION: Debug
TESTING: Func
- CONFIGURATION: Release
TESTING: Func
- CONFIGURATION: Release
TESTING: Perf
install:
- git submodule update --init --recursive
- appveyor AddMessage "Change boot configuration and reboot" -Category Information
- bcdedit /set testsigning on
- if %TESTING%==Func verifier /standard /driver winfsp-x64.sys
- if exist %SystemRoot%\memory.dmp del %SystemRoot%\memory.dmp
- ps: Restart-Computer -Force
- ps: Start-Sleep -s 60
build_script:
- appveyor AddMessage "Reboot complete" -Category Information
- tools\build.bat %CONFIGURATION%
test_script:
- 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 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\run-tests.bat %CONFIGURATION%
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% ifstest
- 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
- choco uninstall winfsp -y
- if exist %SystemRoot%\memory.dmp exit 1
on_finish:
- if exist %SystemRoot%\memory.dmp (7z a memory.dmp.zip %SystemRoot%\memory.dmp && appveyor PushArtifact memory.dmp.zip)
- verifier /query

View File

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

View File

@ -22,7 +22,7 @@
<Media Id="1" Cabinet="WinFsp.cab" EmbedCab="yes" />
<Property Id="P.LauncherName">$(var.MyProductName).Launcher</Property>
<Property Id="P.LauncherRegistryKey">SYSTEM\\CurrentControlSet\\Services\\$(var.MyProductName).Launcher\\Services</Property>
<Property Id="P.LauncherRegistryKey">Software\$(var.MyProductName)\Services</Property>
<Property Id="P.RegistryKey">Software\$(var.MyProductName)</Property>
<Property Id="INSTALLDIR">
<RegistrySearch
@ -55,6 +55,9 @@
Value="[INSTALLDIR]"
KeyPath="yes" />
</Component>
<Component Id="C.License.txt">
<File Name="License.txt" Source="..\..\..\License.txt" KeyPath="yes" />
</Component>
</DirectoryRef>
<DirectoryRef Id="BINDIR" FileSource="..\build\$(var.Configuration)">
<Component Id="C.winfsp_x64.sys">
@ -140,6 +143,9 @@
<Component Id="C.diag.bat">
<File Name="diag.bat" Source="..\..\..\tools\diag.bat" KeyPath="yes" />
</Component>
<Component Id="C.fsreg.bat">
<File Name="fsreg.bat" Source="..\..\..\tools\fsreg.bat" KeyPath="yes" />
</Component>
<Component Id="C.memfs_x64.exe">
<File Name="memfs-x64.exe" KeyPath="yes" />
@ -155,7 +161,7 @@
<RegistryValue
Type="string"
Name="CommandLine"
Value="-i -n 65536 -s 67108864 -u %1 -m %2" />
Value="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2" />
<RegistryValue
Type="string"
Name="Security"
@ -181,7 +187,7 @@
<RegistryValue
Type="string"
Name="CommandLine"
Value="-i -n 65536 -s 67108864 -u %1 -m %2" />
Value="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2" />
<RegistryValue
Type="string"
Name="Security"
@ -258,6 +264,46 @@
<File Name="memfs-main.c" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="SMPDIR.passthrough" Name="passthrough">
<Component Id="C.passthrough.c">
<File Name="passthrough.c" KeyPath="yes" />
</Component>
<Component Id="C.passthrough.sln">
<File Name="passthrough.sln" KeyPath="yes" />
</Component>
<Component Id="C.passthrough.vcxproj">
<File Name="passthrough.vcxproj" KeyPath="yes" />
</Component>
<Component Id="C.passthrough.vcxproj.filters">
<File Name="passthrough.vcxproj.filters" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="SMPDIR.passthrough_fuse" Name="passthrough-fuse">
<Component Id="C.passthrough_fuse.c">
<File Name="passthrough-fuse.c" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.winposix.c">
<File Name="winposix.c" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.winposix.h">
<File Name="winposix.h" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.sln">
<File Name="passthrough-fuse.sln" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.vcxproj">
<File Name="passthrough-fuse.vcxproj" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.vcxproj.filters">
<File Name="passthrough-fuse.vcxproj.filters" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.Makefile">
<File Name="Makefile" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.README.md">
<File Name="README.md" KeyPath="yes" />
</Component>
</Directory>
</DirectoryRef>
<DirectoryRef Id="SYMDIR">
<Component Id="C.winfsp_x64.sys.pdb">
@ -306,6 +352,7 @@
<ComponentRef Id="C.launchctl_x64.exe" />
<ComponentRef Id="C.launchctl_x86.exe" />
<ComponentRef Id="C.diag.bat" />
<ComponentRef Id="C.fsreg.bat" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.inc">
<ComponentRef Id="C.fsctl.h" />
@ -327,6 +374,18 @@
<ComponentRef Id="C.memfs.h" />
<ComponentRef Id="C.memfs.cpp" />
<ComponentRef Id="C.memfs_main.c" />
<ComponentRef Id="C.passthrough.c" />
<ComponentRef Id="C.passthrough.sln" />
<ComponentRef Id="C.passthrough.vcxproj" />
<ComponentRef Id="C.passthrough.vcxproj.filters" />
<ComponentRef Id="C.passthrough_fuse.c" />
<ComponentRef Id="C.passthrough_fuse.winposix.c" />
<ComponentRef Id="C.passthrough_fuse.winposix.h" />
<ComponentRef Id="C.passthrough_fuse.sln" />
<ComponentRef Id="C.passthrough_fuse.vcxproj" />
<ComponentRef Id="C.passthrough_fuse.vcxproj.filters" />
<ComponentRef Id="C.passthrough_fuse.Makefile" />
<ComponentRef Id="C.passthrough_fuse.README.md" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.sym">
<ComponentRef Id="C.winfsp_x64.sys.pdb" />
@ -352,6 +411,7 @@
InstallDefault="local"
Absent="disallow">
<ComponentRef Id="C.INSTALLDIR" />
<ComponentRef Id="C.License.txt" />
<Feature
Id="F.User"
Level="1"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -31,8 +31,10 @@
<ClInclude Include="..\..\src\shared\minimal.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\dll\dirbuf.c" />
<ClCompile Include="..\..\src\dll\eventlog.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_main.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_opt.c" />
@ -50,7 +52,7 @@
<ClCompile Include="..\..\src\dll\util.c" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc">
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc.in">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">echo arch=$(PlatformTarget) &gt;$(OutDir)fuse-$(PlatformTarget).pc
copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(PlatformTarget).pc &gt;nul</Command>
@ -78,10 +80,10 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
<ItemGroup>
<ResourceCompile Include="..\..\src\dll\eventlog\eventlog.rc" />
<ResourceCompile Include="..\..\src\dll\version.rc">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemGroup>
<PropertyGroup Label="Globals">

View File

@ -103,6 +103,12 @@
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c">
<Filter>Source\fuse</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\dirbuf.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\fuse\fuse_compat.c">
<Filter>Source\fuse</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\src\dll\library.def">
@ -118,7 +124,7 @@
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc">
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc.in">
<Filter>Source\fuse</Filter>
</CustomBuild>
</ItemGroup>

View File

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

View File

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

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

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

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

View File

@ -20,19 +20,21 @@ In order to overcome the issue with launching multiple instances of a particular
Services that wish to be controlled by the WinFsp.Launcher must add themselves under the following registry key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services
HKEY_LOCAL_MACHINE\Software\WinFsp\Services
For example, the MEMFS sample adds the following registry entries under this key:
NOTE: Please note that in a 64-bit system the actual location is `HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\WinFsp\Services`.
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services\memfs32]
For example, the MEMFS sample adds the following registry entries in a 64-bit system:
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\WinFsp\Services\memfs32]
"Executable"="C:\\Program Files (x86)\\WinFsp\\bin\\memfs-x86.exe"
"CommandLine"="-u %1 -m %2"
"CommandLine"="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2"
"Security"="D:P(A;;RPWPLC;;;WD)"
"JobControl"=dword:00000001
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services\memfs64]
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\WinFsp\Services\memfs64]
"Executable"="C:\\Program Files (x86)\\WinFsp\\bin\\memfs-x64.exe"
"CommandLine"="-u %1 -m %2"
"CommandLine"="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2"
"Security"="D:P(A;;RPWPLC;;;WD)"
"JobControl"=dword:00000001
@ -44,4 +46,4 @@ One final note regarding security. Notice the `Security` registry value in the e
WinFsp includes a Network Provider that integrates with Windows and can be used to start and stop user mode file systems from the Windows shell. To achieve this the Network Provider (implemented as part of the WinFsp DLL) works closely with the WinFsp.Launcher service.
For example, if a user uses the Windows Explorer to map `\\memfs64\share` to the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to start an instance of the memfs64 service with command line `-u \\memfs64\share -m Z:`. When the user disconnects the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to stop the previously started instance of the memfs64 service.
For example, if a user uses the Windows Explorer to map `\\memfs64\share` to the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to start an instance of the memfs64 service with command line `-i -F NTFS -n 65536 -s 67108864 -u \\memfs64\share -m Z:`. When the user disconnects the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to stop the previously started instance of the memfs64 service.

View File

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

1326
doc/WinFsp-Tutorial.asciidoc Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@
* FUSE: Filesystem in Userspace
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -41,6 +41,15 @@ extern "C" {
#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
#define FUSE_CAP_BIG_WRITES (1 << 5)
#define FUSE_CAP_DONT_MASK (1 << 6)
#define FUSE_CAP_ALLOCATE (1 << 27) /* reserved (OSXFUSE) */
#define FUSE_CAP_EXCHANGE_DATA (1 << 28) /* reserved (OSXFUSE) */
#define FUSE_CAP_CASE_INSENSITIVE (1 << 29) /* file system is case insensitive */
#define FUSE_CAP_VOL_RENAME (1 << 30) /* reserved (OSXFUSE) */
#define FUSE_CAP_XTIMES (1 << 31) /* reserved (OSXFUSE) */
#define FSP_FUSE_CAP_READDIR_PLUS (1 << 21) /* file system supports enhanced readdir */
#define FSP_FUSE_CAP_READ_ONLY (1 << 22) /* file system is marked read-only */
#define FSP_FUSE_CAP_CASE_INSENSITIVE FUSE_CAP_CASE_INSENSITIVE
#define FUSE_IOCTL_COMPAT (1 << 0)
#define FUSE_IOCTL_UNRESTRICTED (1 << 1)

View File

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

View File

@ -2,7 +2,7 @@
* @file fuse/winfsp_fuse.h
* WinFsp FUSE compatible API.
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -177,6 +177,7 @@ struct fuse_flock
MemAlloc, MemFree, \
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
0/*conv_to_win_path*/, \
}
#else
#define FSP_FUSE_ENV_INIT \
@ -185,6 +186,7 @@ struct fuse_flock
malloc, free, \
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
0/*conv_to_win_path*/, \
}
#endif
@ -226,6 +228,7 @@ struct fuse_flock
malloc, free, \
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
fsp_fuse_conv_to_win_path, \
}
/*
@ -244,7 +247,8 @@ struct fsp_fuse_env
void (*memfree)(void *);
int (*daemonize)(int);
int (*set_signal_handlers)(void *);
void (*reserved[4])();
char *(*conv_to_win_path)(const char *);
void (*reserved[3])();
};
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_signal_handler)(int sig);
@ -348,6 +352,13 @@ static inline int fsp_fuse_set_signal_handlers(void *se)
#undef FSP_FUSE_SET_SIGNAL_HANDLER
}
static inline char *fsp_fuse_conv_to_win_path(const char *path)
{
void *cygwin_create_path(unsigned, const void *);
return cygwin_create_path(
0/*CCP_POSIX_TO_WIN_A*/ | 0x100/*CCP_RELATIVE*/,
path);
}
#endif

View File

@ -1,7 +1,7 @@
/**
* @file winfsp/fsctl.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -146,8 +146,10 @@ typedef struct
UINT32 ExtendedAttributes:1; /* unimplemented; set to 0 */
UINT32 ReadOnlyVolume:1;
/* kernel-mode flags */
UINT32 PostCleanupOnDeleteOnly:1; /* post Cleanup when deleting a file only */
UINT32 KmReservedFlags:5;
UINT32 PostCleanupWhenModifiedOnly:1; /* post Cleanup when a file was modified/deleted */
UINT32 PassQueryDirectoryPattern:1; /* pass Pattern during QueryDirectory operations */
UINT32 AlwaysUseDoubleBuffering:1;
UINT32 KmReservedFlags:3;
/* user-mode flags */
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */
@ -185,8 +187,7 @@ typedef struct
{
UINT16 Size;
FSP_FSCTL_FILE_INFO FileInfo;
UINT64 NextOffset;
UINT8 Padding[16];
UINT8 Padding[24];
/* make struct as big as FILE_ID_BOTH_DIR_INFORMATION; allows for in-place copying */
WCHAR FileNameBuf[];
} FSP_FSCTL_DIR_INFO;
@ -232,7 +233,8 @@ typedef struct
UINT32 HasRestorePrivilege:1; /* requestor has TOKEN_HAS_RESTORE_PRIVILEGE */
UINT32 OpenTargetDirectory:1; /* open target dir and report FILE_{EXISTS,DOES_NOT_EXIST} */
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
UINT32 ReservedFlags:26;
UINT32 HasTrailingBackslash:1; /* FileName had trailing backslash */
UINT32 ReservedFlags:25;
UINT16 NamedStream; /* request targets named stream; colon offset in FileName */
} Create;
struct
@ -248,6 +250,11 @@ typedef struct
UINT64 UserContext;
UINT64 UserContext2;
UINT32 Delete:1; /* file must be deleted */
UINT32 SetAllocationSize:1;
UINT32 SetArchiveBit:1;
UINT32 SetLastAccessTime:1;
UINT32 SetLastWriteTime:1;
UINT32 SetChangeTime:1;
} Cleanup;
struct
{
@ -295,6 +302,7 @@ typedef struct
UINT64 CreationTime;
UINT64 LastAccessTime;
UINT64 LastWriteTime;
UINT64 ChangeTime;
} Basic;
struct
{
@ -332,9 +340,9 @@ typedef struct
UINT64 UserContext;
UINT64 UserContext2;
UINT64 Address;
UINT64 Offset;
UINT32 Length;
FSP_FSCTL_TRANSACT_BUF Pattern;
FSP_FSCTL_TRANSACT_BUF Marker;
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
} QueryDirectory;
struct
@ -415,6 +423,10 @@ typedef struct
FSP_FSCTL_FILE_INFO FileInfo; /* valid: File{Allocation,Basic,EndOfFile}Information */
} SetInformation;
struct
{
FSP_FSCTL_FILE_INFO FileInfo; /* valid when flushing file (not volume) */
} FlushBuffers;
struct
{
FSP_FSCTL_VOLUME_INFO VolumeInfo;
} QueryVolumeInformation;

View File

@ -5,7 +5,7 @@
* In order to use the WinFsp API the user mode file system must include &lt;winfsp/winfsp.h&gt;
* and link with the winfsp_x64.dll (or winfsp_x86.dll) library.
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -26,7 +26,10 @@
#include <windows.h>
#undef WIN32_NO_STATUS
#include <winternl.h>
#pragma warning(push)
#pragma warning(disable:4005) /* macro redefinition */
#include <ntstatus.h>
#pragma warning(pop)
#if defined(WINFSP_DLL_INTERNAL)
#define FSP_API __declspec(dllexport)
@ -122,6 +125,15 @@ typedef enum
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0,
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE,
} FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY;
enum
{
FspCleanupDelete = 0x01,
FspCleanupSetAllocationSize = 0x02,
FspCleanupSetArchiveBit = 0x10,
FspCleanupSetLastAccessTime = 0x20,
FspCleanupSetLastWriteTime = 0x40,
FspCleanupSetChangeTime = 0x80,
};
/**
* @class FSP_FILE_SYSTEM
* File system interface.
@ -322,18 +334,40 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* the system sends a Cleanup request to the file system.
*
* There will be a Cleanup operation for every Create or Open operation posted to the user mode
* file system. However the Cleanup operation is <b>not</b> the final close operation on a file. The
* file system must be ready to receive additional operations until close time. This is true
* file system. However the Cleanup operation is <b>not</b> the final close operation on a file.
* The file system must be ready to receive additional operations until close time. This is true
* even when the file is being deleted!
*
* The Flags parameter contains information about the cleanup operation:
* <ul>
* <li>FspCleanupDelete -
* An important function of the Cleanup operation is to complete a delete operation. Deleting
* a file or directory in Windows is a three-stage process where the file is first opened, then
* tested to see if the delete can proceed and if the answer is positive the file is then
* deleted during Cleanup.
*
* When this flag is set, this is the last outstanding cleanup for this particular file node.
* </li>
* <li>FspCleanupSetAllocationSize -
* The NTFS and FAT file systems reset a file's allocation size when they receive the last
* outstanding cleanup for a particular file node. User mode file systems that implement
* allocation size and wish to duplicate the NTFS and FAT behavior can use this flag.
* </li>
* <li>
* FspCleanupSetArchiveBit -
* File systems that support the archive bit should set the file node's archive bit when this
* flag is set.
* </li>
* <li>FspCleanupSetLastAccessTime, FspCleanupSetLastWriteTime, FspCleanupSetChangeTime - File
* systems should set the corresponding file time when each one of these flags is set. Note that
* updating the last access time is expensive and a file system may choose to not implement it.
* </ul>
*
* There is no way to report failure of this operation. This is a Windows limitation.
*
* As an optimization a file system may specify the FSP_FSCTL_VOLUME_PARAMS ::
* PostCleanupOnDeleteOnly flag. In this case the FSD will only post Cleanup requests when a
* file is being deleted.
* PostCleanupWhenModifiedOnly flag. In this case the FSD will only post Cleanup requests when
* the file was modified/deleted.
*
* @param FileSystem
* The file system on which this request is posted.
@ -341,16 +375,14 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* The file context of the file or directory to cleanup.
* @param FileName
* The name of the file or directory to cleanup. Sent only when a Delete is requested.
* @param Delete
* Determines whether to delete the file. Note that there is no way to report failure of
* this operation. Also note that when this parameter is TRUE this is the last outstanding
* cleanup for this particular file node.
* @param Flags
* These flags determine whether the file was modified and whether to delete the file.
* @see
* Close
* CanDelete
*/
VOID (*Cleanup)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PWSTR FileName, BOOLEAN Delete);
PVOID FileContext, PWSTR FileName, ULONG Flags);
/**
* Close a file.
*
@ -423,11 +455,16 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* The file system on which this request is posted.
* @param FileContext
* The file context of the file to be flushed. When NULL the whole volume is being flushed.
* @param FileInfo [out]
* Pointer to a structure that will receive the file information on successful return
* from this call. This information includes file attributes, file times, etc. Used when
* flushing file (not volume).
* @return
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*Flush)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext);
PVOID FileContext,
FSP_FSCTL_FILE_INFO *FileInfo);
/**
* Get file or directory information.
*
@ -463,6 +500,9 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* @param LastWriteTime
* Last write time to apply to the file or directory. If the value 0 is sent, the last
* write time should not be changed.
* @param ChangeTime
* Change time to apply to the file or directory. If the value 0 is sent, the change time
* should not be changed.
* @param FileInfo [out]
* Pointer to a structure that will receive the file information on successful return
* from this call. This information includes file attributes, file times, etc.
@ -471,7 +511,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*/
NTSTATUS (*SetBasicInfo)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, UINT32 FileAttributes,
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime, UINT64 ChangeTime,
FSP_FSCTL_FILE_INFO *FileInfo);
/**
* Set file/allocation size.
@ -518,7 +558,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* directories, etc.
*
* This function should <b>NEVER</b> delete the file or directory in question. Deletion should
* happen during Cleanup with Delete==TRUE.
* happen during Cleanup with the FspCleanupDelete flag set.
*
* This function gets called when Win32 API's such as DeleteFile or RemoveDirectory are used.
* It does not get called when a file or directory is opened with FILE_DELETE_ON_CLOSE.
@ -541,8 +581,6 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*
* The kernel mode FSD provides certain guarantees prior to posting a rename operation:
* <ul>
* <li>A file cannot be renamed if it has any open handles, other than the one used to perform
* the rename.</li>
* <li>A file cannot be renamed if a file with the same name exists and has open handles.</li>
* <li>A directory cannot be renamed if it or any of its subdirectories contains a file that
* has open handles.</li>
@ -612,30 +650,18 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* The file system on which this request is posted.
* @param FileContext
* The file context of the directory to be read.
* @param Buffer
* Pointer to a buffer that will receive the results of the read operation.
* @param Offset
* Offset within the directory to read from. The kernel does not interpret this value
* which is used solely by the file system to locate directory entries. However the
* special value 0 indicates that the read should start from the first entries. The first
* two entries returned by ReadDirectory should always be the "." and ".." entries,
* except for the root directory which does not have these entries.
*
* This parameter is used by the WinFsp FSD to break directory listings into chunks.
* In this case all 64-bits of the Offset are valid. In some cases the Windows kernel
* (NTOS) may also use this parameter. In this case only the lower 32-bits of this
* parameter will be valid. This is an unfortunate limitation of Windows (for more
* information see the documentation for IRP_MJ_DIRECTORY_CONTROL and the flag
* SL_INDEX_SPECIFIED).
*
* In practice this means that you should only rely on the lower 32-bits of this value
* to be valid.
* @param Length
* Length of data to read.
* @param Pattern
* The pattern to match against files in this directory. Can be NULL. The file system
* can choose to ignore this parameter as the FSD will always perform its own pattern
* matching on the returned results.
* @param Marker
* A file name that marks where in the directory to start reading. Files with names
* that are greater than (not equal to) this marker (in the directory order determined
* by the file system) should be returned. Can be NULL.
* @param Buffer
* Pointer to a buffer that will receive the results of the read operation.
* @param Length
* Length of data to read.
* @param PBytesTransferred [out]
* Pointer to a memory location that will receive the actual number of bytes read.
* @return
@ -645,9 +671,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* FspFileSystemAddDirInfo
*/
NTSTATUS (*ReadDirectory)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length,
PWSTR Pattern,
PULONG PBytesTransferred);
PVOID FileContext, PWSTR Pattern, PWSTR Marker,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
/**
* Resolve reparse points.
*
@ -810,6 +835,20 @@ typedef struct _FSP_FILE_SYSTEM_OPERATION_CONTEXT
FSP_FSCTL_TRANSACT_REQ *Request;
FSP_FSCTL_TRANSACT_RSP *Response;
} FSP_FILE_SYSTEM_OPERATION_CONTEXT;
/**
* Check whether creating a file system object is possible.
*
* @param DevicePath
* The name of the control device for this file system. This must be either
* FSP_FSCTL_DISK_DEVICE_NAME or FSP_FSCTL_NET_DEVICE_NAME.
* @param MountPoint
* The mount point for the new file system. A value of NULL means that the file system should
* use the next available drive letter counting downwards from Z: as its mount point.
* @return
* STATUS_SUCCESS or error code.
*/
FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath,
PWSTR MountPoint);
/**
* Create a file system object.
*
@ -857,6 +896,8 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem);
* STATUS_SUCCESS or error code.
*/
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint);
FSP_API NTSTATUS FspFileSystemSetMountPointEx(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint,
PSECURITY_DESCRIPTOR SecurityDescriptor);
/**
* Remove the mount point for a file system.
*
@ -1257,6 +1298,19 @@ FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint(
FSP_API BOOLEAN FspFileSystemAddStreamInfo(FSP_FSCTL_STREAM_INFO *StreamInfo,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
/*
* Directory buffering
*/
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
BOOLEAN Reset, PNTSTATUS PResult);
FSP_API BOOLEAN FspFileSystemFillDirectoryBuffer(PVOID *PDirBuffer,
FSP_FSCTL_DIR_INFO *DirInfo, PNTSTATUS PResult);
FSP_API VOID FspFileSystemReleaseDirectoryBuffer(PVOID *PDirBuffer);
FSP_API VOID FspFileSystemReadDirectoryBuffer(PVOID *PDirBuffer,
PWSTR Marker,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
FSP_API VOID FspFileSystemDeleteDirectoryBuffer(PVOID *PDirBuffer);
/*
* Security
*/
@ -1354,6 +1408,8 @@ NTSTATUS FspPosixMapPosixToWindowsPath(const char *PosixPath, PWSTR *PWindowsPat
return FspPosixMapPosixToWindowsPathEx(PosixPath, PWindowsPath, TRUE);
}
FSP_API VOID FspPosixDeletePath(void *Path);
FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size);
FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size);
/*
* Path Handling
@ -1574,6 +1630,71 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout,
PSID Sid);
FSP_API NTSTATUS FspVersion(PUINT32 PVersion);
/*
* Delay load
*/
static inline
NTSTATUS FspLoad(PVOID *PModule)
{
#if defined(_WIN64)
#define FSP_DLLNAME "winfsp-x64.dll"
#else
#define FSP_DLLNAME "winfsp-x86.dll"
#endif
#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];
DWORD Size;
HKEY RegKey;
LONG Result;
HMODULE Module;
if (0 != PModule)
*PModule = 0;
Module = LoadLibraryW(L"" FSP_DLLNAME);
if (0 == Module)
{
Result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\WinFsp",
0, KEY_READ | KEY_WOW64_32KEY, &RegKey);
if (ERROR_SUCCESS == Result)
{
Size = sizeof PathBuf - sizeof L"" FSP_DLLPATH + sizeof(WCHAR);
Result = RegGetValueW(RegKey, 0, L"InstallDir",
RRF_RT_REG_SZ, 0, PathBuf, &Size);
RegCloseKey(RegKey);
}
if (ERROR_SUCCESS != Result)
return STATUS_OBJECT_NAME_NOT_FOUND;
RtlCopyMemory(PathBuf + (Size / sizeof(WCHAR) - 1), L"" FSP_DLLPATH, sizeof L"" FSP_DLLPATH);
Module = LoadLibraryW(PathBuf);
if (0 == Module)
return STATUS_DLL_NOT_FOUND;
}
if (0 != PModule)
*PModule = Module;
return STATUS_SUCCESS;
#undef FSP_DLLNAME
#undef FSP_DLLPATH
}
#ifdef __cplusplus
}

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/**
* @file dll/debug.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -106,7 +106,7 @@ static const char *FspDebugLogDispositionString(UINT32 CreateOptions)
static const char *FspDebugLogUserContextString(UINT64 UserContext, UINT64 UserContext2, char *Buf)
{
wsprintfA(Buf, 0 == UserContext2 ? "%p" : "%p:%p", UserContext, UserContext2);
wsprintfA(Buf, 0 == UserContext2 ? "%p" : "%p:%p", (PVOID)UserContext, (PVOID)UserContext2);
return Buf;
}
@ -269,13 +269,13 @@ static const char *FspDebugLogReparseDataString(PVOID ReparseData0, char *Buf)
static VOID FspDebugLogRequestVoid(FSP_FSCTL_TRANSACT_REQ *Request, const char *Name)
{
FspDebugLog("%S[TID=%04lx]: %p: >>%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint, Name);
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint, Name);
}
static VOID FspDebugLogResponseStatus(FSP_FSCTL_TRANSACT_RSP *Response, const char *Name)
{
FspDebugLog("%S[TID=%04lx]: %p: <<%s IoStatus=%lx[%ld]\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint, Name,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint, Name,
Response->IoStatus.Status, Response->IoStatus.Information);
}
@ -304,7 +304,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
"AllocationSize=%lx:%lx, "
"AccessToken=%p, DesiredAccess=%lx, GrantedAccess=%lx, "
"ShareAccess=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->Req.Create.UserMode ? 'U' : 'K',
Request->Req.Create.HasTraversePrivilege ? 'T' : '-',
Request->Req.Create.HasBackupPrivilege ? 'B' : '-',
@ -328,7 +328,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case FspFsctlTransactOverwriteKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Overwrite%s %s%S%s%s, "
"FileAttributes=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->Req.Overwrite.Supersede ? " [Supersede]" : "",
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
@ -340,7 +340,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
case FspFsctlTransactCleanupKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Cleanup%s %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->Req.Cleanup.Delete ? " [Delete]" : "",
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
@ -351,7 +351,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
case FspFsctlTransactCloseKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Close %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -362,14 +362,14 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case FspFsctlTransactReadKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Read %s%S%s%s, "
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.Read.UserContext, Request->Req.Read.UserContext2,
UserContextBuf),
Request->Req.Read.Address,
(PVOID)Request->Req.Read.Address,
MAKE_UINT32_PAIR(Request->Req.Read.Offset),
Request->Req.Read.Length,
Request->Req.Read.Key);
@ -377,7 +377,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case FspFsctlTransactWriteKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Write%s %s%S%s%s, "
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->Req.Write.ConstrainedIo ? " [C]" : "",
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
@ -385,14 +385,14 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
FspDebugLogUserContextString(
Request->Req.Write.UserContext, Request->Req.Write.UserContext2,
UserContextBuf),
Request->Req.Write.Address,
(PVOID)Request->Req.Write.Address,
MAKE_UINT32_PAIR(Request->Req.Write.Offset),
Request->Req.Write.Length,
Request->Req.Write.Key);
break;
case FspFsctlTransactQueryInformationKind:
FspDebugLog("%S[TID=%04lx]: %p: >>QueryInformation %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -406,7 +406,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case 4/*FileBasicInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Basic] %s%S%s%s, "
"FileAttributes=%lx, CreationTime=%s, LastAccessTime=%s, LastWriteTime=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -424,7 +424,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case 19/*FileAllocationInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Allocation] %s%S%s%s, "
"AllocationSize=%lx:%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -436,7 +436,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case 20/*FileEndOfFileInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [EndOfFile] %s%S%s%s, "
"FileSize = %lx:%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -448,7 +448,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case 13/*FileDispositionInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Disposition] %s%S%s%s, "
"%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -460,7 +460,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case 10/*FileRenameInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Rename] %s%S%s%s, "
"NewFileName=\"%S\", AccessToken=%p\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -472,7 +472,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
default:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [INVALID] %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -490,7 +490,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
case FspFsctlTransactFlushBuffersKind:
FspDebugLog("%S[TID=%04lx]: %p: >>FlushBuffers %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -507,39 +507,42 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case 2/*FileFsLabelInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [FsLabel] "
"Label=\"%S\"\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
(PWSTR)Request->Buffer);
break;
default:
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [INVALID]\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint);
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint);
break;
}
break;
case FspFsctlTransactQueryDirectoryKind:
FspDebugLog("%S[TID=%04lx]: %p: >>QueryDirectory %s%S%s%s, "
"Address=%p, Offset=%lx:%lx, Length=%ld, Pattern=%s%S%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
"Address=%p, Length=%ld, Pattern=%s%S%s, Marker=%s%S%s\n",
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.QueryDirectory.UserContext, Request->Req.QueryDirectory.UserContext2,
UserContextBuf),
Request->Req.QueryDirectory.Address,
MAKE_UINT32_PAIR(Request->Req.QueryDirectory.Offset),
(PVOID)Request->Req.QueryDirectory.Address,
Request->Req.QueryDirectory.Length,
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "",
Request->Req.QueryDirectory.Pattern.Size ?
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : L"NULL",
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "");
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "",
Request->Req.QueryDirectory.Marker.Size ? "\"" : "",
Request->Req.QueryDirectory.Marker.Size ?
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset) : L"NULL",
Request->Req.QueryDirectory.Marker.Size ? "\"" : "");
break;
case FspFsctlTransactFileSystemControlKind:
switch (Request->Req.FileSystemControl.FsControlCode)
{
case FSCTL_GET_REPARSE_POINT:
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [FSCTL_GET_REPARSE_POINT] %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -551,7 +554,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case FSCTL_DELETE_REPARSE_POINT:
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [%s] %s%S%s%s "
"ReparseData=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
FSCTL_SET_REPARSE_POINT == Request->Req.FileSystemControl.FsControlCode ?
"FSCTL_SET_REPARSE_POINT" : "FSCTL_DELETE_REPARSE_POINT",
Request->FileName.Size ? "\"" : "",
@ -565,7 +568,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
default:
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [INVALID] %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -586,7 +589,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
case FspFsctlTransactQuerySecurityKind:
FspDebugLog("%S[TID=%04lx]: %p: >>QuerySecurity %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -604,7 +607,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
&Sddl, 0);
FspDebugLog("%S[TID=%04lx]: %p: >>SetSecurity %s%S%s%s, "
"SecurityInformation=%lx, Security=%s%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -619,7 +622,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
case FspFsctlTransactQueryStreamInformationKind:
FspDebugLog("%S[TID=%04lx]: %p: >>QueryStreamInformation %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -655,7 +658,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
if (0/*IO_REPARSE*/ == Response->IoStatus.Information)
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
"Reparse.FileName=\"%s\"\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogWideCharBufferString(
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
@ -666,7 +669,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
"Reparse.Data=\"%s\"\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogReparseDataString(
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
@ -675,7 +678,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
"UserContext=%s, GrantedAccess=%lx, FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogUserContextString(
Response->Rsp.Create.Opened.UserContext, Response->Rsp.Create.Opened.UserContext2,
@ -689,7 +692,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<Overwrite IoStatus=%lx[%ld] "
"FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogFileInfoString(&Response->Rsp.Overwrite.FileInfo, InfoBuf));
break;
@ -708,7 +711,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<Write IoStatus=%lx[%ld] "
"FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogFileInfoString(&Response->Rsp.Write.FileInfo, InfoBuf));
break;
@ -718,7 +721,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<QueryInformation IoStatus=%lx[%ld] "
"FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogFileInfoString(&Response->Rsp.QueryInformation.FileInfo, InfoBuf));
break;
@ -728,7 +731,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<SetInformation IoStatus=%lx[%ld] "
"FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogFileInfoString(&Response->Rsp.SetInformation.FileInfo, InfoBuf));
break;
@ -747,7 +750,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<QueryVolumeInformation IoStatus=%lx[%ld] "
"VolumeInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogVolumeInfoString(&Response->Rsp.QueryVolumeInformation.VolumeInfo, InfoBuf));
break;
@ -757,7 +760,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<SetVolumeInformation IoStatus=%lx[%ld] "
"VolumeInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogVolumeInfoString(&Response->Rsp.SetVolumeInformation.VolumeInfo, InfoBuf));
break;
@ -771,7 +774,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<FileSystemControl IoStatus=%lx[%ld] "
"ReparseData=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogReparseDataString(Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset,
InfoBuf));
@ -799,7 +802,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
&Sddl, 0);
FspDebugLog("%S[TID=%04lx]: %p: <<QuerySecurity IoStatus=%lx[%ld] "
"Security=%s%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
Sddl ? "\"" : "",
Sddl ? Sddl : "NULL",
@ -821,7 +824,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
&Sddl, 0);
FspDebugLog("%S[TID=%04lx]: %p: <<SetSecurity IoStatus=%lx[%ld] "
"Security=%s%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
Sddl ? "\"" : "",
Sddl ? Sddl : "NULL",

404
src/dll/dirbuf.c Normal file
View File

@ -0,0 +1,404 @@
/**
* @file dll/dirbuf.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>
#define RETURN(R, B) \
do \
{ \
if (0 != PResult) \
*PResult = R; \
return B; \
} while (0,0)
typedef struct
{
SRWLOCK Lock;
ULONG Capacity, LoMark, HiMark;
PUINT8 Buffer;
} FSP_FILE_SYSTEM_DIRECTORY_BUFFER;
static int FspFileSystemDirectoryBufferFileNameCmp(PWSTR a, int alen, PWSTR b, int blen)
{
int len, res;
if (-1 == alen)
alen = (int)lstrlenW(a);
if (-1 == blen)
blen = (int)lstrlenW(b);
len = alen < blen ? alen : blen;
/* order "." and ".." first */
switch (alen)
{
case 1:
if (L'.' == a[0])
a = L"\1";
break;
case 2:
if (L'.' == a[0] && L'.' == a[1])
a = L"\1\1";
break;
}
/* order "." and ".." first */
switch (blen)
{
case 1:
if (L'.' == b[0])
b = L"\1";
break;
case 2:
if (L'.' == b[0] && L'.' == b[1])
b = L"\1\1";
break;
}
res = invariant_wcsncmp(a, b, len);
if (0 == res)
res = alen - blen;
return res;
}
/*
* Binary search
* "I wish I had the standard library!"
*/
static BOOLEAN FspFileSystemSearchDirectoryBuffer(FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer,
PWSTR Marker, int MarkerLen, PULONG PIndexNum)
{
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
FSP_FSCTL_DIR_INFO *DirInfo;
int Lo = 0, Hi = Count - 1, Mi;
int CmpResult;
while (Lo <= Hi)
{
Mi = (unsigned)(Lo + Hi) >> 1;
DirInfo = (PVOID)(DirBuffer->Buffer + Index[Mi]);
CmpResult = FspFileSystemDirectoryBufferFileNameCmp(
DirInfo->FileNameBuf, (DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR),
Marker, MarkerLen);
if (0 > CmpResult)
Lo = Mi + 1;
else if (0 < CmpResult)
Hi = Mi - 1;
else
{
*PIndexNum = Mi;
return TRUE;
}
}
*PIndexNum = Lo;
return FALSE;
}
/*
* Quick sort
* "I wish I had the standard library!"
*
* Based on Sedgewick's Algorithms in C++; multiple editions.
*
* Implements a non-recursive quicksort with tail-end recursion eliminated
* and median-of-three partitioning.
*/
#define less(a, b) FspFileSystemDirectoryBufferLess(Buffer, a, b)
#define exch(a, b) { ULONG t = a; a = b; b = t; }
#define compexch(a, b) if (less(b, a)) exch(a, b)
#define push(i) (stack[stackpos++] = (i))
#define pop() (stack[--stackpos])
static __forceinline
int FspFileSystemDirectoryBufferLess(PUINT8 Buffer, int a, int b)
{
FSP_FSCTL_DIR_INFO *DirInfoA = (FSP_FSCTL_DIR_INFO *)(Buffer + a);
FSP_FSCTL_DIR_INFO *DirInfoB = (FSP_FSCTL_DIR_INFO *)(Buffer + b);
return 0 > FspFileSystemDirectoryBufferFileNameCmp(
DirInfoA->FileNameBuf, (DirInfoA->Size - sizeof *DirInfoA) / sizeof(WCHAR),
DirInfoB->FileNameBuf, (DirInfoB->Size - sizeof *DirInfoB) / sizeof(WCHAR));
}
static __forceinline
int FspFileSystemPartitionDirectoryBuffer(PUINT8 Buffer, PULONG Index, int l, int r)
{
int i = l - 1, j = r;
ULONG v = Index[r];
for (;;)
{
while (less(Index[++i], v))
;
while (less(v, Index[--j]))
if (j == l)
break;
if (i >= j)
break;
exch(Index[i], Index[j]);
}
exch(Index[i], Index[r]);
return i;
}
static VOID FspFileSystemQSortDirectoryBuffer(PUINT8 Buffer, PULONG Index, int l, int r)
{
int stack[64], stackpos = 0;
int i;
for (;;)
{
while (r > l)
{
#if 0
exch(Index[(l + r) / 2], Index[r - 1]);
compexch(Index[l], Index[r - 1]);
compexch(Index[l], Index[r]);
compexch(Index[r - 1], Index[r]);
i = FspFileSystemPartitionDirectoryBuffer(Buffer, Index, l + 1, r - 1);
#else
i = FspFileSystemPartitionDirectoryBuffer(Buffer, Index, l, r);
#endif
if (i - l > r - i)
{
push(l); push(i - 1);
l = i + 1;
}
else
{
push(i + 1); push(r);
r = i - 1;
}
}
if (0 == stackpos)
break;
r = pop(); l = pop();
}
}
#undef push
#undef pop
#undef less
#undef compexch
#undef exch
static inline VOID FspFileSystemSortDirectoryBuffer(FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer)
{
PUINT8 Buffer = DirBuffer->Buffer;
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
FspFileSystemQSortDirectoryBuffer(Buffer, Index, 0, Count - 1);
}
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
BOOLEAN Reset, PNTSTATUS PResult)
{
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
MemoryBarrier();
if (0 == DirBuffer)
{
static SRWLOCK CreateLock = SRWLOCK_INIT;
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *NewDirBuffer;
NewDirBuffer = MemAlloc(sizeof *NewDirBuffer);
if (0 == NewDirBuffer)
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
memset(NewDirBuffer, 0, sizeof *NewDirBuffer);
InitializeSRWLock(&NewDirBuffer->Lock);
AcquireSRWLockExclusive(&NewDirBuffer->Lock);
AcquireSRWLockExclusive(&CreateLock);
DirBuffer = *PDirBuffer;
MemoryBarrier();
if (0 == DirBuffer)
*PDirBuffer = DirBuffer = NewDirBuffer;
ReleaseSRWLockExclusive(&CreateLock);
if (DirBuffer == NewDirBuffer)
RETURN(STATUS_SUCCESS, TRUE);
ReleaseSRWLockExclusive(&NewDirBuffer->Lock);
MemFree(NewDirBuffer);
}
if (Reset)
{
AcquireSRWLockExclusive(&DirBuffer->Lock);
DirBuffer->LoMark = 0;
DirBuffer->HiMark = DirBuffer->Capacity;
RETURN(STATUS_SUCCESS, TRUE);
}
RETURN(STATUS_SUCCESS, FALSE);
}
FSP_API BOOLEAN FspFileSystemFillDirectoryBuffer(PVOID *PDirBuffer,
FSP_FSCTL_DIR_INFO *DirInfo, PNTSTATUS PResult)
{
/* assume that FspFileSystemAcquireDirectoryBuffer has been called */
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
ULONG Capacity, LoMark, HiMark;
PUINT8 Buffer;
if (0 == DirInfo)
RETURN(STATUS_INVALID_PARAMETER, FALSE);
for (;;)
{
LoMark = DirBuffer->LoMark;
HiMark = DirBuffer->HiMark;
Buffer = DirBuffer->Buffer;
if (FspFileSystemAddDirInfo(DirInfo,
Buffer,
HiMark > sizeof(ULONG) ? HiMark - sizeof(ULONG)/*space for new index entry*/ : HiMark,
&LoMark))
{
HiMark -= sizeof(ULONG);
*(PULONG)(Buffer + HiMark) = DirBuffer->LoMark;
DirBuffer->LoMark = LoMark;
DirBuffer->HiMark = HiMark;
RETURN (STATUS_SUCCESS, TRUE);
}
if (0 == Buffer)
{
Buffer = MemAlloc(Capacity = 512);
if (0 == Buffer)
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
HiMark = Capacity;
}
else
{
Buffer = MemRealloc(Buffer, Capacity = DirBuffer->Capacity * 2);
if (0 == Buffer)
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
ULONG IndexSize = DirBuffer->Capacity - HiMark;
ULONG NewHiMark = Capacity - IndexSize;
memmove(Buffer + NewHiMark, Buffer + HiMark, IndexSize);
HiMark = NewHiMark;
}
DirBuffer->Capacity = Capacity;
DirBuffer->LoMark = LoMark;
DirBuffer->HiMark = HiMark;
DirBuffer->Buffer = Buffer;
}
}
FSP_API VOID FspFileSystemReleaseDirectoryBuffer(PVOID *PDirBuffer)
{
/* assume that FspFileSystemAcquireDirectoryBuffer has been called */
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
FspFileSystemSortDirectoryBuffer(DirBuffer);
ReleaseSRWLockExclusive(&DirBuffer->Lock);
}
FSP_API VOID FspFileSystemReadDirectoryBuffer(PVOID *PDirBuffer,
PWSTR Marker,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
MemoryBarrier();
if (0 != DirBuffer)
{
AcquireSRWLockShared(&DirBuffer->Lock);
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
ULONG IndexNum;
FSP_FSCTL_DIR_INFO *DirInfo;
if (0 == Marker)
IndexNum = 0;
else
{
FspFileSystemSearchDirectoryBuffer(DirBuffer,
Marker, lstrlenW(Marker),
&IndexNum);
IndexNum++;
}
for (; IndexNum < Count; IndexNum++)
{
DirInfo = (PVOID)(DirBuffer->Buffer + Index[IndexNum]);
if (!FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred))
{
ReleaseSRWLockShared(&DirBuffer->Lock);
return;
}
}
ReleaseSRWLockShared(&DirBuffer->Lock);
}
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
}
FSP_API VOID FspFileSystemDeleteDirectoryBuffer(PVOID *PDirBuffer)
{
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
MemoryBarrier();
if (0 != DirBuffer)
{
MemFree(DirBuffer->Buffer);
MemFree(DirBuffer);
*PDirBuffer = 0;
}
}
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount)
{
/* assume that FspFileSystemAcquireDirectoryBuffer has been called */
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
*PBuffer = DirBuffer->Buffer;
*PIndex = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
*PCount = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
}

View File

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

View File

@ -1,7 +1,7 @@
/**
* @file dll/fs.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -72,6 +72,48 @@ VOID FspFileSystemFinalize(BOOLEAN Dynamic)
TlsFree(FspFileSystemTlsKey);
}
FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath,
PWSTR MountPoint)
{
NTSTATUS Result;
WCHAR TargetPath[MAX_PATH];
HANDLE DirHandle;
Result = FspFsctlPreflight(DevicePath);
if (!NT_SUCCESS(Result))
return Result;
if (0 == MountPoint)
Result = STATUS_SUCCESS;
else
{
if (FspPathIsDrive(MountPoint))
Result = QueryDosDeviceW(MountPoint, TargetPath, MAX_PATH) ?
STATUS_OBJECT_NAME_COLLISION : STATUS_SUCCESS;
else
{
DirHandle = 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,
0);
if (INVALID_HANDLE_VALUE != DirHandle)
{
CloseHandle(DirHandle);
Result = STATUS_OBJECT_NAME_COLLISION;
}
else if (ERROR_FILE_NOT_FOUND != GetLastError())
Result = STATUS_OBJECT_NAME_INVALID;
else
Result = STATUS_SUCCESS;
}
}
return Result;
}
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
const FSP_FILE_SYSTEM_INTERFACE *Interface,
@ -145,20 +187,63 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem)
MemFree(FileSystem);
}
static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWSTR VolumeName)
static NTSTATUS FspFileSystemSetMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName,
PHANDLE PMountHandle)
{
*PMountHandle = 0;
if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, VolumeName))
return FspNtStatusFromWin32(GetLastError());
if (0 != FspNtOpenSymbolicLinkObject)
{
NTSTATUS Result;
WCHAR SymlinkBuf[6];
UNICODE_STRING Symlink;
OBJECT_ATTRIBUTES Obja;
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
SymlinkBuf[4] = MountPoint[0];
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
Symlink.Buffer = SymlinkBuf;
memset(&Obja, 0, sizeof Obja);
Obja.Length = sizeof Obja;
Obja.ObjectName = &Symlink;
Obja.Attributes = OBJ_CASE_INSENSITIVE;
Result = FspNtOpenSymbolicLinkObject(PMountHandle, DELETE, &Obja);
if (NT_SUCCESS(Result))
{
Result = FspNtMakeTemporaryObject(*PMountHandle);
if (!NT_SUCCESS(Result))
{
FspNtClose(*PMountHandle);
*PMountHandle = 0;
}
}
}
return STATUS_SUCCESS;
}
static NTSTATUS FspFileSystemSetMountPoint_Directory(PWSTR MountPoint, PWSTR VolumeName,
PSECURITY_DESCRIPTOR SecurityDescriptor, PHANDLE PMountHandle)
{
NTSTATUS Result;
HANDLE DirHandle;
BOOL Success;
SECURITY_ATTRIBUTES SecurityAttributes;
HANDLE MountHandle = INVALID_HANDLE_VALUE;
DWORD Backslashes, Bytes;
USHORT VolumeNameLength, BackslashLength, ReparseDataLength;
PREPARSE_DATA_BUFFER ReparseData = 0;
PWSTR P, PathBuffer;
*PMountHandle = 0;
/*
* Windows does not allow mount points (junctions) to point to network file systems.
*
* Count how many backslashes our VolumeName. If it is 3 or more this is a network
* Count how many backslashes our VolumeName has. If it is 3 or more this is a network
* file system. Preemptively return STATUS_NETWORK_ACCESS_DENIED.
*/
for (P = VolumeName, Backslashes = 0; *P; P++)
@ -169,25 +254,24 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
goto exit;
}
if (!CreateDirectoryW(MountPoint, 0))
memset(&SecurityAttributes, 0, sizeof SecurityAttributes);
SecurityAttributes.nLength = sizeof SecurityAttributes;
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
MountHandle = CreateFileW(MountPoint,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
&SecurityAttributes,
CREATE_NEW,
FILE_ATTRIBUTE_DIRECTORY |
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE,
0);
if (INVALID_HANDLE_VALUE == MountHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
DirHandle = CreateFileW(MountPoint,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
0);
if (INVALID_HANDLE_VALUE == DirHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto rmdir_and_exit;
}
VolumeNameLength = (USHORT)lstrlenW(VolumeName);
BackslashLength = 0 == VolumeNameLength || L'\\' != VolumeName[VolumeNameLength - 1];
VolumeNameLength *= sizeof(WCHAR);
@ -201,7 +285,7 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
if (0 == ReparseData)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto rmdir_and_exit;
goto exit;
}
ReparseData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
@ -228,86 +312,35 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\';
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
Success = DeviceIoControl(DirHandle, FSCTL_SET_REPARSE_POINT,
if (!DeviceIoControl(MountHandle, FSCTL_SET_REPARSE_POINT,
ReparseData, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseData->ReparseDataLength,
0, 0,
&Bytes, 0);
CloseHandle(DirHandle);
if (!Success)
&Bytes, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto rmdir_and_exit;
goto exit;
}
*PMountHandle = MountHandle;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result) && INVALID_HANDLE_VALUE != MountHandle)
CloseHandle(MountHandle);
MemFree(ReparseData);
return Result;
rmdir_and_exit:
RemoveDirectoryW(MountPoint);
goto exit;
}
static NTSTATUS FspFileSystemSetMountPoint_MakeTemporary(PWSTR MountPoint, PHANDLE PMountHandle)
{
NTSTATUS Result = STATUS_SUCCESS;
HANDLE MountHandle = 0;
if (FspPathIsDrive(MountPoint))
{
if (0 != FspNtOpenSymbolicLinkObject)
{
WCHAR SymlinkBuf[6];
UNICODE_STRING Symlink;
OBJECT_ATTRIBUTES Obja;
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
SymlinkBuf[4] = MountPoint[0];
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
Symlink.Buffer = SymlinkBuf;
memset(&Obja, 0, sizeof Obja);
Obja.Length = sizeof Obja;
Obja.ObjectName = &Symlink;
Obja.Attributes = OBJ_CASE_INSENSITIVE;
Result = FspNtOpenSymbolicLinkObject(&MountHandle, DELETE, &Obja);
if (NT_SUCCESS(Result))
{
Result = FspNtMakeTemporaryObject(MountHandle);
if (!NT_SUCCESS(Result))
{
FspNtClose(MountHandle);
MountHandle = 0;
}
}
}
}
else
{
/* open the directory for DELETE_ON_CLOSE; closing it will remove the directory */
MountHandle = CreateFileW(MountPoint,
FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_DELETE_ON_CLOSE,
0);
if (INVALID_HANDLE_VALUE == MountHandle)
{
MountHandle = 0;
Result = FspNtStatusFromWin32(GetLastError());
}
}
*PMountHandle = MountHandle;
return Result;
}
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint)
{
return FspFileSystemSetMountPointEx(FileSystem, MountPoint, 0);
}
FSP_API NTSTATUS FspFileSystemSetMountPointEx(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint,
PSECURITY_DESCRIPTOR SecurityDescriptor)
{
if (0 != FileSystem->MountPoint)
return STATUS_INVALID_PARAMETER;
@ -333,11 +366,10 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
if (0 == (Drives & (1 << (Drive - 'A'))))
{
MountPoint[0] = Drive;
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName))
{
Result = STATUS_SUCCESS;
Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
&MountHandle);
if (NT_SUCCESS(Result))
goto exit;
}
}
Result = STATUS_NO_SUCH_DEVICE;
}
@ -358,22 +390,16 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
MountPoint = P;
if (FspPathIsDrive(MountPoint))
{
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName))
Result = STATUS_SUCCESS;
else
Result = FspNtStatusFromWin32(GetLastError());
}
Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
&MountHandle);
else
Result = FspFileSystemSetMountPoint_CreateDirectory(MountPoint, FileSystem->VolumeName);
Result = FspFileSystemSetMountPoint_Directory(MountPoint, FileSystem->VolumeName,
SecurityDescriptor, &MountHandle);
}
exit:
if (NT_SUCCESS(Result))
{
FspFileSystemSetMountPoint_MakeTemporary(MountPoint, &MountHandle);
/* ignore result; this path always considered successful */
FileSystem->MountPoint = MountPoint;
FileSystem->MountHandle = MountHandle;
}
@ -383,33 +409,35 @@ exit:
return Result;
}
static VOID FspFileSystemRemoveMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName, HANDLE MountHandle)
{
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
MountPoint, VolumeName);
if (0 != MountHandle)
FspNtClose(MountHandle);
}
static VOID FspFileSystemRemoveMountPoint_Directory(HANDLE MountHandle)
{
/* directory is marked DELETE_ON_CLOSE */
CloseHandle(MountHandle);
}
FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
{
BOOLEAN IsDrive;
if (0 == FileSystem->MountPoint)
return;
IsDrive = FspPathIsDrive(FileSystem->MountPoint);
if (IsDrive)
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
FileSystem->MountPoint, FileSystem->VolumeName);
if (FspPathIsDrive(FileSystem->MountPoint))
FspFileSystemRemoveMountPoint_Drive(FileSystem->MountPoint, FileSystem->VolumeName,
FileSystem->MountHandle);
else
/* nothing to do! directory will be deleted when the MountHandle is closed */;
FspFileSystemRemoveMountPoint_Directory(FileSystem->MountHandle);
MemFree(FileSystem->MountPoint);
FileSystem->MountPoint = 0;
if (0 != FileSystem->MountHandle)
{
if (IsDrive)
FspNtClose(FileSystem->MountHandle);
else
/* CloseHandle really calls NtClose, but I like being defensive when programming */
CloseHandle(FileSystem->MountHandle);
FileSystem->MountHandle = 0;
}
FileSystem->MountHandle = 0;
}
static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/**
* @file dll/fuse/fuse.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -32,16 +32,13 @@ struct fsp_fuse_core_opt_data
{
struct fsp_fuse_env *env;
int help, debug;
int hard_remove,
use_ino, readdir_ino,
set_umask, umask,
HANDLE DebugLogHandle;
int set_umask, umask,
set_uid, uid,
set_gid, gid,
set_attr_timeout, attr_timeout,
rellinks;
int set_FileInfoTimeout;
int CaseInsensitiveSearch,
ReadOnlyVolume;
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
};
@ -56,9 +53,11 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FSP_FUSE_CORE_OPT("-d", debug, 1),
FSP_FUSE_CORE_OPT("debug", debug, 1),
FSP_FUSE_CORE_OPT("hard_remove", hard_remove, 1),
FSP_FUSE_CORE_OPT("use_ino", use_ino, 1),
FSP_FUSE_CORE_OPT("readdir_ino", readdir_ino, 1),
FUSE_OPT_KEY("DebugLog=", 'D'),
FUSE_OPT_KEY("hard_remove", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("use_ino", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("readdir_ino", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("direct_io", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("kernel_cache", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("auto_cache", FUSE_OPT_KEY_DISCARD),
@ -89,17 +88,8 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
FSP_FUSE_CORE_OPT("VolumeCreationTime=%lli", VolumeParams.VolumeCreationTime, 0),
FSP_FUSE_CORE_OPT("VolumeSerialNumber=%lx", VolumeParams.VolumeSerialNumber, 0),
FSP_FUSE_CORE_OPT("TransactTimeout=%u", VolumeParams.TransactTimeout, 0),
FSP_FUSE_CORE_OPT("IrpTimeout=%u", VolumeParams.IrpTimeout, 0),
FSP_FUSE_CORE_OPT("IrpCapacity=%u", VolumeParams.IrpCapacity, 0),
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
FSP_FUSE_CORE_OPT("CaseInsensitiveSearch", CaseInsensitiveSearch, 1),
FSP_FUSE_CORE_OPT("ReadOnlyVolume", ReadOnlyVolume, 1),
FUSE_OPT_KEY("ReparsePoints", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("NamedStreams", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("HardLinks", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("ExtendedAttributes", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("--UNC=", 'U'),
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
FUSE_OPT_KEY("--FileSystemName=", 'F'),
@ -131,6 +121,9 @@ static inline void *fsp_fuse_obj_alloc(struct fsp_fuse_env *env, size_t size)
static inline void fsp_fuse_obj_free(void *obj)
{
if (0 == obj)
return;
struct fsp_fuse_obj_hdr *hdr = (PVOID)((PUINT8)obj - sizeof(struct fsp_fuse_obj_hdr));
hdr->dtor(hdr);
@ -190,23 +183,55 @@ FSP_FUSE_API struct fuse_chan *fsp_fuse_mount(struct fsp_fuse_env *env,
const char *mountpoint, struct fuse_args *args)
{
struct fuse_chan *ch = 0;
WCHAR TempMountPointBuf[MAX_PATH], MountPointBuf[MAX_PATH];
int Size;
if (0 == mountpoint)
mountpoint = "";
if (0 == mountpoint || '\0' == mountpoint[0] ||
('*' == mountpoint[0] && '\0' == mountpoint[1]))
{
MountPointBuf[0] = L'*';
MountPointBuf[1] = L'\0';
Size = 2 * sizeof(WCHAR);
}
else if (
(
('A' <= mountpoint[0] && mountpoint[0] <= 'Z') ||
('a' <= mountpoint[0] && mountpoint[0] <= 'z')
) &&
':' == mountpoint[1] && '\0' == mountpoint[2])
{
MountPointBuf[0] = mountpoint[0];
MountPointBuf[1] = ':';
MountPointBuf[2] = '\0';
Size = 3 * sizeof(WCHAR);
}
else
{
char *win_mountpoint = 0;
Size = MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, 0, 0);
if (0 == Size)
goto fail;
if (0 != env->conv_to_win_path)
mountpoint = win_mountpoint = env->conv_to_win_path(mountpoint);
ch = fsp_fuse_obj_alloc(env, sizeof *ch + Size * sizeof(WCHAR));
Size = 0;
if (0 != mountpoint &&
0 != MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, TempMountPointBuf, MAX_PATH))
Size = GetFullPathNameW(TempMountPointBuf, MAX_PATH, MountPointBuf, 0);
env->memfree(win_mountpoint);
if (0 == Size || MAX_PATH <= Size)
goto fail;
mountpoint = 0;
Size = (Size + 1) * sizeof(WCHAR);
}
ch = fsp_fuse_obj_alloc(env, sizeof *ch + Size);
if (0 == ch)
goto fail;
ch->MountPoint = (PVOID)ch->Buffer;
Size = MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, ch->MountPoint, Size);
if (0 == Size)
goto fail;
memcpy(ch->MountPoint, MountPointBuf, Size);
return ch;
@ -230,36 +255,6 @@ FSP_FUSE_API int fsp_fuse_is_lib_option(struct fsp_fuse_env *env,
static void fsp_fuse_cleanup(struct fuse *f);
static NTSTATUS fsp_fuse_preflight(struct fuse *f)
{
NTSTATUS Result;
Result = FspFsctlPreflight(f->VolumeParams.Prefix[0] ?
L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME);
if (!NT_SUCCESS(Result))
return Result;
if (L'\0' != f->MountPoint)
{
if ((
(L'A' <= f->MountPoint[0] && f->MountPoint[0] <= L'Z') ||
(L'a' <= f->MountPoint[0] && f->MountPoint[0] <= L'z')
) &&
L':' == f->MountPoint[1] || L'\0' == f->MountPoint[2])
{
if (GetLogicalDrives() & (1 << ((f->MountPoint[0] & ~0x20) - 'a')))
return STATUS_OBJECT_NAME_COLLISION;
}
else
if (L'*' == f->MountPoint[0] && L'\0' == f->MountPoint[1])
;
else
return STATUS_OBJECT_NAME_INVALID;
}
return STATUS_SUCCESS;
}
static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
{
struct fuse *f = Service->UserContext;
@ -291,9 +286,17 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
//FUSE_CAP_ATOMIC_O_TRUNC | /* due to Windows/WinFsp design, no support */
//FUSE_CAP_EXPORT_SUPPORT | /* not needed in Windows/WinFsp */
FUSE_CAP_BIG_WRITES |
FUSE_CAP_DONT_MASK;
FUSE_CAP_DONT_MASK |
FSP_FUSE_CAP_READDIR_PLUS |
FSP_FUSE_CAP_READ_ONLY |
FSP_FUSE_CAP_CASE_INSENSITIVE;
if (0 != f->ops.init)
{
context->private_data = f->data = f->ops.init(&conn);
f->VolumeParams.ReadOnlyVolume = 0 != (conn.want & FSP_FUSE_CAP_READ_ONLY);
f->VolumeParams.CaseSensitiveSearch = 0 == (conn.want & FSP_FUSE_CAP_CASE_INSENSITIVE);
f->conn_want = conn.want;
}
f->fsinit = TRUE;
if (0 != f->ops.statfs)
{
@ -308,10 +311,12 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
goto fail;
}
if (stbuf.f_frsize > FSP_FUSE_SECTORSIZE_MAX)
stbuf.f_frsize = FSP_FUSE_SECTORSIZE_MAX;
if (0 == f->VolumeParams.SectorSize)
if (0 == f->VolumeParams.SectorSize && 0 != stbuf.f_frsize)
f->VolumeParams.SectorSize = (UINT16)stbuf.f_frsize;
#if 0
if (0 == f->VolumeParams.SectorsPerAllocationUnit && 0 != stbuf.f_frsize)
f->VolumeParams.SectorsPerAllocationUnit = (UINT16)(stbuf.f_bsize / stbuf.f_frsize);
#endif
if (0 == f->VolumeParams.MaxComponentLength)
f->VolumeParams.MaxComponentLength = (UINT16)stbuf.f_namemax;
}
@ -343,9 +348,8 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
}
/* the FSD does not currently limit these VolumeParams fields; do so here! */
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN)
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MIN;
if (f->VolumeParams.SectorSize > FSP_FUSE_SECTORSIZE_MAX)
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN ||
f->VolumeParams.SectorSize > FSP_FUSE_SECTORSIZE_MAX)
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MAX;
if (f->VolumeParams.SectorsPerAllocationUnit == 0)
f->VolumeParams.SectorsPerAllocationUnit = 1;
@ -380,7 +384,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
FspFileSystemSetOperationGuardStrategy(f->FileSystem, f->OpGuardStrategy);
FspFileSystemSetDebugLog(f->FileSystem, f->DebugLog);
if (L'\0' != f->MountPoint)
if (0 != f->MountPoint)
{
Result = FspFileSystemSetMountPoint(f->FileSystem,
L'*' == f->MountPoint[0] && L'\0' == f->MountPoint[1] ? 0 : f->MountPoint);
@ -449,14 +453,13 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
case 'h':
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
FSP_FUSE_LIBRARY_NAME " options:\n"
" -o SectorSize=N sector size for Windows (512-4096, deflt: 512)\n"
" -o SectorsPerAllocationUnit=N allocation unit size (deflt: 1*SectorSize)\n"
" -o DebugLog=FILE debug log file (deflt: stderr)\n"
" -o SectorSize=N sector size for Windows (512-4096, deflt: 4096)\n"
" -o SectorsPerAllocationUnit=N sectors per allocation unit (deflt: 1)\n"
" -o MaxComponentLength=N max file name component length (deflt: 255)\n"
" -o VolumeCreationTime=T volume creation time (FILETIME hex format)\n"
" -o VolumeSerialNumber=N 32-bit wide\n"
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n"
" -o CaseInsensitiveSearch file system supports case-insensitive file names\n"
//" -o ReadOnlyVolume file system is read only\n"
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n"
" --FileSystemName=FSN Name of user mode file system\n");
opt_data->help = 1;
@ -467,6 +470,17 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION);
opt_data->help = 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':
if ('U' == arg[2])
arg += sizeof "--UNC=" - 1;
@ -509,21 +523,55 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
memset(&opt_data, 0, sizeof opt_data);
opt_data.env = env;
opt_data.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))
return 0;
if (opt_data.help)
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) ||
(opt_data.set_gid && -1 == opt_data.gid))
{
HANDLE Token;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token))
{
fsp_fuse_get_token_uidgid(Token, TokenUser,
opt_data.set_uid && -1 == opt_data.uid ? &opt_data.uid : 0,
opt_data.set_gid && -1 == opt_data.gid ? &opt_data.gid : 0);
CloseHandle(Token);
}
if ((opt_data.set_uid && -1 == opt_data.uid) ||
(opt_data.set_gid && -1 == opt_data.gid))
{
ErrorMessage = L": unknown user/group.";
goto fail;
}
}
if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout)
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
opt_data.VolumeParams.CaseSensitiveSearch = !opt_data.CaseInsensitiveSearch;
opt_data.VolumeParams.CaseSensitiveSearch = TRUE;
opt_data.VolumeParams.PersistentAcls = TRUE;
opt_data.VolumeParams.ReparsePoints = TRUE;
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
opt_data.VolumeParams.NamedStreams = FALSE;
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
opt_data.VolumeParams.PostCleanupOnDeleteOnly = TRUE;
opt_data.VolumeParams.ReadOnlyVolume = FALSE;
opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
@ -548,7 +596,9 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
goto fail;
memcpy(f->MountPoint, ch->MountPoint, Size);
Result = fsp_fuse_preflight(f);
Result = FspFileSystemPreflight(
f->VolumeParams.Prefix[0] ? L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME,
'*' != f->MountPoint[0] || '\0' != f->MountPoint[1] ? f->MountPoint : 0);
if (!NT_SUCCESS(Result))
{
switch (Result)

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

@ -1,7 +1,7 @@
/**
* @file dll/fuse/fuse_intf.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -116,19 +116,6 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName = 0, Suffix;
WCHAR Root[2] = L"\\";
HANDLE Token = 0;
union
{
TOKEN_USER V;
UINT8 B[128];
} UserInfoBuf;
PTOKEN_USER UserInfo = &UserInfoBuf.V;
union
{
TOKEN_PRIMARY_GROUP V;
UINT8 B[128];
} GroupInfoBuf;
PTOKEN_PRIMARY_GROUP GroupInfo = &GroupInfoBuf.V;
DWORD Size;
NTSTATUS Result;
if (FspFsctlTransactCreateKind == Request->Kind)
@ -157,55 +144,7 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
if (0 != Token)
{
if (!GetTokenInformation(Token, TokenUser, UserInfo, sizeof UserInfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
UserInfo = MemAlloc(Size);
if (0 == UserInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenUser, UserInfo, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
if (!GetTokenInformation(Token, TokenPrimaryGroup, GroupInfo, sizeof GroupInfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
GroupInfo = MemAlloc(Size);
if (0 == UserInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenPrimaryGroup, GroupInfo, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Result = FspPosixMapSidToUid(UserInfo->User.Sid, &Uid);
if (!NT_SUCCESS(Result))
goto exit;
Result = FspPosixMapSidToUid(GroupInfo->PrimaryGroup, &Gid);
Result = fsp_fuse_get_token_uidgid(Token, TokenUser, &Uid, &Gid);
if (!NT_SUCCESS(Result))
goto exit;
}
@ -230,12 +169,6 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
Result = STATUS_SUCCESS;
exit:
if (UserInfo != &UserInfoBuf.V)
MemFree(UserInfo);
if (GroupInfo != &GroupInfoBuf.V)
MemFree(GroupInfo);
if (!NT_SUCCESS(Result) && 0 != PosixPath)
FspPosixDeletePath(PosixPath);
@ -378,28 +311,34 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
}
#define fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, fi, PUid, PGid, PMode, FileInfo)\
fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, PUid, PGid, PMode, 0, FileInfo)
fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, FileInfo)
static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
const char *PosixPath, struct fuse_file_info *fi,
const char *PosixPath, struct fuse_file_info *fi, const struct fuse_stat *stbufp,
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode, PUINT32 PDev,
FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;
UINT64 AllocationUnit;
struct fuse_stat stbuf;
int err;
memset(&stbuf, 0, sizeof stbuf);
if (0 != f->ops.fgetattr && 0 != fi && -1 != fi->fh)
err = f->ops.fgetattr(PosixPath, (void *)&stbuf, fi);
else if (0 != f->ops.getattr)
err = f->ops.getattr(PosixPath, (void *)&stbuf);
if (0 != stbufp)
memcpy(&stbuf, stbufp, sizeof stbuf);
else
return STATUS_INVALID_DEVICE_REQUEST;
{
int err;
if (0 != err)
return fsp_fuse_ntstatus_from_errno(f->env, err);
memset(&stbuf, 0, sizeof stbuf);
if (0 != f->ops.fgetattr && 0 != fi && -1 != fi->fh)
err = f->ops.fgetattr(PosixPath, (void *)&stbuf, fi);
else if (0 != f->ops.getattr)
err = f->ops.getattr(PosixPath, (void *)&stbuf);
else
return STATUS_INVALID_DEVICE_REQUEST;
if (0 != err)
return fsp_fuse_ntstatus_from_errno(f->env, err);
}
if (f->set_umask)
stbuf.st_mode = (stbuf.st_mode & 0170000) | (0777 & ~f->umask);
@ -580,7 +519,7 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointEx(FSP_FILE_SYSTEM *FileSystem,
SIZE_T Size;
NTSTATUS Result;
Result = fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi,
Result = fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0,
&Uid, &Gid, &Mode, &Dev, &FileInfo);
if (!NT_SUCCESS(Result))
return Result;
@ -697,13 +636,13 @@ static NTSTATUS fsp_fuse_intf_GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
struct fuse_statvfs stbuf;
int err;
if (0 == f->ops.statfs)
return STATUS_INVALID_DEVICE_REQUEST;
memset(&stbuf, 0, sizeof stbuf);
err = f->ops.statfs("/", &stbuf);
if (0 != err)
return fsp_fuse_ntstatus_from_errno(f->env, err);
if (0 != f->ops.statfs)
{
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->FreeSize = (UINT64)stbuf.f_bfree * (UINT64)stbuf.f_frsize;
@ -882,7 +821,6 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
filedesc->OpenFlags = fi.flags;
filedesc->FileHandle = fi.fh;
filedesc->DirBuffer = 0;
filedesc->DirBufferSize = 0;
contexthdr->PosixPath = 0;
Result = STATUS_SUCCESS;
@ -1000,7 +938,6 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
filedesc->OpenFlags = fi.flags;
filedesc->FileHandle = fi.fh;
filedesc->DirBuffer = 0;
filedesc->DirBufferSize = 0;
contexthdr->PosixPath = 0;
Result = STATUS_SUCCESS;
@ -1050,7 +987,7 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
}
static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, PWSTR FileName, BOOLEAN Delete)
PVOID FileNode, PWSTR FileName, ULONG Flags)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileNode;
@ -1072,7 +1009,7 @@ static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem,
* FUSE option and can safely remove the file at this time.
*/
if (Delete)
if (Flags & FspCleanupDelete)
if (filedesc->IsDirectory && !filedesc->IsReparsePoint)
{
if (0 != f->ops.rmdir)
@ -1113,7 +1050,7 @@ static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem,
f->ops.release(filedesc->PosixPath, &fi);
}
MemFree(filedesc->DirBuffer);
FspFileSystemDeleteDirectoryBuffer(&filedesc->DirBuffer);
MemFree(filedesc->PosixPath);
MemFree(filedesc);
}
@ -1215,11 +1152,14 @@ success:
}
static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode)
PVOID FileNode,
FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileNode;
UINT32 Uid, Gid, Mode;
struct fuse_file_info fi;
FSP_FSCTL_FILE_INFO FileInfoBuf;
int err;
NTSTATUS Result;
@ -1249,8 +1189,17 @@ static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
}
}
if (!NT_SUCCESS(Result))
return Result;
return Result;
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi,
&Uid, &Gid, &Mode, &FileInfoBuf);
if (!NT_SUCCESS(Result))
return Result;
memcpy(FileInfo, &FileInfoBuf, sizeof FileInfoBuf);
return STATUS_SUCCESS;
}
static NTSTATUS fsp_fuse_intf_GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
@ -1272,7 +1221,7 @@ static NTSTATUS fsp_fuse_intf_GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, UINT32 FileAttributes,
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime, UINT64 ChangeTime,
FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;
@ -1447,7 +1396,13 @@ static NTSTATUS fsp_fuse_intf_CanDelete(FSP_FILE_SYSTEM *FileSystem,
memset(&dh, 0, sizeof dh);
if (0 != f->ops.readdir)
{
memset(&fi, 0, sizeof fi);
fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle;
err = f->ops.readdir(filedesc->PosixPath, &dh, fsp_fuse_intf_CanDeleteAddDirInfo, 0, &fi);
}
else if (0 != f->ops.getdir)
err = f->ops.getdir(filedesc->PosixPath, &dh, fsp_fuse_intf_CanDeleteAddDirInfoOld);
else
@ -1484,7 +1439,8 @@ static NTSTATUS fsp_fuse_intf_Rename(FSP_FILE_SYSTEM *FileSystem,
STATUS_OBJECT_PATH_NOT_FOUND != Result)
return Result;
if (NT_SUCCESS(Result))
if (NT_SUCCESS(Result) &&
(f->VolumeParams.CaseSensitiveSearch || 0 != invariant_wcsicmp(FileName, NewFileName)))
{
if (!ReplaceIfExists)
return STATUS_OBJECT_NAME_COLLISION;
@ -1591,185 +1547,111 @@ exit:
return Result;
}
int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
static int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
const struct fuse_stat *stbuf, fuse_off_t off)
{
struct fuse_dirhandle *dh = buf;
struct fsp_fuse_dirinfo *di;
ULONG len, xfersize;
len = lstrlenA(name);
if (len > 255)
len = 255;
di = (PVOID)((PUINT8)dh->Buffer + dh->BytesTransferred);
xfersize = FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(struct fsp_fuse_dirinfo) + len + 1);
if ((PUINT8)di + xfersize > (PUINT8)dh->Buffer + dh->Length)
{
PVOID Buffer;
ULONG Length = dh->Length;
if (0 == Length)
Length = 16 * 1024;
else if (Length < 16 * 1024 * 1024)
Length *= 2;
else
return 1;
Buffer = MemAlloc(Length);
if (0 == Buffer)
return 1;
memcpy(Buffer, dh->Buffer, dh->BytesTransferred);
MemFree(dh->Buffer);
dh->Buffer = Buffer;
dh->Length = Length;
di = (PVOID)((PUINT8)dh->Buffer + dh->BytesTransferred);
}
dh->BytesTransferred += xfersize;
dh->NonZeroOffset = dh->NonZeroOffset || 0 != off;
di->Size = (UINT16)(sizeof(struct fsp_fuse_dirinfo) + len + 1);
di->FileInfoValid = FALSE;
di->NextOffset = 0 != off ? off : dh->BytesTransferred;
memcpy(di->PosixNameBuf, name, len);
di->PosixNameBuf[len] = '\0';
return 0;
}
int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name,
int type, fuse_ino_t ino)
{
return fsp_fuse_intf_AddDirInfo(dh, name, 0, 0) ? -ENOMEM : 0;
}
static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
PWSTR Pattern,
PULONG PBytesTransferred)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_file_info fi;
struct fuse_dirhandle dh;
struct fsp_fuse_dirinfo *di;
PUINT8 diend;
struct fsp_fuse_file_desc *filedesc = dh->filedesc;
union
{
FSP_FSCTL_DIR_INFO V;
UINT8 B[sizeof(FSP_FSCTL_DIR_INFO) + 255 * sizeof(WCHAR)];
} DirInfoBuf;
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.V;
UINT32 Uid, Gid, Mode;
ULONG SizeA, SizeW;
if ('/' == filedesc->PosixPath[0] && '\0' == filedesc->PosixPath[1])
{
/* if this is the root directory do not add the dot entries */
if ('.' == name[0] && ('\0' == name[1] ||
('.' == name[1] && '\0' == name[2])))
return 0;
}
SizeA = lstrlenA(name);
if (SizeA > 255)
/* ignore bad filenames; should we return error code? */
return 0;
SizeW = MultiByteToWideChar(CP_UTF8, 0, name, SizeA, DirInfo->FileNameBuf, 255);
if (0 == SizeW)
/* ignore bad filenames; should we return error code? */
return 0;
memset(DirInfo, 0, sizeof *DirInfo);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + SizeW * sizeof(WCHAR));
if (dh->ReaddirPlus && 0 != stbuf)
{
UINT32 Uid, Gid, Mode;
NTSTATUS Result0;
Result0 = fsp_fuse_intf_GetFileInfoFunnel(dh->FileSystem, 0, 0, stbuf,
&Uid, &Gid, &Mode, 0, &DirInfo->FileInfo);
if (NT_SUCCESS(Result0))
DirInfo->Padding[0] = 1; /* HACK: remember that the FileInfo is valid */
}
return !FspFileSystemFillDirectoryBuffer(&filedesc->DirBuffer, DirInfo, &dh->Result);
}
static int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name,
int type, fuse_ino_t ino)
{
return fsp_fuse_intf_AddDirInfo(dh, name, 0, 0) ? -ENOMEM : 0;
}
static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem,
struct fsp_fuse_file_desc *filedesc)
{
char *PosixPath = 0, *PosixName, *PosixPathEnd, SavedPathChar;
PWSTR FileName = 0;
ULONG Size;
int err;
ULONG SizeA, SizeW;
PUINT8 Buffer;
PULONG Index, IndexEnd;
ULONG Count;
FSP_FSCTL_DIR_INFO *DirInfo;
UINT32 Uid, Gid, Mode;
NTSTATUS Result;
if (!filedesc->IsDirectory)
return STATUS_ACCESS_DENIED;
memset(&dh, 0, sizeof dh);
if (0 == filedesc->DirBuffer)
SizeA = lstrlenA(filedesc->PosixPath);
PosixPath = MemAlloc(SizeA + 1 + 255 + 1);
if (0 == PosixPath)
{
if (0 != f->ops.readdir)
{
memset(&fi, 0, sizeof fi);
fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle;
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
err = f->ops.readdir(filedesc->PosixPath, &dh, fsp_fuse_intf_AddDirInfo, Offset, &fi);
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
}
else if (0 != f->ops.getdir)
{
err = f->ops.getdir(filedesc->PosixPath, &dh, fsp_fuse_intf_AddDirInfoOld);
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
}
else
Result = STATUS_INVALID_DEVICE_REQUEST;
memcpy(PosixPath, filedesc->PosixPath, SizeA);
if (1 < SizeA)
/* if not root */
PosixPath[SizeA++] = '/';
PosixPath[SizeA] = '\0';
PosixName = PosixPath + SizeA;
if (!NT_SUCCESS(Result))
goto exit;
FspFileSystemPeekInDirectoryBuffer(&filedesc->DirBuffer, &Buffer, &Index, &Count);
if (0 == dh.BytesTransferred)
for (IndexEnd = Index + Count; IndexEnd > Index; Index++)
{
DirInfo = (FSP_FSCTL_DIR_INFO *)(Buffer + *Index);
SizeW = (DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR);
if (DirInfo->Padding[0])
{
/* EOF */
*PBytesTransferred = 0;
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
goto success;
}
else if (dh.NonZeroOffset)
{
di = (PVOID)((PUINT8)dh.Buffer + 0);
diend = (PUINT8)dh.Buffer + dh.BytesTransferred;
/* DirInfo has been filled already! */
DirInfo->Padding[0] = 0;
}
else
{
di = (PVOID)((PUINT8)dh.Buffer + Offset);
diend = (PUINT8)dh.Buffer + dh.BytesTransferred;
filedesc->DirBuffer = dh.Buffer;
filedesc->DirBufferSize = dh.BytesTransferred;
dh.Buffer = 0;
}
}
else
{
di = (PVOID)((PUINT8)filedesc->DirBuffer + Offset);
diend = (PUINT8)filedesc->DirBuffer + filedesc->DirBufferSize;
}
for (;
(PUINT8)di + sizeof(di->Size) <= diend;
di = (PVOID)((PUINT8)di + FSP_FSCTL_DEFAULT_ALIGN_UP(di->Size)))
{
if (sizeof(struct fsp_fuse_dirinfo) > di->Size)
break;
if ('/' == filedesc->PosixPath[0] && '\0' == filedesc->PosixPath[1])
{
/* if this is the root directory do not add the dot entries */
if ('.' == di->PosixNameBuf[0] && ('\0' == di->PosixNameBuf[1] ||
('.' == di->PosixNameBuf[1] && '\0' == di->PosixNameBuf[2])))
continue;
}
if (!di->FileInfoValid)
{
if (0 == PosixPath)
{
Size = lstrlenA(filedesc->PosixPath);
PosixPath = MemAlloc(Size + 1 + 255 + 1);
if (0 == PosixPath)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
memcpy(PosixPath, filedesc->PosixPath, Size);
if (1 < Size)
/* if not root */
PosixPath[Size++] = '/';
PosixPath[Size] = '\0';
PosixName = PosixPath + Size;
}
if ('.' == di->PosixNameBuf[0] && '\0' == di->PosixNameBuf[1])
if (1 == SizeW && L'.' == DirInfo->FileNameBuf[0])
{
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 1 : PosixName;
SavedPathChar = *PosixPathEnd;
*PosixPathEnd = '\0';
}
else
if ('.' == di->PosixNameBuf[0] && '.' == di->PosixNameBuf[1] && '\0' == di->PosixNameBuf[2])
if (2 == SizeW && L'.' == DirInfo->FileNameBuf[0] && L'.' == DirInfo->FileNameBuf[1])
{
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 2 : PosixName;
while (PosixPath < PosixPathEnd && '/' != *PosixPathEnd)
@ -1782,58 +1664,91 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
else
{
PosixPathEnd = 0;
Size = lstrlenA(di->PosixNameBuf);
if (Size > 255)
Size = 255;
memcpy(PosixName, di->PosixNameBuf, Size);
PosixName[Size] = '\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, &di->FileInfo);
&Uid, &Gid, &Mode, &DirInfo->FileInfo);
if (!NT_SUCCESS(Result))
goto exit;
if (0 != PosixPathEnd)
*PosixPathEnd = SavedPathChar;
di->FileInfoValid = TRUE;
}
memcpy(&DirInfo->FileInfo, &di->FileInfo, sizeof di->FileInfo);
Result = FspPosixMapPosixToWindowsPath(di->PosixNameBuf, &FileName);
if (!NT_SUCCESS(Result))
goto exit;
Size = lstrlenW(FileName);
if (Size > 255)
Size = 255;
Size *= sizeof(WCHAR);
memcpy(DirInfo->FileNameBuf, FileName, Size);
FspPosixDeletePath(FileName);
memset(DirInfo->Padding, 0, sizeof DirInfo->Padding);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + Size);
DirInfo->NextOffset = di->NextOffset;
if (!FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred))
break;
FspPosixDecodeWindowsPath(DirInfo->FileNameBuf, SizeW);
}
if ((PUINT8)di + sizeof(di->Size) > diend)
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
success:
Result = STATUS_SUCCESS;
exit:
MemFree(PosixPath);
MemFree(dh.Buffer);
return Result;
}
static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, PWSTR Pattern, PWSTR Marker,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_dirhandle dh;
struct fuse_file_info fi;
int err;
NTSTATUS Result;
if (FspFileSystemAcquireDirectoryBuffer(&filedesc->DirBuffer, 0 == Marker, &Result))
{
memset(&dh, 0, sizeof dh);
dh.filedesc = filedesc;
dh.FileSystem = FileSystem;
dh.ReaddirPlus = 0 != (f->conn_want & FSP_FUSE_CAP_READDIR_PLUS);
dh.Result = STATUS_SUCCESS;
if (0 != f->ops.readdir)
{
memset(&fi, 0, sizeof fi);
fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle;
err = f->ops.readdir(filedesc->PosixPath, &dh, fsp_fuse_intf_AddDirInfo, 0, &fi);
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
}
else if (0 != f->ops.getdir)
{
err = f->ops.getdir(filedesc->PosixPath, &dh, fsp_fuse_intf_AddDirInfoOld);
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
}
else
Result = STATUS_INVALID_DEVICE_REQUEST;
if (NT_SUCCESS(Result))
{
Result = dh.Result;
if (NT_SUCCESS(Result))
Result = fsp_fuse_intf_FixDirInfo(FileSystem, filedesc);
}
FspFileSystemReleaseDirectoryBuffer(&filedesc->DirBuffer);
}
if (!NT_SUCCESS(Result))
return Result;
FspFileSystemReadDirectoryBuffer(&filedesc->DirBuffer,
Marker, Buffer, Length, PBytesTransferred);
return STATUS_SUCCESS;
}
static NTSTATUS fsp_fuse_intf_ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent,
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize)
@ -2108,3 +2023,140 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
fsp_fuse_intf_SetReparsePoint,
fsp_fuse_intf_DeleteReparsePoint,
};
/*
* Utility
*/
NTSTATUS fsp_fuse_get_token_uidgid(
HANDLE Token,
TOKEN_INFORMATION_CLASS UserOrOwnerClass, /* TokenUser|TokenOwner */
PUINT32 PUid, PUINT32 PGid)
{
UINT32 Uid, Gid;
union
{
TOKEN_USER V;
UINT8 B[128];
} UserInfoBuf;
PTOKEN_USER UserInfo = &UserInfoBuf.V;
union
{
TOKEN_OWNER V;
UINT8 B[128];
} OwnerInfoBuf;
PTOKEN_OWNER OwnerInfo = &OwnerInfoBuf.V;
union
{
TOKEN_PRIMARY_GROUP V;
UINT8 B[128];
} GroupInfoBuf;
PTOKEN_PRIMARY_GROUP GroupInfo = &GroupInfoBuf.V;
DWORD Size;
NTSTATUS Result;
if (0 != PUid && TokenUser == UserOrOwnerClass)
{
if (!GetTokenInformation(Token, TokenUser, UserInfo, sizeof UserInfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
UserInfo = MemAlloc(Size);
if (0 == UserInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenUser, UserInfo, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Result = FspPosixMapSidToUid(UserInfo->User.Sid, &Uid);
if (!NT_SUCCESS(Result))
goto exit;
}
else if (0 != PUid && TokenOwner == UserOrOwnerClass)
{
if (!GetTokenInformation(Token, TokenOwner, OwnerInfo, sizeof OwnerInfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
OwnerInfo = MemAlloc(Size);
if (0 == OwnerInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenOwner, OwnerInfo, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Result = FspPosixMapSidToUid(OwnerInfo->Owner, &Uid);
if (!NT_SUCCESS(Result))
goto exit;
}
if (0 != PGid)
{
if (!GetTokenInformation(Token, TokenPrimaryGroup, GroupInfo, sizeof GroupInfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
GroupInfo = MemAlloc(Size);
if (0 == GroupInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenPrimaryGroup, GroupInfo, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Result = FspPosixMapSidToUid(GroupInfo->PrimaryGroup, &Gid);
if (!NT_SUCCESS(Result))
goto exit;
}
if (0 != PUid)
*PUid = Uid;
if (0 != PGid)
*PGid = Gid;
Result = STATUS_SUCCESS;
exit:
if (UserInfo != &UserInfoBuf.V)
MemFree(UserInfo);
if (OwnerInfo != &OwnerInfoBuf.V)
MemFree(OwnerInfo);
if (GroupInfo != &GroupInfoBuf.V)
MemFree(GroupInfo);
return Result;
}

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/**
* @file dll/fuse/library.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -40,12 +40,13 @@ struct fuse
int rellinks;
struct fuse_operations ops;
void *data;
unsigned conn_want;
BOOLEAN fsinit;
UINT32 DebugLog;
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
PWSTR MountPoint;
FSP_FILE_SYSTEM *FileSystem;
BOOLEAN fsinit;
FSP_SERVICE *Service; /* weak */
};
@ -62,27 +63,19 @@ struct fsp_fuse_file_desc
int OpenFlags;
UINT64 FileHandle;
PVOID DirBuffer;
ULONG DirBufferSize;
};
struct fuse_dirhandle
{
PVOID Buffer;
ULONG Length;
ULONG BytesTransferred;
BOOLEAN NonZeroOffset;
/* ReadDirectory */
struct fsp_fuse_file_desc *filedesc;
FSP_FILE_SYSTEM *FileSystem;
BOOLEAN ReaddirPlus;
NTSTATUS Result;
/* CanDelete */
BOOLEAN DotFiles, HasChild;
};
struct fsp_fuse_dirinfo
{
UINT16 Size;
FSP_FSCTL_FILE_INFO FileInfo;
BOOLEAN FileInfoValid;
UINT64 NextOffset;
char PosixNameBuf[]; /* includes term-0 (unlike FSP_FSCTL_DIR_INFO) */
};
NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem,
@ -90,6 +83,11 @@ NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem,
extern FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf;
NTSTATUS fsp_fuse_get_token_uidgid(
HANDLE Token,
TOKEN_INFORMATION_CLASS UserOrOwnerClass, /* TokenUser|TokenOwner */
PUINT32 PUid, PUINT32 PGid);
/* NFS reparse points */
#define NFS_SPECFILE_FIFO 0x000000004F464946

View File

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

View File

@ -1,7 +1,7 @@
/**
* @file dll/library.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -51,6 +51,9 @@ NTSTATUS FspEventLogUnregister(VOID);
PWSTR FspDiagIdent(VOID);
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount);
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
static inline ULONG FspPathSuffixIndex(PWSTR FileName)
@ -73,7 +76,7 @@ static inline BOOLEAN FspPathIsDrive(PWSTR FileName)
(L'A' <= FileName[0] && FileName[0] <= L'Z') ||
(L'a' <= FileName[0] && FileName[0] <= L'z')
) &&
L':' == FileName[1] || L'\0' == FileName[2];
L':' == FileName[1] && L'\0' == FileName[2];
}
#endif

View File

@ -1,7 +1,7 @@
/**
* @file dll/np.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -22,6 +22,7 @@
#define FSP_NP_NAME LIBRARY_NAME ".Np"
#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */
#define FSP_NP_ADDCONNECTION_TIMEOUT 15000
/*
* Define the following macro to use CredUIPromptForWindowsCredentials.
@ -283,7 +284,8 @@ static DWORD FspNpGetCredentialsKind(PWSTR RemoteName, PDWORD PCredentialsKind)
memcpy(ClassNameBuf, ClassName, ClassNameLen * sizeof(WCHAR));
ClassNameBuf[ClassNameLen] = '\0';
NpResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY, 0, KEY_READ, &RegKey);
NpResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY,
0, LAUNCHER_REGKEY_WOW64 | KEY_READ, &RegKey);
if (ERROR_SUCCESS != NpResult)
goto exit;
@ -583,6 +585,63 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
switch (NpResult)
{
case WN_SUCCESS:
/*
* The Launcher is reporting success. Wait until we can access the new volume
* root directory. If we see it report success, otherwise report error.
*/
{
WCHAR RemoteNameBuf[9 + sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
HANDLE Handle;
if (L'\0' != LocalNameBuf[0])
{
P = RemoteNameBuf;
*P++ = L'\\'; *P++ = L'\\'; *P++ = L'?'; *P++ = L'\\';
*P++ = LocalNameBuf[0]; *P++ = L':'; *P++ = L'\\';
*P++ = L'\0';
}
else
{
P = RemoteNameBuf;
*P++ = L'\\'; *P++ = L'\\'; *P++ = L'?'; *P++ = L'\\';
*P++ = L'U'; *P++ = L'N'; *P++ = L'C'; *P++ = L'\\';
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\\';
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\\';
*P++ = L'\0';
}
NpResult = WN_NO_NETWORK; /* timeout error */
for (ULONG I = 0, N = 1 + FSP_NP_ADDCONNECTION_TIMEOUT / 500; N > I; I++)
{
if (0 != I)
Sleep(500);
Handle = CreateFileW(RemoteNameBuf,
FILE_READ_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (INVALID_HANDLE_VALUE != Handle)
{
/* the file system is up and running */
CloseHandle(Handle);
NpResult = WN_SUCCESS;
break;
}
P = PipeBuf;
*P++ = LauncherSvcInstanceInfo;
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
if (WN_SUCCESS != FspNpCallLauncherPipe(
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE))
{
/* looks like the file system is gone! */
NpResult = WN_NO_NETWORK;
break;
}
}
}
break;
case WN_ACCESS_DENIED:
break;
case ERROR_ALREADY_EXISTS:

View File

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

View File

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

View File

@ -14,7 +14,7 @@
* [SNAME]
* https://www.cygwin.com/cygwin-ug-net/using-specialnames.html
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -923,3 +923,30 @@ FSP_API VOID FspPosixDeletePath(void *Path)
{
MemFree(Path);
}
FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size)
{
for (PWSTR p = WindowsPath, endp = p + Size; endp > p; p++)
{
WCHAR c = *p;
if (L'\\' == c)
*p = L'/';
/* encode characters in the Unicode private use area: U+F0XX -> XX */
else if (0xf000 <= c && c <= 0xf0ff)
*p &= ~0xf000;
}
}
FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size)
{
for (PWSTR p = WindowsPath, endp = p + Size; endp > p; p++)
{
WCHAR c = *p;
if (L'/' == c)
*p = L'\\';
else if (128 > c && (FspPosixInvalidPathChars[c >> 5] & (0x80000000 >> (c & 0x1f))))
*p |= 0xf000;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/**
* @file launcher/launcher.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -19,7 +19,6 @@
#include <sddl.h>
#define PROGNAME "WinFsp.Launcher"
#define REGKEY LAUNCHER_REGKEY
BOOL CreateOverlappedPipe(
PHANDLE PReadPipe, PHANDLE PWritePipe, PSECURITY_ATTRIBUTES SecurityAttributes, DWORD Size,
@ -441,7 +440,8 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
goto exit;
}
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" REGKEY, 0, KEY_READ, &RegKey);
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY,
0, LAUNCHER_REGKEY_WOW64 | KEY_READ, &RegKey);
if (ERROR_SUCCESS != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);

View File

@ -1,7 +1,7 @@
/**
* @file launcher/launcher.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -21,7 +21,8 @@
#include <winfsp/winfsp.h>
#include <shared/minimal.h>
#define LAUNCHER_REGKEY "SYSTEM\\CurrentControlSet\\Services\\WinFsp.Launcher\\Services"
#define LAUNCHER_REGKEY "Software\\WinFsp\\Services"
#define LAUNCHER_REGKEY_WOW64 KEY_WOW64_32KEY
#define LAUNCHER_STOP_TIMEOUT 5500
#define LAUNCHER_KILL_TIMEOUT 5000

View File

@ -1,7 +1,7 @@
/**
* @file shared/minimal.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -126,6 +126,10 @@ static inline void *MemAlloc(size_t Size)
{
return HeapAlloc(GetProcessHeap(), 0, Size);
}
static inline void *MemRealloc(void *Pointer, size_t Size)
{
return HeapReAlloc(GetProcessHeap(), 0, Pointer, Size);
}
static inline void MemFree(void *Pointer)
{
if (0 != Pointer)

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/**
* @file sys/create.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -193,6 +193,7 @@ static NTSTATUS FspFsvolCreateNoLock(
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_BACKUP_PRIVILEGE);
BOOLEAN HasRestorePrivilege =
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE);
BOOLEAN HasTrailingBackslash = FALSE;
FSP_FILE_NODE *FileNode, *RelatedFileNode;
FSP_FILE_DESC *FileDesc;
UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 };
@ -216,6 +217,12 @@ static NTSTATUS FspFsvolCreateNoLock(
FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
return STATUS_INVALID_PARAMETER;
/* do not allow the temporary bit on a directory */
if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE) &&
FlagOn(FileAttributes, FILE_ATTRIBUTE_TEMPORARY) &&
(FILE_CREATE == CreateDisposition || FILE_OPEN_IF == CreateDisposition))
return STATUS_INVALID_PARAMETER;
/* check security descriptor validity */
if (0 != SecurityDescriptor)
{
@ -257,7 +264,7 @@ static NTSTATUS FspFsvolCreateNoLock(
/* must be a relative path */
if (sizeof(WCHAR) <= FileName.Length && L'\\' == FileName.Buffer[0])
return STATUS_OBJECT_NAME_INVALID;
return STATUS_INVALID_PARAMETER; /* IFSTEST */
BOOLEAN AppendBackslash =
sizeof(WCHAR) * 2/* not empty or root */ <= RelatedFileNode->FileName.Length &&
@ -293,7 +300,7 @@ static NTSTATUS FspFsvolCreateNoLock(
ASSERT(NT_SUCCESS(Result));
/* check filename validity */
if (!FspFileNameIsValid(&FileNode->FileName,
if (!FspFileNameIsValid(&FileNode->FileName, FsvolDeviceExtension->VolumeParams.MaxComponentLength,
FsvolDeviceExtension->VolumeParams.NamedStreams ? &StreamPart : 0,
&StreamType))
{
@ -344,12 +351,7 @@ static NTSTATUS FspFsvolCreateNoLock(
if (sizeof(WCHAR) * 2/* not empty or root */ <= FileNode->FileName.Length &&
L'\\' == FileNode->FileName.Buffer[FileNode->FileName.Length / sizeof(WCHAR) - 1])
{
if (!FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
{
FspFileNodeDereference(FileNode);
return STATUS_OBJECT_NAME_INVALID;
}
HasTrailingBackslash = TRUE;
FileNode->FileName.Length -= sizeof(WCHAR);
}
@ -442,7 +444,9 @@ static NTSTATUS FspFsvolCreateNoLock(
FileAttributes = 0;
/* remember the main file node */
ASSERT(0 == FileNode->MainFileNode);
FileNode->MainFileNode = FileDesc->MainFileObject->FsContext;
FspFileNodeReference(FileNode->MainFileNode);
Result = STATUS_SUCCESS;
@ -501,6 +505,7 @@ static NTSTATUS FspFsvolCreateNoLock(
Request->Req.Create.HasRestorePrivilege = HasRestorePrivilege;
Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY);
Request->Req.Create.CaseSensitive = CaseSensitive;
Request->Req.Create.HasTrailingBackslash = HasTrailingBackslash;
Request->Req.Create.NamedStream = MainFileName.Length;
ASSERT(
@ -803,6 +808,16 @@ NTSTATUS FspFsvolCreateComplete(
}
/* populate the FileNode/FileDesc fields from the Response */
FileNode->UserContext = Response->Rsp.Create.Opened.UserContext;
FileNode->IndexNumber = Response->Rsp.Create.Opened.FileInfo.IndexNumber;
FileNode->IsDirectory = BooleanFlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes,
FILE_ATTRIBUTE_DIRECTORY);
FileNode->IsRootDirectory = FileNode->IsDirectory &&
sizeof(WCHAR) == FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0];
FileDesc->UserContext2 = Response->Rsp.Create.Opened.UserContext2;
FileDesc->DeleteOnClose = BooleanFlagOn(IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE);
/* handle normalized names */
if (!FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch)
{
/* is there a normalized file name as part of the response? */
@ -818,7 +833,10 @@ NTSTATUS FspFsvolCreateComplete(
if (Response->Buffer + Response->Rsp.Create.Opened.FileName.Size >
(PUINT8)Response + Response->Size)
{
FspFsvolCreatePostClose(FileDesc);
FSP_RETURN(Result = STATUS_OBJECT_NAME_INVALID);
}
NormalizedName.Length = NormalizedName.MaximumLength =
Response->Rsp.Create.Opened.FileName.Size;
@ -826,20 +844,15 @@ NTSTATUS FspFsvolCreateComplete(
/* normalized file name can only differ in case from requested one */
if (0 != FspFileNameCompare(&FileNode->FileName, &NormalizedName, TRUE, 0))
{
FspFsvolCreatePostClose(FileDesc);
FSP_RETURN(Result = STATUS_OBJECT_NAME_INVALID);
}
ASSERT(FileNode->FileName.Length == NormalizedName.Length);
RtlCopyMemory(FileNode->FileName.Buffer, NormalizedName.Buffer, NormalizedName.Length);
}
}
FileNode->UserContext = Response->Rsp.Create.Opened.UserContext;
FileNode->IndexNumber = Response->Rsp.Create.Opened.FileInfo.IndexNumber;
FileNode->IsDirectory = BooleanFlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes,
FILE_ATTRIBUTE_DIRECTORY);
FileNode->IsRootDirectory = FileNode->IsDirectory &&
sizeof(WCHAR) == FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0];
FileDesc->UserContext2 = Response->Rsp.Create.Opened.UserContext2;
FileDesc->DeleteOnClose = BooleanFlagOn(IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE);
/* open the FileNode */
Result = FspFileNodeOpen(FileNode, FileObject,
@ -865,8 +878,7 @@ NTSTATUS FspFsvolCreateComplete(
Result = FspFsvolCreateSharingViolationOplock(
FsvolDeviceObject, Irp, IrpSp, FALSE);
if (STATUS_PENDING == Result)
FSP_RETURN();
FSP_RETURN();
}
else
{
@ -892,6 +904,7 @@ NTSTATUS FspFsvolCreateComplete(
/* set up the AccessState */
AccessState->RemainingDesiredAccess = 0;
AccessState->PreviouslyGrantedAccess = Response->Rsp.Create.Opened.GrantedAccess;
FileDesc->GrantedAccess = Response->Rsp.Create.Opened.GrantedAccess;
/* set up the FileObject */
if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
@ -901,6 +914,13 @@ NTSTATUS FspFsvolCreateComplete(
FileObject->PrivateCacheMap = 0;
FileObject->FsContext = FileNode;
FileObject->FsContext2 = FileDesc;
if (!FileNode->IsDirectory)
{
/* properly set temporary bit for lazy writer */
if (FlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes,
FILE_ATTRIBUTE_TEMPORARY))
SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
}
if (FspTimeoutInfinity32 == FsvolDeviceExtension->VolumeParams.FileInfoTimeout &&
!FlagOn(IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING) &&
!Response->Rsp.Create.Opened.DisableCache)
@ -939,6 +959,19 @@ NTSTATUS FspFsvolCreateComplete(
if (FileNode->IsDirectory)
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
/* overwrite/supersede operations must have the correct hidden/system attributes set */
if ((FlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes, FILE_ATTRIBUTE_HIDDEN) &&
!FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) ||
(FlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes, FILE_ATTRIBUTE_SYSTEM) &&
!FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM)))
{
FspFsvolCreatePostClose(FileDesc);
FspFileNodeClose(FileNode, FileObject, TRUE);
Result = STATUS_ACCESS_DENIED;
FSP_RETURN();
}
PVOID RequestDeviceObjectValue = FspIopRequestContext(Request, RequestDeviceObject);
/* disassociate the FileDesc momentarily from the Request */
@ -998,10 +1031,11 @@ NTSTATUS FspFsvolCreateComplete(
/* file was successfully overwritten/superseded */
if (0 == FileNode->MainFileNode)
FspFileNodeOverwriteStreams(FileNode);
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Overwrite.FileInfo);
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Overwrite.FileInfo, TRUE);
FspFileNodeNotifyChange(FileNode,
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE,
FILE_ACTION_MODIFIED);
FILE_ACTION_MODIFIED,
FALSE);
FspFileNodeReleaseOwner(FileNode, Full, Request);
@ -1064,7 +1098,8 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
return Result;
}
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Create.Opened.FileInfo);
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Create.Opened.FileInfo,
FILE_CREATED == Response->IoStatus.Information);
if (FlushImage)
{
@ -1091,7 +1126,8 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
if (FILE_CREATED == Response->IoStatus.Information)
FspFileNodeNotifyChange(FileNode,
FileNode->IsDirectory ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_ADDED);
FILE_ACTION_ADDED,
TRUE);
FspFileNodeRelease(FileNode, Main);
@ -1280,6 +1316,7 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock(
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
FSP_FSCTL_TRANSACT_RSP *Response;
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
FSP_FILE_NODE *ExtraFileNode = FspIopRequestContext(Request, FspIopRequestExtraContext);
ULONG SharingViolationReason = (ULONG)Irp->IoStatus.Information;
NTSTATUS Result;
@ -1316,6 +1353,12 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock(
return FspWqRepostIrpWorkItem(Irp,
FspFsvolCreateSharingViolationOplock, FspFsvolCreateRequestFini);
FspFileNodeClose(ExtraFileNode, 0, TRUE);
FspFileNodeDereference(ExtraFileNode);
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
FspFsvolCreatePostClose(FileDesc);
Irp->IoStatus.Information = 0;
return STATUS_SHARING_VIOLATION;
}
@ -1334,7 +1377,6 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock(
* stream.
*/
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
/* break Batch oplocks on the main file and this stream */
@ -1390,14 +1432,14 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock(
Response = FspIopIrpResponse(Irp);
if (STATUS_SUCCESS == Result)
{
FspFileNodeClose(ExtraFileNode, 0, TRUE);
FspFileNodeDereference(ExtraFileNode);
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
}
else
FspFileNodeClose(ExtraFileNode, 0, TRUE);
FspFileNodeDereference(ExtraFileNode);
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
if (STATUS_SUCCESS != Result)
{
FspFsvolCreatePostClose(FileDesc);
Response->IoStatus.Status = (UINT32)Result;
Response->IoStatus.Information = (UINT32)Irp->IoStatus.Information;
}

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/**
* @file sys/dirctl.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -28,7 +28,7 @@
static NTSTATUS FspFsvolQueryDirectoryCopy(
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
UINT64 DirectoryOffset, PUINT64 PDirectoryOffset,
PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut,
FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry,
FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize,
PVOID DestBuf, PULONG PDestLen);
@ -74,13 +74,11 @@ FSP_DRIVER_DISPATCH FspDirectoryControl;
#pragma alloc_text(PAGE, FspDirectoryControl)
#endif
#define FILE_INDEX_FROM_OFFSET(v) ((ULONG)(v))
#define OFFSET_FROM_FILE_INDEX(v) ((UINT64)(v))
enum
{
/* QueryDirectory */
RequestIrp = 0,
RequestCookie = 1,
RequestMdl = 1,
RequestAddress = 2,
RequestProcess = 3,
@ -91,10 +89,11 @@ enum
/* DirectoryControlComplete retry */
RequestDirInfoChangeNumber = 0,
};
FSP_FSCTL_STATIC_ASSERT(RequestCookie == RequestMdl, "");
static NTSTATUS FspFsvolQueryDirectoryCopy(
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
UINT64 DirectoryOffset, PUINT64 PDirectoryOffset,
PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut,
FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry,
FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize,
PVOID DestBuf, PULONG PDestLen)
@ -104,7 +103,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
{\
TYPE InfoStruct = { 0 }, *Info = &InfoStruct;\
Info->NextEntryOffset = 0;\
Info->FileIndex = FILE_INDEX_FROM_OFFSET(DirInfo->NextOffset);\
Info->FileIndex = 0;\
Info->FileNameLength = FileName.Length;\
__VA_ARGS__\
Info = DestBuf;\
@ -128,7 +127,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
NTSTATUS Result = STATUS_SUCCESS;
BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer, Match;
BOOLEAN Loop = TRUE, DirectoryOffsetFound = FALSE;
BOOLEAN Loop = TRUE, DirectoryMarkerFound = FALSE;
FSP_FSCTL_DIR_INFO *DirInfo = *PDirInfo;
PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize;
PUINT8 DestBufBgn = (PUINT8)DestBuf;
@ -178,16 +177,18 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
break;
}
if (0 != DirectoryOffset && !DirectoryOffsetFound)
{
DirectoryOffsetFound = DirInfo->NextOffset == DirectoryOffset;
continue;
}
FileName.Length =
FileName.MaximumLength = (USHORT)(DirInfoSize - sizeof(FSP_FSCTL_DIR_INFO));
FileName.Buffer = DirInfo->FileNameBuf;
if (0 != DirectoryMarker && 0 != DirectoryMarker->Buffer &&
!DirectoryMarkerFound)
{
DirectoryMarkerFound = 0 == FspFileNameCompare(
&FileName, DirectoryMarker, CaseInsensitive, 0);
continue;
}
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
CopyLength = FileName.Length;
@ -223,7 +224,6 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
*(PULONG)PrevDestBuf = (ULONG)((PUINT8)DestBuf - (PUINT8)PrevDestBuf);
PrevDestBuf = DestBuf;
*PDirectoryOffset = DirInfo->NextOffset;
*PDestLen = (ULONG)((PUINT8)DestBuf + BaseInfoLen + CopyLength - DestBufBgn);
switch (FileInformationClass)
@ -265,6 +265,9 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
break;
}
DirectoryMarkerOut->Length = DirectoryMarkerOut->MaximumLength = FileName.Length;
DirectoryMarkerOut->Buffer = (PVOID)((PUINT8)DestBuf + BaseInfoLen);
DestBuf = (PVOID)((PUINT8)DestBuf +
FSP_FSCTL_ALIGN_UP(BaseInfoLen + CopyLength, sizeof(LONGLONG)));
@ -273,7 +276,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
Loop = FALSE;
}
else
*PDirectoryOffset = DirInfo->NextOffset;
*DirectoryMarkerOut = FileName;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
@ -315,7 +318,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopyCache(
NTSTATUS Result;
BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive;
PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern;
UINT64 DirectoryOffset = FileDesc->DirectoryOffset;
UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker;
PUINT8 DirInfoBgn = (PUINT8)DirInfo;
PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize;
@ -323,17 +326,20 @@ static NTSTATUS FspFsvolQueryDirectoryCopyCache(
DirInfoSize = (ULONG)(DirInfoEnd - (PUINT8)DirInfo);
Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive,
0 != FileDesc->DirInfoCacheHint ? 0 : DirectoryOffset, &DirectoryOffset,
0 != FileDesc->DirInfoCacheHint ? 0 : &FileDesc->DirectoryMarker, &DirectoryMarker,
FileInformationClass, ReturnSingleEntry,
&DirInfo, DirInfoSize,
DestBuf, PDestLen);
if (NT_SUCCESS(Result))
{
if (0 != *PDestLen)
FileDesc->DirectoryHasSuchFile = TRUE;
FileDesc->DirectoryOffset = DirectoryOffset;
FileDesc->DirInfoCacheHint = (ULONG)((PUINT8)DirInfo - DirInfoBgn);
Result = FspFileDescSetDirectoryMarker(FileDesc, &DirectoryMarker);
if (NT_SUCCESS(Result))
{
if (0 != *PDestLen)
FileDesc->DirectoryHasSuchFile = TRUE;
FileDesc->DirInfoCacheHint = (ULONG)((PUINT8)DirInfo - DirInfoBgn);
}
}
else if (STATUS_NO_MORE_FILES == Result && !FileDesc->DirectoryHasSuchFile)
Result = STATUS_NO_SUCH_FILE;
@ -354,7 +360,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
NTSTATUS Result;
BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive;
PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern;
UINT64 DirectoryOffset = FileDesc->DirectoryOffset;
UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker;
ASSERT(DirInfo == DestBuf);
FSP_FSCTL_STATIC_ASSERT(
@ -363,16 +369,19 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
"FSP_FSCTL_DIR_INFO must be bigger than FILE_ID_BOTH_DIR_INFORMATION");
Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive,
0, &DirectoryOffset,
0, &DirectoryMarker,
FileInformationClass, ReturnSingleEntry,
&DirInfo, DirInfoSize,
DestBuf, PDestLen);
if (NT_SUCCESS(Result))
{
if (0 != *PDestLen)
FileDesc->DirectoryHasSuchFile = TRUE;
FileDesc->DirectoryOffset = DirectoryOffset;
Result = FspFileDescSetDirectoryMarker(FileDesc, &DirectoryMarker);
if (NT_SUCCESS(Result))
{
if (0 != *PDestLen)
FileDesc->DirectoryHasSuchFile = TRUE;
}
}
else if (STATUS_NO_MORE_FILES == Result && !FileDesc->DirectoryHasSuchFile)
Result = STATUS_NO_SUCH_FILE;
@ -442,7 +451,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
* counter-productive to try to read more than we need.
*/
#define GetSystemBufferLengthMaybeCached()\
(0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout && 0 == FileDesc->DirectoryOffset) ||\
(0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout && 0 == FileDesc->DirectoryMarker.Buffer) ||\
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ?\
FspFsvolDeviceDirInfoCacheItemSizeMax : Length
#define GetSystemBufferLengthNonCached()\
@ -463,7 +472,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
BOOLEAN ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
PUNICODE_STRING FileName = IrpSp->Parameters.QueryDirectory.FileName;
ULONG FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;
//ULONG FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;
PVOID Buffer = 0 != Irp->AssociatedIrp.SystemBuffer ?
Irp->AssociatedIrp.SystemBuffer : Irp->UserBuffer;
ULONG Length = IrpSp->Parameters.QueryDirectory.Length;
@ -511,26 +520,14 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
Request = 0;
}
/* set the DirectoryPattern in the FileDesc */
Result = FspFileDescResetDirectoryPattern(FileDesc, FileName, RestartScan);
/* reset the FileDesc */
Result = FspFileDescResetDirectory(FileDesc, FileName, RestartScan, IndexSpecified);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
return Result;
}
/* determine where to (re)start */
if (IndexSpecified)
{
FileDesc->DirectoryHasSuchFile = FALSE;
FileDesc->DirectoryOffset = OFFSET_FROM_FILE_INDEX(FileIndex);
}
else if (RestartScan)
{
FileDesc->DirectoryHasSuchFile = FALSE;
FileDesc->DirectoryOffset = 0;
}
/* see if the required information is still in the cache and valid! */
if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize))
{
@ -570,8 +567,10 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
/* create request */
Result = FspIopCreateRequestEx(Irp, 0,
(FsvolDeviceExtension->VolumeParams.PassQueryDirectoryPattern &&
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ?
FileDesc->DirectoryPattern.Length + sizeof(WCHAR) : 0,
FileDesc->DirectoryPattern.Length + sizeof(WCHAR) : 0) +
(FsvolDeviceExtension->VolumeParams.MaxComponentLength + 1) * sizeof(WCHAR),
FspFsvolQueryDirectoryRequestFini, &Request);
if (!NT_SUCCESS(Result))
{
@ -582,19 +581,38 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
Request->Kind = FspFsctlTransactQueryDirectoryKind;
Request->Req.QueryDirectory.UserContext = FileNode->UserContext;
Request->Req.QueryDirectory.UserContext2 = FileDesc->UserContext2;
Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset;
Request->Req.QueryDirectory.Length = SystemBufferLength;
Request->Req.QueryDirectory.CaseSensitive = FileDesc->CaseSensitive;
if (FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer)
if (FsvolDeviceExtension->VolumeParams.PassQueryDirectoryPattern &&
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer)
{
Request->Req.QueryDirectory.Pattern.Offset = Request->FileName.Size;
Request->Req.QueryDirectory.Pattern.Offset =
Request->FileName.Size;
Request->Req.QueryDirectory.Pattern.Size =
FileDesc->DirectoryPattern.Length + sizeof(WCHAR);
RtlCopyMemory(Request->Buffer + Request->FileName.Size,
RtlCopyMemory(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset,
FileDesc->DirectoryPattern.Buffer, FileDesc->DirectoryPattern.Length);
*(PWSTR)(Request->Buffer + Request->FileName.Size + FileDesc->DirectoryPattern.Length) =
L'\0';
*(PWSTR)(Request->Buffer +
Request->Req.QueryDirectory.Pattern.Offset +
FileDesc->DirectoryPattern.Length) = L'\0';
}
if (0 != FileDesc->DirectoryMarker.Buffer)
{
ASSERT(
FsvolDeviceExtension->VolumeParams.MaxComponentLength >=
FileDesc->DirectoryMarker.Length);
Request->Req.QueryDirectory.Marker.Offset =
Request->FileName.Size + Request->Req.QueryDirectory.Pattern.Size;
Request->Req.QueryDirectory.Marker.Size =
FileDesc->DirectoryMarker.Length + sizeof(WCHAR);
RtlCopyMemory(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset,
FileDesc->DirectoryMarker.Buffer, FileDesc->DirectoryMarker.Length);
*(PWSTR)(Request->Buffer +
Request->Req.QueryDirectory.Marker.Offset +
FileDesc->DirectoryMarker.Length) = L'\0';
}
FspFileNodeSetOwner(FileNode, Full, Request);
@ -617,6 +635,7 @@ static NTSTATUS FspFsvolQueryDirectory(
return STATUS_INVALID_DEVICE_REQUEST;
NTSTATUS Result;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
@ -636,7 +655,8 @@ static NTSTATUS FspFsvolQueryDirectory(
return STATUS_INVALID_PARAMETER;
/* check that FileName is valid (if supplied) */
if (0 != FileName && !FspFileNameIsValidPattern(FileName))
if (0 != FileName &&
!FspFileNameIsValidPattern(FileName, FsvolDeviceExtension->VolumeParams.MaxComponentLength))
return STATUS_INVALID_PARAMETER;
/* is this an allowed file information class? */
@ -815,41 +835,67 @@ NTSTATUS FspFsvolDirectoryControlPrepare(
{
PAGED_CODE();
NTSTATUS Result;
PMDL Mdl = 0;
PVOID Address;
PEPROCESS Process;
Mdl = IoAllocateMdl(
Irp->AssociatedIrp.SystemBuffer,
Request->Req.QueryDirectory.Length,
FALSE, FALSE, 0);
if (0 == Mdl)
return STATUS_INSUFFICIENT_RESOURCES;
MmBuildMdlForNonPagedPool(Mdl);
/* map the MDL into user-mode */
Result = FspMapLockedPagesInUserMode(Mdl, &Address, 0);
if (!NT_SUCCESS(Result))
if (FspQueryDirectoryIrpShouldUseProcessBuffer(Irp, Request->Req.QueryDirectory.Length))
{
if (0 != Mdl)
IoFreeMdl(Mdl);
NTSTATUS Result;
PVOID Cookie;
PVOID Address;
PEPROCESS Process;
return Result;
Result = FspProcessBufferAcquire(Request->Req.QueryDirectory.Length, &Cookie, &Address);
if (!NT_SUCCESS(Result))
return Result;
/* get a pointer to the current process so that we can release the buffer later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Request->Req.QueryDirectory.Address = (UINT64)(UINT_PTR)Address;
FspIopRequestContext(Request, RequestCookie) = (PVOID)((UINT_PTR)Cookie | 1);
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
return STATUS_SUCCESS;
}
else
{
NTSTATUS Result;
PMDL Mdl = 0;
PVOID Address;
PEPROCESS Process;
/* get a pointer to the current process so that we can unmap the address later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Mdl = IoAllocateMdl(
Irp->AssociatedIrp.SystemBuffer,
Request->Req.QueryDirectory.Length,
FALSE, FALSE, 0);
if (0 == Mdl)
return STATUS_INSUFFICIENT_RESOURCES;
Request->Req.QueryDirectory.Address = (UINT64)(UINT_PTR)Address;
MmBuildMdlForNonPagedPool(Mdl);
FspIopRequestContext(Request, RequestMdl) = Mdl;
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
/* map the MDL into user-mode */
Result = FspMapLockedPagesInUserMode(Mdl, &Address, 0);
if (!NT_SUCCESS(Result))
{
if (0 != Mdl)
IoFreeMdl(Mdl);
return STATUS_SUCCESS;
return Result;
}
/* get a pointer to the current process so that we can unmap the address later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
Request->Req.QueryDirectory.Address = (UINT64)(UINT_PTR)Address;
FspIopRequestContext(Request, RequestMdl) = Mdl;
FspIopRequestContext(Request, RequestAddress) = Address;
FspIopRequestContext(Request, RequestProcess) = Process;
return STATUS_SUCCESS;
}
}
NTSTATUS FspFsvolDirectoryControlComplete(
@ -882,7 +928,6 @@ NTSTATUS FspFsvolDirectoryControlComplete(
BOOLEAN Success;
ASSERT(FileNode == FileDesc->FileNode);
ASSERT(Request->Req.QueryDirectory.Offset == FileDesc->DirectoryOffset);
if (0 == Response->IoStatus.Information)
{
@ -893,6 +938,23 @@ NTSTATUS FspFsvolDirectoryControlComplete(
if (FspFsctlTransactQueryDirectoryKind == Request->Kind)
{
if ((UINT_PTR)FspIopRequestContext(Request, RequestCookie) & 1)
{
PVOID Address = FspIopRequestContext(Request, RequestAddress);
ASSERT(0 != Address);
try
{
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Address, Response->IoStatus.Information);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Result = GetExceptionCode();
Result = FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
FSP_RETURN();
}
}
DirInfoChangeNumber = FspFileNodeDirInfoChangeNumber(FileNode);
Request->Kind = FspFsctlTransactReservedKind;
FspIopResetRequest(Request, 0);
@ -910,7 +972,8 @@ NTSTATUS FspFsvolDirectoryControlComplete(
FSP_RETURN();
}
if (0 == FileDesc->DirectoryOffset &&
if (0 == Request->Req.QueryDirectory.Pattern.Size &&
0 == Request->Req.QueryDirectory.Marker.Size &&
FspFileNodeTrySetDirInfo(FileNode,
Irp->AssociatedIrp.SystemBuffer,
(ULONG)Response->IoStatus.Information,
@ -949,7 +1012,24 @@ NTSTATUS FspFsvolDirectoryControlComplete(
FspIopResetRequest(Request, FspFsvolQueryDirectoryRequestFini);
Request->Req.QueryDirectory.Address = 0;
Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset;
Request->Req.QueryDirectory.Marker.Offset = 0;
Request->Req.QueryDirectory.Marker.Size = 0;
if (0 != FileDesc->DirectoryMarker.Buffer)
{
ASSERT(
FsvolDeviceExtension->VolumeParams.MaxComponentLength >=
FileDesc->DirectoryMarker.Length);
Request->Req.QueryDirectory.Marker.Offset =
Request->FileName.Size + Request->Req.QueryDirectory.Pattern.Size;
Request->Req.QueryDirectory.Marker.Size =
FileDesc->DirectoryMarker.Length + sizeof(WCHAR);
RtlCopyMemory(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset,
FileDesc->DirectoryMarker.Buffer, FileDesc->DirectoryMarker.Length);
*(PWSTR)(Request->Buffer +
Request->Req.QueryDirectory.Marker.Offset +
FileDesc->DirectoryMarker.Length) = L'\0';
}
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp;
@ -975,29 +1055,56 @@ static VOID FspFsvolQueryDirectoryRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
PAGED_CODE();
PIRP Irp = Context[RequestIrp];
PMDL Mdl = Context[RequestMdl];
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
if (0 != Address)
if ((UINT_PTR)Context[RequestCookie] & 1)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
PVOID Cookie = (PVOID)((UINT_PTR)Context[RequestCookie] & ~1);
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
if (0 != Address)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
if (Attach)
KeStackAttachProcess(Process, &ApcState);
MmUnmapLockedPages(Address, Mdl);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
ObDereferenceObject(Process);
if (Attach)
KeStackAttachProcess(Process, &ApcState);
FspProcessBufferRelease(Cookie, Address);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
}
}
else
{
PMDL Mdl = Context[RequestMdl];
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
if (0 != Mdl)
IoFreeMdl(Mdl);
if (0 != Address)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
if (Attach)
KeStackAttachProcess(Process, &ApcState);
MmUnmapLockedPages(Address, Mdl);
if (Attach)
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
}
if (0 != Mdl)
IoFreeMdl(Mdl);
}
if (0 != Irp)
{

View File

@ -1,7 +1,7 @@
/**
* @file sys/driver.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -46,6 +46,10 @@ NTSTATUS DriverEntry(
FspDriverMultiVersionInitialize();
Result = FspProcessBufferInitialize();
if (!NT_SUCCESS(Result))
FSP_RETURN();
FspDriverObject = DriverObject;
ExInitializeResourceLite(&FspDeviceGlobalResource);
@ -59,14 +63,21 @@ NTSTATUS DriverEntry(
&DeviceSddl, &FspFsctlDeviceClassGuid,
&FspFsctlDiskDeviceObject);
if (!NT_SUCCESS(Result))
{
FspProcessBufferFinalize();
FSP_RETURN();
}
RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
&DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
&DeviceSddl, &FspFsctlDeviceClassGuid,
&FspFsctlNetDeviceObject);
if (!NT_SUCCESS(Result))
FSP_RETURN(FspDeviceDelete(FspFsctlDiskDeviceObject));
{
FspDeviceDelete(FspFsctlDiskDeviceObject);
FspProcessBufferFinalize();
FSP_RETURN();
}
Result = FspDeviceInitialize(FspFsctlDiskDeviceObject);
ASSERT(STATUS_SUCCESS == Result);
Result = FspDeviceInitialize(FspFsctlNetDeviceObject);
@ -176,6 +187,9 @@ NTSTATUS DriverEntry(
static VOID FspDriverMultiVersionInitialize(VOID)
{
FspProcessorCount = KeQueryActiveProcessorCount(0);
#pragma prefast(suppress:30035, "FspDriverMultiVersionInitialize is called from DriverEntry")
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
if (RtlIsNtDdiVersionAvailable(NTDDI_WIN7))
@ -204,6 +218,8 @@ VOID FspUnload(
ExDeleteResourceLite(&FspDeviceGlobalResource);
FspDriverObject = 0;
FspProcessBufferFinalize();
#pragma prefast(suppress:28175, "We are in DriverUnload: ok to access DriverName")
FSP_LEAVE_VOID("DriverName=\"%wZ\"",
&DriverObject->DriverName);
@ -216,5 +232,6 @@ PDEVICE_OBJECT FspFsctlNetDeviceObject;
FAST_IO_DISPATCH FspFastIoDispatch;
CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks;
ULONG FspProcessorCount;
FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;
ULONG FspMvMdlMappingNoWrite = 0;

View File

@ -1,7 +1,7 @@
/**
* @file sys/driver.h
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -40,6 +40,7 @@
/* private NTSTATUS codes */
#define FSP_STATUS_PRIVATE_BIT (0x20000000)
#define FSP_STATUS_IGNORE_BIT (0x10000000)
#define FSP_STATUS_IOQ_POST (FSP_STATUS_PRIVATE_BIT | 0x0000)
#define FSP_STATUS_IOQ_POST_BEST_EFFORT (FSP_STATUS_PRIVATE_BIT | 0x0001)
@ -198,7 +199,7 @@ VOID FspDebugLogIrp(const char *func, PIRP Irp, NTSTATUS Result);
} while (0,0)
#define FSP_LEAVE_MJ(fmt, ...) \
FSP_LEAVE_( \
if (STATUS_PENDING != Result) \
if (STATUS_PENDING != Result && !(FSP_STATUS_IGNORE_BIT & Result))\
{ \
ASSERT(0 == (FSP_STATUS_PRIVATE_BIT & Result) ||\
FSP_STATUS_IOQ_POST == Result || FSP_STATUS_IOQ_POST_BEST_EFFORT == Result);\
@ -225,6 +226,8 @@ VOID FspDebugLogIrp(const char *func, PIRP Irp, NTSTATUS Result);
else \
FspIopCompleteIrpEx(Irp, Result, fsp_device_deref);\
} \
else \
Result &= ~FSP_STATUS_IGNORE_BIT;\
IoSetTopLevelIrp(fsp_top_level_irp);\
); \
return Result
@ -437,8 +440,9 @@ enum
FspFileNameStreamTypeNone = 0,
FspFileNameStreamTypeData = 1,
};
BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType);
BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Pattern);
BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, ULONG MaxComponentLength,
PUNICODE_STRING StreamPart, PULONG StreamType);
BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Pattern, ULONG MaxComponentLength);
VOID FspFileNameSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
#if 0
NTSTATUS FspFileNameUpcase(
@ -597,6 +601,14 @@ VOID FspIrpHookReset(PIRP Irp);
PVOID FspIrpHookContext(PVOID Context);
NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
/* process buffers */
#define FspProcessBufferSizeMax (64 * 1024)
NTSTATUS FspProcessBufferInitialize(VOID);
VOID FspProcessBufferFinalize(VOID);
VOID FspProcessBufferCollect(HANDLE ProcessId);
NTSTATUS FspProcessBufferAcquire(SIZE_T BufferSize, PVOID *PBufferCookie, PVOID *PBuffer);
VOID FspProcessBufferRelease(PVOID BufferCookie, PVOID Buffer);
/* IRP context */
#define FspIrpTimestampInfinity ((ULONG)-1L)
#define FspIrpTimestamp(Irp) \
@ -910,7 +922,7 @@ BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
VOID FspIopSetIrpResponse(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
FSP_FSCTL_TRANSACT_RSP *FspIopIrpResponse(PIRP Irp);
NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request);
NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
NTSTATUS FspIopDispatchComplete(PIRP Irp, FSP_FSCTL_TRANSACT_RSP *Response);
static inline
VOID FspIrpDeleteRequest(PIRP Irp)
{
@ -948,6 +960,21 @@ VOID FspWqPostIrpWorkItem(PIRP Irp);
#define FspWqRepostIrpWorkItem(I, RW, RF)\
FspWqCreateAndPostIrpWorkItem(I, RW, RF, TRUE)
/* file system statistics */
typedef struct
{
FILESYSTEM_STATISTICS Base;
FAT_STATISTICS Specific; /* pretend that we are FAT when it comes to stats */
/* align to 64 bytes */
__declspec(align(64)) UINT8 EndOfStruct[];
} FSP_STATISTICS;
NTSTATUS FspStatisticsCreate(FSP_STATISTICS **PStatistics);
VOID FspStatisticsDelete(FSP_STATISTICS *Statistics);
NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLength);
#define FspStatistics(S) (&(S)[KeGetCurrentProcessorNumber() % FspProcessorCount])
#define FspStatisticsInc(S,F) ((S)->F++)
#define FspStatisticsAdd(S,F,V) ((S)->F += (V))
/* device management */
enum
{
@ -989,7 +1016,7 @@ typedef struct
{
FSP_DEVICE_EXTENSION Base;
UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, InitDoneStrm:1,
InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1;
InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1, InitDoneStat:1;
PDEVICE_OBJECT FsctlDeviceObject;
PDEVICE_OBJECT FsvrtDeviceObject;
HANDLE MupHandle;
@ -1006,6 +1033,7 @@ typedef struct
BOOLEAN ExpirationInProgress;
ERESOURCE FileRenameResource;
ERESOURCE ContextTableResource;
LIST_ENTRY ContextList;
RTL_AVL_TABLE ContextByNameTable;
PVOID ContextByNameTableElementStorage;
UNICODE_STRING VolumeName;
@ -1015,6 +1043,7 @@ typedef struct
FSP_FSCTL_VOLUME_INFO VolumeInfo;
PNOTIFY_SYNC NotifySync;
LIST_ENTRY NotifyList;
FSP_STATISTICS *Statistics;
} FSP_FSVOL_DEVICE_EXTENSION;
static inline
FSP_DEVICE_EXTENSION *FspDeviceExtension(PDEVICE_OBJECT DeviceObject)
@ -1043,11 +1072,14 @@ VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
BOOLEAN FspFsvolDeviceFileRenameIsAcquiredExclusive(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject);
NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount);
NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount);
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
VOID FspFsvolDeviceDeleteContextList(PVOID *Contexts, ULONG ContextCount);
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
BOOLEAN NextFlag, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY *RestartKey);
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
@ -1082,11 +1114,42 @@ VOID FspDeviceGlobalUnlock(VOID)
extern ERESOURCE FspDeviceGlobalResource;
ExReleaseResourceLite(&FspDeviceGlobalResource);
}
#define FspFsvolDeviceStatistics(DeviceObject)\
FspStatistics(FspFsvolDeviceExtension(DeviceObject)->Statistics)
#define FspFsvolDeviceStoppedStatus(DeviceObject)\
STATUS_VOLUME_DISMOUNTED
//(FILE_DEVICE_DISK_FILE_SYSTEM == (DeviceObject)->DeviceType ?\
// STATUS_VOLUME_DISMOUNTED : STATUS_DEVICE_NOT_CONNECTED)
/* process buffers conditional usage */
static inline
BOOLEAN FspReadIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
{
ASSERT(0 != Irp);
#if DBG
return DEBUGTEST(50) ||
#else
return FspProcessBufferSizeMax >= BufferSize ||
#endif
FspFsvolDeviceExtension(IoGetCurrentIrpStackLocation(Irp)->DeviceObject)->
VolumeParams.AlwaysUseDoubleBuffering;
}
static inline
BOOLEAN FspWriteIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
{
ASSERT(0 != Irp);
#if DBG
return DEBUGTEST(50);
#else
return FspProcessBufferSizeMax >= BufferSize;
#endif
}
static inline
BOOLEAN FspQueryDirectoryIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
{
return FspReadIrpShouldUseProcessBuffer(Irp, BufferSize);
}
/* volume management */
#define FspVolumeTransactEarlyTimeout (1 * 10000ULL)
NTSTATUS FspVolumeCreate(
@ -1147,11 +1210,13 @@ typedef struct FSP_FILE_NODE
LONG RefCount;
UINT32 DeletePending;
/* locked under FSP_FSVOL_DEVICE_EXTENSION::ContextTableResource */
LONG ActiveCount; /* CREATE w/o CLOSE count */
LONG OpenCount; /* ContextTable ref count */
LONG HandleCount; /* HANDLE count (CREATE/CLEANUP) */
SHARE_ACCESS ShareAccess;
ULONG MainFileDenyDeleteCount; /* number of times main file is denying delete */
ULONG StreamDenyDeleteCount; /* number of times open streams are denying delete */
LIST_ENTRY ActiveEntry;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT ContextByNameElementStorage;
/* locked under FSP_FSVOL_DEVICE_EXTENSION::FileRenameResource or Header.Resource */
UNICODE_STRING FileName;
@ -1189,26 +1254,31 @@ typedef struct FSP_FILE_NODE
UINT64 IndexNumber;
BOOLEAN IsDirectory;
BOOLEAN IsRootDirectory;
struct FSP_FILE_NODE *MainFileNode; /* this becomes invalid after our last desc close */
struct FSP_FILE_NODE *MainFileNode;
WCHAR FileNameBuf[];
} FSP_FILE_NODE;
typedef struct
{
FSP_FILE_NODE *FileNode;
UINT64 UserContext2;
BOOLEAN CaseSensitive;
BOOLEAN HasTraversePrivilege;
BOOLEAN DeleteOnClose;
BOOLEAN DirectoryHasSuchFile;
UINT32 GrantedAccess;
UINT32
CaseSensitive:1, HasTraversePrivilege:1, DeleteOnClose:1,
DidSetMetadata:1,
DidSetFileAttributes:1, DidSetReparsePoint:1, DidSetSecurity:1,
DidSetCreationTime:1, DidSetLastAccessTime:1, DidSetLastWriteTime:1, DidSetChangeTime:1,
DirectoryHasSuchFile:1;
UNICODE_STRING DirectoryPattern;
UINT64 DirectoryOffset;
UNICODE_STRING DirectoryMarker;
UINT64 DirInfo;
ULONG DirInfoCacheHint;
/* stream support */
HANDLE MainFileHandle;
PFILE_OBJECT MainFileObject;
} FSP_FILE_DESC;
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
NTSTATUS FspFileNodeCopyActiveList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
NTSTATUS FspFileNodeCopyOpenList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
VOID FspFileNodeDeleteList(FSP_FILE_NODE **FileNodes, ULONG FileNodeCount);
NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
@ -1258,8 +1328,7 @@ VOID FspFileNodeReleaseForeign(FSP_FILE_NODE *FileNode)
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
UINT32 GrantedAccess, UINT32 ShareAccess,
FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PBOOLEAN PDeletePending);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PULONG PCleanupFlags);
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
PFILE_OBJECT FileObject, /* non-0 to remove share access */
@ -1280,9 +1349,10 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo);
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
static inline
ULONG FspFileNodeFileInfoChangeNumber(FSP_FILE_NODE *FileNode)
{
@ -1312,6 +1382,7 @@ ULONG FspFileNodeDirInfoChangeNumber(FSP_FILE_NODE *FileNode)
{
return FileNode->DirInfoChangeNumber;
}
VOID FspFileNodeInvalidateParentDirInfo(FSP_FILE_NODE *FileNode);
BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
VOID FspFileNodeSetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
@ -1323,12 +1394,16 @@ ULONG FspFileNodeStreamInfoChangeNumber(FSP_FILE_NODE *FileNode)
FileNode = FileNode->MainFileNode;
return FileNode->StreamInfoChangeNumber;
}
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action);
VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode);
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action,
BOOLEAN InvalidateCaches);
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN Reset);
NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN RestartScan, BOOLEAN IndexSpecified);
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName);
NTSTATUS FspMainFileOpen(
PDEVICE_OBJECT FsvolDeviceObject,
PDEVICE_OBJECT DeviceObjectHint,
@ -1483,6 +1558,7 @@ extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[];
extern ERESOURCE FspDeviceGlobalResource;
extern WCHAR FspFileDescDirectoryPatternMatchAll[];
extern const GUID FspMainFileOpenEcpGuid;
extern ULONG FspProcessorCount;
extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;
extern ULONG FspMvMdlMappingNoWrite;

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

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

View File

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

View File

@ -1,7 +1,7 @@
/**
* @file sys/file.c
*
* @copyright 2015-2016 Bill Zissimopoulos
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -17,7 +17,9 @@
#include <sys/driver.h>
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
NTSTATUS FspFileNodeCopyActiveList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
NTSTATUS FspFileNodeCopyOpenList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
VOID FspFileNodeDeleteList(FSP_FILE_NODE **FileNodes, ULONG FileNodeCount);
NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
@ -34,8 +36,7 @@ VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
UINT32 GrantedAccess, UINT32 ShareAccess,
FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PBOOLEAN PDeletePending);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PULONG PCleanupFlags);
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
PFILE_OBJECT FileObject, /* non-0 to remove share access */
@ -56,9 +57,10 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo);
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
@ -68,19 +70,24 @@ VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG DirInfoChangeNumber);
static VOID FspFileNodeInvalidateDirInfo(FSP_FILE_NODE *FileNode);
static VOID FspFileNodeInvalidateDirInfoByName(PDEVICE_OBJECT FsvolDeviceObject,
PUNICODE_STRING FileName);
VOID FspFileNodeInvalidateParentDirInfo(FSP_FILE_NODE *FileNode);
BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
VOID FspFileNodeSetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG StreamInfoChangeNumber);
static VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode);
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
ULONG Filter, ULONG Action);
VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode);
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action,
BOOLEAN InvalidateCaches);
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
static NTSTATUS FspFileNodeCompleteLockIrp(PVOID Context, PIRP Irp);
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN Reset);
NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN RestartScan, BOOLEAN IndexSpecified);
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName);
NTSTATUS FspMainFileOpen(
PDEVICE_OBJECT FsvolDeviceObject,
PDEVICE_OBJECT DeviceObjectHint,
@ -97,7 +104,8 @@ VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp);
VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFileNodeCopyList)
#pragma alloc_text(PAGE, FspFileNodeCopyActiveList)
#pragma alloc_text(PAGE, FspFileNodeCopyOpenList)
#pragma alloc_text(PAGE, FspFileNodeDeleteList)
#pragma alloc_text(PAGE, FspFileNodeCreate)
#pragma alloc_text(PAGE, FspFileNodeDelete)
@ -122,6 +130,7 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
#pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeSetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeInvalidateFileInfo)
#pragma alloc_text(PAGE, FspFileNodeReferenceSecurity)
#pragma alloc_text(PAGE, FspFileNodeSetSecurity)
#pragma alloc_text(PAGE, FspFileNodeTrySetSecurity)
@ -129,6 +138,8 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
// !#pragma alloc_text(PAGE, FspFileNodeSetDirInfo)
// !#pragma alloc_text(PAGE, FspFileNodeTrySetDirInfo)
// !#pragma alloc_text(PAGE, FspFileNodeInvalidateDirInfo)
#pragma alloc_text(PAGE, FspFileNodeInvalidateDirInfoByName)
#pragma alloc_text(PAGE, FspFileNodeInvalidateParentDirInfo)
// !#pragma alloc_text(PAGE, FspFileNodeReferenceStreamInfo)
// !#pragma alloc_text(PAGE, FspFileNodeSetStreamInfo)
// !#pragma alloc_text(PAGE, FspFileNodeTrySetStreamInfo)
@ -138,7 +149,8 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
#pragma alloc_text(PAGE, FspFileNodeCompleteLockIrp)
#pragma alloc_text(PAGE, FspFileDescCreate)
#pragma alloc_text(PAGE, FspFileDescDelete)
#pragma alloc_text(PAGE, FspFileDescResetDirectoryPattern)
#pragma alloc_text(PAGE, FspFileDescResetDirectory)
#pragma alloc_text(PAGE, FspFileDescSetDirectoryMarker)
#pragma alloc_text(PAGE, FspMainFileOpen)
#pragma alloc_text(PAGE, FspMainFileClose)
#pragma alloc_text(PAGE, FspFileNodeOplockPrepare)
@ -162,7 +174,86 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
if (IrpValid) \
FspIrpSetFlags(Irp, FspIrpFlags(Irp) & (~Flags & 3))
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
#define GATHER_DESCENDANTS(FILENAME, REFERENCE, ...)\
FSP_FILE_NODE *DescendantFileNode;\
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;\
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;\
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;\
DescendantFileNodes = DescendantFileNodeArray;\
DescendantFileNodeCount = 0;\
memset(&RestartKey, 0, sizeof RestartKey);\
for (;;) \
{ \
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
FILENAME, FALSE, &RestartKey);\
if (0 == DescendantFileNode) \
break; \
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
__VA_ARGS__; \
if (REFERENCE) \
FspFileNodeReference((PVOID)((UINT_PTR)DescendantFileNode & ~7));\
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)\
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;\
DescendantFileNodeCount++; \
} \
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount ||\
DEBUGTEST_EX(0 != DescendantFileNodeCount, 10, FALSE)) \
{ \
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));\
DescendantFileNodeIndex = 0; \
memset(&RestartKey, 0, sizeof RestartKey);\
for (;;) \
{ \
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
FILENAME, FALSE, &RestartKey);\
if (0 == DescendantFileNode)\
break; \
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
__VA_ARGS__; \
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode;\
DescendantFileNodeIndex++; \
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);\
} \
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);\
} \
((VOID)0)
#define SCATTER_DESCENDANTS(REFERENCE) \
if (REFERENCE) \
{ \
for ( \
DescendantFileNodeIndex = 0;\
DescendantFileNodeCount > DescendantFileNodeIndex;\
DescendantFileNodeIndex++) \
{ \
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];\
FspFileNodeDereference((PVOID)((UINT_PTR)DescendantFileNode & ~7));\
} \
} \
if (DescendantFileNodeArray != DescendantFileNodes)\
FspFree(DescendantFileNodes); \
((VOID)0)
NTSTATUS FspFileNodeCopyActiveList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount)
{
PAGED_CODE();
NTSTATUS Result;
ULONG Index;
FspFsvolDeviceLockContextTable(DeviceObject);
Result = FspFsvolDeviceCopyContextList(DeviceObject, PFileNodes, PFileNodeCount);
if (NT_SUCCESS(Result))
{
for (Index = 0; *PFileNodeCount > Index; Index++)
FspFileNodeReference((*PFileNodes)[Index]);
}
FspFsvolDeviceUnlockContextTable(DeviceObject);
return Result;
}
NTSTATUS FspFileNodeCopyOpenList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount)
{
PAGED_CODE();
@ -191,7 +282,7 @@ VOID FspFileNodeDeleteList(FSP_FILE_NODE **FileNodes, ULONG FileNodeCount)
for (Index = 0; FileNodeCount > Index; Index++)
FspFileNodeDereference(FileNodes[Index]);
FspFsvolDeviceDeleteContextByNameList(FileNodes, FileNodeCount);
FspFsvolDeviceDeleteContextList(FileNodes, FileNodeCount);
}
NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
@ -248,6 +339,9 @@ VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode)
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
if (0 != FileNode->MainFileNode)
FspFileNodeDereference(FileNode->MainFileNode);
FsRtlUninitializeOplock(FspFileNodeAddrOfOplock(FileNode));
FsRtlUninitializeFileLock(&FileNode->FileLock);
@ -624,6 +718,14 @@ exit:
if (0 != OpenedFileNode)
{
FspFileNodeReference(OpenedFileNode);
ASSERT(0 <= OpenedFileNode->ActiveCount);
ASSERT(0 <= OpenedFileNode->OpenCount);
ASSERT(0 <= OpenedFileNode->HandleCount);
if (0 == OpenedFileNode->ActiveCount++)
InsertTailList(&FspFsvolDeviceExtension(FsvolDeviceObject)->ContextList,
&FileNode->ActiveEntry);
OpenedFileNode->OpenCount++;
OpenedFileNode->HandleCount++;
}
@ -635,8 +737,7 @@ exit:
return Result;
}
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PBOOLEAN PDeletePending)
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PULONG PCleanupFlags)
{
/*
* Determine whether a FileNode should be deleted. Note that when FileNode->DeletePending
@ -650,7 +751,7 @@ VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
BOOLEAN DeletePending, SingleHandle;
BOOLEAN DeletePending, SetAllocationSize, SingleHandle;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
@ -659,12 +760,13 @@ VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
DeletePending = 0 != FileNode->DeletePending;
MemoryBarrier();
SetAllocationSize = !DeletePending && FileNode->TruncateOnClose;
SingleHandle = 1 == FileNode->HandleCount;
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (0 != PDeletePending)
*PDeletePending = SingleHandle && DeletePending;
*PCleanupFlags = SingleHandle ? DeletePending | (SetAllocationSize << 1) : 0;
}
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject)
@ -684,7 +786,7 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
PAGED_CODE();
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
LARGE_INTEGER TruncateSize = { 0 }, *PTruncateSize = 0;
LARGE_INTEGER TruncateSize, *PTruncateSize = 0;
BOOLEAN DeletePending;
BOOLEAN DeletedFromContextTable = FALSE;
@ -708,6 +810,7 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
IoRemoveShareAccess(FileObject, &FileNode->ShareAccess);
ASSERT(0 < FileNode->HandleCount);
if (0 == --FileNode->HandleCount)
{
DeletePending = 0 != FileNode->DeletePending;
@ -715,23 +818,72 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
if (DeletePending)
{
PTruncateSize = &TruncateSize;
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName,
&DeletedFromContextTable);
ASSERT(DeletedFromContextTable);
FileNode->OpenCount = 0;
FileNode->Header.FileSize.QuadPart = 0;
/*
* We now have to deal with the scenario where there are cleaned up,
* but unclosed streams for this file still in the context table.
*/
if (FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.NamedStreams &&
0 == FileNode->MainFileNode)
{
BOOLEAN StreamDeletedFromContextTable;
USHORT FileNameLength = FileNode->FileName.Length;
GATHER_DESCENDANTS(&FileNode->FileName, FALSE,
if (DescendantFileNode->FileName.Length > FileNameLength &&
L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)])
break;
ASSERT(FileNode != DescendantFileNode);
ASSERT(0 != DescendantFileNode->OpenCount);
ASSERT(0 == DescendantFileNode->HandleCount);
);
for (
DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &DescendantFileNode->FileName,
&StreamDeletedFromContextTable);
if (StreamDeletedFromContextTable)
{
DescendantFileNode->OpenCount = 0;
FspFileNodeDereference(DescendantFileNode);
}
}
SCATTER_DESCENDANTS(FALSE);
}
}
else if (FileNode->TruncateOnClose && FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
if (DeletePending || FileNode->TruncateOnClose)
{
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FsvolDeviceObject);
UINT64 AllocationUnit =
FsvolDeviceExtension->VolumeParams.SectorSize *
FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit;
/*
* Even when the FileInfo is expired, this is the best guess for a file size
* without asking the user-mode file system.
*/
TruncateSize = FileNode->Header.FileSize;
PTruncateSize = &TruncateSize;
FileNode->Header.AllocationSize.QuadPart = (TruncateSize.QuadPart + AllocationUnit - 1)
/ AllocationUnit * AllocationUnit;
}
FileNode->TruncateOnClose = FALSE;
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
@ -791,6 +943,15 @@ VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
ASSERT(DeletedFromContextTable);
}
ASSERT(0 < FileNode->ActiveCount);
if (0 == --FileNode->ActiveCount)
{
ASSERT(0 == FileNode->OpenCount);
ASSERT(0 == FileNode->HandleCount);
RemoveEntryList(&FileNode->ActiveEntry);
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (DeletedFromContextTable)
@ -854,65 +1015,6 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
return IoStatus.Status;
}
#define GATHER_DESCENDANTS(FILENAME, REFERENCE, ...)\
FSP_FILE_NODE *DescendantFileNode;\
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;\
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;\
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;\
DescendantFileNodes = DescendantFileNodeArray;\
DescendantFileNodeCount = 0;\
memset(&RestartKey, 0, sizeof RestartKey);\
for (;;) \
{ \
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
FILENAME, FALSE, &RestartKey);\
if (0 == DescendantFileNode) \
break; \
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
__VA_ARGS__; \
if (REFERENCE) \
FspFileNodeReference((PVOID)((UINT_PTR)DescendantFileNode & ~7));\
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)\
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;\
DescendantFileNodeCount++; \
} \
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount ||\
DEBUGTEST_EX(0 != DescendantFileNodeCount, 10, FALSE)) \
{ \
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));\
DescendantFileNodeIndex = 0; \
memset(&RestartKey, 0, sizeof RestartKey);\
for (;;) \
{ \
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
FILENAME, FALSE, &RestartKey);\
if (0 == DescendantFileNode)\
break; \
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
__VA_ARGS__; \
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode;\
DescendantFileNodeIndex++; \
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);\
} \
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);\
} \
((VOID)0)
#define SCATTER_DESCENDANTS(REFERENCE) \
if (REFERENCE) \
{ \
for ( \
DescendantFileNodeIndex = 0;\
DescendantFileNodeCount > DescendantFileNodeIndex;\
DescendantFileNodeIndex++) \
{ \
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];\
FspFileNodeDereference((PVOID)((UINT_PTR)DescendantFileNode & ~7));\
} \
} \
if (DescendantFileNodeArray != DescendantFileNodes)\
FspFree(DescendantFileNodes); \
((VOID)0)
VOID FspFileNodeOverwriteStreams(FSP_FILE_NODE *FileNode)
{
/*
@ -1141,6 +1243,50 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp
}
}
/* flush and purge cleaned up but still open files affected by rename (github issue #45) */
{
PIRP TopLevelIrp;
IO_STATUS_BLOCK IoStatus;
/* reset the top-level IRP to avoid deadlock on the FileNodes' resources */
TopLevelIrp = IoGetTopLevelIrp();
IoSetTopLevelIrp(0);
/* enumerate in reverse order so that files are flushed before containing directories */
for (
DescendantFileNodeIndex = DescendantFileNodeCount - 1;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex--)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
HasHandles = (UINT_PTR)DescendantFileNode & 1;
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
if (HasHandles)
continue;
if (CheckingOldName &&
(DescendantFileNode->FileName.Length <= FileName->Length ||
L'\\' != DescendantFileNode->FileName.Buffer[FileName->Length / sizeof(WCHAR)]))
continue;
if (MmDoesFileHaveUserWritableReferences(&DescendantFileNode->NonPaged->SectionObjectPointers))
continue;
/*
* There are no handles and no writable user mappings. [Ideally we would want to know
* that there are no handles and no user mappings, period. Is there an DDI/method to
* do that?] There may be a read-only user mapping, but in this case CcFlushCache
* should be a no-op and MmForceSectionClosed will fail (which is fine).
*/
ASSERT(DescendantFileNode != FileNode && DescendantFileNode->MainFileNode != FileNode);
FspCcFlushCache(&DescendantFileNode->NonPaged->SectionObjectPointers, 0, 0, &IoStatus);
MmForceSectionClosed(&DescendantFileNode->NonPaged->SectionObjectPointers, FALSE);
}
IoSetTopLevelIrp(TopLevelIrp);
}
/* break any Batch or Handle oplocks on descendants */
Result = STATUS_SUCCESS;
for (
@ -1237,8 +1383,7 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp
if (0 == DescendantFileNode)
break;
/* if this is the FileNode being renamed then HandleCount must be 1, else 0 */
if ((DescendantFileNode == FileNode) < DescendantFileNode->HandleCount)
if (DescendantFileNode != FileNode && 0 < DescendantFileNode->HandleCount)
{
/* release the FileNode in case of failure! */
FspFileNodeReleaseF(FileNode, AcquireFlags);
@ -1406,7 +1551,7 @@ BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *
}
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo)
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose)
{
PAGED_CODE();
@ -1420,8 +1565,20 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit;
AllocationSize = (AllocationSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
FileNode->Header.AllocationSize.QuadPart = AllocationSize;
FileNode->Header.FileSize.QuadPart = FileInfo->FileSize;
if (TruncateOnClose)
{
if ((UINT64)FileNode->Header.AllocationSize.QuadPart != AllocationSize ||
(UINT64)FileNode->Header.FileSize.QuadPart != FileInfo->FileSize)
FileNode->TruncateOnClose = TRUE;
FileNode->Header.AllocationSize.QuadPart = AllocationSize;
FileNode->Header.FileSize.QuadPart = FileInfo->FileSize;
}
else
{
FileNode->Header.AllocationSize.QuadPart = AllocationSize;
FileNode->Header.FileSize.QuadPart = FileInfo->FileSize;
}
FileNode->FileInfoExpirationTime = FileNode->BasicInfoExpirationTime =
FspExpirationTimeFromMillis(FsvolDeviceExtension->VolumeParams.FileInfoTimeout);
@ -1511,10 +1668,20 @@ BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileOb
if (FspFileNodeFileInfoChangeNumber(FileNode) != InfoChangeNumber)
return FALSE;
FspFileNodeSetFileInfo(FileNode, CcFileObject, FileInfo);
FspFileNodeSetFileInfo(FileNode, CcFileObject, FileInfo, FALSE);
return TRUE;
}
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode)
{
PAGED_CODE();
FileNode->FileInfoExpirationTime = FileNode->BasicInfoExpirationTime = 0;
if (0 != FileNode->MainFileNode)
FileNode->MainFileNode->BasicInfoExpirationTime = 0;
}
BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize)
{
PAGED_CODE();
@ -1627,6 +1794,40 @@ static VOID FspFileNodeInvalidateDirInfo(FSP_FILE_NODE *FileNode)
FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, DirInfo);
}
static VOID FspFileNodeInvalidateDirInfoByName(PDEVICE_OBJECT FsvolDeviceObject,
PUNICODE_STRING FileName)
{
PAGED_CODE();
FSP_FILE_NODE *FileNode;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
FileNode = FspFsvolDeviceLookupContextByName(FsvolDeviceObject, FileName);
if (0 != FileNode)
FspFileNodeReference(FileNode);
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (0 != FileNode)
{
FspFileNodeInvalidateDirInfo(FileNode);
FspFileNodeDereference(FileNode);
}
}
VOID FspFileNodeInvalidateParentDirInfo(FSP_FILE_NODE *FileNode)
{
PAGED_CODE();
if (sizeof(WCHAR) == FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0])
return; /* root does not have a parent */
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
UNICODE_STRING Parent, Suffix;
FspFileNameSuffix(&FileNode->FileName, &Parent, &Suffix);
FspFileNodeInvalidateDirInfoByName(FsvolDeviceObject, &Parent);
}
BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize)
{
// !PAGED_CODE();
@ -1685,7 +1886,7 @@ BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULON
return TRUE;
}
static VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode)
VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode)
{
// !PAGED_CODE();
@ -1706,8 +1907,8 @@ static VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode)
FspMetaCacheInvalidateItem(FsvolDeviceExtension->StreamInfoCache, StreamInfo);
}
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
ULONG Filter, ULONG Action)
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action,
BOOLEAN InvalidateCaches)
{
/* FileNode must be acquired (exclusive or shared) Main */
@ -1716,32 +1917,6 @@ VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
UNICODE_STRING Parent, Suffix;
FSP_FILE_NODE *ParentNode;
FspFileNameSuffix(&FileNode->FileName, &Parent, &Suffix);
switch (Action)
{
case FILE_ACTION_ADDED:
case FILE_ACTION_REMOVED:
//case FILE_ACTION_MODIFIED:
case FILE_ACTION_RENAMED_OLD_NAME:
case FILE_ACTION_RENAMED_NEW_NAME:
FspFsvolDeviceInvalidateVolumeInfo(FsvolDeviceObject);
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
ParentNode = FspFsvolDeviceLookupContextByName(FsvolDeviceObject, &Parent);
if (0 != ParentNode)
FspFileNodeReference(ParentNode);
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (0 != ParentNode)
{
FspFileNodeInvalidateDirInfo(ParentNode);
FspFileNodeDereference(ParentNode);
}
break;
}
if (0 != FileNode->MainFileNode)
{
@ -1749,65 +1924,78 @@ VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
SetFlag(Filter, FILE_NOTIFY_CHANGE_STREAM_NAME);
if (FlagOn(Filter, FILE_NOTIFY_CHANGE_SIZE))
SetFlag(Filter, FILE_NOTIFY_CHANGE_STREAM_SIZE);
/* ???: what about FILE_NOTIFY_CHANGE_STREAM_WRITE */
ClearFlag(Filter, ~(FILE_NOTIFY_CHANGE_STREAM_NAME | FILE_NOTIFY_CHANGE_STREAM_SIZE));
if (FlagOn(Filter, FILE_NOTIFY_CHANGE_LAST_WRITE))
SetFlag(Filter, FILE_NOTIFY_CHANGE_STREAM_WRITE);
ClearFlag(Filter, ~(FILE_NOTIFY_CHANGE_STREAM_NAME | FILE_NOTIFY_CHANGE_STREAM_SIZE |
FILE_NOTIFY_CHANGE_STREAM_WRITE));
switch (Action)
{
case FILE_ACTION_ADDED:
Action = FILE_ACTION_ADDED_STREAM;
FspFileNodeInvalidateStreamInfo(FileNode);
break;
case FILE_ACTION_REMOVED:
Action = FILE_ACTION_REMOVED_STREAM;
FspFileNodeInvalidateStreamInfo(FileNode);
break;
case FILE_ACTION_MODIFIED:
Action = FILE_ACTION_MODIFIED_STREAM;
//FspFileNodeInvalidateStreamInfo(FileNode);
break;
}
}
if (0 != Filter)
{
FspFileNameSuffix(&FileNode->FileName, &Parent, &Suffix);
if (InvalidateCaches)
{
FspFsvolDeviceInvalidateVolumeInfo(FsvolDeviceObject);
if (0 == FileNode->MainFileNode)
{
if (sizeof(WCHAR) == FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0])
; /* root does not have a parent */
else
FspFileNodeInvalidateDirInfoByName(FsvolDeviceObject, &Parent);
}
else
FspFileNodeInvalidateStreamInfo(FileNode);
}
FspNotifyReportChange(
FsvolDeviceExtension->NotifySync, &FsvolDeviceExtension->NotifyList,
&FileNode->FileName,
(USHORT)((PUINT8)Suffix.Buffer - (PUINT8)FileNode->FileName.Buffer),
0, Filter, Action);
}
}
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp)
{
PAGED_CODE();
IoMarkIrpPending(Irp);
FspFileNodeSetOwnerF(FileNode, FspIrpFlags(Irp), Irp);
NTSTATUS Result;
try
{
FsRtlProcessFileLock(&FileNode->FileLock, Irp, FileNode);
Result = FsRtlProcessFileLock(&FileNode->FileLock, Irp, FileNode);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Irp->IoStatus.Status = GetExceptionCode();
Irp->IoStatus.Information = 0;
FspFileNodeCompleteLockIrp(FileNode, Irp);
Result = FspFileNodeCompleteLockIrp(FileNode, Irp);
}
return STATUS_PENDING;
return Result;
}
static NTSTATUS FspFileNodeCompleteLockIrp(PVOID Context, PIRP Irp)
{
PAGED_CODE();
FSP_FILE_NODE *FileNode = Context;
NTSTATUS Result = Irp->IoStatus.Status;
FspFileNodeReleaseOwnerF(FileNode, FspIrpFlags(Irp), Irp);
DEBUGLOGIRP(Irp, Result);
FspIopCompleteIrp(Irp, Result);
@ -1843,15 +2031,19 @@ VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc)
RtlFreeUnicodeString(&FileDesc->DirectoryPattern);
}
if (0 != FileDesc->DirectoryMarker.Buffer)
FspFree(FileDesc->DirectoryMarker.Buffer);
FspFree(FileDesc);
}
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN Reset)
NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN RestartScan, BOOLEAN IndexSpecified)
{
PAGED_CODE();
if (Reset || 0 == FileDesc->DirectoryPattern.Buffer)
if (0 == FileDesc->DirectoryPattern.Buffer ||
(RestartScan && 0 != FileName && 0 != FileName->Length))
{
UNICODE_STRING DirectoryPattern;
@ -1888,7 +2080,65 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
}
FileDesc->DirectoryPattern = DirectoryPattern;
FileDesc->DirectoryHasSuchFile = FALSE;
if (0 != FileDesc->DirectoryMarker.Buffer)
{
FspFree(FileDesc->DirectoryMarker.Buffer);
FileDesc->DirectoryMarker.Buffer = 0;
}
}
else if (RestartScan)
{
ASSERT(0 == FileName || 0 == FileName->Length);
FileDesc->DirectoryHasSuchFile = FALSE;
if (0 != FileDesc->DirectoryMarker.Buffer)
{
FspFree(FileDesc->DirectoryMarker.Buffer);
FileDesc->DirectoryMarker.Buffer = 0;
}
}
else if (IndexSpecified && 0 != FileName && 0 != FileName->Length)
{
NTSTATUS Result;
Result = FspFileDescSetDirectoryMarker(FileDesc, FileName);
if (!NT_SUCCESS(Result))
return Result;
FileDesc->DirectoryHasSuchFile = FALSE;
}
return STATUS_SUCCESS;
}
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName)
{
PAGED_CODE();
if (&FileDesc->DirectoryMarker == FileName)
return STATUS_SUCCESS;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileDesc->FileNode->FsvolDeviceObject);
UNICODE_STRING DirectoryMarker;
if (FsvolDeviceExtension->VolumeParams.MaxComponentLength < FileName->Length)
return STATUS_OBJECT_NAME_INVALID;
DirectoryMarker.Length = DirectoryMarker.MaximumLength = FileName->Length;
DirectoryMarker.Buffer = FspAlloc(FileName->Length);
if (0 == DirectoryMarker.Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
RtlCopyMemory(DirectoryMarker.Buffer, FileName->Buffer, FileName->Length);
if (0 != FileDesc->DirectoryMarker.Buffer)
FspFree(FileDesc->DirectoryMarker.Buffer);
FileDesc->DirectoryMarker = DirectoryMarker;
return STATUS_SUCCESS;
}
@ -1915,7 +2165,9 @@ NTSTATUS FspMainFileOpen(
PFILE_OBJECT MainFileObject;
/* assert that the supplied name is actually a main file name */
ASSERT(FspFileNameIsValid(MainFileName, 0, 0));
ASSERT(FspFileNameIsValid(MainFileName,
FsvolDeviceExtension->VolumeParams.MaxComponentLength,
0, 0));
*PMainFileHandle = 0;
*PMainFileObject = 0;
@ -1925,11 +2177,11 @@ NTSTATUS FspMainFileOpen(
case FILE_CREATE:
case FILE_OPEN_IF:
case FILE_OVERWRITE_IF:
case FILE_SUPERSEDE:
Disposition = FILE_OPEN_IF;
break;
case FILE_OPEN:
case FILE_OVERWRITE:
case FILE_SUPERSEDE:
Disposition = FILE_OPEN;
break;
default:

View File

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

View File

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

View File

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

View File

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

View File

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

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