Compare commits

..

227 Commits

Author SHA1 Message Date
56873406e3 appveyor: run-perf-tests 2017-01-04 16:04:43 -08:00
40735c4687 sys: POOL_NX_OPTIN 2016-12-14 15:06:00 -08:00
08c283f2a9 tools: run-tests: reorder tests 2016-12-13 16:15:50 -08:00
4fc740588e tst: memfs: disable test that fails with --oplock option 2016-12-13 15:41:00 -08:00
54050c7e1d tst: memfs: stream_create_overwrite_test 2016-12-13 15:17:22 -08:00
ff08d63a82 sys,dll: Overwrite: named streams are now removed as per NTFS 2016-12-13 14:37:44 -08:00
c37444b0ae tst: memfs: reference counting and descendant enumeration improvements 2016-12-13 13:24:46 -08:00
bbb51b4971 sys,dll: Overwrite now correctly handles AllocationSize 2016-12-13 11:52:32 -08:00
6de998ff98 sys: rename: capture correct security context 2016-12-12 13:20:42 -08:00
4b024ebe74 sys: security: turns out that the AccessToken is not needed 2016-12-10 17:45:36 -08:00
418c454a4a dll: FspSetSecurityDescriptor: turns out that the AccessToken is not needed 2016-12-09 17:43:11 -08:00
0b61c48cd6 inc: fsctl: FSP_FSCTL_TRANSACT_REQ QueryDirectory: CaseSensitive 2016-12-09 15:35:55 -08:00
945509ef93 tools: run-tests: net use test 2016-12-09 14:43:10 -08:00
3a65ce332b dll,launcher: invariant string comparisons 2016-12-09 14:23:53 -08:00
228f9e2708 tst: memfs: MEMFS_REPARSE_POINTS conditional 2016-12-08 18:58:05 -08:00
ee3918436b fix erroneous file permissions 2016-12-08 18:43:49 -08:00
1bb6d2a0e7 installer: register MEMFS to accommodate bigger file sizes and more files 2016-12-08 12:54:22 -08:00
6d1b9e95db inc: winfsp: add comment regarding limitations of ReadDirectory/Offset 2016-12-08 09:18:09 -08:00
1d8d72129d sys: util: fix Delays when retrying MustSucceed allocations 2016-12-07 17:19:26 -08:00
2ad4e30754 inc: fsctl: add FSP_FSCTL_FILE_INFO::HardLinks field 2016-12-07 16:43:55 -08:00
26cba02091 doc: minor fix in performance testing document 2016-12-07 14:47:10 -08:00
3697defd16 doc: update performance testing document 2016-12-06 22:14:39 -08:00
69a22f1044 doc: update WinFsp Testing document 2016-12-06 19:24:59 -08:00
5a49115a66 doc: fix case insensitive file names 2016-12-06 17:48:04 -08:00
82c8b0d00f doc: rename Performance Testing document 2016-12-06 17:36:47 -08:00
d00b5d88af doc: rename documents 2016-12-06 17:25:51 -08:00
6d19176d7c update README 2016-12-06 17:06:44 -08:00
e231b9c662 doc: add winfsp.h documentation in markdown format 2016-12-06 17:04:44 -08:00
025a74e663 rename .adoc files to .asciidoc 2016-12-06 16:57:09 -08:00
834adbdc36 restructure project to accommodate wiki 2016-12-06 16:40:32 -08:00
25c687d5c5 doc; winfsp-ipc: update document 2016-12-06 15:25:59 -08:00
200de2a7f9 doc: winfsp-ipc: WinFsp as IPC Mechanism 2016-12-06 09:50:37 -08:00
8e7c241f32 doc: perf-tests: update Performance Testing document 2016-12-05 16:37:31 -08:00
e530e671a5 doc: perf-tests: update Performance Testing document 2016-12-05 14:50:29 -08:00
d804f5674d tst: fsbench: disable rdwr sector tests as they are too slow 2016-12-05 11:54:59 -08:00
ac6f024715 fsbench: expand on read/write tests and fixes 2016-12-04 14:41:38 -08:00
a1af8ff921 sys: Queued Events and use fin FSP_IOQ 2016-12-03 19:41:26 -08:00
f7ca9f0522 tst: memfs: ReadDirectory im: optimization to improve quadratic behavior 2016-11-30 21:50:44 -08:00
3518d7a8c2 tst: memfs: ReadDirectory improvements 2016-11-30 16:12:00 -08:00
281d92f2bc doc: perf-tests: improve conditional check for AsciidocFX 2016-11-30 10:00:43 -08:00
7769a2c062 doc: perf-tests: typos 2016-11-30 09:43:10 -08:00
595a77bd2e doc: update perf-tests document 2016-11-29 23:42:41 -08:00
6860a6986a doc: update perf-tests document 2016-11-29 23:34:54 -08:00
63e8cf1090 doc: add perf-tests document and supporting files 2016-11-29 22:22:45 -08:00
7bdca634aa tools: run-perf-tests: only iterate 5 times 2016-11-29 12:43:25 -08:00
535babc0d5 tools: run-perf-tests 2016-11-27 16:32:45 -08:00
e86dcde1a1 tst: fsbench: improvements 2016-11-27 11:16:06 -08:00
6e10e0489b tst: fsbench: mmap tests 2016-11-26 22:09:40 -08:00
f82cad712a tst: fsbench: rdwr test 2016-11-26 20:50:35 -08:00
d12234bb01 tst: memfs: improve memory allocation scheme 2016-11-26 20:08:55 -08:00
10a8519294 tst: fsbench: file_open_test, file_overwrite_test 2016-11-26 12:01:01 -08:00
1b6395fc91 tst: fsbench: file_list_test 2016-11-25 15:10:07 -08:00
f1a363b848 tst: fsbench: simple benchmark program 2016-11-25 11:46:21 -08:00
eea1a8fd8b tst: winfsp-tests: disable tests that cannot work under a network share 2016-11-24 17:35:45 -08:00
5444ce7f50 sys: rename: only do MmFlushImageSection when ImageSectionObject is not NULL 2016-11-24 15:09:39 -08:00
29c140b9cd tst: winfsp-tests: delete_pending_test 2016-11-24 13:34:51 -08:00
cdfd60877b tst: winfsp-tests: delete_mmap_test 2016-11-24 13:26:50 -08:00
e7931e28fd tst: make non-essential and long running tests optional 2016-11-23 21:26:21 -08:00
002a0262f7 sys: FspFileNodeOplockCheckAsyncEx: DEBUGTEST 2016-11-23 21:23:57 -08:00
1ffba78a18 tst: winfsp-tests: oplock testing 2016-11-23 16:19:46 -08:00
1d3423d5fb tst: winfsp-tests: oplock testing 2016-11-23 16:11:24 -08:00
a894e4a2af tst: winfsp-tests: oplock testing 2016-11-23 15:41:28 -08:00
b6f084d71f tst: winfsp-tests: oplock testing 2016-11-23 11:46:46 -08:00
ca6d0d2dcf tst: winfsp-tests: disable oplock tests on shares 2016-11-22 22:15:46 -08:00
d6d781355f sys: DEBUGTEST_EX macro: fix 2016-11-22 22:20:14 -08:00
851a6145cd tst: winfsp-tests: oplock testing 2016-11-22 21:20:31 -08:00
aec7b34e13 tst: winfsp-tests: HookDeleteFileW: oplock testing 2016-11-22 20:21:35 -08:00
38006ba553 tst: HookMoveFileExW: fix problem with requesting oplock on same file 2016-11-22 18:30:08 -08:00
ee469b40e7 sys: FspFileNodeRename: handle cleaned up but not closed file 2016-11-22 17:27:52 -08:00
1f385a9ab5 sys: rename: bail early when attempting to replace directory 2016-11-22 15:47:34 -08:00
ba78fbb956 sys: rename: oplock refactoring 2016-11-22 14:18:10 -08:00
8f10ba4fc9 sys: file: GATHER_DESCENDANTS, SCATTER_DESCENDANTS macros 2016-11-22 11:32:40 -08:00
b0a59e42fc tst: add oplock testsuite run and disable some tests according to configuration 2016-11-21 16:45:10 -08:00
2e089b92c5 sys: FspFileNodeCheckBatchOplocksOnAllStreams: fix oplock related deadlock
- fix: initiate oplock break, release FileNode and wait for oplock break completion
2016-11-21 16:28:00 -08:00
37362cb8cc sys: file,wq: make oplock functions paged 2016-11-20 17:52:38 -08:00
127d4cc4eb sys: fsctl: oplock fixes 2016-11-20 15:27:24 -08:00
ce551d4e0d sys: oplock: refactoring/cleanup 2016-11-20 14:08:23 -08:00
53f60a698a tst: winfsp-tests: add oplock option 2016-11-19 22:58:40 -08:00
aa23672b01 sys: fsctl: enable oplock processing 2016-11-18 22:20:03 -08:00
e4de0f0513 sys: oplock: perform stream oplock checks
sys: rename: fix some rename issues
2016-11-18 18:38:15 -08:00
8750451e10 sys: FspFsvolDeviceEnumerateContextByName, FspFileNodeRename: bugfix: properly enumerate/rename streams 2016-11-16 14:34:01 -08:00
358db2a54f sys: oplock: misc fixes and improvements 2016-11-16 13:34:43 -08:00
4294182c1a sys: oplock testing 2016-11-15 17:05:05 -08:00
f17168f2fa sys: oplock testing: DEBUGTEST_EX 2016-11-15 13:17:49 -08:00
959d8537c6 sys: oplock testing 2016-11-14 20:36:51 -08:00
6a48087d5f sys: create: oplock testing 2016-11-14 17:28:53 -08:00
0a59c5d685 tools: add executable bit to batch files 2016-11-14 17:21:00 -08:00
5b1b8288c2 sys: create: FspFsvolCreateOpenOrOverwiteOplock: fix typo 2016-11-14 17:15:09 -08:00
53e2f13e38 sys: FspFileNodeRenameCheck 2016-11-14 11:20:32 -08:00
cb6b10385b sys: rename: oplocks 2016-11-13 22:06:53 -08:00
f49cf412a8 sys: fileinfo: oplocks 2016-11-13 10:45:24 -08:00
764b772731 sys: lockctl, read, write: oplocks 2016-11-12 18:01:27 -08:00
7518a6e418 sys: read, write: oplocks 2016-11-12 13:12:35 -08:00
2772af5478 sys: FspWqOplockPrepare: use work routine 2016-11-12 12:06:28 -08:00
f2535484ea sys: wq: WIP 2016-11-12 11:43:47 -08:00
97ee4fa77f sys: lockctl: oplocks 2016-11-12 11:32:37 -08:00
7c34d738b7 sys: wq: FspWqOplockPrepare, FspWqOplockComplete 2016-11-12 11:31:38 -08:00
93254bede4 sys: lockctl: oplocks 2016-11-11 22:54:09 -08:00
f3894dbc7b sys: cleanup: oplocks 2016-11-11 22:08:14 -08:00
dc684acd41 sys: create: oplocks WIP 2016-11-11 21:34:57 -08:00
69935525da sys: create: oplocks WIP 2016-11-11 17:58:57 -08:00
6ba6e16851 sys: create: oplocks: WIP 2016-11-11 17:06:19 -08:00
d33089331b sys: create: sharing violation oplock checks 2016-11-11 16:53:35 -08:00
74de84aaab sys: create: sharing violation oplock checks 2016-11-11 16:52:21 -08:00
a9b4fd4634 sys: FspFileNodeClose 2016-11-11 10:54:21 -08:00
c6798b3060 sys: create: move some code around 2016-11-11 09:39:17 -08:00
f6e3b8e416 sys: create: oplock: WIP 2016-11-11 09:30:29 -08:00
f05ebd9d20 sys: FspFsvolCreateSharingViolationWork 2016-11-10 18:14:17 -08:00
e50c9ff649 sys: IRP_MJ_CREATE: oplock support 2016-11-10 15:03:58 -08:00
fb70eccc9c sys: IRP_MJ_CREATE: oplock support 2016-11-10 14:54:41 -08:00
7adbd7a56c sys: FspIopSetIrpResponse 2016-11-10 13:20:03 -08:00
55c7384c65 sys: FspIopCreateRequestWorkItem 2016-11-10 12:40:21 -08:00
bc8962d2b6 sys: FspOplockBreakH 2016-11-10 12:29:11 -08:00
2267eadbca sys: disable oplock requests momentarily for testing 2016-11-10 12:12:35 -08:00
154aa28381 sys: FspFsvolFileSystemControlOplock: WIP 2016-11-10 12:11:35 -08:00
2d98cda607 sys: oplocks: WIP 2016-11-10 12:11:14 -08:00
8395b22ddc sys: oplocks: WIP 2016-11-10 12:10:55 -08:00
809505d8a3 appveyor: on_finish: perform verifier_query 2016-11-10 11:47:24 -08:00
9df0920de1 tools: run-tests: always do leak test (even on failures) 2016-11-10 11:47:15 -08:00
c10c7cc672 sys: FspFileNodeClose: ensure that cleanup also happens when Create fails 2016-11-10 11:47:06 -08:00
a0cb134bd3 sys: FspFsvolReadNonCached,FspFsvolWriteNonCached: reuse work Requests 2016-11-10 11:46:16 -08:00
becfd2e1c5 sys: request work item refactoring 2016-11-10 11:45:58 -08:00
1e93f0d10d sys: request work item refactoring 2016-11-10 11:45:38 -08:00
adeb847c7e sys: request work item refactoring 2016-11-10 11:45:17 -08:00
5a83c68f56 sys: request work item refactoring 2016-11-10 11:45:04 -08:00
9d176643c3 sys: driver.h: add static assert for size of FSP_FSCTL_TRANSACT_REQ_HEADER 2016-11-10 11:44:42 -08:00
b1d8192d59 sys: restrict build to Win7 2016-11-10 11:44:26 -08:00
bd3d462bce sys: FspFileNodeSetFileInfo: fix Release build warning 2016-11-06 18:44:58 -08:00
aa2d70d8de sys: FspFileNodeSetFileInfo: make CcSetFileSizes failures benign
tst: fscrash: test huge allocation size failures
2016-11-06 17:15:07 -08:00
31c40d017d sys: create: allow user mode file system to disable caching for individual files 2016-11-04 13:08:10 -07:00
5c8da5518c sys: FspFsvolCreate: clarify comment 2016-11-04 12:22:43 -07:00
a80a9d3d4c doc: update winfsp-testing.adoc 2016-11-04 09:58:01 -07:00
57580e91f5 tools: run-tests: fscrash 2016-11-04 00:32:16 -07:00
1a43619c5e tst: fscrash: WIP 2016-11-04 00:03:30 -07:00
aae6a15e5a tst: fscrash: WIP 2016-11-03 22:31:59 -07:00
f54ce6a65d tst: fscrash: WIP 2016-11-03 21:48:34 -07:00
ab0c2fc25c tst: fscrash: WIP 2016-11-03 20:39:28 -07:00
fd439add27 doc: winfsp-testing: add information about fscrash 2016-11-03 19:53:02 -07:00
8855a2b896 tst: fscrash: WIP 2016-11-03 19:18:53 -07:00
7c41ffd64e tst: fscrash: initial commit 2016-11-03 16:15:32 -07:00
621eb63029 doc: minor fix in winfsp-testing.adoc 2016-11-03 12:42:28 -07:00
f1b96f8a28 doc: add WinFsp Testing Strategy document 2016-11-03 12:39:14 -07:00
4512dac0a9 doc: update Changelog 2016-11-03 09:36:50 -07:00
deee32b743 tools: run-tests: perform leak-test after all WinFsp drives have been unmounted 2016-11-02 22:12:39 -07:00
5f1b723fab tools: run-tests: leak-test 2016-11-02 21:31:28 -07:00
453f1732dc tools: run-tests: leak-test: add output 2016-11-02 21:00:08 -07:00
8c8d669be8 tools: run-tests: leak-test: add output 2016-11-02 20:59:16 -07:00
53077d990a tools: run-tests: leak-test 2016-11-02 20:16:18 -07:00
c665812d76 sys: FspVolumeDelete: perform MmForceSectionClosed on open files
- this removes them from the Mm Standby List
2016-11-02 18:27:38 -07:00
b56379b542 tools: run-tests: simple standby list test 2016-11-02 16:22:47 -07:00
83c1489b92 sys: FspVolumeMountNoLock: dereference FsvrtDeviceObject on success
resolves a VPB/FsvrtDeviceObject leak
2016-11-02 13:00:46 -07:00
3e3aa7651f dll: UmFileContextIsUserContext2, UmFileContextIsFullContext support 2016-11-01 18:49:28 -07:00
ec2cf5106d src: ioctl.i: comment out symbol that does not exist during Debug build on AppVeyor 2016-11-01 16:10:19 -07:00
25322059b3 appveyor: build Debug and Release configurations 2016-11-01 16:03:00 -07:00
a255fa11e7 tst: winfsp-tests: disable FILE_FLAG_NO_BUFFERING mmap test against localhost share (Win8 bug) 2016-11-01 14:56:01 -07:00
dbb8b5d3b9 tst: winfsp-tests: --share option now allows running tests against remote share 2016-11-01 13:32:51 -07:00
4c6a61d2c9 tst: winfsp-tests: refactoring/fixes when running --ntfs/--external tests 2016-11-01 11:13:25 -07:00
ac4828ec11 tools: run-tests: disable rdwr_mmap and reparse_symlink tests which currently fail under redirector/SRV2 2016-10-31 12:18:53 -07:00
e0f163e9ba sys: maintain FO_FILE_MODIFIED bit 2016-10-29 13:04:13 -07:00
9bcd8dcb8e sys: FspIopCompleteIrpEx: handle SRV2 query directory completion 2016-10-28 16:33:54 -07:00
096e5b7eb1 Revert "sys: FspFsvolDirectoryControlComplete: support SRV2 queries"
This reverts commit 7f2426271c.
2016-10-28 11:43:26 -07:00
1c85fb94f0 sys: FspFileNodeCleanupComplete, FspFileNodeClose: fix problem with OpenCount handling 2016-10-27 23:57:27 -07:00
4417ebcc92 sys: util: FspSafeMdlCreate: assertion fix 2016-10-27 23:30:16 -07:00
5fa631339d sys: FspFsvolSetRenameInformation: correctly compute Suffix for SRV2 renames 2016-10-27 11:44:43 -07:00
26092211a8 tst: winfsp-tests: --external tests done within a temporary directory 2016-10-26 20:24:57 -07:00
50af8f6444 tools: run-tests: winfsp-tests --external 2016-10-26 16:55:17 -07:00
ee0031f995 sys: FspFsvolQueryInformation: add stub FileEaInformation support 2016-10-26 16:45:18 -07:00
75ff7f2c01 tools: run-tests: add net share tests (currently multiple failures) 2016-10-26 16:03:20 -07:00
3e557e1b65 tools: run-tests: add case-insensitive option when testing dir mounts 2016-10-26 15:09:46 -07:00
79bf651203 tst: winfsp-tests: add WINAPI for Hook* and Resilient* APIs 2016-10-26 15:11:06 -07:00
205a59dbc6 tst: winfsp-tests: ResilientRemoveDirectoryW 2016-10-26 14:36:38 -07:00
8f54152096 tst: winfsp-tests: WIP 2016-10-26 13:59:21 -07:00
5e71992153 tst: winfsp-tests: WIP 2016-10-26 13:40:30 -07:00
dfe45e1be5 tst: winfsp-tests: WIP 2016-10-26 13:27:49 -07:00
ff7a446194 tst: winfsp-tests: WIP 2016-10-26 13:16:27 -07:00
17056b4f3f tst: winfsp-tests: always use CreateDirectoryW 2016-10-26 12:48:30 -07:00
b19621233a tst: winfsp-tests: HookCreateDirectoryW, HookMoveFileExW, HookFindFirstFileW 2016-10-26 12:37:36 -07:00
e07ef0712e tst: winfsp-tests: HookRemoveDirectoryW 2016-10-26 12:08:29 -07:00
0532cee99c tst: winfsp-tests: refactor hooks 2016-10-26 12:02:30 -07:00
b072a1f0da tst: winfsp-tests: add license headers 2016-10-25 20:29:05 -07:00
badaf82462 tst: winfsp-tests: --resilient command line option 2016-10-25 20:19:04 -07:00
3f79b2e46d tst: winfsp-tests: --resilient command line option 2016-10-25 15:35:46 -07:00
319e5d4ee6 tst: winfsp-tests: --resilient command line option 2016-10-25 14:50:12 -07:00
66d5fe98df tst: winfsp-tests: add --ntfs option 2016-10-25 14:03:26 -07:00
8abadf94f3 tst: winfsp-tests: minor fix 2016-10-25 12:52:06 -07:00
728c1b3402 tst: winfsp-tests: add/remove network shares from memfs_start/memfs_stop to properly support test file system 2016-10-25 11:38:26 -07:00
8b31b1018b tst: winfsp-tests: abort messages 2016-10-25 11:15:47 -07:00
310fd23035 tst: winfsp-tests: initial network share support 2016-10-25 11:04:53 -07:00
7f2426271c sys: FspFsvolDirectoryControlComplete: support SRV2 queries 2016-10-23 21:53:45 -07:00
3cfa4156d2 sys: IRP_MN_QUERY_DIRECTORY: prep work to handle non-NULL Irp->MdlAddress 2016-10-23 17:47:57 -07:00
23dadcf8a0 dll,tst: do not add dot entries for root directory 2016-10-23 11:03:44 -07:00
e0b0b1b367 sys: read,write: IRP_MN_MDL improvements 2016-10-22 14:04:31 -07:00
a525e095d3 sys: check Response->IoStatus.Information for Read, Write, QueryDirectory 2016-10-21 21:46:47 -07:00
e16dfd8a43 dll: debug: QueryStreamInformation logging 2016-10-21 21:02:59 -07:00
3bf4140f91 sys,dll: backup/restore privilege support 2016-10-21 19:13:05 -07:00
b194a33406 tst: winfsp-tests: backup/restore privilege testing 2016-10-21 17:43:25 -07:00
0dd452fac1 tools: run-tests: improvements 2016-10-20 18:48:39 -07:00
df11a7d7ff dll: FspAccessCheckEx: fix traverse check problem with reparse points 2016-10-20 18:32:01 -07:00
51d29c172a tools: run-tests: improvements 2016-10-20 17:52:41 -07:00
2803a1b0cf tools: run-tests: correctly test ERRORLEVEL 2016-10-20 16:48:36 -07:00
067a0f1b37 dll: API polishing 2016-10-20 16:32:12 -07:00
03611b6210 sys: FspFsvolSetRenameInformation: when doing an exact case rename do not send it to the user mode file system 2016-10-19 16:15:23 -07:00
2ff60e5e98 tst: memfs: Rename: fix problem when renaming names differing in case only 2016-10-19 15:52:22 -07:00
488993d22b doc: update Changelog 2016-10-19 14:32:00 -07:00
3cba22b9a5 tst: winfsp-tests: replace abort with ABORT in HookCreateFile, etc. 2016-10-19 13:56:15 -07:00
a3e577b091 tst: winfsp-tests: create_notraverse_test: fix security descriptor 2016-10-19 13:55:23 -07:00
9b287fb559 tst: winfsp-tests: create_notraverse_test 2016-10-19 12:40:52 -07:00
f642ea57be dll: FspAccessCheckEx: test access checks without traverse privilege 2016-10-19 11:54:22 -07:00
cb17b7e2e0 dll: FspFileSystemSetMountPoint: testing 2016-10-18 14:08:58 -07:00
82a9c8e80f dll: FspFileSystemSetMountPoint: now supports directories 2016-10-17 21:04:22 -07:00
628dae38d7 case-insensitivity testing 2016-10-17 15:33:23 -07:00
958b5a47a8 installer: include product version in product name 2016-10-17 15:05:45 -07:00
8d38a0dac6 sys,dll: support file name normalization 2016-10-17 14:23:56 -07:00
a653a010ce ext: tlib: fix mistake in cmdline handling introduced in latest change 2016-10-17 13:19:20 -07:00
31eedbddb3 sys: create: OpenTargetDirectory handling moved before the Prepare phase 2016-10-17 11:05:49 -07:00
5bf913045e update submodules 2016-10-16 15:22:19 -07:00
a10a09d4e9 tst: winfsp-tests: dirnotify_test improvements 2016-10-16 14:58:37 -07:00
3e0db6da07 tst: winfsp-tests: dirnotify_test changed to catch filename case problems 2016-10-16 13:30:48 -07:00
77df532ac3 tst: winfsp-tests: getfileinfo_name_test 2016-10-16 13:14:36 -07:00
222da362ec tlib: catch unknown options in tlib_run_tests 2016-10-16 11:27:01 -07:00
3ed7847d84 tst: test case insensitivity
sys: FspFileNameIsValid: $DATA is case insensitive
2016-10-15 19:50:47 -07:00
5773c6eab7 sys: FspFileNodeRename: acquire resource of descendant file nodes when renaming them 2016-10-14 22:47:10 -07:00
5a5a1008de sys: FspFileNameCompare, FspFileNameIsPrefix 2016-10-14 16:01:05 -07:00
32c289fa34 sys: FspFsvolFileSystemControlReparsePoint: replace use of RtlEqualUnicodeString with FspFsvolDeviceVolumePrefixInString 2016-10-14 15:13:52 -07:00
0534225662 sys: canonicalize filename related functions under the name FspFileName* 2016-10-14 14:47:16 -07:00
096b2dabde sys: refactor util.c into strutil.c; introduce FspIsNameInExpression to wrap FsRtlIsNameInExpression 2016-10-14 14:09:54 -07:00
5770f2d901 build: improve build versioning 2016-10-13 14:32:09 -07:00
148 changed files with 12604 additions and 1587 deletions

View File

@ -1,6 +1,18 @@
= Changelog
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:
- API has been polished and finalized.
- Sharing a (disk) file system over the network is supported.
- Case insensitive file systems are supported.
- Directories are supported as mount points.
- Access checks are performed correctly in the absense of the traverse privilege.
- Access checks are performed correctly in the presence of the backup and restore privileges.
v0.17::
This release brings support for named streams.

View File

@ -23,7 +23,7 @@ WinFsp consists of a kernel mode FSD (File System Driver) and a user mode DLL (D
The project source code is organized as follows:
* build/VStudio: WinFsp solution and project files.
* doc: WinFsp license, contributor agreement and additional documentation. The WinFsp design documents can be found here.
* doc: The WinFsp design documents and additional documentation can be found here.
* ext/tlib: A small test library originally from the secfs (Secure Cloud File System) project.
* ext/test: Submodule pointing to the secfs.test project, which contains a number of tools for testing Windows and POSIX file systems.
* inc/winfsp: Public headers for the WinFsp API.

View File

@ -1,23 +1,33 @@
version: '{build}'
environment:
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%
- verifier /query
version: '{build}'
environment:
matrix:
- 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:
- for %%f in ("build\VStudio\build\%CONFIGURATION%\winfsp-*.msi") do start /wait msiexec /i %%f /qn INSTALLLEVEL=1000
- 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%==Perf tools\run-perf-tests.bat %CONFIGURATION% baseline > perf-tests.csv && type perf-tests.csv & appveyor PushArtifact perf-tests.csv
- 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

@ -2,7 +2,7 @@
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product
Id="*"
Name="$(var.MyProductName)"
Name="$(var.MyProductName) $(var.MyProductVersion)"
Manufacturer="$(var.MyCompanyName)"
Version="$(var.MyVersion)"
Language="1033"
@ -17,8 +17,8 @@
Disallow="yes"
AllowDowngrades="no"
AllowSameVersionUpgrades="no"
DisallowUpgradeErrorMessage="An older version of [ProductName] is already installed. You must uninstall it before you can install this version."
DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
DisallowUpgradeErrorMessage="An older version of $(var.MyProductName) is already installed. You must uninstall it before you can install this version."
DowngradeErrorMessage="A newer version of $(var.MyProductName) is already installed." />
<Media Id="1" Cabinet="WinFsp.cab" EmbedCab="yes" />
<Property Id="P.LauncherName">$(var.MyProductName).Launcher</Property>
@ -155,7 +155,7 @@
<RegistryValue
Type="string"
Name="CommandLine"
Value="-u %1 -m %2" />
Value="-i -n 65536 -s 67108864 -u %1 -m %2" />
<RegistryValue
Type="string"
Name="Security"
@ -181,7 +181,7 @@
<RegistryValue
Type="string"
Name="CommandLine"
Value="-u %1 -m %2" />
Value="-i -n 65536 -s 67108864 -u %1 -m %2" />
<RegistryValue
Type="string"
Name="Security"
@ -344,7 +344,7 @@
<Feature
Id="F.Main"
Level="1"
Title="$(var.MyProductName) $(var.MyVersion)"
Title="$(var.MyProductName) $(var.MyProductVersion)"
Description="$(var.MyDescription)"
Display="expand"
ConfigurableDirectory="INSTALLDIR"
@ -378,7 +378,7 @@
</Feature>
<WixVariable Id="WixUIBannerBmp" Value="wixbanner.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="wixdialog-$(var.MyDevStage).bmp" />
<WixVariable Id="WixUIDialogBmp" Value="wixdialog-$(var.MyProductStage).bmp" />
<UI Id="FeatureTree">
<UIRef Id="WixUI_FeatureTree" />
<!-- skip the license agreement dialog; higher Order takes priority (weird) -->

View File

@ -16,7 +16,7 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<IntermediateOutputPath>$(SolutionDir)build\$(Name).build\$(Configuration)\$(Platform)\</IntermediateOutputPath>
<DefineConstants>Debug;MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyDevStage=$(MyDevStage);MyVersion=$(MyVersion)</DefineConstants>
<DefineConstants>Debug;MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion)</DefineConstants>
<SuppressAllWarnings>False</SuppressAllWarnings>
<Pedantic>True</Pedantic>
<SuppressPdbOutput>True</SuppressPdbOutput>
@ -25,7 +25,7 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<IntermediateOutputPath>$(SolutionDir)build\$(Name).build\$(Configuration)\$(Platform)\</IntermediateOutputPath>
<DefineConstants>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyDevStage=$(MyDevStage);MyVersion=$(MyVersion)</DefineConstants>
<DefineConstants>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion)</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);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<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>
</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);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<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>
</ResourceCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -0,0 +1,187 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>fsbench</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\..\..\ext</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\..\..\ext</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\..\..\ext</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\..\..\ext</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\ext\tlib\testsuite.c">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">TurnOffAllWarnings</WarningLevel>
<SDLCheck Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</SDLCheck>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">TurnOffAllWarnings</WarningLevel>
<SDLCheck Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</SDLCheck>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">TurnOffAllWarnings</WarningLevel>
<SDLCheck Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</SDLCheck>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">TurnOffAllWarnings</WarningLevel>
<SDLCheck Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</SDLCheck>
</ClCompile>
<ClCompile Include="..\..\..\tst\fsbench\fsbench.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Source\tlib">
<UniqueIdentifier>{d76fc01e-0f8d-4596-bdef-c2a5d3fede2e}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\tst\fsbench\fsbench.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\ext\tlib\testsuite.c">
<Filter>Source\tlib</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
<Filter>Source\tlib</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{10757011-749D-4954-873B-AE38D8145472}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>fscrash</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\inc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\inc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\inc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\inc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\tst\fscrash\fscrash-main.c" />
<ClCompile Include="..\..\..\tst\fscrash\fscrash.c" />
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\tst\fscrash\fscrash.h" />
<ClInclude Include="..\..\..\tst\memfs\memfs.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\winfsp_dll.vcxproj">
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

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

View File

@ -107,7 +107,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -124,7 +124,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -145,7 +145,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -166,7 +166,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@ -186,15 +186,17 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\hook.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\hooks.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\info-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\lock-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\memfs-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\mount-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\oplock-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\path-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\posix-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\rdwr-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\reparse-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\resilient.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\security-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />

View File

@ -64,10 +64,16 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\reparse-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\hook.c">
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c">
<ClCompile Include="..\..\..\tst\winfsp-tests\resilient.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\hooks.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\oplock-test.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>

View File

@ -4,16 +4,23 @@
<MyProductName>WinFsp</MyProductName>
<MyDescription>Windows File System Proxy</MyDescription>
<MyCompanyName>Navimatics Corporation</MyCompanyName>
<MyCopyright>2015-2016 Bill Zissimopoulos</MyCopyright>
<MyDevStage>Beta</MyDevStage>
<MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
<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>
<MyVersion>0.17.$(MyBuildNumber)</MyVersion>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>NTDDI_VERSION=0x06000000;_WIN32_WINNT=0x0600</PreprocessorDefinitions>
<PreprocessorDefinitions>NTDDI_VERSION=0x06010000;_WIN32_WINNT=0x0601</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
</Project>

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winfsp.dll", "winfsp_dll.vcxproj", "{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}"
ProjectSection(ProjectDependencies) = postProject
@ -45,6 +45,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launchctl", "launcher\launc
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {A5EFD487-0140-4184-8C54-FFAEC2F85E35}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fscrash", "testing\fscrash.vcxproj", "{10757011-749D-4954-873B-AE38D8145472}"
ProjectSection(ProjectDependencies) = postProject
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}
{C85C26BA-8C22-4D30-83DA-46C3548E6332} = {C85C26BA-8C22-4D30-83DA-46C3548E6332}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fsbench", "testing\fsbench.vcxproj", "{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -153,6 +161,38 @@ Global
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.Build.0 = Release|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.ActiveCfg = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.Build.0 = Release|Win32
{10757011-749D-4954-873B-AE38D8145472}.Debug|x64.ActiveCfg = Debug|x64
{10757011-749D-4954-873B-AE38D8145472}.Debug|x64.Build.0 = Debug|x64
{10757011-749D-4954-873B-AE38D8145472}.Debug|x86.ActiveCfg = Debug|Win32
{10757011-749D-4954-873B-AE38D8145472}.Debug|x86.Build.0 = Debug|Win32
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.ActiveCfg = Debug|x64
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.Build.0 = Debug|x64
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.Build.0 = Debug|Win32
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.ActiveCfg = Release|x64
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.Build.0 = Release|x64
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.ActiveCfg = Release|Win32
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.Build.0 = Release|Win32
{10757011-749D-4954-873B-AE38D8145472}.Release|x64.ActiveCfg = Release|x64
{10757011-749D-4954-873B-AE38D8145472}.Release|x64.Build.0 = Release|x64
{10757011-749D-4954-873B-AE38D8145472}.Release|x86.ActiveCfg = Release|Win32
{10757011-749D-4954-873B-AE38D8145472}.Release|x86.Build.0 = Release|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x64.ActiveCfg = Debug|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x64.Build.0 = Debug|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x86.ActiveCfg = Debug|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x86.Build.0 = Debug|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x64.ActiveCfg = Debug|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x64.Build.0 = Debug|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x86.Build.0 = Debug|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x64.ActiveCfg = Release|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x64.Build.0 = Release|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x86.ActiveCfg = Release|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x86.Build.0 = Release|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x64.ActiveCfg = Release|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x64.Build.0 = Release|x64
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x86.ActiveCfg = Release|Win32
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -164,5 +204,7 @@ Global
{95C223E6-B5F1-4FD0-9376-41CDBC824445} = {B464EF06-42AE-4674-81BB-FDDE80204822}
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
{73EAAEDA-557B-48D5-A137-328934720FB4} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
{10757011-749D-4954-873B-AE38D8145472} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
EndGlobalSection
EndGlobal

View File

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

View File

@ -173,6 +173,7 @@
<ClCompile Include="..\..\src\sys\ioq.c" />
<ClCompile Include="..\..\src\sys\lockctl.c" />
<ClCompile Include="..\..\src\sys\meta.c" />
<ClCompile Include="..\..\src\sys\name.c" />
<ClCompile Include="..\..\src\sys\read.c" />
<ClCompile Include="..\..\src\sys\security.c" />
<ClCompile Include="..\..\src\sys\shutdown.c" />
@ -188,10 +189,10 @@
</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);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);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_WIN64;_AMD64_=1;AMD64;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WIN64;_AMD64_=1;AMD64;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
<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>
</ResourceCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

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

View File

@ -1,21 +0,0 @@
web: \
web/winfsp-design.html \
web/service-architecture.html \
web/sshfs-port-case-study.html \
web/winfsp.h.html
web/winfsp-design.html:
mkdir -p web
asciidoc -b html4 -a hr= -s -o $@ winfsp-design.adoc
web/service-architecture.html:
mkdir -p web
asciidoc -b html4 -a hr= -s -o $@ service-architecture.adoc
web/sshfs-port-case-study.html:
mkdir -p web
asciidoc -b html4 -a hr= -s -o $@ sshfs-port-case-study.adoc
web/winfsp.h.html:
mkdir -p web
prettydoc -H-O -o web ../inc/winfsp/winfsp.h

View File

@ -0,0 +1,192 @@
= Performance Testing
:caption:
This document discusses performance testing for WinFsp. The goal of this performance testing is to discover optimization opportunities for WinFsp and compare its performance to that of NTFS and Dokany.
== Executive Summary
This performance testing shows that WinFsp has excellent performance in all tested scenarios. It outperforms NTFS in most scenarios (an unfair comparison as NTFS is a disk file system and WinFsp is tested with an in-memory file system). It also outperforms Dokany in all scenarios, often by an order of magnitude.
ifdef::env-browser[chart::bar[data-uri="WinFsp-Performance-Testing/file_tests.csv",file="WinFsp-Performance-Testing/file_tests.png",opt="y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/file_tests.png[]]
ifdef::env-browser[chart::bar[data-uri="WinFsp-Performance-Testing/rdwr_tests.csv",file="WinFsp-Performance-Testing/rdwr_tests.png",opt="y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/rdwr_tests.png[]]
== Fsbench
All testing was performed using a new performance test suite developed as part of WinFsp, called https://github.com/billziss-gh/winfsp/blob/master/tst/fsbench/fsbench.c[fsbench]. Fsbench was developed because it allows the creation of tests that are important to file system developers; for example, it can answer questions of the type: "how long does it take to delete 1000 files" or "how long does it take to list a directory with 10000 files in it".
Fsbench is based on the https://github.com/billziss-gh/winfsp/tree/master/ext/tlib[tlib] library, originally from the *secfs* project. Tlib is usually used to develop regression test suites in C/C++, but can be also used to create performance tests.
Fsbench currently includes the following tests:
[width="100%",cols="20%,60%,20%",options="header"]
|===
|Test |Measures performance of |Parameters
|file_create_test |CreateFileW(CREATE_NEW) / CloseHandle |file count
|file_open_test |CreateFileW(OPEN_EXISTING) / CloseHandle |file count
|file_overwrite_test|CreateFileW(CREATE_ALWAYS) / CloseHandle with existing files|file count
|file_list_test |FindFirstFileW / FindNextFile / FindClose |iterations
|file_delete_test |DeleteFileW |file count
|file_mkdir_test |CreateDirectoryW |file count
|file_rmdir_test |RemoveDirectoryW |file count
|rdwr_cc_write_page_test |WriteFile (1 page; cached) |iterations
|rdwr_cc_read_page_test |ReadFile (1 page; cached) |iterations
|rdwr_nc_write_page_test |WriteFile (1 page; non-cached) |iterations
|rdwr_nc_read_page_test |ReadFile (1 page; non-cached) |iterations
|rdwr_cc_write_large_test |WriteFile (16 pages; cached) |iterations
|rdwr_cc_read_large_test |ReadFile (16 pages; cached) |iterations
|rdwr_nc_write_large_test |WriteFile (16 pages; non-cached) |iterations
|rdwr_nc_read_large_test |ReadFile (16 pages; non-cached) |iterations
|mmap_write_test |Memory mapped write test |iterations
|mmap_write_test |Memory mapped read test |iterations
|===
== Tested File Systems
=== NTFS
The comparison to NTFS is very important to establish a baseline. It is also very misleading because NTFS is a disk file system and MEMFS (either the WinFsp or Dokany variants) is an in memory file system. The tests will show that MEMFS is faster than NTFS. This should not be taken to mean that we are trying to make the (obvious) claim that an in memory file system is faster than a disk file system, but to show that the approach of writing a file system in user mode is a valid proposition and can be efficient.
=== WinFsp/MEMFS
MEMFS is the file system used to test WinFsp and shipped as a sample bundled with the WinFsp installer. MEMFS is a simple in memory file system and as such is very fast under most conditions. This is desirable because our goal with this performance testing is to measure the speed of the WinFsp system components rather the performance of a complex user mode file system. MEMFS has minimal overhead and is ideal for this purpose.
WinFsp/MEMFS can be run in different configurations, which enable or disable WinFsp caching features. The tested configurations were:
- An infinite FileInfoTimeout, which enables caching of metadata and data.
- A FileInfoTimeout of 1s (second), which enables caching of metadata but disables caching of data.
- A FileInfoTimeout of 0, which completely disables caching.
The WinFsp git commit at the time of testing was d804f5674d76f11ea86d14f4bcb1157e6e40e719.
=== Dokany/MEMFS
To achieve fairness when comparing Dokany to WinFsp the MEMFS file system has been ported to Dokany. Substantial care was taken to ensure that WinFsp/MEMFS and Dokany/MEMFS perform equally well, so that the performance of the Dokany FSD and user-mode components can be measured and compared accurately.
The Dokany/MEMFS project has its own https://github.com/billziss-gh/memfs-dokany[repository]. The project comes without a license, which means that it may not be used for any purpose other than as a reference.
The Dokany version used for testing was 1.0.1. The Dokany/MEMFS git commit was 27a678d7c0d5ee2fb3fb2ecc8e38210857ae941c.
== Test Environment
Tests were performed on an idle computer/VM. There was a reboot of both the computer and VM before each file system was tested. Each test was run twice and the smaller time value chosen. The assumption is that even in a seemingly idle desktop system there is some activity which will affect the results; the smaller value is the preferred one to use because it reflects the time when there is less or no other activity.
The test environment was as follows:
----
MacBook Pro (Retina, 13-inch, Early 2015)
3.1 GHz Intel Core i7
16 GB 1867 MHz DDR3
500 GB SSD
VirtualBox Version 5.0.20 r106931
1 CPU
4 GB RAM
80 GB Dynamically allocated differencing storage
Windows 10 (64-bit) Version 1511 (OS Build 10586.420)
----
== Test Results
In the graphs below we use consistent coloring to quickly identify a file system. Red is used for NTFS, yellow for WinFsp/MEMFS with a FileInfoTimeout of 0, green for WinFsp/MEMFS with a FileInfoTimeout of 1, light blue for WinFsp/MEMFS with an infinite FileInfoTimeout and deep blue for Dokany/MEMFS.
In all tests lower times are better (the file system is faster).
=== File Tests
These tests measure the performance of creating, opening, overwriting and listing files and directories.
==== file_create_test
This test measures the performance of CreateFileW(CREATE_NEW) / CloseHandle. WinFsp has the best performance here. Dokany follows and NTFS is last as it has to actually update its data structures on disk.
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/file_create_test.csv",file="WinFsp-Performance-Testing/file_create_test.png",opt="x-label=file count,y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/file_create_test.png[]]
==== file_open_test
This test measures the performance of CreateFileW(OPEN_EXISTING) / CloseHandle. WinFsp again has the best (although uneven) performance, followed by NTFS and then Dokany.
WinFsp appears to have very uneven performance here. In particular notice that opening 1000 files is slower than opening 2000 files, which makes no sense! I suspect that the test observes an initial acquisition of resouces when the test first starts, which is not necessary when the test runs for 2000 files at a later time. This uneven performance should probably be investigated in the future.
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/file_open_test.csv",file="WinFsp-Performance-Testing/file_open_test.png",opt="x-label=file count,y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/file_open_test.png[]]
==== file_overwrite_test
This test measures the performance of CreateFileW(CREATE_ALWAYS) / CloseHandle. WinFsp is fastest, followed by NTFS and then Dokany.
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/file_overwrite_test.csv",file="WinFsp-Performance-Testing/file_overwrite_test.png",opt="x-label=file count,y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/file_overwrite_test.png[]]
==== file_list_test
This test measures the performance of FindFirstFileW / FindNextFile / FindClose. NTFS wins this scenario, likely because it can satisfy the list operation from cache. WinFsp has overall good performance. Dokany appears to show slightly quadratic performance in this scenario.
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/file_list_test.csv",file="WinFsp-Performance-Testing/file_list_test.png",opt="x-label=file count,y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/file_list_test.png[]]
==== file_delete_test
This test measures the performance of DeleteFileW. WinFsp has the best performance, followed by Dokany and NTFS with very similar performance.
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/file_delete_test.csv",file="WinFsp-Performance-Testing/file_delete_test.png",opt="x-label=file count,y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/file_delete_test.png[]]
=== Read/Write Tests
These tests measure the performance of cached, non-cached and memory-mapped I/O.
==== rdwr_cc_write_page_test
This test measures the performance of cached WriteFile with 1 page writes. NTFS and WinFsp with an infinite FileInfoTimeout have the best performance, with a clear edge to NTFS (likely because of its use of FastIO, which WinFsp does not currently support). WinFsp with a FileInfoTimeout of 0 or 1 performance is next, because WinFsp does not use the NTOS Cache Manager in this scenario. Dokany performance is last.
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/rdwr_cc_write_page_test.csv",file="WinFsp-Performance-Testing/rdwr_cc_write_page_test.png",opt="x-label=iterations,y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/rdwr_cc_write_page_test.png[]]
==== rdwr_cc_read_page_test
This test measures the performance of cached ReadFile with 1 page reads. The results here are very similar to the rdwr_cc_write_page_test case and similar comments apply.
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/rdwr_cc_read_page_test.csv",file="WinFsp-Performance-Testing/rdwr_cc_read_page_test.png",opt="x-label=iterations,y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/rdwr_cc_read_page_test.png[]]
==== rdwr_nc_write_page_test
This test measures the performance of non-cached WriteFile with 1 page writes. WinFsp has the best performance, followed by Dokany. NTFS shows bad performance, which of course make sense as we are asking it to write all data to the disk.
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/rdwr_nc_write_page_test.csv",file="WinFsp-Performance-Testing/rdwr_nc_write_page_test.png",opt="x-label=iterations,y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/rdwr_nc_write_page_test.png[]]
==== rdwr_nc_read_page_test
This test measures the performance of non-cached ReadFile with 1 page reads. The results here are very similar to the rdwr_nc_write_page_test case and similar comments apply.
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/rdwr_nc_read_page_test.csv",file="WinFsp-Performance-Testing/rdwr_nc_read_page_test.png",opt="x-label=iterations,y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/rdwr_nc_read_page_test.png[]]
==== mmap_write_test
This test measures the performance of memory mapped writes. NTFS and WinFsp seem to have identical performance here, which actually makes sense because memory mapped I/O is effectively always cached and most of the actual I/O is done asynchronously by the system.
There are no results for Dokany as it seems to (still) not support memory mapped files:
----
Y:\>c:\Users\billziss\Projects\winfsp\build\VStudio\build\Release\fsbench-x64.exe --mmap=100 mmap*
mmap_write_test........................ KO
ASSERT(0 != Mapping) failed at fsbench.c:226:mmap_dotest
----
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/mmap_write_test.csv",file="WinFsp-Performance-Testing/mmap_write_test.png",opt="x-label=iterations,y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/mmap_write_test.png[]]
==== mmap_read_test
This test measures the performance of memory mapped reads. Again NTFS and WinFsp seem to have identical performance here.
There are no results for Dokany as it faces the same issue as with mmap_write_test.
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/mmap_read_test.csv",file="WinFsp-Performance-Testing/mmap_read_test.png",opt="x-label=iterations,y-label=time"]]
ifndef::env-browser[image::WinFsp-Performance-Testing/mmap_read_test.png[]]

View File

@ -0,0 +1,75 @@
file_create_test,1000,0.28
file_open_test,1000,0.14
file_overwrite_test,1000,0.33
file_list_test,1000,0.16
file_delete_test,1000,0.17
file_mkdir_test,1000,0.08
file_rmdir_test,1000,0.14
file_create_test,2000,0.67
file_open_test,2000,0.27
file_overwrite_test,2000,0.69
file_list_test,2000,0.36
file_delete_test,2000,0.36
file_mkdir_test,2000,0.33
file_rmdir_test,2000,0.23
file_create_test,3000,0.91
file_open_test,3000,0.42
file_overwrite_test,3000,1.03
file_list_test,3000,0.64
file_delete_test,3000,0.56
file_mkdir_test,3000,0.52
file_rmdir_test,3000,0.34
file_create_test,4000,1.25
file_open_test,4000,0.55
file_overwrite_test,4000,1.34
file_list_test,4000,0.97
file_delete_test,4000,0.72
file_mkdir_test,4000,0.66
file_rmdir_test,4000,0.47
file_create_test,5000,1.87
file_open_test,5000,0.67
file_overwrite_test,5000,1.64
file_list_test,5000,1.38
file_delete_test,5000,0.91
file_mkdir_test,5000,0.83
file_rmdir_test,5000,0.59
rdwr_cc_write_page_test,100,2.19
rdwr_cc_read_page_test,100,2.31
rdwr_cc_write_large_test,100,0.33
rdwr_cc_read_large_test,100,0.28
rdwr_cc_write_page_test,200,4.33
rdwr_cc_read_page_test,200,4.58
rdwr_cc_write_large_test,200,0.59
rdwr_cc_read_large_test,200,0.59
rdwr_cc_write_page_test,300,6.37
rdwr_cc_read_page_test,300,7.00
rdwr_cc_write_large_test,300,0.91
rdwr_cc_read_large_test,300,0.89
rdwr_cc_write_page_test,400,8.59
rdwr_cc_read_page_test,400,9.34
rdwr_cc_write_large_test,400,1.22
rdwr_cc_read_large_test,400,1.17
rdwr_cc_write_page_test,500,10.70
rdwr_cc_read_page_test,500,11.47
rdwr_cc_write_large_test,500,1.47
rdwr_cc_read_large_test,500,1.45
rdwr_nc_write_page_test,100,2.20
rdwr_nc_read_page_test,100,2.22
rdwr_nc_write_large_test,100,0.36
rdwr_nc_read_large_test,100,0.30
rdwr_nc_write_page_test,200,4.72
rdwr_nc_read_page_test,200,4.48
rdwr_nc_write_large_test,200,0.63
rdwr_nc_read_large_test,200,0.58
rdwr_nc_write_page_test,300,6.53
rdwr_nc_read_page_test,300,6.56
rdwr_nc_write_large_test,300,0.91
rdwr_nc_read_large_test,300,0.84
rdwr_nc_write_page_test,400,9.05
rdwr_nc_read_page_test,400,8.67
rdwr_nc_write_large_test,400,1.22
rdwr_nc_read_large_test,400,1.13
rdwr_nc_write_page_test,500,11.45
rdwr_nc_read_page_test,500,10.86
rdwr_nc_write_large_test,500,1.50
rdwr_nc_read_large_test,500,1.44
1 file_create_test 1000 0.28
2 file_open_test 1000 0.14
3 file_overwrite_test 1000 0.33
4 file_list_test 1000 0.16
5 file_delete_test 1000 0.17
6 file_mkdir_test 1000 0.08
7 file_rmdir_test 1000 0.14
8 file_create_test 2000 0.67
9 file_open_test 2000 0.27
10 file_overwrite_test 2000 0.69
11 file_list_test 2000 0.36
12 file_delete_test 2000 0.36
13 file_mkdir_test 2000 0.33
14 file_rmdir_test 2000 0.23
15 file_create_test 3000 0.91
16 file_open_test 3000 0.42
17 file_overwrite_test 3000 1.03
18 file_list_test 3000 0.64
19 file_delete_test 3000 0.56
20 file_mkdir_test 3000 0.52
21 file_rmdir_test 3000 0.34
22 file_create_test 4000 1.25
23 file_open_test 4000 0.55
24 file_overwrite_test 4000 1.34
25 file_list_test 4000 0.97
26 file_delete_test 4000 0.72
27 file_mkdir_test 4000 0.66
28 file_rmdir_test 4000 0.47
29 file_create_test 5000 1.87
30 file_open_test 5000 0.67
31 file_overwrite_test 5000 1.64
32 file_list_test 5000 1.38
33 file_delete_test 5000 0.91
34 file_mkdir_test 5000 0.83
35 file_rmdir_test 5000 0.59
36 rdwr_cc_write_page_test 100 2.19
37 rdwr_cc_read_page_test 100 2.31
38 rdwr_cc_write_large_test 100 0.33
39 rdwr_cc_read_large_test 100 0.28
40 rdwr_cc_write_page_test 200 4.33
41 rdwr_cc_read_page_test 200 4.58
42 rdwr_cc_write_large_test 200 0.59
43 rdwr_cc_read_large_test 200 0.59
44 rdwr_cc_write_page_test 300 6.37
45 rdwr_cc_read_page_test 300 7.00
46 rdwr_cc_write_large_test 300 0.91
47 rdwr_cc_read_large_test 300 0.89
48 rdwr_cc_write_page_test 400 8.59
49 rdwr_cc_read_page_test 400 9.34
50 rdwr_cc_write_large_test 400 1.22
51 rdwr_cc_read_large_test 400 1.17
52 rdwr_cc_write_page_test 500 10.70
53 rdwr_cc_read_page_test 500 11.47
54 rdwr_cc_write_large_test 500 1.47
55 rdwr_cc_read_large_test 500 1.45
56 rdwr_nc_write_page_test 100 2.20
57 rdwr_nc_read_page_test 100 2.22
58 rdwr_nc_write_large_test 100 0.36
59 rdwr_nc_read_large_test 100 0.30
60 rdwr_nc_write_page_test 200 4.72
61 rdwr_nc_read_page_test 200 4.48
62 rdwr_nc_write_large_test 200 0.63
63 rdwr_nc_read_large_test 200 0.58
64 rdwr_nc_write_page_test 300 6.53
65 rdwr_nc_read_page_test 300 6.56
66 rdwr_nc_write_large_test 300 0.91
67 rdwr_nc_read_large_test 300 0.84
68 rdwr_nc_write_page_test 400 9.05
69 rdwr_nc_read_page_test 400 8.67
70 rdwr_nc_write_large_test 400 1.22
71 rdwr_nc_read_large_test 400 1.13
72 rdwr_nc_write_page_test 500 11.45
73 rdwr_nc_read_page_test 500 10.86
74 rdwr_nc_write_large_test 500 1.50
75 rdwr_nc_read_large_test 500 1.44

View File

@ -0,0 +1,75 @@
file_create_test,1000,0.28
file_open_test,1000,0.15
file_overwrite_test,1000,0.33
file_list_test,1000,0.16
file_delete_test,1000,0.19
file_mkdir_test,1000,0.08
file_rmdir_test,1000,0.13
file_create_test,2000,0.69
file_open_test,2000,0.27
file_overwrite_test,2000,0.67
file_list_test,2000,0.37
file_delete_test,2000,0.36
file_mkdir_test,2000,0.33
file_rmdir_test,2000,0.25
file_create_test,3000,0.92
file_open_test,3000,0.41
file_overwrite_test,3000,1.08
file_list_test,3000,0.66
file_delete_test,3000,0.56
file_mkdir_test,3000,0.48
file_rmdir_test,3000,0.38
file_create_test,4000,1.31
file_open_test,4000,0.61
file_overwrite_test,4000,1.38
file_list_test,4000,1.00
file_delete_test,4000,0.73
file_mkdir_test,4000,0.66
file_rmdir_test,4000,0.53
file_create_test,5000,1.64
file_open_test,5000,0.67
file_overwrite_test,5000,1.67
file_list_test,5000,1.38
file_delete_test,5000,0.91
file_mkdir_test,5000,0.98
file_rmdir_test,5000,0.66
rdwr_cc_write_page_test,100,2.08
rdwr_cc_read_page_test,100,2.23
rdwr_cc_write_large_test,100,0.33
rdwr_cc_read_large_test,100,0.28
rdwr_cc_write_page_test,200,4.23
rdwr_cc_read_page_test,200,4.63
rdwr_cc_write_large_test,200,0.61
rdwr_cc_read_large_test,200,0.58
rdwr_cc_write_page_test,300,6.33
rdwr_cc_read_page_test,300,6.78
rdwr_cc_write_large_test,300,0.92
rdwr_cc_read_large_test,300,0.86
rdwr_cc_write_page_test,400,8.48
rdwr_cc_read_page_test,400,9.02
rdwr_cc_write_large_test,400,1.20
rdwr_cc_read_large_test,400,1.16
rdwr_cc_write_page_test,500,10.33
rdwr_cc_read_page_test,500,11.20
rdwr_cc_write_large_test,500,1.53
rdwr_cc_read_large_test,500,1.47
rdwr_nc_write_page_test,100,2.23
rdwr_nc_read_page_test,100,2.22
rdwr_nc_write_large_test,100,0.31
rdwr_nc_read_large_test,100,0.30
rdwr_nc_write_page_test,200,4.66
rdwr_nc_read_page_test,200,4.34
rdwr_nc_write_large_test,200,0.61
rdwr_nc_read_large_test,200,0.63
rdwr_nc_write_page_test,300,6.44
rdwr_nc_read_page_test,300,6.34
rdwr_nc_write_large_test,300,0.92
rdwr_nc_read_large_test,300,0.84
rdwr_nc_write_page_test,400,8.56
rdwr_nc_read_page_test,400,8.78
rdwr_nc_write_large_test,400,1.26
rdwr_nc_read_large_test,400,1.11
rdwr_nc_write_page_test,500,10.73
rdwr_nc_read_page_test,500,10.59
rdwr_nc_write_large_test,500,1.53
rdwr_nc_read_large_test,500,1.41
1 file_create_test 1000 0.28
2 file_open_test 1000 0.15
3 file_overwrite_test 1000 0.33
4 file_list_test 1000 0.16
5 file_delete_test 1000 0.19
6 file_mkdir_test 1000 0.08
7 file_rmdir_test 1000 0.13
8 file_create_test 2000 0.69
9 file_open_test 2000 0.27
10 file_overwrite_test 2000 0.67
11 file_list_test 2000 0.37
12 file_delete_test 2000 0.36
13 file_mkdir_test 2000 0.33
14 file_rmdir_test 2000 0.25
15 file_create_test 3000 0.92
16 file_open_test 3000 0.41
17 file_overwrite_test 3000 1.08
18 file_list_test 3000 0.66
19 file_delete_test 3000 0.56
20 file_mkdir_test 3000 0.48
21 file_rmdir_test 3000 0.38
22 file_create_test 4000 1.31
23 file_open_test 4000 0.61
24 file_overwrite_test 4000 1.38
25 file_list_test 4000 1.00
26 file_delete_test 4000 0.73
27 file_mkdir_test 4000 0.66
28 file_rmdir_test 4000 0.53
29 file_create_test 5000 1.64
30 file_open_test 5000 0.67
31 file_overwrite_test 5000 1.67
32 file_list_test 5000 1.38
33 file_delete_test 5000 0.91
34 file_mkdir_test 5000 0.98
35 file_rmdir_test 5000 0.66
36 rdwr_cc_write_page_test 100 2.08
37 rdwr_cc_read_page_test 100 2.23
38 rdwr_cc_write_large_test 100 0.33
39 rdwr_cc_read_large_test 100 0.28
40 rdwr_cc_write_page_test 200 4.23
41 rdwr_cc_read_page_test 200 4.63
42 rdwr_cc_write_large_test 200 0.61
43 rdwr_cc_read_large_test 200 0.58
44 rdwr_cc_write_page_test 300 6.33
45 rdwr_cc_read_page_test 300 6.78
46 rdwr_cc_write_large_test 300 0.92
47 rdwr_cc_read_large_test 300 0.86
48 rdwr_cc_write_page_test 400 8.48
49 rdwr_cc_read_page_test 400 9.02
50 rdwr_cc_write_large_test 400 1.20
51 rdwr_cc_read_large_test 400 1.16
52 rdwr_cc_write_page_test 500 10.33
53 rdwr_cc_read_page_test 500 11.20
54 rdwr_cc_write_large_test 500 1.53
55 rdwr_cc_read_large_test 500 1.47
56 rdwr_nc_write_page_test 100 2.23
57 rdwr_nc_read_page_test 100 2.22
58 rdwr_nc_write_large_test 100 0.31
59 rdwr_nc_read_large_test 100 0.30
60 rdwr_nc_write_page_test 200 4.66
61 rdwr_nc_read_page_test 200 4.34
62 rdwr_nc_write_large_test 200 0.61
63 rdwr_nc_read_large_test 200 0.63
64 rdwr_nc_write_page_test 300 6.44
65 rdwr_nc_read_page_test 300 6.34
66 rdwr_nc_write_large_test 300 0.92
67 rdwr_nc_read_large_test 300 0.84
68 rdwr_nc_write_page_test 400 8.56
69 rdwr_nc_read_page_test 400 8.78
70 rdwr_nc_write_large_test 400 1.26
71 rdwr_nc_read_large_test 400 1.11
72 rdwr_nc_write_page_test 500 10.73
73 rdwr_nc_read_page_test 500 10.59
74 rdwr_nc_write_large_test 500 1.53
75 rdwr_nc_read_large_test 500 1.41

View File

@ -0,0 +1,85 @@
file_create_test,1000,0.92
file_open_test,1000,0.08
file_overwrite_test,1000,0.19
file_list_test,1000,0.08
file_delete_test,1000,0.19
file_mkdir_test,1000,0.16
file_rmdir_test,1000,0.11
file_create_test,2000,1.45
file_open_test,2000,0.17
file_overwrite_test,2000,0.38
file_list_test,2000,0.16
file_delete_test,2000,0.39
file_mkdir_test,2000,0.25
file_rmdir_test,2000,0.28
file_create_test,3000,1.11
file_open_test,3000,0.23
file_overwrite_test,3000,0.72
file_list_test,3000,0.23
file_delete_test,3000,0.56
file_mkdir_test,3000,0.56
file_rmdir_test,3000,0.36
file_create_test,4000,1.45
file_open_test,4000,0.36
file_overwrite_test,4000,0.97
file_list_test,4000,0.33
file_delete_test,4000,0.77
file_mkdir_test,4000,0.48
file_rmdir_test,4000,0.47
file_create_test,5000,2.47
file_open_test,5000,0.45
file_overwrite_test,5000,1.23
file_list_test,5000,0.41
file_delete_test,5000,1.03
file_mkdir_test,5000,0.70
file_rmdir_test,5000,0.70
rdwr_cc_write_page_test,100,0.25
rdwr_cc_read_page_test,100,0.19
rdwr_cc_write_large_test,100,0.09
rdwr_cc_read_large_test,100,0.08
rdwr_cc_write_page_test,200,0.47
rdwr_cc_read_page_test,200,0.52
rdwr_cc_write_large_test,200,0.22
rdwr_cc_read_large_test,200,0.16
rdwr_cc_write_page_test,300,0.72
rdwr_cc_read_page_test,300,0.62
rdwr_cc_write_large_test,300,0.30
rdwr_cc_read_large_test,300,0.23
rdwr_cc_write_page_test,400,0.92
rdwr_cc_read_page_test,400,0.88
rdwr_cc_write_large_test,400,0.41
rdwr_cc_read_large_test,400,0.31
rdwr_cc_write_page_test,500,1.20
rdwr_cc_read_page_test,500,0.97
rdwr_cc_write_large_test,500,0.50
rdwr_cc_read_large_test,500,0.39
rdwr_nc_write_page_test,100,7.56
rdwr_nc_read_page_test,100,10.14
rdwr_nc_write_large_test,100,0.88
rdwr_nc_read_large_test,100,0.56
rdwr_nc_write_page_test,200,14.36
rdwr_nc_read_page_test,200,21.39
rdwr_nc_write_large_test,200,1.72
rdwr_nc_read_large_test,200,1.34
rdwr_nc_write_page_test,300,21.86
rdwr_nc_read_page_test,300,19.56
rdwr_nc_write_large_test,300,2.53
rdwr_nc_read_large_test,300,1.64
rdwr_nc_write_page_test,400,28.52
rdwr_nc_read_page_test,400,26.11
rdwr_nc_write_large_test,400,3.42
rdwr_nc_read_large_test,400,2.22
rdwr_nc_write_page_test,500,35.45
rdwr_nc_read_page_test,500,33.05
rdwr_nc_write_large_test,500,4.33
rdwr_nc_read_large_test,500,2.77
mmap_write_test,100,0.16
mmap_read_test,100,0.20
mmap_write_test,200,0.30
mmap_read_test,200,0.39
mmap_write_test,300,0.44
mmap_read_test,300,0.59
mmap_write_test,400,0.58
mmap_read_test,400,0.78
mmap_write_test,500,0.72
mmap_read_test,500,1.06
1 file_create_test 1000 0.92
2 file_open_test 1000 0.08
3 file_overwrite_test 1000 0.19
4 file_list_test 1000 0.08
5 file_delete_test 1000 0.19
6 file_mkdir_test 1000 0.16
7 file_rmdir_test 1000 0.11
8 file_create_test 2000 1.45
9 file_open_test 2000 0.17
10 file_overwrite_test 2000 0.38
11 file_list_test 2000 0.16
12 file_delete_test 2000 0.39
13 file_mkdir_test 2000 0.25
14 file_rmdir_test 2000 0.28
15 file_create_test 3000 1.11
16 file_open_test 3000 0.23
17 file_overwrite_test 3000 0.72
18 file_list_test 3000 0.23
19 file_delete_test 3000 0.56
20 file_mkdir_test 3000 0.56
21 file_rmdir_test 3000 0.36
22 file_create_test 4000 1.45
23 file_open_test 4000 0.36
24 file_overwrite_test 4000 0.97
25 file_list_test 4000 0.33
26 file_delete_test 4000 0.77
27 file_mkdir_test 4000 0.48
28 file_rmdir_test 4000 0.47
29 file_create_test 5000 2.47
30 file_open_test 5000 0.45
31 file_overwrite_test 5000 1.23
32 file_list_test 5000 0.41
33 file_delete_test 5000 1.03
34 file_mkdir_test 5000 0.70
35 file_rmdir_test 5000 0.70
36 rdwr_cc_write_page_test 100 0.25
37 rdwr_cc_read_page_test 100 0.19
38 rdwr_cc_write_large_test 100 0.09
39 rdwr_cc_read_large_test 100 0.08
40 rdwr_cc_write_page_test 200 0.47
41 rdwr_cc_read_page_test 200 0.52
42 rdwr_cc_write_large_test 200 0.22
43 rdwr_cc_read_large_test 200 0.16
44 rdwr_cc_write_page_test 300 0.72
45 rdwr_cc_read_page_test 300 0.62
46 rdwr_cc_write_large_test 300 0.30
47 rdwr_cc_read_large_test 300 0.23
48 rdwr_cc_write_page_test 400 0.92
49 rdwr_cc_read_page_test 400 0.88
50 rdwr_cc_write_large_test 400 0.41
51 rdwr_cc_read_large_test 400 0.31
52 rdwr_cc_write_page_test 500 1.20
53 rdwr_cc_read_page_test 500 0.97
54 rdwr_cc_write_large_test 500 0.50
55 rdwr_cc_read_large_test 500 0.39
56 rdwr_nc_write_page_test 100 7.56
57 rdwr_nc_read_page_test 100 10.14
58 rdwr_nc_write_large_test 100 0.88
59 rdwr_nc_read_large_test 100 0.56
60 rdwr_nc_write_page_test 200 14.36
61 rdwr_nc_read_page_test 200 21.39
62 rdwr_nc_write_large_test 200 1.72
63 rdwr_nc_read_large_test 200 1.34
64 rdwr_nc_write_page_test 300 21.86
65 rdwr_nc_read_page_test 300 19.56
66 rdwr_nc_write_large_test 300 2.53
67 rdwr_nc_read_large_test 300 1.64
68 rdwr_nc_write_page_test 400 28.52
69 rdwr_nc_read_page_test 400 26.11
70 rdwr_nc_write_large_test 400 3.42
71 rdwr_nc_read_large_test 400 2.22
72 rdwr_nc_write_page_test 500 35.45
73 rdwr_nc_read_page_test 500 33.05
74 rdwr_nc_write_large_test 500 4.33
75 rdwr_nc_read_large_test 500 2.77
76 mmap_write_test 100 0.16
77 mmap_read_test 100 0.20
78 mmap_write_test 200 0.30
79 mmap_read_test 200 0.39
80 mmap_write_test 300 0.44
81 mmap_read_test 300 0.59
82 mmap_write_test 400 0.58
83 mmap_read_test 400 0.78
84 mmap_write_test 500 0.72
85 mmap_read_test 500 1.06

View File

@ -0,0 +1,85 @@
file_create_test,1000,0.97
file_open_test,1000,0.08
file_overwrite_test,1000,0.19
file_list_test,1000,0.08
file_delete_test,1000,0.19
file_mkdir_test,1000,0.13
file_rmdir_test,1000,0.13
file_create_test,2000,1.38
file_open_test,2000,0.23
file_overwrite_test,2000,0.36
file_list_test,2000,0.17
file_delete_test,2000,0.41
file_mkdir_test,2000,0.25
file_rmdir_test,2000,0.36
file_create_test,3000,1.34
file_open_test,3000,0.28
file_overwrite_test,3000,0.78
file_list_test,3000,0.27
file_delete_test,3000,0.59
file_mkdir_test,3000,0.36
file_rmdir_test,3000,0.36
file_create_test,4000,1.33
file_open_test,4000,0.36
file_overwrite_test,4000,1.06
file_list_test,4000,0.33
file_delete_test,4000,0.81
file_mkdir_test,4000,0.67
file_rmdir_test,4000,0.41
file_create_test,5000,1.94
file_open_test,5000,0.48
file_overwrite_test,5000,1.14
file_list_test,5000,0.44
file_delete_test,5000,1.06
file_mkdir_test,5000,0.87
file_rmdir_test,5000,0.59
rdwr_cc_write_page_test,100,0.25
rdwr_cc_read_page_test,100,0.19
rdwr_cc_write_large_test,100,0.11
rdwr_cc_read_large_test,100,0.08
rdwr_cc_write_page_test,200,0.61
rdwr_cc_read_page_test,200,0.42
rdwr_cc_write_large_test,200,0.22
rdwr_cc_read_large_test,200,0.25
rdwr_cc_write_page_test,300,0.69
rdwr_cc_read_page_test,300,0.61
rdwr_cc_write_large_test,300,0.28
rdwr_cc_read_large_test,300,0.22
rdwr_cc_write_page_test,400,0.91
rdwr_cc_read_page_test,400,0.78
rdwr_cc_write_large_test,400,0.38
rdwr_cc_read_large_test,400,0.28
rdwr_cc_write_page_test,500,1.19
rdwr_cc_read_page_test,500,1.03
rdwr_cc_write_large_test,500,0.48
rdwr_cc_read_large_test,500,0.36
rdwr_nc_write_page_test,100,7.55
rdwr_nc_read_page_test,100,9.38
rdwr_nc_write_large_test,100,0.86
rdwr_nc_read_large_test,100,0.58
rdwr_nc_write_page_test,200,15.69
rdwr_nc_read_page_test,200,21.78
rdwr_nc_write_large_test,200,1.73
rdwr_nc_read_large_test,200,1.16
rdwr_nc_write_page_test,300,21.58
rdwr_nc_read_page_test,300,21.92
rdwr_nc_write_large_test,300,2.59
rdwr_nc_read_large_test,300,1.84
rdwr_nc_write_page_test,400,28.91
rdwr_nc_read_page_test,400,26.31
rdwr_nc_write_large_test,400,3.38
rdwr_nc_read_large_test,400,2.20
rdwr_nc_write_page_test,500,36.69
rdwr_nc_read_page_test,500,33.52
rdwr_nc_write_large_test,500,4.36
rdwr_nc_read_large_test,500,2.80
mmap_write_test,100,0.16
mmap_read_test,100,0.19
mmap_write_test,200,0.31
mmap_read_test,200,0.39
mmap_write_test,300,0.44
mmap_read_test,300,0.58
mmap_write_test,400,0.59
mmap_read_test,400,0.78
mmap_write_test,500,0.72
mmap_read_test,500,1.09
1 file_create_test 1000 0.97
2 file_open_test 1000 0.08
3 file_overwrite_test 1000 0.19
4 file_list_test 1000 0.08
5 file_delete_test 1000 0.19
6 file_mkdir_test 1000 0.13
7 file_rmdir_test 1000 0.13
8 file_create_test 2000 1.38
9 file_open_test 2000 0.23
10 file_overwrite_test 2000 0.36
11 file_list_test 2000 0.17
12 file_delete_test 2000 0.41
13 file_mkdir_test 2000 0.25
14 file_rmdir_test 2000 0.36
15 file_create_test 3000 1.34
16 file_open_test 3000 0.28
17 file_overwrite_test 3000 0.78
18 file_list_test 3000 0.27
19 file_delete_test 3000 0.59
20 file_mkdir_test 3000 0.36
21 file_rmdir_test 3000 0.36
22 file_create_test 4000 1.33
23 file_open_test 4000 0.36
24 file_overwrite_test 4000 1.06
25 file_list_test 4000 0.33
26 file_delete_test 4000 0.81
27 file_mkdir_test 4000 0.67
28 file_rmdir_test 4000 0.41
29 file_create_test 5000 1.94
30 file_open_test 5000 0.48
31 file_overwrite_test 5000 1.14
32 file_list_test 5000 0.44
33 file_delete_test 5000 1.06
34 file_mkdir_test 5000 0.87
35 file_rmdir_test 5000 0.59
36 rdwr_cc_write_page_test 100 0.25
37 rdwr_cc_read_page_test 100 0.19
38 rdwr_cc_write_large_test 100 0.11
39 rdwr_cc_read_large_test 100 0.08
40 rdwr_cc_write_page_test 200 0.61
41 rdwr_cc_read_page_test 200 0.42
42 rdwr_cc_write_large_test 200 0.22
43 rdwr_cc_read_large_test 200 0.25
44 rdwr_cc_write_page_test 300 0.69
45 rdwr_cc_read_page_test 300 0.61
46 rdwr_cc_write_large_test 300 0.28
47 rdwr_cc_read_large_test 300 0.22
48 rdwr_cc_write_page_test 400 0.91
49 rdwr_cc_read_page_test 400 0.78
50 rdwr_cc_write_large_test 400 0.38
51 rdwr_cc_read_large_test 400 0.28
52 rdwr_cc_write_page_test 500 1.19
53 rdwr_cc_read_page_test 500 1.03
54 rdwr_cc_write_large_test 500 0.48
55 rdwr_cc_read_large_test 500 0.36
56 rdwr_nc_write_page_test 100 7.55
57 rdwr_nc_read_page_test 100 9.38
58 rdwr_nc_write_large_test 100 0.86
59 rdwr_nc_read_large_test 100 0.58
60 rdwr_nc_write_page_test 200 15.69
61 rdwr_nc_read_page_test 200 21.78
62 rdwr_nc_write_large_test 200 1.73
63 rdwr_nc_read_large_test 200 1.16
64 rdwr_nc_write_page_test 300 21.58
65 rdwr_nc_read_page_test 300 21.92
66 rdwr_nc_write_large_test 300 2.59
67 rdwr_nc_read_large_test 300 1.84
68 rdwr_nc_write_page_test 400 28.91
69 rdwr_nc_read_page_test 400 26.31
70 rdwr_nc_write_large_test 400 3.38
71 rdwr_nc_read_large_test 400 2.20
72 rdwr_nc_write_page_test 500 36.69
73 rdwr_nc_read_page_test 500 33.52
74 rdwr_nc_write_large_test 500 4.36
75 rdwr_nc_read_large_test 500 2.80
76 mmap_write_test 100 0.16
77 mmap_read_test 100 0.19
78 mmap_write_test 200 0.31
79 mmap_read_test 200 0.39
80 mmap_write_test 300 0.44
81 mmap_read_test 300 0.58
82 mmap_write_test 400 0.59
83 mmap_read_test 400 0.78
84 mmap_write_test 500 0.72
85 mmap_read_test 500 1.09

View File

@ -0,0 +1,85 @@
file_create_test,1000,0.20
file_open_test,1000,0.08
file_overwrite_test,1000,0.06
file_list_test,1000,0.11
file_delete_test,1000,0.09
file_mkdir_test,1000,0.06
file_rmdir_test,1000,0.08
file_create_test,2000,0.48
file_open_test,2000,0.11
file_overwrite_test,2000,0.11
file_list_test,2000,0.23
file_delete_test,2000,0.19
file_mkdir_test,2000,0.09
file_rmdir_test,2000,0.14
file_create_test,3000,0.61
file_open_test,3000,0.30
file_overwrite_test,3000,0.17
file_list_test,3000,0.33
file_delete_test,3000,0.27
file_mkdir_test,3000,0.41
file_rmdir_test,3000,0.20
file_create_test,4000,0.64
file_open_test,4000,0.23
file_overwrite_test,4000,0.25
file_list_test,4000,0.47
file_delete_test,4000,0.48
file_mkdir_test,4000,0.53
file_rmdir_test,4000,0.27
file_create_test,5000,1.08
file_open_test,5000,0.28
file_overwrite_test,5000,0.30
file_list_test,5000,0.61
file_delete_test,5000,0.52
file_mkdir_test,5000,0.66
file_rmdir_test,5000,0.39
rdwr_cc_write_page_test,100,1.30
rdwr_cc_read_page_test,100,1.44
rdwr_cc_write_large_test,100,0.17
rdwr_cc_read_large_test,100,0.17
rdwr_cc_write_page_test,200,2.67
rdwr_cc_read_page_test,200,2.97
rdwr_cc_write_large_test,200,0.33
rdwr_cc_read_large_test,200,0.39
rdwr_cc_write_page_test,300,4.00
rdwr_cc_read_page_test,300,4.42
rdwr_cc_write_large_test,300,0.48
rdwr_cc_read_large_test,300,0.50
rdwr_cc_write_page_test,400,5.36
rdwr_cc_read_page_test,400,5.86
rdwr_cc_write_large_test,400,0.63
rdwr_cc_read_large_test,400,0.66
rdwr_cc_write_page_test,500,6.55
rdwr_cc_read_page_test,500,7.05
rdwr_cc_write_large_test,500,0.89
rdwr_cc_read_large_test,500,0.89
rdwr_nc_write_page_test,100,1.33
rdwr_nc_read_page_test,100,1.33
rdwr_nc_write_large_test,100,0.16
rdwr_nc_read_large_test,100,0.16
rdwr_nc_write_page_test,200,2.67
rdwr_nc_read_page_test,200,2.67
rdwr_nc_write_large_test,200,0.31
rdwr_nc_read_large_test,200,0.33
rdwr_nc_write_page_test,300,4.01
rdwr_nc_read_page_test,300,4.06
rdwr_nc_write_large_test,300,0.48
rdwr_nc_read_large_test,300,0.47
rdwr_nc_write_page_test,400,5.44
rdwr_nc_read_page_test,400,5.42
rdwr_nc_write_large_test,400,0.63
rdwr_nc_read_large_test,400,0.66
rdwr_nc_write_page_test,500,6.41
rdwr_nc_read_page_test,500,6.56
rdwr_nc_write_large_test,500,0.83
rdwr_nc_read_large_test,500,0.78
mmap_write_test,100,0.14
mmap_read_test,100,0.20
mmap_write_test,200,0.30
mmap_read_test,200,0.39
mmap_write_test,300,0.45
mmap_read_test,300,0.59
mmap_write_test,400,0.56
mmap_read_test,400,0.83
mmap_write_test,500,0.72
mmap_read_test,500,1.00
1 file_create_test 1000 0.20
2 file_open_test 1000 0.08
3 file_overwrite_test 1000 0.06
4 file_list_test 1000 0.11
5 file_delete_test 1000 0.09
6 file_mkdir_test 1000 0.06
7 file_rmdir_test 1000 0.08
8 file_create_test 2000 0.48
9 file_open_test 2000 0.11
10 file_overwrite_test 2000 0.11
11 file_list_test 2000 0.23
12 file_delete_test 2000 0.19
13 file_mkdir_test 2000 0.09
14 file_rmdir_test 2000 0.14
15 file_create_test 3000 0.61
16 file_open_test 3000 0.30
17 file_overwrite_test 3000 0.17
18 file_list_test 3000 0.33
19 file_delete_test 3000 0.27
20 file_mkdir_test 3000 0.41
21 file_rmdir_test 3000 0.20
22 file_create_test 4000 0.64
23 file_open_test 4000 0.23
24 file_overwrite_test 4000 0.25
25 file_list_test 4000 0.47
26 file_delete_test 4000 0.48
27 file_mkdir_test 4000 0.53
28 file_rmdir_test 4000 0.27
29 file_create_test 5000 1.08
30 file_open_test 5000 0.28
31 file_overwrite_test 5000 0.30
32 file_list_test 5000 0.61
33 file_delete_test 5000 0.52
34 file_mkdir_test 5000 0.66
35 file_rmdir_test 5000 0.39
36 rdwr_cc_write_page_test 100 1.30
37 rdwr_cc_read_page_test 100 1.44
38 rdwr_cc_write_large_test 100 0.17
39 rdwr_cc_read_large_test 100 0.17
40 rdwr_cc_write_page_test 200 2.67
41 rdwr_cc_read_page_test 200 2.97
42 rdwr_cc_write_large_test 200 0.33
43 rdwr_cc_read_large_test 200 0.39
44 rdwr_cc_write_page_test 300 4.00
45 rdwr_cc_read_page_test 300 4.42
46 rdwr_cc_write_large_test 300 0.48
47 rdwr_cc_read_large_test 300 0.50
48 rdwr_cc_write_page_test 400 5.36
49 rdwr_cc_read_page_test 400 5.86
50 rdwr_cc_write_large_test 400 0.63
51 rdwr_cc_read_large_test 400 0.66
52 rdwr_cc_write_page_test 500 6.55
53 rdwr_cc_read_page_test 500 7.05
54 rdwr_cc_write_large_test 500 0.89
55 rdwr_cc_read_large_test 500 0.89
56 rdwr_nc_write_page_test 100 1.33
57 rdwr_nc_read_page_test 100 1.33
58 rdwr_nc_write_large_test 100 0.16
59 rdwr_nc_read_large_test 100 0.16
60 rdwr_nc_write_page_test 200 2.67
61 rdwr_nc_read_page_test 200 2.67
62 rdwr_nc_write_large_test 200 0.31
63 rdwr_nc_read_large_test 200 0.33
64 rdwr_nc_write_page_test 300 4.01
65 rdwr_nc_read_page_test 300 4.06
66 rdwr_nc_write_large_test 300 0.48
67 rdwr_nc_read_large_test 300 0.47
68 rdwr_nc_write_page_test 400 5.44
69 rdwr_nc_read_page_test 400 5.42
70 rdwr_nc_write_large_test 400 0.63
71 rdwr_nc_read_large_test 400 0.66
72 rdwr_nc_write_page_test 500 6.41
73 rdwr_nc_read_page_test 500 6.56
74 rdwr_nc_write_large_test 500 0.83
75 rdwr_nc_read_large_test 500 0.78
76 mmap_write_test 100 0.14
77 mmap_read_test 100 0.20
78 mmap_write_test 200 0.30
79 mmap_read_test 200 0.39
80 mmap_write_test 300 0.45
81 mmap_read_test 300 0.59
82 mmap_write_test 400 0.56
83 mmap_read_test 400 0.83
84 mmap_write_test 500 0.72
85 mmap_read_test 500 1.00

View File

@ -0,0 +1,85 @@
file_create_test,1000,0.20
file_open_test,1000,0.06
file_overwrite_test,1000,0.05
file_list_test,1000,0.11
file_delete_test,1000,0.09
file_mkdir_test,1000,0.05
file_rmdir_test,1000,0.08
file_create_test,2000,0.47
file_open_test,2000,0.13
file_overwrite_test,2000,0.11
file_list_test,2000,0.22
file_delete_test,2000,0.19
file_mkdir_test,2000,0.11
file_rmdir_test,2000,0.14
file_create_test,3000,0.59
file_open_test,3000,0.27
file_overwrite_test,3000,0.17
file_list_test,3000,0.34
file_delete_test,3000,0.27
file_mkdir_test,3000,0.41
file_rmdir_test,3000,0.20
file_create_test,4000,0.62
file_open_test,4000,0.22
file_overwrite_test,4000,0.41
file_list_test,4000,0.47
file_delete_test,4000,0.34
file_mkdir_test,4000,0.55
file_rmdir_test,4000,0.28
file_create_test,5000,1.08
file_open_test,5000,0.28
file_overwrite_test,5000,0.30
file_list_test,5000,0.61
file_delete_test,5000,0.45
file_mkdir_test,5000,0.67
file_rmdir_test,5000,0.34
rdwr_cc_write_page_test,100,1.36
rdwr_cc_read_page_test,100,1.47
rdwr_cc_write_large_test,100,0.17
rdwr_cc_read_large_test,100,0.17
rdwr_cc_write_page_test,200,2.63
rdwr_cc_read_page_test,200,3.00
rdwr_cc_write_large_test,200,0.31
rdwr_cc_read_large_test,200,0.34
rdwr_cc_write_page_test,300,3.91
rdwr_cc_read_page_test,300,4.20
rdwr_cc_write_large_test,300,0.50
rdwr_cc_read_large_test,300,0.52
rdwr_cc_write_page_test,400,5.23
rdwr_cc_read_page_test,400,5.64
rdwr_cc_write_large_test,400,0.72
rdwr_cc_read_large_test,400,0.66
rdwr_cc_write_page_test,500,6.12
rdwr_cc_read_page_test,500,6.83
rdwr_cc_write_large_test,500,0.80
rdwr_cc_read_large_test,500,0.83
rdwr_nc_write_page_test,100,1.30
rdwr_nc_read_page_test,100,1.36
rdwr_nc_write_large_test,100,0.16
rdwr_nc_read_large_test,100,0.20
rdwr_nc_write_page_test,200,2.73
rdwr_nc_read_page_test,200,2.64
rdwr_nc_write_large_test,200,0.31
rdwr_nc_read_large_test,200,0.31
rdwr_nc_write_page_test,300,3.95
rdwr_nc_read_page_test,300,4.06
rdwr_nc_write_large_test,300,0.48
rdwr_nc_read_large_test,300,0.48
rdwr_nc_write_page_test,400,5.33
rdwr_nc_read_page_test,400,5.47
rdwr_nc_write_large_test,400,0.64
rdwr_nc_read_large_test,400,0.64
rdwr_nc_write_page_test,500,6.48
rdwr_nc_read_page_test,500,6.41
rdwr_nc_write_large_test,500,0.81
rdwr_nc_read_large_test,500,0.81
mmap_write_test,100,0.14
mmap_read_test,100,0.20
mmap_write_test,200,0.30
mmap_read_test,200,0.39
mmap_write_test,300,0.45
mmap_read_test,300,0.59
mmap_write_test,400,0.64
mmap_read_test,400,0.77
mmap_write_test,500,0.73
mmap_read_test,500,1.00
1 file_create_test 1000 0.20
2 file_open_test 1000 0.06
3 file_overwrite_test 1000 0.05
4 file_list_test 1000 0.11
5 file_delete_test 1000 0.09
6 file_mkdir_test 1000 0.05
7 file_rmdir_test 1000 0.08
8 file_create_test 2000 0.47
9 file_open_test 2000 0.13
10 file_overwrite_test 2000 0.11
11 file_list_test 2000 0.22
12 file_delete_test 2000 0.19
13 file_mkdir_test 2000 0.11
14 file_rmdir_test 2000 0.14
15 file_create_test 3000 0.59
16 file_open_test 3000 0.27
17 file_overwrite_test 3000 0.17
18 file_list_test 3000 0.34
19 file_delete_test 3000 0.27
20 file_mkdir_test 3000 0.41
21 file_rmdir_test 3000 0.20
22 file_create_test 4000 0.62
23 file_open_test 4000 0.22
24 file_overwrite_test 4000 0.41
25 file_list_test 4000 0.47
26 file_delete_test 4000 0.34
27 file_mkdir_test 4000 0.55
28 file_rmdir_test 4000 0.28
29 file_create_test 5000 1.08
30 file_open_test 5000 0.28
31 file_overwrite_test 5000 0.30
32 file_list_test 5000 0.61
33 file_delete_test 5000 0.45
34 file_mkdir_test 5000 0.67
35 file_rmdir_test 5000 0.34
36 rdwr_cc_write_page_test 100 1.36
37 rdwr_cc_read_page_test 100 1.47
38 rdwr_cc_write_large_test 100 0.17
39 rdwr_cc_read_large_test 100 0.17
40 rdwr_cc_write_page_test 200 2.63
41 rdwr_cc_read_page_test 200 3.00
42 rdwr_cc_write_large_test 200 0.31
43 rdwr_cc_read_large_test 200 0.34
44 rdwr_cc_write_page_test 300 3.91
45 rdwr_cc_read_page_test 300 4.20
46 rdwr_cc_write_large_test 300 0.50
47 rdwr_cc_read_large_test 300 0.52
48 rdwr_cc_write_page_test 400 5.23
49 rdwr_cc_read_page_test 400 5.64
50 rdwr_cc_write_large_test 400 0.72
51 rdwr_cc_read_large_test 400 0.66
52 rdwr_cc_write_page_test 500 6.12
53 rdwr_cc_read_page_test 500 6.83
54 rdwr_cc_write_large_test 500 0.80
55 rdwr_cc_read_large_test 500 0.83
56 rdwr_nc_write_page_test 100 1.30
57 rdwr_nc_read_page_test 100 1.36
58 rdwr_nc_write_large_test 100 0.16
59 rdwr_nc_read_large_test 100 0.20
60 rdwr_nc_write_page_test 200 2.73
61 rdwr_nc_read_page_test 200 2.64
62 rdwr_nc_write_large_test 200 0.31
63 rdwr_nc_read_large_test 200 0.31
64 rdwr_nc_write_page_test 300 3.95
65 rdwr_nc_read_page_test 300 4.06
66 rdwr_nc_write_large_test 300 0.48
67 rdwr_nc_read_large_test 300 0.48
68 rdwr_nc_write_page_test 400 5.33
69 rdwr_nc_read_page_test 400 5.47
70 rdwr_nc_write_large_test 400 0.64
71 rdwr_nc_read_large_test 400 0.64
72 rdwr_nc_write_page_test 500 6.48
73 rdwr_nc_read_page_test 500 6.41
74 rdwr_nc_write_large_test 500 0.81
75 rdwr_nc_read_large_test 500 0.81
76 mmap_write_test 100 0.14
77 mmap_read_test 100 0.20
78 mmap_write_test 200 0.30
79 mmap_read_test 200 0.39
80 mmap_write_test 300 0.45
81 mmap_read_test 300 0.59
82 mmap_write_test 400 0.64
83 mmap_read_test 400 0.77
84 mmap_write_test 500 0.73
85 mmap_read_test 500 1.00

View File

@ -0,0 +1,85 @@
file_create_test,1000,0.06
file_open_test,1000,0.16
file_overwrite_test,1000,0.05
file_list_test,1000,0.09
file_delete_test,1000,0.08
file_mkdir_test,1000,0.05
file_rmdir_test,1000,0.08
file_create_test,2000,0.42
file_open_test,2000,0.09
file_overwrite_test,2000,0.08
file_list_test,2000,0.22
file_delete_test,2000,0.14
file_mkdir_test,2000,0.09
file_rmdir_test,2000,0.13
file_create_test,3000,0.58
file_open_test,3000,0.22
file_overwrite_test,3000,0.25
file_list_test,3000,0.36
file_delete_test,3000,0.22
file_mkdir_test,3000,0.39
file_rmdir_test,3000,0.17
file_create_test,4000,0.59
file_open_test,4000,0.19
file_overwrite_test,4000,0.17
file_list_test,4000,0.58
file_delete_test,4000,0.33
file_mkdir_test,4000,0.55
file_rmdir_test,4000,0.22
file_create_test,5000,0.95
file_open_test,5000,0.22
file_overwrite_test,5000,0.23
file_list_test,5000,0.59
file_delete_test,5000,0.34
file_mkdir_test,5000,0.66
file_rmdir_test,5000,0.28
rdwr_cc_write_page_test,100,1.37
rdwr_cc_read_page_test,100,1.47
rdwr_cc_write_large_test,100,0.16
rdwr_cc_read_large_test,100,0.17
rdwr_cc_write_page_test,200,2.47
rdwr_cc_read_page_test,200,3.00
rdwr_cc_write_large_test,200,0.31
rdwr_cc_read_large_test,200,0.34
rdwr_cc_write_page_test,300,3.89
rdwr_cc_read_page_test,300,4.45
rdwr_cc_write_large_test,300,0.47
rdwr_cc_read_large_test,300,0.50
rdwr_cc_write_page_test,400,4.92
rdwr_cc_read_page_test,400,5.78
rdwr_cc_write_large_test,400,0.61
rdwr_cc_read_large_test,400,0.67
rdwr_cc_write_page_test,500,6.17
rdwr_cc_read_page_test,500,7.33
rdwr_cc_write_large_test,500,0.78
rdwr_cc_read_large_test,500,0.95
rdwr_nc_write_page_test,100,1.30
rdwr_nc_read_page_test,100,1.39
rdwr_nc_write_large_test,100,0.19
rdwr_nc_read_large_test,100,0.17
rdwr_nc_write_page_test,200,2.61
rdwr_nc_read_page_test,200,2.80
rdwr_nc_write_large_test,200,0.31
rdwr_nc_read_large_test,200,0.34
rdwr_nc_write_page_test,300,3.94
rdwr_nc_read_page_test,300,4.23
rdwr_nc_write_large_test,300,0.48
rdwr_nc_read_large_test,300,0.50
rdwr_nc_write_page_test,400,5.36
rdwr_nc_read_page_test,400,5.52
rdwr_nc_write_large_test,400,0.63
rdwr_nc_read_large_test,400,0.69
rdwr_nc_write_page_test,500,6.51
rdwr_nc_read_page_test,500,7.00
rdwr_nc_write_large_test,500,0.81
rdwr_nc_read_large_test,500,0.81
mmap_write_test,100,0.16
mmap_read_test,100,0.19
mmap_write_test,200,0.31
mmap_read_test,200,0.39
mmap_write_test,300,0.44
mmap_read_test,300,0.59
mmap_write_test,400,0.59
mmap_read_test,400,0.78
mmap_write_test,500,0.73
mmap_read_test,500,0.98
1 file_create_test 1000 0.06
2 file_open_test 1000 0.16
3 file_overwrite_test 1000 0.05
4 file_list_test 1000 0.09
5 file_delete_test 1000 0.08
6 file_mkdir_test 1000 0.05
7 file_rmdir_test 1000 0.08
8 file_create_test 2000 0.42
9 file_open_test 2000 0.09
10 file_overwrite_test 2000 0.08
11 file_list_test 2000 0.22
12 file_delete_test 2000 0.14
13 file_mkdir_test 2000 0.09
14 file_rmdir_test 2000 0.13
15 file_create_test 3000 0.58
16 file_open_test 3000 0.22
17 file_overwrite_test 3000 0.25
18 file_list_test 3000 0.36
19 file_delete_test 3000 0.22
20 file_mkdir_test 3000 0.39
21 file_rmdir_test 3000 0.17
22 file_create_test 4000 0.59
23 file_open_test 4000 0.19
24 file_overwrite_test 4000 0.17
25 file_list_test 4000 0.58
26 file_delete_test 4000 0.33
27 file_mkdir_test 4000 0.55
28 file_rmdir_test 4000 0.22
29 file_create_test 5000 0.95
30 file_open_test 5000 0.22
31 file_overwrite_test 5000 0.23
32 file_list_test 5000 0.59
33 file_delete_test 5000 0.34
34 file_mkdir_test 5000 0.66
35 file_rmdir_test 5000 0.28
36 rdwr_cc_write_page_test 100 1.37
37 rdwr_cc_read_page_test 100 1.47
38 rdwr_cc_write_large_test 100 0.16
39 rdwr_cc_read_large_test 100 0.17
40 rdwr_cc_write_page_test 200 2.47
41 rdwr_cc_read_page_test 200 3.00
42 rdwr_cc_write_large_test 200 0.31
43 rdwr_cc_read_large_test 200 0.34
44 rdwr_cc_write_page_test 300 3.89
45 rdwr_cc_read_page_test 300 4.45
46 rdwr_cc_write_large_test 300 0.47
47 rdwr_cc_read_large_test 300 0.50
48 rdwr_cc_write_page_test 400 4.92
49 rdwr_cc_read_page_test 400 5.78
50 rdwr_cc_write_large_test 400 0.61
51 rdwr_cc_read_large_test 400 0.67
52 rdwr_cc_write_page_test 500 6.17
53 rdwr_cc_read_page_test 500 7.33
54 rdwr_cc_write_large_test 500 0.78
55 rdwr_cc_read_large_test 500 0.95
56 rdwr_nc_write_page_test 100 1.30
57 rdwr_nc_read_page_test 100 1.39
58 rdwr_nc_write_large_test 100 0.19
59 rdwr_nc_read_large_test 100 0.17
60 rdwr_nc_write_page_test 200 2.61
61 rdwr_nc_read_page_test 200 2.80
62 rdwr_nc_write_large_test 200 0.31
63 rdwr_nc_read_large_test 200 0.34
64 rdwr_nc_write_page_test 300 3.94
65 rdwr_nc_read_page_test 300 4.23
66 rdwr_nc_write_large_test 300 0.48
67 rdwr_nc_read_large_test 300 0.50
68 rdwr_nc_write_page_test 400 5.36
69 rdwr_nc_read_page_test 400 5.52
70 rdwr_nc_write_large_test 400 0.63
71 rdwr_nc_read_large_test 400 0.69
72 rdwr_nc_write_page_test 500 6.51
73 rdwr_nc_read_page_test 500 7.00
74 rdwr_nc_write_large_test 500 0.81
75 rdwr_nc_read_large_test 500 0.81
76 mmap_write_test 100 0.16
77 mmap_read_test 100 0.19
78 mmap_write_test 200 0.31
79 mmap_read_test 200 0.39
80 mmap_write_test 300 0.44
81 mmap_read_test 300 0.59
82 mmap_write_test 400 0.59
83 mmap_read_test 400 0.78
84 mmap_write_test 500 0.73
85 mmap_read_test 500 0.98

View File

@ -0,0 +1,85 @@
file_create_test,1000,0.08
file_open_test,1000,0.16
file_overwrite_test,1000,0.05
file_list_test,1000,0.11
file_delete_test,1000,0.06
file_mkdir_test,1000,0.16
file_rmdir_test,1000,0.06
file_create_test,2000,0.36
file_open_test,2000,0.09
file_overwrite_test,2000,0.09
file_list_test,2000,0.20
file_delete_test,2000,0.16
file_mkdir_test,2000,0.09
file_rmdir_test,2000,0.12
file_create_test,3000,0.58
file_open_test,3000,0.20
file_overwrite_test,3000,0.16
file_list_test,3000,0.33
file_delete_test,3000,0.22
file_mkdir_test,3000,0.41
file_rmdir_test,3000,0.17
file_create_test,4000,0.58
file_open_test,4000,0.17
file_overwrite_test,4000,0.20
file_list_test,4000,0.44
file_delete_test,4000,0.38
file_mkdir_test,4000,0.59
file_rmdir_test,4000,0.25
file_create_test,5000,0.97
file_open_test,5000,0.22
file_overwrite_test,5000,0.22
file_list_test,5000,0.61
file_delete_test,5000,0.36
file_mkdir_test,5000,0.69
file_rmdir_test,5000,0.30
rdwr_cc_write_page_test,100,1.30
rdwr_cc_read_page_test,100,1.53
rdwr_cc_write_large_test,100,0.17
rdwr_cc_read_large_test,100,0.17
rdwr_cc_write_page_test,200,2.62
rdwr_cc_read_page_test,200,3.06
rdwr_cc_write_large_test,200,0.31
rdwr_cc_read_large_test,200,0.34
rdwr_cc_write_page_test,300,3.89
rdwr_cc_read_page_test,300,4.50
rdwr_cc_write_large_test,300,0.50
rdwr_cc_read_large_test,300,0.59
rdwr_cc_write_page_test,400,5.14
rdwr_cc_read_page_test,400,5.94
rdwr_cc_write_large_test,400,0.62
rdwr_cc_read_large_test,400,0.70
rdwr_cc_write_page_test,500,6.25
rdwr_cc_read_page_test,500,7.33
rdwr_cc_write_large_test,500,0.81
rdwr_cc_read_large_test,500,0.83
rdwr_nc_write_page_test,100,1.34
rdwr_nc_read_page_test,100,1.38
rdwr_nc_write_large_test,100,0.19
rdwr_nc_read_large_test,100,0.16
rdwr_nc_write_page_test,200,2.67
rdwr_nc_read_page_test,200,2.78
rdwr_nc_write_large_test,200,0.38
rdwr_nc_read_large_test,200,0.33
rdwr_nc_write_page_test,300,3.98
rdwr_nc_read_page_test,300,4.44
rdwr_nc_write_large_test,300,0.52
rdwr_nc_read_large_test,300,0.50
rdwr_nc_write_page_test,400,5.36
rdwr_nc_read_page_test,400,5.69
rdwr_nc_write_large_test,400,0.66
rdwr_nc_read_large_test,400,0.67
rdwr_nc_write_page_test,500,6.66
rdwr_nc_read_page_test,500,6.94
rdwr_nc_write_large_test,500,0.81
rdwr_nc_read_large_test,500,0.81
mmap_write_test,100,0.14
mmap_read_test,100,0.20
mmap_write_test,200,0.31
mmap_read_test,200,0.39
mmap_write_test,300,0.44
mmap_read_test,300,0.59
mmap_write_test,400,0.59
mmap_read_test,400,0.78
mmap_write_test,500,0.75
mmap_read_test,500,0.98
1 file_create_test 1000 0.08
2 file_open_test 1000 0.16
3 file_overwrite_test 1000 0.05
4 file_list_test 1000 0.11
5 file_delete_test 1000 0.06
6 file_mkdir_test 1000 0.16
7 file_rmdir_test 1000 0.06
8 file_create_test 2000 0.36
9 file_open_test 2000 0.09
10 file_overwrite_test 2000 0.09
11 file_list_test 2000 0.20
12 file_delete_test 2000 0.16
13 file_mkdir_test 2000 0.09
14 file_rmdir_test 2000 0.12
15 file_create_test 3000 0.58
16 file_open_test 3000 0.20
17 file_overwrite_test 3000 0.16
18 file_list_test 3000 0.33
19 file_delete_test 3000 0.22
20 file_mkdir_test 3000 0.41
21 file_rmdir_test 3000 0.17
22 file_create_test 4000 0.58
23 file_open_test 4000 0.17
24 file_overwrite_test 4000 0.20
25 file_list_test 4000 0.44
26 file_delete_test 4000 0.38
27 file_mkdir_test 4000 0.59
28 file_rmdir_test 4000 0.25
29 file_create_test 5000 0.97
30 file_open_test 5000 0.22
31 file_overwrite_test 5000 0.22
32 file_list_test 5000 0.61
33 file_delete_test 5000 0.36
34 file_mkdir_test 5000 0.69
35 file_rmdir_test 5000 0.30
36 rdwr_cc_write_page_test 100 1.30
37 rdwr_cc_read_page_test 100 1.53
38 rdwr_cc_write_large_test 100 0.17
39 rdwr_cc_read_large_test 100 0.17
40 rdwr_cc_write_page_test 200 2.62
41 rdwr_cc_read_page_test 200 3.06
42 rdwr_cc_write_large_test 200 0.31
43 rdwr_cc_read_large_test 200 0.34
44 rdwr_cc_write_page_test 300 3.89
45 rdwr_cc_read_page_test 300 4.50
46 rdwr_cc_write_large_test 300 0.50
47 rdwr_cc_read_large_test 300 0.59
48 rdwr_cc_write_page_test 400 5.14
49 rdwr_cc_read_page_test 400 5.94
50 rdwr_cc_write_large_test 400 0.62
51 rdwr_cc_read_large_test 400 0.70
52 rdwr_cc_write_page_test 500 6.25
53 rdwr_cc_read_page_test 500 7.33
54 rdwr_cc_write_large_test 500 0.81
55 rdwr_cc_read_large_test 500 0.83
56 rdwr_nc_write_page_test 100 1.34
57 rdwr_nc_read_page_test 100 1.38
58 rdwr_nc_write_large_test 100 0.19
59 rdwr_nc_read_large_test 100 0.16
60 rdwr_nc_write_page_test 200 2.67
61 rdwr_nc_read_page_test 200 2.78
62 rdwr_nc_write_large_test 200 0.38
63 rdwr_nc_read_large_test 200 0.33
64 rdwr_nc_write_page_test 300 3.98
65 rdwr_nc_read_page_test 300 4.44
66 rdwr_nc_write_large_test 300 0.52
67 rdwr_nc_read_large_test 300 0.50
68 rdwr_nc_write_page_test 400 5.36
69 rdwr_nc_read_page_test 400 5.69
70 rdwr_nc_write_large_test 400 0.66
71 rdwr_nc_read_large_test 400 0.67
72 rdwr_nc_write_page_test 500 6.66
73 rdwr_nc_read_page_test 500 6.94
74 rdwr_nc_write_large_test 500 0.81
75 rdwr_nc_read_large_test 500 0.81
76 mmap_write_test 100 0.14
77 mmap_read_test 100 0.20
78 mmap_write_test 200 0.31
79 mmap_read_test 200 0.39
80 mmap_write_test 300 0.44
81 mmap_read_test 300 0.59
82 mmap_write_test 400 0.59
83 mmap_read_test 400 0.78
84 mmap_write_test 500 0.75
85 mmap_read_test 500 0.98

View File

@ -0,0 +1,85 @@
file_create_test,1000,0.06
file_open_test,1000,0.17
file_overwrite_test,1000,0.05
file_list_test,1000,0.11
file_delete_test,1000,0.06
file_mkdir_test,1000,0.05
file_rmdir_test,1000,0.06
file_create_test,2000,0.44
file_open_test,2000,0.08
file_overwrite_test,2000,0.09
file_list_test,2000,0.22
file_delete_test,2000,0.14
file_mkdir_test,2000,0.09
file_rmdir_test,2000,0.14
file_create_test,3000,0.56
file_open_test,3000,0.20
file_overwrite_test,3000,0.14
file_list_test,3000,0.33
file_delete_test,3000,0.20
file_mkdir_test,3000,0.41
file_rmdir_test,3000,0.16
file_create_test,4000,0.59
file_open_test,4000,0.16
file_overwrite_test,4000,0.19
file_list_test,4000,0.47
file_delete_test,4000,0.31
file_mkdir_test,4000,0.66
file_rmdir_test,4000,0.23
file_create_test,5000,0.98
file_open_test,5000,0.22
file_overwrite_test,5000,0.22
file_list_test,5000,0.59
file_delete_test,5000,0.36
file_mkdir_test,5000,0.66
file_rmdir_test,5000,0.31
rdwr_cc_write_page_test,100,0.34
rdwr_cc_read_page_test,100,0.28
rdwr_cc_write_large_test,100,0.11
rdwr_cc_read_large_test,100,0.08
rdwr_cc_write_page_test,200,0.67
rdwr_cc_read_page_test,200,0.58
rdwr_cc_write_large_test,200,0.22
rdwr_cc_read_large_test,200,0.22
rdwr_cc_write_page_test,300,1.01
rdwr_cc_read_page_test,300,0.88
rdwr_cc_write_large_test,300,0.34
rdwr_cc_read_large_test,300,0.25
rdwr_cc_write_page_test,400,1.38
rdwr_cc_read_page_test,400,1.12
rdwr_cc_write_large_test,400,0.42
rdwr_cc_read_large_test,400,0.33
rdwr_cc_write_page_test,500,1.70
rdwr_cc_read_page_test,500,1.48
rdwr_cc_write_large_test,500,0.64
rdwr_cc_read_large_test,500,0.44
rdwr_nc_write_page_test,100,1.31
rdwr_nc_read_page_test,100,1.36
rdwr_nc_write_large_test,100,0.17
rdwr_nc_read_large_test,100,0.16
rdwr_nc_write_page_test,200,2.56
rdwr_nc_read_page_test,200,2.81
rdwr_nc_write_large_test,200,0.33
rdwr_nc_read_large_test,200,0.31
rdwr_nc_write_page_test,300,3.86
rdwr_nc_read_page_test,300,3.95
rdwr_nc_write_large_test,300,0.47
rdwr_nc_read_large_test,300,0.48
rdwr_nc_write_page_test,400,5.11
rdwr_nc_read_page_test,400,5.19
rdwr_nc_write_large_test,400,0.64
rdwr_nc_read_large_test,400,0.64
rdwr_nc_write_page_test,500,6.42
rdwr_nc_read_page_test,500,6.58
rdwr_nc_write_large_test,500,0.78
rdwr_nc_read_large_test,500,0.78
mmap_write_test,100,0.16
mmap_read_test,100,0.20
mmap_write_test,200,0.30
mmap_read_test,200,0.39
mmap_write_test,300,0.44
mmap_read_test,300,0.59
mmap_write_test,400,0.59
mmap_read_test,400,0.78
mmap_write_test,500,0.75
mmap_read_test,500,1.03
1 file_create_test 1000 0.06
2 file_open_test 1000 0.17
3 file_overwrite_test 1000 0.05
4 file_list_test 1000 0.11
5 file_delete_test 1000 0.06
6 file_mkdir_test 1000 0.05
7 file_rmdir_test 1000 0.06
8 file_create_test 2000 0.44
9 file_open_test 2000 0.08
10 file_overwrite_test 2000 0.09
11 file_list_test 2000 0.22
12 file_delete_test 2000 0.14
13 file_mkdir_test 2000 0.09
14 file_rmdir_test 2000 0.14
15 file_create_test 3000 0.56
16 file_open_test 3000 0.20
17 file_overwrite_test 3000 0.14
18 file_list_test 3000 0.33
19 file_delete_test 3000 0.20
20 file_mkdir_test 3000 0.41
21 file_rmdir_test 3000 0.16
22 file_create_test 4000 0.59
23 file_open_test 4000 0.16
24 file_overwrite_test 4000 0.19
25 file_list_test 4000 0.47
26 file_delete_test 4000 0.31
27 file_mkdir_test 4000 0.66
28 file_rmdir_test 4000 0.23
29 file_create_test 5000 0.98
30 file_open_test 5000 0.22
31 file_overwrite_test 5000 0.22
32 file_list_test 5000 0.59
33 file_delete_test 5000 0.36
34 file_mkdir_test 5000 0.66
35 file_rmdir_test 5000 0.31
36 rdwr_cc_write_page_test 100 0.34
37 rdwr_cc_read_page_test 100 0.28
38 rdwr_cc_write_large_test 100 0.11
39 rdwr_cc_read_large_test 100 0.08
40 rdwr_cc_write_page_test 200 0.67
41 rdwr_cc_read_page_test 200 0.58
42 rdwr_cc_write_large_test 200 0.22
43 rdwr_cc_read_large_test 200 0.22
44 rdwr_cc_write_page_test 300 1.01
45 rdwr_cc_read_page_test 300 0.88
46 rdwr_cc_write_large_test 300 0.34
47 rdwr_cc_read_large_test 300 0.25
48 rdwr_cc_write_page_test 400 1.38
49 rdwr_cc_read_page_test 400 1.12
50 rdwr_cc_write_large_test 400 0.42
51 rdwr_cc_read_large_test 400 0.33
52 rdwr_cc_write_page_test 500 1.70
53 rdwr_cc_read_page_test 500 1.48
54 rdwr_cc_write_large_test 500 0.64
55 rdwr_cc_read_large_test 500 0.44
56 rdwr_nc_write_page_test 100 1.31
57 rdwr_nc_read_page_test 100 1.36
58 rdwr_nc_write_large_test 100 0.17
59 rdwr_nc_read_large_test 100 0.16
60 rdwr_nc_write_page_test 200 2.56
61 rdwr_nc_read_page_test 200 2.81
62 rdwr_nc_write_large_test 200 0.33
63 rdwr_nc_read_large_test 200 0.31
64 rdwr_nc_write_page_test 300 3.86
65 rdwr_nc_read_page_test 300 3.95
66 rdwr_nc_write_large_test 300 0.47
67 rdwr_nc_read_large_test 300 0.48
68 rdwr_nc_write_page_test 400 5.11
69 rdwr_nc_read_page_test 400 5.19
70 rdwr_nc_write_large_test 400 0.64
71 rdwr_nc_read_large_test 400 0.64
72 rdwr_nc_write_page_test 500 6.42
73 rdwr_nc_read_page_test 500 6.58
74 rdwr_nc_write_large_test 500 0.78
75 rdwr_nc_read_large_test 500 0.78
76 mmap_write_test 100 0.16
77 mmap_read_test 100 0.20
78 mmap_write_test 200 0.30
79 mmap_read_test 200 0.39
80 mmap_write_test 300 0.44
81 mmap_read_test 300 0.59
82 mmap_write_test 400 0.59
83 mmap_read_test 400 0.78
84 mmap_write_test 500 0.75
85 mmap_read_test 500 1.03

View File

@ -0,0 +1,85 @@
file_create_test,1000,0.06
file_open_test,1000,0.16
file_overwrite_test,1000,0.05
file_list_test,1000,0.11
file_delete_test,1000,0.06
file_mkdir_test,1000,0.05
file_rmdir_test,1000,0.06
file_create_test,2000,0.44
file_open_test,2000,0.08
file_overwrite_test,2000,0.09
file_list_test,2000,0.20
file_delete_test,2000,0.16
file_mkdir_test,2000,0.09
file_rmdir_test,2000,0.13
file_create_test,3000,0.58
file_open_test,3000,0.22
file_overwrite_test,3000,0.13
file_list_test,3000,0.34
file_delete_test,3000,0.22
file_mkdir_test,3000,0.39
file_rmdir_test,3000,0.17
file_create_test,4000,0.61
file_open_test,4000,0.17
file_overwrite_test,4000,0.19
file_list_test,4000,0.44
file_delete_test,4000,0.27
file_mkdir_test,4000,0.67
file_rmdir_test,4000,0.22
file_create_test,5000,0.97
file_open_test,5000,0.20
file_overwrite_test,5000,0.23
file_list_test,5000,0.61
file_delete_test,5000,0.33
file_mkdir_test,5000,0.67
file_rmdir_test,5000,0.28
rdwr_cc_write_page_test,100,0.36
rdwr_cc_read_page_test,100,0.30
rdwr_cc_write_large_test,100,0.12
rdwr_cc_read_large_test,100,0.08
rdwr_cc_write_page_test,200,0.69
rdwr_cc_read_page_test,200,0.58
rdwr_cc_write_large_test,200,0.30
rdwr_cc_read_large_test,200,0.23
rdwr_cc_write_page_test,300,1.02
rdwr_cc_read_page_test,300,0.87
rdwr_cc_write_large_test,300,0.34
rdwr_cc_read_large_test,300,0.23
rdwr_cc_write_page_test,400,1.41
rdwr_cc_read_page_test,400,1.14
rdwr_cc_write_large_test,400,0.47
rdwr_cc_read_large_test,400,0.33
rdwr_cc_write_page_test,500,1.73
rdwr_cc_read_page_test,500,1.50
rdwr_cc_write_large_test,500,0.53
rdwr_cc_read_large_test,500,0.41
rdwr_nc_write_page_test,100,1.33
rdwr_nc_read_page_test,100,1.44
rdwr_nc_write_large_test,100,0.17
rdwr_nc_read_large_test,100,0.17
rdwr_nc_write_page_test,200,2.75
rdwr_nc_read_page_test,200,2.94
rdwr_nc_write_large_test,200,0.38
rdwr_nc_read_large_test,200,0.33
rdwr_nc_write_page_test,300,3.94
rdwr_nc_read_page_test,300,4.17
rdwr_nc_write_large_test,300,0.48
rdwr_nc_read_large_test,300,0.56
rdwr_nc_write_page_test,400,5.25
rdwr_nc_read_page_test,400,5.58
rdwr_nc_write_large_test,400,0.63
rdwr_nc_read_large_test,400,0.64
rdwr_nc_write_page_test,500,6.52
rdwr_nc_read_page_test,500,6.78
rdwr_nc_write_large_test,500,0.80
rdwr_nc_read_large_test,500,0.80
mmap_write_test,100,0.17
mmap_read_test,100,0.20
mmap_write_test,200,0.30
mmap_read_test,200,0.41
mmap_write_test,300,0.44
mmap_read_test,300,0.61
mmap_write_test,400,0.61
mmap_read_test,400,0.78
mmap_write_test,500,0.73
mmap_read_test,500,0.98
1 file_create_test 1000 0.06
2 file_open_test 1000 0.16
3 file_overwrite_test 1000 0.05
4 file_list_test 1000 0.11
5 file_delete_test 1000 0.06
6 file_mkdir_test 1000 0.05
7 file_rmdir_test 1000 0.06
8 file_create_test 2000 0.44
9 file_open_test 2000 0.08
10 file_overwrite_test 2000 0.09
11 file_list_test 2000 0.20
12 file_delete_test 2000 0.16
13 file_mkdir_test 2000 0.09
14 file_rmdir_test 2000 0.13
15 file_create_test 3000 0.58
16 file_open_test 3000 0.22
17 file_overwrite_test 3000 0.13
18 file_list_test 3000 0.34
19 file_delete_test 3000 0.22
20 file_mkdir_test 3000 0.39
21 file_rmdir_test 3000 0.17
22 file_create_test 4000 0.61
23 file_open_test 4000 0.17
24 file_overwrite_test 4000 0.19
25 file_list_test 4000 0.44
26 file_delete_test 4000 0.27
27 file_mkdir_test 4000 0.67
28 file_rmdir_test 4000 0.22
29 file_create_test 5000 0.97
30 file_open_test 5000 0.20
31 file_overwrite_test 5000 0.23
32 file_list_test 5000 0.61
33 file_delete_test 5000 0.33
34 file_mkdir_test 5000 0.67
35 file_rmdir_test 5000 0.28
36 rdwr_cc_write_page_test 100 0.36
37 rdwr_cc_read_page_test 100 0.30
38 rdwr_cc_write_large_test 100 0.12
39 rdwr_cc_read_large_test 100 0.08
40 rdwr_cc_write_page_test 200 0.69
41 rdwr_cc_read_page_test 200 0.58
42 rdwr_cc_write_large_test 200 0.30
43 rdwr_cc_read_large_test 200 0.23
44 rdwr_cc_write_page_test 300 1.02
45 rdwr_cc_read_page_test 300 0.87
46 rdwr_cc_write_large_test 300 0.34
47 rdwr_cc_read_large_test 300 0.23
48 rdwr_cc_write_page_test 400 1.41
49 rdwr_cc_read_page_test 400 1.14
50 rdwr_cc_write_large_test 400 0.47
51 rdwr_cc_read_large_test 400 0.33
52 rdwr_cc_write_page_test 500 1.73
53 rdwr_cc_read_page_test 500 1.50
54 rdwr_cc_write_large_test 500 0.53
55 rdwr_cc_read_large_test 500 0.41
56 rdwr_nc_write_page_test 100 1.33
57 rdwr_nc_read_page_test 100 1.44
58 rdwr_nc_write_large_test 100 0.17
59 rdwr_nc_read_large_test 100 0.17
60 rdwr_nc_write_page_test 200 2.75
61 rdwr_nc_read_page_test 200 2.94
62 rdwr_nc_write_large_test 200 0.38
63 rdwr_nc_read_large_test 200 0.33
64 rdwr_nc_write_page_test 300 3.94
65 rdwr_nc_read_page_test 300 4.17
66 rdwr_nc_write_large_test 300 0.48
67 rdwr_nc_read_large_test 300 0.56
68 rdwr_nc_write_page_test 400 5.25
69 rdwr_nc_read_page_test 400 5.58
70 rdwr_nc_write_large_test 400 0.63
71 rdwr_nc_read_large_test 400 0.64
72 rdwr_nc_write_page_test 500 6.52
73 rdwr_nc_read_page_test 500 6.78
74 rdwr_nc_write_large_test 500 0.80
75 rdwr_nc_read_large_test 500 0.80
76 mmap_write_test 100 0.17
77 mmap_read_test 100 0.20
78 mmap_write_test 200 0.30
79 mmap_read_test 200 0.41
80 mmap_write_test 300 0.44
81 mmap_read_test 300 0.61
82 mmap_write_test 400 0.61
83 mmap_read_test 400 0.78
84 mmap_write_test 500 0.73
85 mmap_read_test 500 0.98

View File

@ -0,0 +1,30 @@
//ntfs
1000,0.92
2000,1.38
3000,1.11
4000,1.33
5000,1.94
//winfsp-t0
1000,0.20
2000,0.47
3000,0.59
4000,0.62
5000,1.08
//winfsp-t1
1000,0.06
2000,0.36
3000,0.58
4000,0.58
5000,0.95
//winfsp-tinf
1000,0.06
2000,0.44
3000,0.56
4000,0.59
5000,0.97
//dokany
1000,0.28
2000,0.67
3000,0.91
4000,1.25
5000,1.64
1 //ntfs
2 1000,0.92
3 2000,1.38
4 3000,1.11
5 4000,1.33
6 5000,1.94
7 //winfsp-t0
8 1000,0.20
9 2000,0.47
10 3000,0.59
11 4000,0.62
12 5000,1.08
13 //winfsp-t1
14 1000,0.06
15 2000,0.36
16 3000,0.58
17 4000,0.58
18 5000,0.95
19 //winfsp-tinf
20 1000,0.06
21 2000,0.44
22 3000,0.56
23 4000,0.59
24 5000,0.97
25 //dokany
26 1000,0.28
27 2000,0.67
28 3000,0.91
29 4000,1.25
30 5000,1.64

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

@ -0,0 +1,30 @@
//ntfs
1000,0.19
2000,0.39
3000,0.56
4000,0.77
5000,1.03
//winfsp-t0
1000,0.09
2000,0.19
3000,0.27
4000,0.34
5000,0.45
//winfsp-t1
1000,0.06
2000,0.14
3000,0.22
4000,0.33
5000,0.34
//winfsp-tinf
1000,0.06
2000,0.14
3000,0.20
4000,0.27
5000,0.33
//dokany
1000,0.17
2000,0.36
3000,0.56
4000,0.72
5000,0.91
1 //ntfs
2 1000,0.19
3 2000,0.39
4 3000,0.56
5 4000,0.77
6 5000,1.03
7 //winfsp-t0
8 1000,0.09
9 2000,0.19
10 3000,0.27
11 4000,0.34
12 5000,0.45
13 //winfsp-t1
14 1000,0.06
15 2000,0.14
16 3000,0.22
17 4000,0.33
18 5000,0.34
19 //winfsp-tinf
20 1000,0.06
21 2000,0.14
22 3000,0.20
23 4000,0.27
24 5000,0.33
25 //dokany
26 1000,0.17
27 2000,0.36
28 3000,0.56
29 4000,0.72
30 5000,0.91

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -0,0 +1,30 @@
//ntfs
1000,0.08
2000,0.16
3000,0.23
4000,0.33
5000,0.41
//winfsp-t0
1000,0.11
2000,0.22
3000,0.33
4000,0.47
5000,0.61
//winfsp-t1
1000,0.09
2000,0.20
3000,0.33
4000,0.44
5000,0.59
//winfsp-tinf
1000,0.11
2000,0.20
3000,0.33
4000,0.44
5000,0.59
//dokany
1000,0.16
2000,0.36
3000,0.64
4000,0.97
5000,1.38
1 //ntfs
2 1000,0.08
3 2000,0.16
4 3000,0.23
5 4000,0.33
6 5000,0.41
7 //winfsp-t0
8 1000,0.11
9 2000,0.22
10 3000,0.33
11 4000,0.47
12 5000,0.61
13 //winfsp-t1
14 1000,0.09
15 2000,0.20
16 3000,0.33
17 4000,0.44
18 5000,0.59
19 //winfsp-tinf
20 1000,0.11
21 2000,0.20
22 3000,0.33
23 4000,0.44
24 5000,0.59
25 //dokany
26 1000,0.16
27 2000,0.36
28 3000,0.64
29 4000,0.97
30 5000,1.38

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -0,0 +1,30 @@
//ntfs
1000,0.08
2000,0.17
3000,0.23
4000,0.36
5000,0.45
//winfsp-t0
1000,0.06
2000,0.11
3000,0.27
4000,0.22
5000,0.28
//winfsp-t1
1000,0.16
2000,0.09
3000,0.20
4000,0.17
5000,0.22
//winfsp-tinf
1000,0.16
2000,0.08
3000,0.20
4000,0.16
5000,0.20
//dokany
1000,0.14
2000,0.27
3000,0.41
4000,0.55
5000,0.67
1 //ntfs
2 1000,0.08
3 2000,0.17
4 3000,0.23
5 4000,0.36
6 5000,0.45
7 //winfsp-t0
8 1000,0.06
9 2000,0.11
10 3000,0.27
11 4000,0.22
12 5000,0.28
13 //winfsp-t1
14 1000,0.16
15 2000,0.09
16 3000,0.20
17 4000,0.17
18 5000,0.22
19 //winfsp-tinf
20 1000,0.16
21 2000,0.08
22 3000,0.20
23 4000,0.16
24 5000,0.20
25 //dokany
26 1000,0.14
27 2000,0.27
28 3000,0.41
29 4000,0.55
30 5000,0.67

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -0,0 +1,30 @@
//ntfs
1000,0.19
2000,0.36
3000,0.72
4000,0.97
5000,1.14
//winfsp-t0
1000,0.05
2000,0.11
3000,0.17
4000,0.25
5000,0.30
//winfsp-t1
1000,0.05
2000,0.08
3000,0.16
4000,0.17
5000,0.22
//winfsp-tinf
1000,0.05
2000,0.09
3000,0.13
4000,0.19
5000,0.22
//dokany
1000,0.33
2000,0.67
3000,1.03
4000,1.34
5000,1.64
1 //ntfs
2 1000,0.19
3 2000,0.36
4 3000,0.72
5 4000,0.97
6 5000,1.14
7 //winfsp-t0
8 1000,0.05
9 2000,0.11
10 3000,0.17
11 4000,0.25
12 5000,0.30
13 //winfsp-t1
14 1000,0.05
15 2000,0.08
16 3000,0.16
17 4000,0.17
18 5000,0.22
19 //winfsp-tinf
20 1000,0.05
21 2000,0.09
22 3000,0.13
23 4000,0.19
24 5000,0.22
25 //dokany
26 1000,0.33
27 2000,0.67
28 3000,1.03
29 4000,1.34
30 5000,1.64

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -0,0 +1,30 @@
//ntfs
file_create_test,1.94
file_open_test,0.45
file_overwrite_test,1.14
file_list_test,0.41
file_delete_test,1.03
//winfsp-t0
file_create_test,1.08
file_open_test,0.28
file_overwrite_test,0.30
file_list_test,0.61
file_delete_test,0.45
//winfsp-t1
file_create_test,0.95
file_open_test,0.22
file_overwrite_test,0.22
file_list_test,0.59
file_delete_test,0.34
//winfsp-tinf
file_create_test,0.97
file_open_test,0.20
file_overwrite_test,0.22
file_list_test,0.59
file_delete_test,0.33
//dokany
file_create_test,1.64
file_open_test,0.67
file_overwrite_test,1.64
file_list_test,1.38
file_delete_test,0.91
1 //ntfs
2 file_create_test,1.94
3 file_open_test,0.45
4 file_overwrite_test,1.14
5 file_list_test,0.41
6 file_delete_test,1.03
7 //winfsp-t0
8 file_create_test,1.08
9 file_open_test,0.28
10 file_overwrite_test,0.30
11 file_list_test,0.61
12 file_delete_test,0.45
13 //winfsp-t1
14 file_create_test,0.95
15 file_open_test,0.22
16 file_overwrite_test,0.22
17 file_list_test,0.59
18 file_delete_test,0.34
19 //winfsp-tinf
20 file_create_test,0.97
21 file_open_test,0.20
22 file_overwrite_test,0.22
23 file_list_test,0.59
24 file_delete_test,0.33
25 //dokany
26 file_create_test,1.64
27 file_open_test,0.67
28 file_overwrite_test,1.64
29 file_list_test,1.38
30 file_delete_test,0.91

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -0,0 +1,24 @@
//ntfs
100,0.19
200,0.39
300,0.58
400,0.78
500,1.06
//winfsp-t0
100,0.20
200,0.39
300,0.59
400,0.77
500,1.00
//winfsp-t1
100,0.19
200,0.39
300,0.59
400,0.78
500,0.98
//winfsp-tinf
100,0.20
200,0.39
300,0.59
400,0.78
500,0.98
1 //ntfs
2 100,0.19
3 200,0.39
4 300,0.58
5 400,0.78
6 500,1.06
7 //winfsp-t0
8 100,0.20
9 200,0.39
10 300,0.59
11 400,0.77
12 500,1.00
13 //winfsp-t1
14 100,0.19
15 200,0.39
16 300,0.59
17 400,0.78
18 500,0.98
19 //winfsp-tinf
20 100,0.20
21 200,0.39
22 300,0.59
23 400,0.78
24 500,0.98

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1,24 @@
//ntfs
100,0.16
200,0.30
300,0.44
400,0.58
500,0.72
//winfsp-t0
100,0.14
200,0.30
300,0.45
400,0.56
500,0.72
//winfsp-t1
100,0.14
200,0.31
300,0.44
400,0.59
500,0.73
//winfsp-tinf
100,0.16
200,0.30
300,0.44
400,0.59
500,0.73
1 //ntfs
2 100,0.16
3 200,0.30
4 300,0.44
5 400,0.58
6 500,0.72
7 //winfsp-t0
8 100,0.14
9 200,0.30
10 300,0.45
11 400,0.56
12 500,0.72
13 //winfsp-t1
14 100,0.14
15 200,0.31
16 300,0.44
17 400,0.59
18 500,0.73
19 //winfsp-tinf
20 100,0.16
21 200,0.30
22 300,0.44
23 400,0.59
24 500,0.73

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -0,0 +1,74 @@
#!/usr/bin/python
# usage: ./munge.py ORIG/*.csv
# munge CSV files into a format that asciidocFX understands
import csv, os, sys
snames = ["ntfs", "winfsp-t0", "winfsp-t1", "winfsp-tinf", "dokany"]
file_tnames = [
"file_create_test",
"file_open_test",
"file_overwrite_test",
"file_list_test",
"file_delete_test"]
#"file_mkdir_test",
#"file_rmdir_test"]
rdwr_tnames = [
"rdwr_cc_read_page_test",
"rdwr_cc_write_page_test",
"rdwr_nc_read_page_test",
"rdwr_nc_write_page_test",
"mmap_read_test",
"mmap_write_test"]
tnames = file_tnames + rdwr_tnames
aggregate = min
tests = {}
for arg in sys.argv[1:]:
name = os.path.splitext(os.path.basename(arg))[0]
if name[-1].isdigit() and name[-2] == '-':
name = name[:-2]
with open(arg, "r") as fin:
for row in csv.reader(fin):
tests.\
setdefault(row[0], {}).\
setdefault(name, {}).\
setdefault(int(row[1]), []).\
append(float(row[2]))
if False:
for tname in (tnames if tnames else sorted(tests.keys())):
print "%s:" % tname
test = tests[tname]
for sname in (snames if snames else sorted(test.keys())):
if sname not in test:
continue
print " %s:" % sname
series = test[sname]
for param in sorted(series.keys()):
print " %s: %s -> %.2f" % (param, series[param], aggregate(series[param]))
else:
for tname in (tnames if tnames else sorted(tests.keys())):
with open(tname + ".csv", "w") as fout:
test = tests[tname]
for sname in (snames if snames else sorted(test.keys())):
if sname not in test:
continue
fout.write("//%s\r\n" % sname)
series = test[sname]
for param in sorted(series.keys()):
fout.write("%s,%.2f\r\n" % (param, aggregate(series[param])))
def master_write(fname, tnames):
with open(fname + ".csv", "w") as fout:
for sname in snames:
fout.write("//%s\r\n" % sname)
for tname in (tnames if tnames else sorted(tests.keys())):
test = tests[tname]
if sname not in test:
continue
series = test[sname]
param = max(series.keys())
fout.write("%s,%.2f\r\n" % (tname, aggregate(series[param])))
master_write("file_tests", file_tnames)
master_write("rdwr_tests", rdwr_tnames)

View File

@ -0,0 +1,30 @@
//ntfs
100,0.19
200,0.42
300,0.61
400,0.78
500,0.97
//winfsp-t0
100,1.44
200,2.97
300,4.20
400,5.64
500,6.83
//winfsp-t1
100,1.47
200,3.00
300,4.45
400,5.78
500,7.33
//winfsp-tinf
100,0.28
200,0.58
300,0.87
400,1.12
500,1.48
//dokany
100,2.23
200,4.58
300,6.78
400,9.02
500,11.20
1 //ntfs
2 100,0.19
3 200,0.42
4 300,0.61
5 400,0.78
6 500,0.97
7 //winfsp-t0
8 100,1.44
9 200,2.97
10 300,4.20
11 400,5.64
12 500,6.83
13 //winfsp-t1
14 100,1.47
15 200,3.00
16 300,4.45
17 400,5.78
18 500,7.33
19 //winfsp-tinf
20 100,0.28
21 200,0.58
22 300,0.87
23 400,1.12
24 500,1.48
25 //dokany
26 100,2.23
27 200,4.58
28 300,6.78
29 400,9.02
30 500,11.20

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -0,0 +1,30 @@
//ntfs
100,0.25
200,0.47
300,0.69
400,0.91
500,1.19
//winfsp-t0
100,1.30
200,2.63
300,3.91
400,5.23
500,6.12
//winfsp-t1
100,1.30
200,2.47
300,3.89
400,4.92
500,6.17
//winfsp-tinf
100,0.34
200,0.67
300,1.01
400,1.38
500,1.70
//dokany
100,2.08
200,4.23
300,6.33
400,8.48
500,10.33
1 //ntfs
2 100,0.25
3 200,0.47
4 300,0.69
5 400,0.91
6 500,1.19
7 //winfsp-t0
8 100,1.30
9 200,2.63
10 300,3.91
11 400,5.23
12 500,6.12
13 //winfsp-t1
14 100,1.30
15 200,2.47
16 300,3.89
17 400,4.92
18 500,6.17
19 //winfsp-tinf
20 100,0.34
21 200,0.67
22 300,1.01
23 400,1.38
24 500,1.70
25 //dokany
26 100,2.08
27 200,4.23
28 300,6.33
29 400,8.48
30 500,10.33

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -0,0 +1,30 @@
//ntfs
100,9.38
200,21.39
300,19.56
400,26.11
500,33.05
//winfsp-t0
100,1.33
200,2.64
300,4.06
400,5.42
500,6.41
//winfsp-t1
100,1.38
200,2.78
300,4.23
400,5.52
500,6.94
//winfsp-tinf
100,1.36
200,2.81
300,3.95
400,5.19
500,6.58
//dokany
100,2.22
200,4.34
300,6.34
400,8.67
500,10.59
1 //ntfs
2 100,9.38
3 200,21.39
4 300,19.56
5 400,26.11
6 500,33.05
7 //winfsp-t0
8 100,1.33
9 200,2.64
10 300,4.06
11 400,5.42
12 500,6.41
13 //winfsp-t1
14 100,1.38
15 200,2.78
16 300,4.23
17 400,5.52
18 500,6.94
19 //winfsp-tinf
20 100,1.36
21 200,2.81
22 300,3.95
23 400,5.19
24 500,6.58
25 //dokany
26 100,2.22
27 200,4.34
28 300,6.34
29 400,8.67
30 500,10.59

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -0,0 +1,30 @@
//ntfs
100,7.55
200,14.36
300,21.58
400,28.52
500,35.45
//winfsp-t0
100,1.30
200,2.67
300,3.95
400,5.33
500,6.41
//winfsp-t1
100,1.30
200,2.61
300,3.94
400,5.36
500,6.51
//winfsp-tinf
100,1.31
200,2.56
300,3.86
400,5.11
500,6.42
//dokany
100,2.20
200,4.66
300,6.44
400,8.56
500,10.73
1 //ntfs
2 100,7.55
3 200,14.36
4 300,21.58
5 400,28.52
6 500,35.45
7 //winfsp-t0
8 100,1.30
9 200,2.67
10 300,3.95
11 400,5.33
12 500,6.41
13 //winfsp-t1
14 100,1.30
15 200,2.61
16 300,3.94
17 400,5.36
18 500,6.51
19 //winfsp-tinf
20 100,1.31
21 200,2.56
22 300,3.86
23 400,5.11
24 500,6.42
25 //dokany
26 100,2.20
27 200,4.66
28 300,6.44
29 400,8.56
30 500,10.73

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -0,0 +1,33 @@
//ntfs
rdwr_cc_read_page_test,0.97
rdwr_cc_write_page_test,1.19
rdwr_nc_read_page_test,33.05
rdwr_nc_write_page_test,35.45
mmap_read_test,1.06
mmap_write_test,0.72
//winfsp-t0
rdwr_cc_read_page_test,6.83
rdwr_cc_write_page_test,6.12
rdwr_nc_read_page_test,6.41
rdwr_nc_write_page_test,6.41
mmap_read_test,1.00
mmap_write_test,0.72
//winfsp-t1
rdwr_cc_read_page_test,7.33
rdwr_cc_write_page_test,6.17
rdwr_nc_read_page_test,6.94
rdwr_nc_write_page_test,6.51
mmap_read_test,0.98
mmap_write_test,0.73
//winfsp-tinf
rdwr_cc_read_page_test,1.48
rdwr_cc_write_page_test,1.70
rdwr_nc_read_page_test,6.58
rdwr_nc_write_page_test,6.42
mmap_read_test,0.98
mmap_write_test,0.73
//dokany
rdwr_cc_read_page_test,11.20
rdwr_cc_write_page_test,10.33
rdwr_nc_read_page_test,10.59
rdwr_nc_write_page_test,10.73
1 //ntfs
2 rdwr_cc_read_page_test,0.97
3 rdwr_cc_write_page_test,1.19
4 rdwr_nc_read_page_test,33.05
5 rdwr_nc_write_page_test,35.45
6 mmap_read_test,1.06
7 mmap_write_test,0.72
8 //winfsp-t0
9 rdwr_cc_read_page_test,6.83
10 rdwr_cc_write_page_test,6.12
11 rdwr_nc_read_page_test,6.41
12 rdwr_nc_write_page_test,6.41
13 mmap_read_test,1.00
14 mmap_write_test,0.72
15 //winfsp-t1
16 rdwr_cc_read_page_test,7.33
17 rdwr_cc_write_page_test,6.17
18 rdwr_nc_read_page_test,6.94
19 rdwr_nc_write_page_test,6.51
20 mmap_read_test,0.98
21 mmap_write_test,0.73
22 //winfsp-tinf
23 rdwr_cc_read_page_test,1.48
24 rdwr_cc_write_page_test,1.70
25 rdwr_nc_read_page_test,6.58
26 rdwr_nc_write_page_test,6.42
27 mmap_read_test,0.98
28 mmap_write_test,0.73
29 //dokany
30 rdwr_cc_read_page_test,11.20
31 rdwr_cc_write_page_test,10.33
32 rdwr_nc_read_page_test,10.59
33 rdwr_nc_write_page_test,10.73

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -0,0 +1,180 @@
= WinFsp as an IPC Mechanism
WinFsp enables the creation of user mode file systems for Windows. At its core WinFsp is also an Inter-Process Communication (IPC) mechanism that uses the familiar file system interface for communication. This document discusses WinFsp from that viewpoint.
== Single File API Request
When a process uses the familiar file API to access a file on Windows, this API request gets packaged into an I/O Request Packet (IRP) and gets routed to the relevant File System Driver (FSD). The usual FSD's in Windows (NTFS, FastFat, etc.) will process the IRP and return a response to the process. For the remainder of this discussion, we will call this process the Originating Process (OP).
In the WinFsp case things are more complicated. WinFsp will forward IRP's to another process, which implements a user mode file system. This process will process the IRP and return a response, which WinFsp will eventually forward to the OP. We will call the process that implements the user mode file system, the File System process (FS).
In the following we will also use the notation [U] to denote user mode processing and [K] to denote kernel mode processing. Additionally because a Context Switch always goes through kernel mode, we will simplify the diagrams and omit this detail when it is not important.
Consider then what happens when an OP issues a synchronous (non-overlapped), non-cached (non-buffered) WriteFile call.
ifdef::env-browser[]
[uml,file="WinFsp-as-an-IPC-Mechanism/synchronous.png"]
--
hide footbox
participant "OP[U]" as OPU
participant "OP[K]" as OPK
participant "FS[K]" as FSK
participant "FS[U]" as FSU
activate OPU
OPU ->OPK: WriteFile
deactivate OPU
activate OPK #Salmon
OPK-->FSK: Context Switch
deactivate OPK
activate FSK #Salmon
FSK ->FSU: TRANSACT Req
deactivate FSK
activate FSU #Salmon
FSU ->FSU: Process
activate FSU
deactivate FSU
FSU ->FSK: TRANSACT Rsp
deactivate FSU
activate FSK #Salmon
FSK-->OPU: Context Switch and Return
deactivate FSK
activate OPU
note over FSK, FSU #Salmon
Salmon color denotes WinFsp processing.
end note
--
endif::env-browser[]
ifndef::env-browser[image::WinFsp-as-an-IPC-Mechanism/synchronous.png[]]
Let us now consider what happens when an OP issues an asynchronous (overlapped), non-cached (non-buffered) WriteFile call. This scenario does not show how the OP receives the WriteFile result.
ifdef::env-browser[]
[uml,file="WinFsp-as-an-IPC-Mechanism/asynchronous.png"]
--
hide footbox
participant "OP[U]" as OPU
participant "OP[K]" as OPK
participant "FS[K]" as FSK
participant "FS[U]" as FSU
activate OPU
OPU ->OPK: WriteFile
deactivate OPU
activate OPK #Salmon
OPK ->OPU: Return
deactivate OPK
activate OPU
OPU ->OPU: Process
activate OPU
deactivate OPU
OPU-->FSK: Context Switch
deactivate OPU
activate FSK #Salmon
FSK ->FSU: TRANSACT Req
deactivate FSK
activate FSU #Salmon
FSU ->FSU: Process
activate FSU
deactivate FSU
FSU ->FSK: TRANSACT Rsp
deactivate FSU
activate FSK #Salmon
FSK-->OPU: Context Switch
deactivate FSK
activate OPU
note over FSK, FSU #Salmon
Salmon color denotes WinFsp processing.
end note
--
endif::env-browser[]
ifndef::env-browser[image::WinFsp-as-an-IPC-Mechanism/asynchronous.png[]]
It should be noted that from the WinFsp perspective both cases look similar. WinFsp processing occurs:
- At *OP[K]* time immediately after receipt of an IRP. An IRP is said to be in the _Pending_ stage at this point.
- At *FS[K]* time after a context switch, but before the TRANSACT call. An IRP is said to be in the _Prepare_ stage at this point.
- At *FS[K]* time after the TRANSACT call. An IRP is said to be in the _Complete_ stage at this point. Upon completion of this stage the IRP will be completed and relinquished to the OS.
- AT *FS[U]* time between the two TRANSACT calls.
The TRANSACT calls are DeviceIoControl requests that the FS issues to WinFsp. A single TRANSACT call can be used to communicate a file system response and retrieve the next file system request.
## Multiple File API Requests
Let us now consider what may happen with two simultaneous API Requests from two different processes. For example, two WriteFile requests for different files.
ifdef::env-browser[]
[uml,file="WinFsp-as-an-IPC-Mechanism/multiple.png"]
--
hide footbox
participant "OP<sub>1</sub>[U]" as OP1U
participant "OP<sub>1</sub>[K]" as OP1K
participant "OP<sub>2</sub>[U]" as OP2U
participant "OP<sub>2</sub>[K]" as OP2K
participant "FS[K]" as FSK
participant "FS[U]" as FSU
activate OP1U
OP1U ->OP1K: WriteFile
deactivate OP1U
activate OP1K #Salmon
OP1K-->OP2U: Context Switch
deactivate OP1K
activate OP2U
OP2U ->OP2K: WriteFile
deactivate OP2U
activate OP2K #Salmon
OP2K-->FSK: Context Switch
deactivate OP2K
activate FSK #Salmon
FSK ->FSU: TRANSACT\nReq<sub>1</sub>
deactivate FSK
activate FSU #Salmon
FSU ->FSU: Process
activate FSU
deactivate FSU
FSU ->FSK: TRANSACT\nRsp<sub>1</sub>
deactivate FSU
activate FSK #Salmon
FSK ->FSU: TRANSACT\nReq<sub>2</sub>
deactivate FSK
activate FSU #Salmon
FSU ->FSU: Process
activate FSU
deactivate FSU
FSU ->FSK: TRANSACT\nRsp<sub>2</sub>
deactivate FSU
activate FSK #Salmon
FSK-->OP1U: Context Switch and Return
deactivate FSK
activate OP1U
OP1U ->OP1U: Process
activate OP1U
deactivate OP1U
OP1U-->OP2U: Context Switch and Return
deactivate OP1U
activate OP2U
note over FSK, FSU #Salmon
Salmon color denotes WinFsp processing.
end note
--
endif::env-browser[]
ifndef::env-browser[image::WinFsp-as-an-IPC-Mechanism/multiple.png[]]
Notice that it is possible for the FS to process multiple file system requests without context switching.
## I/O Queues and Performance
I/O Queues are the fundamental IPC mechanism in WinFsp. The purpose of the I/O Queue is to forward an IRP from the OP to the FS and when FS processing is complete to forward the response back to the OP. I/O Queues are discussed in detail in the WinFsp design document.
WinFsp owes its excellent performance primarily to the design of the I/O Queues. I/O Queues borrow heavily from the design of I/O completion ports and schedule threads in a similar manner:
- They have a Last-In First-Out (LIFO) wait discipline.
- They limit the number of threads that can be satisfied concurrently to the number of processors.
The first property ensures that when an FS thread finishes processing a file system request, it will very likely pick up the next one from the I/O Queue without blocking and context switching to another FS thread. Minimizing context switches results in better performance.
The second property ensures that even if there are multiple file system requests waiting to be serviced in the I/O Queue, it will not schedule more thread than the number of processors. Having more than one threads scheduled on each processor is counter-productive.

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

120
doc/Winfsp-Testing.asciidoc Normal file
View File

@ -0,0 +1,120 @@
= WinFsp Testing Strategy
WinFsp maintains quality through rigorous testing under a variety of scenarios. This document discusses its testing strategy.
== Importance of Testing
A file system is a fundamental block of an OS. It provides the primary means for storing persistent information and capturing system state. A file system must not only be reliable and stable when the computer is running, it must also store data in a manner as to eliminate data loss or data corruption. Furthermore a file system must provide semantics that closely adhere to existing standards and conventions for its OS to avoid confusion or even accidental corruption from programs that use it. For these reasons rigorous and extensive testing of a file system is of paramount importance.
WinFsp enables the creation of user mode file systems that fully integrate with the Windows OS. WinFsp is a system component and the user mode file systems that integrate with it also become system components. The need for thorough testing of WinFsp becomes apparent.
== Test Suites
WinFsp currently has the following test suites:
- *Winfsp-tests*: This test suite provides comprehensive testing of WinFsp's capabilities under various scenarios. This includes general Win32 (and NTDLL) file API testing, but also includes WinFsp specific tests, such as incorrectly functioning user mode file systems. The non-WinFsp specific tests are verified against NTFS.
+
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.
+
This test suite is written in Python and C. 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.
- *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++.
- *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.
+
This tool is currently developed together with WinFsp. It is written in C.
These test suites and a few smaller tests are run through Continuous Integration testing every time a push is made into the WinFsp repository.
=== 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.
== Tested Scenarios
The combined test suites exercise the majority of Win32 file API's and a few NTDLL ones. The tested API's include:
- API's to create, open, close files/streams.
- API's to perform file/stream I/O in cached, non-cached, write-through, overlapped, etc. modes.
- API's to perform memory mapped I/O.
- API's to get or set file/stream metadata and security.
- API's to rename or delete files/streams.
- API's to enumerate directories and streams.
- API's that act on reparse points and symbolic links.
These tests are run under a variety of conditions:
- When the file system is a "disk" file system (+FILE_DEVICE_DISK_FILE_SYSTEM+).
- When the file system is a "network" file system (+FILE_DEVICE_NETWORK_FILE_SYSTEM+).
- When the file system is a "disk" file system exposed as a network share (+NetShareAdd+).
- When the file system is mapped as a drive (+DefineDosDeviceW+).
- When the file system is mounted on a directory (using junctions).
- When the file system is case-sensitive or case-insensitive.
- When the process making the API calls lacks the traverse privilege (+SE_CHANGE_NOTIFY_NAME+).
- When the process making the API calls has the backup or restore privilege (+SE_BACKUP_NAME+, +SE_RESTORE_NAME+).
Not all tests apply to all conditions. The test suites will disable/skip tests that do not apply to a particular scenario.
In addition the tests are run both on Debug and Release builds. Debug builds includes numerous ASSERT() statements that test various conditions within the WinFsp code.
=== Coverage
Windows File System Drivers (FSD) run in a variety of conditions that are not always easy to replicate during testing. For example, an FSD may not be able to get locks to perform an operation, in which case it may retry the operation later. Or it may be unable to allocate memory for a MustSucceed task, in which case it may wait a bit and retry.
Such situations may not arise during normal testing. For this reason, WinFsp uses the +DEBUGTEST()+ macro, which takes a single +Percent+ argument. In Release builds this macro always evaluates to +TRUE+. In Debug builds this macro may evaluate to +TRUE+ or +FALSE+ depending on the value of the +Percent+ argument, which specifies the percentage of times that +DEBUGTEST()+ should evaluate to +TRUE+. For example, a +DEBUGTEST(90)+ means that 90% of the time the macro should evaluate to +TRUE+ and 10% of the time it should evaluate to +FALSE+.
The WinFsp FSD uses the +DEBUGTEST()+ macro in various places where an operation may have to be retried. For example, here is how it handles deferred writes:
----
/* should we defer the write? */
Success = DEBUGTEST(90) && CcCanIWrite(FileObject, WriteLength, CanWait, Retrying);
if (!Success)
{
Result = FspWqCreateIrpWorkItem(Irp, FspFsvolWriteCached, 0);
if (NT_SUCCESS(Result))
{
IoMarkIrpPending(Irp);
CcDeferWrite(FileObject, FspFsvolWriteCachedDeferred, Irp, 0, WriteLength, Retrying);
return STATUS_PENDING;
}
/* if we are unable to defer we will go ahead and (try to) service the IRP now! */
}
----
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.
== 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.
In such cases WinFsp is able to recover gracefully and clean up its resources and data structures. This is a fundamental capability of WinFsp and one that must be tested thoroughly.
For this purpose WinFsp is tested using the fscrash tool. Fscrash includes a special version of MEMFS, where file operations can potentially cause a crash. Fscrash also includes a simple test that is run in a loop until the included file system crashes. When the OS kills the process, the WinFsp FSD steps in and cleans up all resources used by the faulty file system. The intent of the test is to verify that WinFsp handles the crash properly, without leaving any leaks and without crashing the OS.
== Verifier
All development and testing of WinFsp is done under the Driver Verifier with standard settings enabled. The Driver Verifier is an invaluable tool for Windows Driver development. It has caught numerous issues within WinFsp, in most cases immediately after the faulty code was written and run for the first time.
=== Leak Testing
One of the most important aspects of the Driver Verifier is that it can track the pool (memory) usage of WinFsp. The WinFsp master test driver uses this to confirm that the WinFsp FSD does not leak memory. At the end of the tests the master test driver unmounts any remaining WinFsp file systems and then verifies that there are zero pool allocations for the WinFsp FSD.
== Performance Testing
The goal of performance testing is to evaluate and understand how software behaves under certain workloads. Performance testing can help identify cases where the software requires too much time or resources. It is also useful to establish a performance baseline to ensure that software performance does not degrade over time.
WinFsp uses a tool called fsbench for this purpose. Fsbench is able to test specific scenarios, for example: "how long does it take to delete 1000 files?" Fsbench has been very useful for WinFsp and has helped improve its performance: in one situation it helped identify quadratic behavior with the MEMFS ReadDirectory operation, in another situation it helped fine tune the performance of the WinFsp I/O Queue.
== Code Analysis
WinFsp is regularly run under the Visual Studio's Code Analyzer. Any issues found are examined and if necessary acted upon.
WinFsp compiles cleanly without any warnings.

1785
doc/winfsp.h.markdown Normal file

File diff suppressed because it is too large Load Diff

View File

@ -54,10 +54,19 @@ static char assert_buf[256];
static void test_printf(const char *fmt, ...);
static double run_test(struct test *test)
{
#if defined(_WIN64) || defined(_WIN32)
#pragma comment(lib, "winmm.lib")
unsigned long __stdcall timeGetTime(void);
unsigned long t0 = timeGetTime();
test->fn();
unsigned long t1 = timeGetTime();
return (t1 - t0) / 1000.0;
#else
time_t t0 = time(0);
test->fn();
time_t t1 = time(0);
return difftime(t1, t0);
#endif
}
static void do_test_default(struct test *test, int testno)
{
@ -73,7 +82,7 @@ static void do_test_default(struct test *test, int testno)
dispname[sizeof dispname - 1] = '\0';
test_printf("%s ", dispname);
double d = run_test(test);
test_printf("OK %.0fs\n", d);
test_printf("OK %.2fs\n", d);
}
else
test_printf("--- COMPLETE ---\n");
@ -131,6 +140,11 @@ void tlib_run_tests(int argc, char *argv[])
no_abort = 1;
else if (0 == strcmp("--repeat-forever", a))
repeat = ULONG_MAX;
else if ('-' == a[1])
{
fprintf(stderr, "tlib_run_tests: unknown option %s\n", a);
exit(2);
}
}
else
match_any = 0;

View File

@ -28,7 +28,7 @@ extern "C" {
#if defined(WINFSP_SYS_INTERNAL) || defined(WINFSP_DLL_INTERNAL)
#define FSP_FSCTL_STATIC_ASSERT(e,m) static_assert(e,m)
#else
#define FSP_FSCTL_STATIC_ASSERT(e,m)
#define FSP_FSCTL_STATIC_ASSERT(e,m) static_assert(1,"")
#endif
#define FSP_FSCTL_DRIVER_NAME "WinFsp"
@ -78,8 +78,6 @@ FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024)
#define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX
#define FSP_FSCTL_TRANSACT_USERCONTEXT(s,i) (((PUINT64)&(s).UserContext)[i])
/* marshalling */
#pragma warning(push)
#pragma warning(disable:4200) /* zero-sized array in struct/union */
@ -151,8 +149,9 @@ typedef struct
UINT32 PostCleanupOnDeleteOnly:1; /* post Cleanup when deleting a file only */
UINT32 KmReservedFlags:5;
/* user-mode flags */
UINT32 UmFileNodeIsUserContext2:1; /* user mode: FileNode parameter is UserContext2 */
UINT32 UmReservedFlags:15;
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */
UINT32 UmReservedFlags:14;
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
} FSP_FSCTL_VOLUME_PARAMS;
@ -174,13 +173,20 @@ typedef struct
UINT64 LastWriteTime;
UINT64 ChangeTime;
UINT64 IndexNumber;
UINT32 HardLinks; /* unimplemented: set to 0 */
} FSP_FSCTL_FILE_INFO;
typedef struct
{
FSP_FSCTL_FILE_INFO FileInfo;
PWSTR NormalizedName;
UINT16 NormalizedNameSize;
} FSP_FSCTL_OPEN_FILE_INFO;
typedef struct
{
UINT16 Size;
FSP_FSCTL_FILE_INFO FileInfo;
UINT64 NextOffset;
UINT8 Padding[24];
UINT8 Padding[16];
/* make struct as big as FILE_ID_BOTH_DIR_INFORMATION; allows for in-place copying */
WCHAR FileNameBuf[];
} FSP_FSCTL_DIR_INFO;
@ -192,6 +198,11 @@ typedef struct
WCHAR StreamNameBuf[];
} FSP_FSCTL_STREAM_INFO;
typedef struct
{
UINT64 UserContext;
UINT64 UserContext2;
} FSP_FSCTL_TRANSACT_FULL_CONTEXT;
typedef struct
{
UINT16 Offset;
UINT16 Size;
@ -212,13 +223,16 @@ typedef struct
UINT64 AllocationSize; /* initial allocation size */
UINT64 AccessToken; /* request access token (HANDLE) */
UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */
FSP_FSCTL_TRANSACT_BUF Ea; /* reserved; not currently implemented */
UINT32 UserMode:1; /* request originated in user mode */
UINT32 HasTraversePrivilege:1; /* requestor has TOKEN_HAS_TRAVERSE_PRIVILEGE */
UINT32 HasBackupPrivilege:1; /* requestor has TOKEN_HAS_BACKUP_PRIVILEGE */
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:28;
UINT32 ReservedFlags:26;
UINT16 NamedStream; /* request targets named stream; colon offset in FileName */
} Create;
struct
@ -226,6 +240,7 @@ typedef struct
UINT64 UserContext;
UINT64 UserContext2;
UINT32 FileAttributes; /* file attributes for overwritten/superseded files */
UINT64 AllocationSize; /* allocation size for overwritten/superseded files */
UINT32 Supersede:1; /* 0: FILE_OVERWRITE operation, 1: FILE_SUPERSEDE operation */
} Overwrite;
struct
@ -320,6 +335,7 @@ typedef struct
UINT64 Offset;
UINT32 Length;
FSP_FSCTL_TRANSACT_BUF Pattern;
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
} QueryDirectory;
struct
{
@ -339,7 +355,6 @@ typedef struct
UINT64 UserContext;
UINT64 UserContext2;
UINT32 SecurityInformation;
UINT64 AccessToken; /* request access token (HANDLE) */
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
} SetSecurity;
struct
@ -348,7 +363,8 @@ typedef struct
UINT64 UserContext2;
} QueryStreamInformation;
} Req;
FSP_FSCTL_TRANSACT_BUF FileName; /* {Create,Cleanup,SetInformation/{...},QueryDirectory} */
FSP_FSCTL_TRANSACT_BUF FileName;
/* Create,Cleanup,SetInformation{Disposition,Rename},FileSystemControl{ReparsePoint} */
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
} FSP_FSCTL_TRANSACT_REQ;
typedef struct
@ -373,6 +389,8 @@ typedef struct
UINT64 UserContext2; /* user context associated with file descriptor (handle) */
UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
FSP_FSCTL_FILE_INFO FileInfo;
FSP_FSCTL_TRANSACT_BUF FileName;
UINT32 DisableCache:1;
} Opened;
/* IoStatus.Status == STATUS_REPARSE */
struct
@ -424,6 +442,9 @@ typedef struct
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
} FSP_FSCTL_TRANSACT_RSP;
#pragma warning(pop)
FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX > FSP_FSCTL_TRANSACT_PATH_SIZEMAX,
"FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX must be greater than FSP_FSCTL_TRANSACT_PATH_SIZEMAX "
"to detect when a normalized name has been set during a Create/Open request.");
static inline BOOLEAN FspFsctlTransactCanProduceRequest(
FSP_FSCTL_TRANSACT_REQ *Request, PVOID RequestBufEnd)
{

View File

@ -127,7 +127,35 @@ typedef enum
* File system interface.
*
* The operations in this interface must be implemented by the user mode
* file system.
* file system. Not all operations need be implemented. For example,
* a user mode file system that does not wish to support reparse points,
* need not implement the reparse point operations.
*
* Most of the operations accept a FileContext parameter. This parameter
* has different meanings depending on the value of the FSP_FSCTL_VOLUME_PARAMS
* flags UmFileContextIsUserContext2 and UmFileContextIsFullContext.
*
* There are three cases to consider:
* <ul>
* <li>When both of these flags are unset (default), the FileContext parameter
* represents the file node. The file node is a void pointer (or an integer
* that can fit in a pointer) that is used to uniquely identify an open file.
* Opening the same file name should always yield the same file node value
* for as long as the file with that name remains open anywhere in the system.
* </li>
* <li>When the UmFileContextIsUserContext2 is set, the FileContext parameter
* represents the file descriptor. The file descriptor is a void pointer (or
* an integer that can fit in a pointer) that is used to identify an open
* instance of a file. Opening the same file name may yield a different file
* descriptor.
* </li>
* <li>When the UmFileContextIsFullContext is set, the FileContext parameter
* is a pointer to a FSP_FSCTL_TRANSACT_FULL_CONTEXT. This allows a user mode
* file system to access the low-level UserContext and UserContext2 values.
* The UserContext is used to store the file node and the UserContext2 is
* used to store the file descriptor for an open file.
* </li>
* </ul>
*/
typedef struct _FSP_FILE_SYSTEM_INTERFACE
{
@ -136,8 +164,6 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param VolumeInfo [out]
* Pointer to a structure that will receive the volume information on successful return
* from this call.
@ -145,15 +171,12 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*GetVolumeInfo)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
FSP_FSCTL_VOLUME_INFO *VolumeInfo);
/**
* Set volume label.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param VolumeLabel
* The new label for the volume.
* @param VolumeInfo [out]
@ -163,7 +186,6 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*SetVolumeLabel)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PWSTR VolumeLabel,
FSP_FSCTL_VOLUME_INFO *VolumeInfo);
/**
@ -202,13 +224,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileName
* The name of the file or directory to be created.
* @param CaseSensitive
* Whether to treat the FileName as case-sensitive or case-insensitive. Case-sensitive
* file systems always treat FileName as case-sensitive regardless of this parameter.
* @param CreateOptions
* Create options for this request. This parameter has the same meaning as the
* CreateOptions parameter of the NtCreateFile API. User mode file systems should typically
@ -216,20 +233,22 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* directory rather than a file. Some file systems may also want to pay attention to the
* FILE_NO_INTERMEDIATE_BUFFERING and FILE_WRITE_THROUGH flags, although these are
* typically handled by the FSD component.
* @param GrantedAccess
* Determines the specific access rights that have been granted for this request. Upon
* receiving this call all access checks have been performed and the user mode file system
* need not perform any additional checks. However this parameter may be useful to a user
* mode file system; for example the WinFsp-FUSE layer uses this parameter to determine
* which flags to use in its POSIX open() call.
* @param FileAttributes
* File attributes to apply to the newly created file or directory.
* @param SecurityDescriptor
* Security descriptor to apply to the newly created file or directory. This security
* descriptor will always be in self-relative format. Its length can be retrieved using the
* Windows GetSecurityDescriptorLength API.
* Windows GetSecurityDescriptorLength API. Will be NULL for named streams.
* @param AllocationSize
* Allocation size for the newly created file.
* @param PFileNode [out]
* Pointer that will receive the file node on successful return from this call. The file
* node is a void pointer (or an integer that can fit in a pointer) that is used to
* uniquely identify an open file. Opening the same file name should always return the same
* file node value for as long as the file with that name remains open anywhere in the
* system. The file system can place any value it needs here.
* @param PFileContext [out]
* Pointer that will receive the file context on successful return from this call.
* @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.
@ -237,34 +256,30 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*Create)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PWSTR FileName, BOOLEAN CaseSensitive, UINT32 CreateOptions,
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo);
PVOID *PFileContext, FSP_FSCTL_FILE_INFO *FileInfo);
/**
* Open a file or directory.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileName
* The name of the file or directory to be opened.
* @param CaseSensitive
* Whether to treat the FileName as case-sensitive or case-insensitive. Case-sensitive
* file systems always treat FileName as case-sensitive regardless of this parameter.
* @param CreateOptions
* Create options for this request. This parameter has the same meaning as the
* CreateOptions parameter of the NtCreateFile API. User mode file systems typically
* do not need to do anything special with respect to this parameter. Some file systems may
* also want to pay attention to the FILE_NO_INTERMEDIATE_BUFFERING and FILE_WRITE_THROUGH
* flags, although these are typically handled by the FSD component.
* @param PFileNode [out]
* Pointer that will receive the file node on successful return from this call. The file
* node is a void pointer (or an integer that can fit in a pointer) that is used to
* uniquely identify an open file. Opening the same file name should always return the same
* file node value for as long as the file with that name remains open anywhere in the
* system. The file system can place any value it needs here.
* @param GrantedAccess
* Determines the specific access rights that have been granted for this request. Upon
* receiving this call all access checks have been performed and the user mode file system
* need not perform any additional checks. However this parameter may be useful to a user
* mode file system; for example the WinFsp-FUSE layer uses this parameter to determine
* which flags to use in its POSIX open() call.
* @param PFileContext [out]
* Pointer that will receive the file context on successful return from this call.
* @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.
@ -272,23 +287,22 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*Open)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PWSTR FileName, BOOLEAN CaseSensitive, UINT32 CreateOptions,
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo);
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
PVOID *PFileContext, FSP_FSCTL_FILE_INFO *FileInfo);
/**
* Overwrite a file.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file to overwrite.
* @param FileContext
* The file context of the file to overwrite.
* @param FileAttributes
* File attributes to apply to the overwritten file.
* @param ReplaceFileAttributes
* When TRUE the existing file attributes should be replaced with the new ones.
* When FALSE the existing file attributes should be merged (or'ed) with the new ones.
* @param AllocationSize
* Allocation size for the overwritten file.
* @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.
@ -296,8 +310,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*Overwrite)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes,
PVOID FileContext, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes, UINT64 AllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo);
/**
* Cleanup a file.
@ -324,10 +337,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file or directory to cleanup.
* @param FileContext
* 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
@ -339,30 +350,24 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* CanDelete
*/
VOID (*Cleanup)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PWSTR FileName, BOOLEAN Delete);
PVOID FileContext, PWSTR FileName, BOOLEAN Delete);
/**
* Close a file.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file or directory to be closed.
* @param FileContext
* The file context of the file or directory to be closed.
*/
VOID (*Close)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode);
PVOID FileContext);
/**
* Read a file.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file to be read.
* @param FileContext
* The file context of the file to be read.
* @param Buffer
* Pointer to a buffer that will receive the results of the read operation.
* @param Offset
@ -376,18 +381,15 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* operation.
*/
NTSTATUS (*Read)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length,
PULONG PBytesTransferred);
/**
* Write a file.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file to be written.
* @param FileContext
* The file context of the file to be written.
* @param Buffer
* Pointer to a buffer that contains the data to write.
* @param Offset
@ -409,8 +411,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* operation.
*/
NTSTATUS (*Write)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length,
BOOLEAN WriteToEndOfFile, BOOLEAN ConstrainedIo,
PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo);
/**
@ -420,25 +421,20 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file to be flushed. When NULL the whole volume is being flushed.
* @param FileContext
* The file context of the file to be flushed. When NULL the whole volume is being flushed.
* @return
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*Flush)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode);
PVOID FileContext);
/**
* Get file or directory information.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file or directory to get information for.
* @param FileContext
* The file context of the file or directory to get information for.
* @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.
@ -446,18 +442,15 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*GetFileInfo)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
PVOID FileContext,
FSP_FSCTL_FILE_INFO *FileInfo);
/**
* Set file or directory basic information.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file or directory to set information for.
* @param FileContext
* The file context of the file or directory to set information for.
* @param FileAttributes
* File attributes to apply to the file or directory. If the value INVALID_FILE_ATTRIBUTES
* is sent, the file attributes should not be changed.
@ -477,8 +470,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*SetBasicInfo)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, UINT32 FileAttributes,
PVOID FileContext, UINT32 FileAttributes,
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
FSP_FSCTL_FILE_INFO *FileInfo);
/**
@ -503,10 +495,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file to set the file/allocation size for.
* @param FileContext
* The file context of the file to set the file/allocation size for.
* @param NewSize
* New file/allocation size to apply to the file.
* @param SetAllocationSize
@ -518,8 +508,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*SetFileSize)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, UINT64 NewSize, BOOLEAN SetAllocationSize,
PVOID FileContext, UINT64 NewSize, BOOLEAN SetAllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo);
/**
* Determine whether a file or directory can be deleted.
@ -536,10 +525,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file or directory to test for deletion.
* @param FileContext
* The file context of the file or directory to test for deletion.
* @param FileName
* The name of the file or directory to test for deletion.
* @return
@ -548,8 +535,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* Cleanup
*/
NTSTATUS (*CanDelete)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PWSTR FileName);
PVOID FileContext, PWSTR FileName);
/**
* Renames a file or directory.
*
@ -564,10 +550,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file or directory to be renamed.
* @param FileContext
* The file context of the file or directory to be renamed.
* @param FileName
* The current name of the file or directory to rename.
* @param NewFileName
@ -578,16 +562,15 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*Rename)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
PVOID FileContext,
PWSTR FileName, PWSTR NewFileName, BOOLEAN ReplaceIfExists);
/**
* Get file or directory security descriptor.
*
* @param FileSystem
* The file system on which this request is posted.
* @param FileNode
* The file node of the file or directory to get the security descriptor for.
* @param FileContext
* The file context of the file or directory to get the security descriptor for.
* @param SecurityDescriptor
* Pointer to a buffer that will receive the file security descriptor on successful return
* from this call. May be NULL.
@ -599,44 +582,54 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*GetSecurity)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
PVOID FileContext,
PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T *PSecurityDescriptorSize);
/**
* Set file or directory security descriptor.
*
* @param FileSystem
* The file system on which this request is posted.
* @param FileNode
* The file node of the file or directory to set the security descriptor for.
* @param FileContext
* The file context of the file or directory to set the security descriptor for.
* @param SecurityInformation
* Indicates what part of the file or directory security descriptor to change.
* @param SecurityDescriptor
* Security descriptor to apply to the file or directory. This security descriptor will
* always be in self-relative format.
* Describes what parts of the file or directory security descriptor should
* be modified.
* @param ModificationDescriptor
* Describes the modifications to apply to the file or directory security descriptor.
* @return
* STATUS_SUCCESS or error code.
* @see
* FspSetSecurityDescriptor
* FspDeleteSecurityDescriptor
*/
NTSTATUS (*SetSecurity)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor);
PVOID FileContext,
SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor);
/**
* Read a directory.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the directory to be read.
* @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.
* 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
@ -652,8 +645,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* FspFileSystemAddDirInfo
*/
NTSTATUS (*ReadDirectory)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length,
PWSTR Pattern,
PULONG PBytesTransferred);
/**
@ -705,10 +697,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the reparse point.
* @param FileContext
* The file context of the reparse point.
* @param FileName
* The file name of the reparse point.
* @param Buffer
@ -723,18 +713,15 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* SetReparsePoint
*/
NTSTATUS (*GetReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
PVOID FileContext,
PWSTR FileName, PVOID Buffer, PSIZE_T PSize);
/**
* Set reparse point.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the reparse point.
* @param FileContext
* The file context of the reparse point.
* @param FileName
* The file name of the reparse point.
* @param Buffer
@ -748,18 +735,15 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* GetReparsePoint
*/
NTSTATUS (*SetReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
PVOID FileContext,
PWSTR FileName, PVOID Buffer, SIZE_T Size);
/**
* Delete reparse point.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the reparse point.
* @param FileContext
* The file context of the reparse point.
* @param FileName
* The file name of the reparse point.
* @param Buffer
@ -770,18 +754,15 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*DeleteReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
PVOID FileContext,
PWSTR FileName, PVOID Buffer, SIZE_T Size);
/**
* Get named streams information.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file or directory to get stream information for.
* @param FileContext
* The file context of the file or directory to get stream information for.
* @param Buffer
* Pointer to a buffer that will receive the stream information.
* @param Length
@ -794,8 +775,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* FspFileSystemAddStreamInfo
*/
NTSTATUS (*GetStreamInfo)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PVOID Buffer, ULONG Length,
PVOID FileContext, PVOID Buffer, ULONG Length,
PULONG PBytesTransferred);
/*
@ -823,8 +803,13 @@ typedef struct _FSP_FILE_SYSTEM
UINT32 DebugLog;
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
SRWLOCK OpGuardLock;
BOOLEAN UmFileNodeIsUserContext2;
BOOLEAN UmFileContextIsUserContext2, UmFileContextIsFullContext;
} FSP_FILE_SYSTEM;
typedef struct _FSP_FILE_SYSTEM_OPERATION_CONTEXT
{
FSP_FSCTL_TRANSACT_REQ *Request;
FSP_FSCTL_TRANSACT_RSP *Response;
} FSP_FILE_SYSTEM_OPERATION_CONTEXT;
/**
* Create a file system object.
*
@ -855,9 +840,13 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem);
/**
* Set the mount point for a file system.
*
* This function currently only supports drive letters (X:) as mount points. Refer to the
* documentation of the DefineDosDevice Windows API to better understand how drive letters are
* created.
* This function supports drive letters (X:) or directories as mount points:
* <ul>
* <li>Drive letters: Refer to the documentation of the DefineDosDevice Windows API
* to better understand how they are created.</li>
* <li>Directories: They can be used as mount points for disk based file systems. They cannot
* be used for network file systems. This is a limitation that Windows imposes on junctions.</li>
* </ul>
*
* @param FileSystem
* The file system object.
@ -920,6 +909,17 @@ FSP_API VOID FspFileSystemStopDispatcher(FSP_FILE_SYSTEM *FileSystem);
*/
FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_RSP *Response);
/**
* Get the current operation context.
*
* This function may be used only when servicing one of the FSP_FILE_SYSTEM_INTERFACE operations.
* The current operation context is stored in thread local storage. It allows access to the
* Request and Response associated with this operation.
*
* @return
* The current operation context.
*/
FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID);
static inline
PWSTR FspFileSystemMountPoint(FSP_FILE_SYSTEM *FileSystem)
{
@ -996,6 +996,14 @@ VOID FspFileSystemSetDebugLog(FSP_FILE_SYSTEM *FileSystem,
{
FileSystem->DebugLog = DebugLog;
}
static inline
BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID)
{
FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request;
return
FspFsctlTransactCreateKind == Request->Kind && Request->Req.Create.CaseSensitive ||
FspFsctlTransactQueryDirectoryKind == Request->Kind && Request->Req.QueryDirectory.CaseSensitive;
}
/*
* Operations
@ -1040,6 +1048,54 @@ FSP_API NTSTATUS FspFileSystemOpQueryStreamInformation(FSP_FILE_SYSTEM *FileSyst
/*
* Helpers
*/
/**
* Get open information buffer.
*
* This is a helper for implementing the Create and Open operations. It cannot be used with
* any other operations.
*
* The FileInfo parameter to Create and Open is typed as pointer to FSP_FSCTL_FILE_INFO. The
* true type of this parameter is pointer to FSP_FSCTL_OPEN_FILE_INFO. This simple function
* converts from one type to the other.
*
* The FSP_FSCTL_OPEN_FILE_INFO type contains a FSP_FSCTL_FILE_INFO as well as the fields
* NormalizedName and NormalizedNameSize. These fields can be used for file name normalization.
* File name normalization is used to ensure that the FSD and the OS know the correct case
* of a newly opened file name.
*
* For case-sensitive file systems this functionality should be ignored. The FSD will always
* assume that the normalized file name is the same as the file name used to open the file.
*
* For case-insensitive file systems this functionality may be ignored. In this case the FSD
* will assume that the normalized file name is the upper case version of the file name used
* to open the file. The file system will work correctly and the only way an application will
* be able to tell that the file system does not preserve case in normalized file names is by
* issuing a GetFinalPathNameByHandle API call (or NtQueryInformationFile with
* FileNameInformation/FileNormalizedNameInformation).
*
* For case-insensitive file systems this functionality may also be used. In this case the
* user mode file system may use the NormalizedName and NormalizedNameSize parameters to
* report to the FSD the normalized file name. It should be noted that the normalized file
* name may only differ in case from the file name used to open the file. The NormalizedName
* field will point to a buffer that can receive the normalized file name. The
* NormalizedNameSize field will contain the size of the normalized file name buffer. On
* completion of the Create or Open operation it should contain the actual size of the
* normalized file name copied into the normalized file name buffer. The normalized file name
* should not contain a terminating zero.
*
* @param FileInfo
* The FileInfo parameter as passed to Create or Open operation.
* @return
* A pointer to the open information buffer for this Create or Open operation.
* @see
* Create
* Open
*/
static inline
FSP_FSCTL_OPEN_FILE_INFO *FspFileSystemGetOpenFileInfo(FSP_FSCTL_FILE_INFO *FileInfo)
{
return (FSP_FSCTL_OPEN_FILE_INFO *)FileInfo;
}
/**
* Add directory information to a buffer.
*
@ -1214,10 +1270,49 @@ FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PSECURITY_DESCRIPTOR ParentDescriptor,
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
FSP_API NTSTATUS FspSetSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
/**
* Modify security descriptor.
*
* This is a helper for implementing the SetSecurity operation.
*
* @param InputDescriptor
* The input security descriptor to be modified.
* @param SecurityInformation
* Describes what parts of the InputDescriptor should be modified. This should contain
* the same value passed to the SetSecurity SecurityInformation parameter.
* @param ModificationDescriptor
* Describes the modifications to apply to the InputDescriptor. This should contain
* the same value passed to the SetSecurity ModificationDescriptor parameter.
* @param PSecurityDescriptor [out]
* Pointer to a memory location that will receive the resulting security descriptor.
* This security descriptor can be later freed using FspDeleteSecurityDescriptor.
* @return
* STATUS_SUCCESS or error code.
* @see
* SetSecurity
* FspDeleteSecurityDescriptor
*/
FSP_API NTSTATUS FspSetSecurityDescriptor(
PSECURITY_DESCRIPTOR InputDescriptor,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR ModificationDescriptor,
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
/**
* Delete security descriptor.
*
* This is a helper for implementing the SetSecurity operation.
*
* @param SecurityDescriptor
* The security descriptor to be deleted.
* @param CreateFunc
* Function used to create the security descriptor. This parameter should be
* set to FspSetSecurityDescriptor for the public API.
* @return
* STATUS_SUCCESS or error code.
* @see
* SetSecurity
* FspSetSecurityDescriptor
*/
FSP_API VOID FspDeleteSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
NTSTATUS (*CreateFunc)());
static inline

View File

@ -299,12 +299,16 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
&Sddl, 0);
FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c] \"%S\", "
FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c%c%c] \"%S\", "
"%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, "
"AllocationSize=%lx:%lx, AccessToken=%p, DesiredAccess=%lx, ShareAccess=%lx\n",
"AllocationSize=%lx:%lx, "
"AccessToken=%p, DesiredAccess=%lx, GrantedAccess=%lx, "
"ShareAccess=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->Req.Create.UserMode ? 'U' : 'K',
Request->Req.Create.HasTraversePrivilege ? 'T' : '-',
Request->Req.Create.HasBackupPrivilege ? 'B' : '-',
Request->Req.Create.HasRestorePrivilege ? 'R' : '-',
Request->Req.Create.OpenTargetDirectory ? 'D' : '-',
Request->Req.Create.CaseSensitive ? 'C' : '-',
(PWSTR)Request->Buffer,
@ -317,6 +321,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
MAKE_UINT32_PAIR(Request->Req.Create.AllocationSize),
(PVOID)Request->Req.Create.AccessToken,
Request->Req.Create.DesiredAccess,
Request->Req.Create.GrantedAccess,
Request->Req.Create.ShareAccess);
LocalFree(Sddl);
break;
@ -598,7 +603,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
&Sddl, 0);
FspDebugLog("%S[TID=%04lx]: %p: >>SetSecurity %s%S%s%s, "
"SecurityInformation=%lx, AccessToken=%p, Security=%s%s%s\n",
"SecurityInformation=%lx, Security=%s%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
@ -607,12 +612,21 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
Request->Req.SetSecurity.UserContext, Request->Req.SetSecurity.UserContext2,
UserContextBuf),
Request->Req.SetSecurity.SecurityInformation,
(PVOID)Request->Req.SetSecurity.AccessToken,
Sddl ? "\"" : "",
Sddl ? Sddl : "NULL",
Sddl ? "\"" : "");
LocalFree(Sddl);
break;
case FspFsctlTransactQueryStreamInformationKind:
FspDebugLog("%S[TID=%04lx]: %p: >>QueryStreamInformation %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.QueryStreamInformation.UserContext, Request->Req.QueryStreamInformation.UserContext2,
UserContextBuf));
break;
default:
FspDebugLogRequestVoid(Request, "INVALID");
break;
@ -815,6 +829,9 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
LocalFree(Sddl);
}
break;
case FspFsctlTransactQueryStreamInformationKind:
FspDebugLogResponseStatus(Response, "QueryStreamInformation");
break;
default:
FspDebugLogResponseStatus(Response, "INVALID");
break;

View File

@ -25,6 +25,7 @@ enum
static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface;
static INIT_ONCE FspFileSystemInitOnce = INIT_ONCE_STATIC_INIT;
static DWORD FspFileSystemTlsKey = TLS_OUT_OF_INDEXES;
static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
static NTSTATUS (NTAPI *FspNtMakeTemporaryObject)(
@ -37,6 +38,8 @@ static BOOL WINAPI FspFileSystemInitialize(
{
HANDLE Handle;
FspFileSystemTlsKey = TlsAlloc();
Handle = GetModuleHandleW(L"ntdll.dll");
if (0 != Handle)
{
@ -55,6 +58,20 @@ static BOOL WINAPI FspFileSystemInitialize(
return TRUE;
}
VOID FspFileSystemFinalize(BOOLEAN Dynamic)
{
/*
* This function is called during DLL_PROCESS_DETACH. We must therefore keep
* finalization tasks to a minimum.
*
* We must free our TLS key (if any). We only do so if the library
* is being explicitly unloaded (rather than the process exiting).
*/
if (Dynamic && TLS_OUT_OF_INDEXES != FspFileSystemTlsKey)
TlsFree(FspFileSystemTlsKey);
}
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
const FSP_FILE_SYSTEM_INTERFACE *Interface,
@ -65,10 +82,16 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
*PFileSystem = 0;
if (VolumeParams->UmFileContextIsUserContext2 &&
VolumeParams->UmFileContextIsFullContext)
return STATUS_INVALID_PARAMETER;
if (0 == Interface)
Interface = &FspFileSystemNullInterface;
InitOnceExecuteOnce(&FspFileSystemInitOnce, FspFileSystemInitialize, 0, 0);
if (TLS_OUT_OF_INDEXES == FspFileSystemTlsKey)
return STATUS_INSUFFICIENT_RESOURCES;
FileSystem = MemAlloc(sizeof *FileSystem);
if (0 == FileSystem)
@ -107,7 +130,8 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
FileSystem->EnterOperation = FspFileSystemOpEnter;
FileSystem->LeaveOperation = FspFileSystemOpLeave;
FileSystem->UmFileNodeIsUserContext2 = !!VolumeParams->UmFileNodeIsUserContext2;
FileSystem->UmFileContextIsUserContext2 = !!VolumeParams->UmFileContextIsUserContext2;
FileSystem->UmFileContextIsFullContext = !!VolumeParams->UmFileContextIsFullContext;
*PFileSystem = FileSystem;
@ -121,6 +145,168 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem)
MemFree(FileSystem);
}
static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWSTR VolumeName)
{
NTSTATUS Result;
HANDLE DirHandle;
BOOL Success;
DWORD Backslashes, Bytes;
USHORT VolumeNameLength, BackslashLength, ReparseDataLength;
PREPARSE_DATA_BUFFER ReparseData = 0;
PWSTR P, PathBuffer;
/*
* 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
* file system. Preemptively return STATUS_NETWORK_ACCESS_DENIED.
*/
for (P = VolumeName, Backslashes = 0; *P; P++)
if (L'\\' == *P)
if (3 == ++Backslashes)
{
Result = STATUS_NETWORK_ACCESS_DENIED;
goto exit;
}
if (!CreateDirectoryW(MountPoint, 0))
{
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);
BackslashLength *= sizeof(WCHAR);
ReparseDataLength = (USHORT)(
FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) -
FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer)) +
2 * (VolumeNameLength + BackslashLength + sizeof(WCHAR));
ReparseData = MemAlloc(REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataLength);
if (0 == ReparseData)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto rmdir_and_exit;
}
ReparseData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
ReparseData->ReparseDataLength = ReparseDataLength;
ReparseData->Reserved = 0;
ReparseData->MountPointReparseBuffer.SubstituteNameOffset = 0;
ReparseData->MountPointReparseBuffer.SubstituteNameLength =
VolumeNameLength + BackslashLength;
ReparseData->MountPointReparseBuffer.PrintNameOffset =
ReparseData->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR);
ReparseData->MountPointReparseBuffer.PrintNameLength =
VolumeNameLength + BackslashLength;
PathBuffer = ReparseData->MountPointReparseBuffer.PathBuffer;
memcpy(PathBuffer, VolumeName, VolumeNameLength);
if (BackslashLength)
PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\';
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
PathBuffer = ReparseData->MountPointReparseBuffer.PathBuffer +
(ReparseData->MountPointReparseBuffer.PrintNameOffset) / sizeof(WCHAR);
memcpy(PathBuffer, VolumeName, VolumeNameLength);
if (BackslashLength)
PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\';
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
Success = DeviceIoControl(DirHandle, FSCTL_SET_REPARSE_POINT,
ReparseData, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseData->ReparseDataLength,
0, 0,
&Bytes, 0);
CloseHandle(DirHandle);
if (!Success)
{
Result = FspNtStatusFromWin32(GetLastError());
goto rmdir_and_exit;
}
Result = STATUS_SUCCESS;
exit:
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)
{
if (0 != FileSystem->MountPoint)
@ -163,9 +349,7 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
PWSTR P;
ULONG L;
for (P = MountPoint; *P; P++)
;
L = (ULONG)((P - MountPoint + 1) * sizeof(WCHAR));
L = (ULONG)((lstrlenW(MountPoint) + 1) * sizeof(WCHAR));
P = MemAlloc(L);
if (0 == P)
@ -173,46 +357,23 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
memcpy(P, MountPoint, L);
MountPoint = P;
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName))
Result = STATUS_SUCCESS;
if (FspPathIsDrive(MountPoint))
{
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName))
Result = STATUS_SUCCESS;
else
Result = FspNtStatusFromWin32(GetLastError());
}
else
Result = FspNtStatusFromWin32(GetLastError());
Result = FspFileSystemSetMountPoint_CreateDirectory(MountPoint, FileSystem->VolumeName);
}
exit:
if (NT_SUCCESS(Result) && 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;
}
}
/* this path always considered successful regardless if we made symlink temporary */
Result = STATUS_SUCCESS;
}
if (NT_SUCCESS(Result))
{
FspFileSystemSetMountPoint_MakeTemporary(MountPoint, &MountHandle);
/* ignore result; this path always considered successful */
FileSystem->MountPoint = MountPoint;
FileSystem->MountHandle = MountHandle;
}
@ -224,17 +385,29 @@ exit:
FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
{
BOOLEAN IsDrive;
if (0 == FileSystem->MountPoint)
return;
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
FileSystem->MountPoint, FileSystem->VolumeName);
IsDrive = FspPathIsDrive(FileSystem->MountPoint);
if (IsDrive)
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
FileSystem->MountPoint, FileSystem->VolumeName);
else
/* nothing to do! directory will be deleted when the MountHandle is closed */;
MemFree(FileSystem->MountPoint);
FileSystem->MountPoint = 0;
if (0 != FileSystem->MountHandle)
{
FspNtClose(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;
}
}
@ -246,6 +419,7 @@ static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
SIZE_T RequestSize, ResponseSize;
FSP_FSCTL_TRANSACT_REQ *Request = 0;
FSP_FSCTL_TRANSACT_RSP *Response = 0;
FSP_FILE_SYSTEM_OPERATION_CONTEXT OperationContext;
HANDLE DispatcherThread = 0;
Request = MemAlloc(FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN);
@ -267,6 +441,10 @@ static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
}
}
OperationContext.Request = Request;
OperationContext.Response = Response;
TlsSetValue(FspFileSystemTlsKey, &OperationContext);
memset(Response, 0, sizeof *Response);
for (;;)
{
@ -330,6 +508,7 @@ static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
}
exit:
TlsSetValue(FspFileSystemTlsKey, 0);
MemFree(Response);
MemFree(Request);
@ -407,3 +586,8 @@ FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
FspFsctlStop(FileSystem->VolumeHandle);
}
}
FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID)
{
return (FSP_FILE_SYSTEM_OPERATION_CONTEXT *)TlsGetValue(FspFileSystemTlsKey);
}

View File

@ -17,8 +17,28 @@
#include <dll/library.h>
#define USERCONTEXT(s) \
FSP_FSCTL_TRANSACT_USERCONTEXT(s, FileSystem->UmFileNodeIsUserContext2)
#define AddrOfFileContext(s) \
( \
(PVOID)&(((PUINT64)&(s).UserContext)[FileSystem->UmFileContextIsUserContext2])\
)
#define ValOfFileContext(s) \
( \
FileSystem->UmFileContextIsFullContext ?\
(PVOID)(&(s)) : \
(PVOID)(((PUINT64)&(s).UserContext)[FileSystem->UmFileContextIsUserContext2])\
)
#define SetFileContext(t, s) \
( \
FileSystem->UmFileContextIsFullContext ?\
(VOID)( \
(t).UserContext = (s).UserContext,\
(t).UserContext2 = (s).UserContext2\
) : \
(VOID)( \
((PUINT64)&(t).UserContext)[FileSystem->UmFileContextIsUserContext2] =\
((PUINT64)&(s).UserContext)[FileSystem->UmFileContextIsUserContext2]\
) \
)
FSP_API NTSTATUS FspFileSystemOpEnter(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
@ -28,6 +48,7 @@ FSP_API NTSTATUS FspFileSystemOpEnter(FSP_FILE_SYSTEM *FileSystem,
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
if ((FspFsctlTransactCreateKind == Request->Kind &&
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
FspFsctlTransactOverwriteKind == Request->Kind ||
(FspFsctlTransactCleanupKind == Request->Kind &&
Request->Req.Cleanup.Delete) ||
(FspFsctlTransactSetInformationKind == Request->Kind &&
@ -66,6 +87,7 @@ FSP_API NTSTATUS FspFileSystemOpLeave(FSP_FILE_SYSTEM *FileSystem,
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
if ((FspFsctlTransactCreateKind == Request->Kind &&
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
FspFsctlTransactOverwriteKind == Request->Kind ||
(FspFsctlTransactCleanupKind == Request->Kind &&
Request->Req.Cleanup.Delete) ||
(FspFsctlTransactSetInformationKind == Request->Kind &&
@ -137,7 +159,7 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
{
NTSTATUS Result;
UINT32 GrantedAccess;
UINT32 ParentDesiredAccess, GrantedAccess;
/*
* CreateCheck does different checks depending on whether we are
@ -161,9 +183,14 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
if (!Request->Req.Create.NamedStream)
{
if (Request->Req.Create.HasRestorePrivilege)
ParentDesiredAccess = 0;
else if (Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE)
ParentDesiredAccess = FILE_ADD_SUBDIRECTORY;
else
ParentDesiredAccess = FILE_ADD_FILE;
Result = FspAccessCheckEx(FileSystem, Request, TRUE, AllowTraverseCheck,
(Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) ?
FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE,
ParentDesiredAccess,
&GrantedAccess, PSecurityDescriptor);
if (STATUS_REPARSE == Result)
Result = FspFileSystemCallResolveReparsePoints(FileSystem, Request, Response, GrantedAccess);
@ -171,6 +198,7 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
{
*PGrantedAccess = (MAXIMUM_ALLOWED & Request->Req.Create.DesiredAccess) ?
FspGetFileGenericMapping()->GenericAll : Request->Req.Create.DesiredAccess;
*PGrantedAccess |= Request->Req.Create.GrantedAccess;
}
}
else
@ -190,6 +218,7 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
*PGrantedAccess &= ~(DELETE | FILE_WRITE_DATA) |
(Request->Req.Create.DesiredAccess & (DELETE | FILE_WRITE_DATA));
*PGrantedAccess |= Request->Req.Create.GrantedAccess;
}
}
@ -225,6 +254,7 @@ NTSTATUS FspFileSystemOpenCheck(FSP_FILE_SYSTEM *FileSystem,
*PGrantedAccess = GrantedAccess;
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
*PGrantedAccess &= ~DELETE | (Request->Req.Create.DesiredAccess & DELETE);
*PGrantedAccess |= Request->Req.Create.GrantedAccess;
}
return Result;
@ -263,6 +293,7 @@ NTSTATUS FspFileSystemOverwriteCheck(FSP_FILE_SYSTEM *FileSystem,
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
*PGrantedAccess &= ~(DELETE | FILE_WRITE_DATA) |
(Request->Req.Create.DesiredAccess & (DELETE | FILE_WRITE_DATA));
*PGrantedAccess |= Request->Req.Create.GrantedAccess;
}
return Result;
@ -286,7 +317,7 @@ NTSTATUS FspFileSystemOpenTargetDirectoryCheck(FSP_FILE_SYSTEM *FileSystem,
if (STATUS_REPARSE == Result)
Result = FspFileSystemCallResolveReparsePoints(FileSystem, Request, Response, GrantedAccess);
else if (NT_SUCCESS(Result))
*PGrantedAccess = GrantedAccess;
*PGrantedAccess = GrantedAccess | Request->Req.Create.GrantedAccess;
return Result;
}
@ -352,8 +383,8 @@ static NTSTATUS FspFileSystemOpCreate_FileCreate(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS Result;
UINT32 GrantedAccess;
PSECURITY_DESCRIPTOR ParentDescriptor, ObjectDescriptor;
PVOID FileNode;
FSP_FSCTL_FILE_INFO FileInfo;
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
Result = FspFileSystemCreateCheck(FileSystem, Request, Response, TRUE,
&GrantedAccess, &ParentDescriptor);
@ -365,20 +396,31 @@ static NTSTATUS FspFileSystemOpCreate_FileCreate(FSP_FILE_SYSTEM *FileSystem,
if (!NT_SUCCESS(Result))
return Result;
FileNode = 0;
memset(&FileInfo, 0, sizeof FileInfo);
Result = FileSystem->Interface->Create(FileSystem, Request,
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
FullContext.UserContext = 0;
FullContext.UserContext2 = 0;
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
Result = FileSystem->Interface->Create(FileSystem,
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
Request->Req.Create.FileAttributes, ObjectDescriptor, Request->Req.Create.AllocationSize,
&FileNode, &FileInfo);
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
FspDeleteSecurityDescriptor(ObjectDescriptor, FspCreateSecurityDescriptor);
if (!NT_SUCCESS(Result))
return Result;
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX >= OpenFileInfo.NormalizedNameSize)
{
Response->Size = (UINT16)(sizeof *Response + OpenFileInfo.NormalizedNameSize);
Response->Rsp.Create.Opened.FileName.Offset = 0;
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
}
Response->IoStatus.Information = FILE_CREATED;
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
SetFileContext(Response->Rsp.Create.Opened, FullContext);
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
memcpy(&Response->Rsp.Create.Opened.FileInfo,
&OpenFileInfo.FileInfo, sizeof OpenFileInfo.FileInfo);
return STATUS_SUCCESS;
}
@ -387,25 +429,36 @@ static NTSTATUS FspFileSystemOpCreate_FileOpen(FSP_FILE_SYSTEM *FileSystem,
{
NTSTATUS Result;
UINT32 GrantedAccess;
PVOID FileNode;
FSP_FSCTL_FILE_INFO FileInfo;
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
Result = FspFileSystemOpenCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
return Result;
FileNode = 0;
memset(&FileInfo, 0, sizeof FileInfo);
Result = FileSystem->Interface->Open(FileSystem, Request,
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
&FileNode, &FileInfo);
FullContext.UserContext = 0;
FullContext.UserContext2 = 0;
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
Result = FileSystem->Interface->Open(FileSystem,
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
if (!NT_SUCCESS(Result))
return Result;
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX >= OpenFileInfo.NormalizedNameSize)
{
Response->Size = (UINT16)(sizeof *Response + OpenFileInfo.NormalizedNameSize);
Response->Rsp.Create.Opened.FileName.Offset = 0;
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
}
Response->IoStatus.Information = FILE_OPENED;
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
SetFileContext(Response->Rsp.Create.Opened, FullContext);
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
memcpy(&Response->Rsp.Create.Opened.FileInfo,
&OpenFileInfo.FileInfo, sizeof OpenFileInfo.FileInfo);
return STATUS_SUCCESS;
}
@ -415,8 +468,8 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS Result;
UINT32 GrantedAccess;
PSECURITY_DESCRIPTOR ParentDescriptor, ObjectDescriptor;
PVOID FileNode;
FSP_FSCTL_FILE_INFO FileInfo;
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
BOOLEAN Create = FALSE;
Result = FspFileSystemOpenCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
@ -429,11 +482,14 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem,
if (!Create)
{
FileNode = 0;
memset(&FileInfo, 0, sizeof FileInfo);
Result = FileSystem->Interface->Open(FileSystem, Request,
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
&FileNode, &FileInfo);
FullContext.UserContext = 0;
FullContext.UserContext2 = 0;
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
Result = FileSystem->Interface->Open(FileSystem,
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
if (!NT_SUCCESS(Result))
{
if (STATUS_OBJECT_NAME_NOT_FOUND != Result)
@ -454,21 +510,32 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem,
if (!NT_SUCCESS(Result))
return Result;
FileNode = 0;
memset(&FileInfo, 0, sizeof FileInfo);
Result = FileSystem->Interface->Create(FileSystem, Request,
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
FullContext.UserContext = 0;
FullContext.UserContext2 = 0;
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
Result = FileSystem->Interface->Create(FileSystem,
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
Request->Req.Create.FileAttributes, ObjectDescriptor, Request->Req.Create.AllocationSize,
&FileNode, &FileInfo);
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
FspDeleteSecurityDescriptor(ObjectDescriptor, FspCreateSecurityDescriptor);
if (!NT_SUCCESS(Result))
return Result;
}
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX >= OpenFileInfo.NormalizedNameSize)
{
Response->Size = (UINT16)(sizeof *Response + OpenFileInfo.NormalizedNameSize);
Response->Rsp.Create.Opened.FileName.Offset = 0;
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
}
Response->IoStatus.Information = Create ? FILE_CREATED : FILE_OPENED;
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
SetFileContext(Response->Rsp.Create.Opened, FullContext);
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
memcpy(&Response->Rsp.Create.Opened.FileInfo,
&OpenFileInfo.FileInfo, sizeof OpenFileInfo.FileInfo);
return STATUS_SUCCESS;
}
@ -477,26 +544,37 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwrite(FSP_FILE_SYSTEM *FileSystem,
{
NTSTATUS Result;
UINT32 GrantedAccess;
PVOID FileNode;
FSP_FSCTL_FILE_INFO FileInfo;
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)
return Result;
FileNode = 0;
memset(&FileInfo, 0, sizeof FileInfo);
Result = FileSystem->Interface->Open(FileSystem, Request,
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
&FileNode, &FileInfo);
FullContext.UserContext = 0;
FullContext.UserContext2 = 0;
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
Result = FileSystem->Interface->Open(FileSystem,
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
if (!NT_SUCCESS(Result))
return Result;
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX >= OpenFileInfo.NormalizedNameSize)
{
Response->Size = (UINT16)(sizeof *Response + OpenFileInfo.NormalizedNameSize);
Response->Rsp.Create.Opened.FileName.Offset = 0;
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
}
Response->IoStatus.Information = Supersede ? FILE_SUPERSEDED : FILE_OVERWRITTEN;
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
SetFileContext(Response->Rsp.Create.Opened, FullContext);
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
memcpy(&Response->Rsp.Create.Opened.FileInfo,
&OpenFileInfo.FileInfo, sizeof OpenFileInfo.FileInfo);
return STATUS_SUCCESS;
}
@ -506,8 +584,8 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
NTSTATUS Result;
UINT32 GrantedAccess;
PSECURITY_DESCRIPTOR ParentDescriptor, ObjectDescriptor;
PVOID FileNode;
FSP_FSCTL_FILE_INFO FileInfo;
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
BOOLEAN Create = FALSE;
Result = FspFileSystemOverwriteCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
@ -520,11 +598,14 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
if (!Create)
{
FileNode = 0;
memset(&FileInfo, 0, sizeof FileInfo);
Result = FileSystem->Interface->Open(FileSystem, Request,
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
&FileNode, &FileInfo);
FullContext.UserContext = 0;
FullContext.UserContext2 = 0;
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
Result = FileSystem->Interface->Open(FileSystem,
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
if (!NT_SUCCESS(Result))
{
if (STATUS_OBJECT_NAME_NOT_FOUND != Result)
@ -545,21 +626,32 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
if (!NT_SUCCESS(Result))
return Result;
FileNode = 0;
memset(&FileInfo, 0, sizeof FileInfo);
Result = FileSystem->Interface->Create(FileSystem, Request,
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
FullContext.UserContext = 0;
FullContext.UserContext2 = 0;
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
Result = FileSystem->Interface->Create(FileSystem,
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
Request->Req.Create.FileAttributes, ObjectDescriptor, Request->Req.Create.AllocationSize,
&FileNode, &FileInfo);
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
FspDeleteSecurityDescriptor(ObjectDescriptor, FspCreateSecurityDescriptor);
if (!NT_SUCCESS(Result))
return Result;
}
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX >= OpenFileInfo.NormalizedNameSize)
{
Response->Size = (UINT16)(sizeof *Response + OpenFileInfo.NormalizedNameSize);
Response->Rsp.Create.Opened.FileName.Offset = 0;
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
}
Response->IoStatus.Information = Create ? FILE_CREATED : FILE_OVERWRITTEN;
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
SetFileContext(Response->Rsp.Create.Opened, FullContext);
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
memcpy(&Response->Rsp.Create.Opened.FileInfo,
&OpenFileInfo.FileInfo, sizeof OpenFileInfo.FileInfo);
return STATUS_SUCCESS;
}
@ -570,20 +662,23 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenTargetDirectory(FSP_FILE_SYSTEM *F
WCHAR Root[2] = L"\\";
PWSTR Parent, Suffix;
UINT32 GrantedAccess;
PVOID FileNode;
FSP_FSCTL_FILE_INFO FileInfo;
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
UINT32 Information;
Result = FspFileSystemOpenTargetDirectoryCheck(FileSystem, Request, Response, &GrantedAccess);
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
return Result;
FileNode = 0;
memset(&FileInfo, 0, sizeof FileInfo);
FullContext.UserContext = 0;
FullContext.UserContext2 = 0;
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
FspPathSuffix((PWSTR)Request->Buffer, &Parent, &Suffix, Root);
Result = FileSystem->Interface->Open(FileSystem, Request,
Parent, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
&FileNode, &FileInfo);
Result = FileSystem->Interface->Open(FileSystem,
Parent, Request->Req.Create.CreateOptions, GrantedAccess,
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
FspPathCombine((PWSTR)Request->Buffer, Suffix);
if (!NT_SUCCESS(Result))
return Result;
@ -595,10 +690,18 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenTargetDirectory(FSP_FILE_SYSTEM *F
Information = NT_SUCCESS(Result) ? FILE_EXISTS : FILE_DOES_NOT_EXIST;
}
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX >= OpenFileInfo.NormalizedNameSize)
{
Response->Size = (UINT16)(sizeof *Response + OpenFileInfo.NormalizedNameSize);
Response->Rsp.Create.Opened.FileName.Offset = 0;
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
}
Response->IoStatus.Information = Information;
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
SetFileContext(Response->Rsp.Create.Opened, FullContext);
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
memcpy(&Response->Rsp.Create.Opened.FileInfo,
&OpenFileInfo.FileInfo, sizeof OpenFileInfo.FileInfo);
return STATUS_SUCCESS;
}
@ -742,16 +845,17 @@ FSP_API NTSTATUS FspFileSystemOpOverwrite(FSP_FILE_SYSTEM *FileSystem,
return STATUS_INVALID_DEVICE_REQUEST;
memset(&FileInfo, 0, sizeof FileInfo);
Result = FileSystem->Interface->Overwrite(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.Overwrite),
Result = FileSystem->Interface->Overwrite(FileSystem,
(PVOID)ValOfFileContext(Request->Req.Overwrite),
Request->Req.Overwrite.FileAttributes,
Request->Req.Overwrite.Supersede,
Request->Req.Overwrite.AllocationSize,
&FileInfo);
if (!NT_SUCCESS(Result))
{
if (0 != FileSystem->Interface->Close)
FileSystem->Interface->Close(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.Overwrite));
FileSystem->Interface->Close(FileSystem,
(PVOID)ValOfFileContext(Request->Req.Overwrite));
return Result;
}
@ -763,8 +867,8 @@ FSP_API NTSTATUS FspFileSystemOpCleanup(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{
if (0 != FileSystem->Interface->Cleanup)
FileSystem->Interface->Cleanup(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.Cleanup),
FileSystem->Interface->Cleanup(FileSystem,
(PVOID)ValOfFileContext(Request->Req.Cleanup),
0 != Request->FileName.Size ? (PWSTR)Request->Buffer : 0,
0 != Request->Req.Cleanup.Delete);
@ -775,8 +879,8 @@ FSP_API NTSTATUS FspFileSystemOpClose(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{
if (0 != FileSystem->Interface->Close)
FileSystem->Interface->Close(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.Close));
FileSystem->Interface->Close(FileSystem,
(PVOID)ValOfFileContext(Request->Req.Close));
return STATUS_SUCCESS;
}
@ -791,8 +895,8 @@ FSP_API NTSTATUS FspFileSystemOpRead(FSP_FILE_SYSTEM *FileSystem,
return STATUS_INVALID_DEVICE_REQUEST;
BytesTransferred = 0;
Result = FileSystem->Interface->Read(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.Read),
Result = FileSystem->Interface->Read(FileSystem,
(PVOID)ValOfFileContext(Request->Req.Read),
(PVOID)Request->Req.Read.Address,
Request->Req.Read.Offset,
Request->Req.Read.Length,
@ -817,8 +921,8 @@ FSP_API NTSTATUS FspFileSystemOpWrite(FSP_FILE_SYSTEM *FileSystem,
return STATUS_INVALID_DEVICE_REQUEST;
BytesTransferred = 0;
Result = FileSystem->Interface->Write(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.Write),
Result = FileSystem->Interface->Write(FileSystem,
(PVOID)ValOfFileContext(Request->Req.Write),
(PVOID)Request->Req.Write.Address,
Request->Req.Write.Offset,
Request->Req.Write.Length,
@ -844,8 +948,8 @@ FSP_API NTSTATUS FspFileSystemOpFlushBuffers(FSP_FILE_SYSTEM *FileSystem,
if (0 == FileSystem->Interface->Flush)
return STATUS_SUCCESS; /* liar! */
return FileSystem->Interface->Flush(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.FlushBuffers));
return FileSystem->Interface->Flush(FileSystem,
(PVOID)ValOfFileContext(Request->Req.FlushBuffers));
}
FSP_API NTSTATUS FspFileSystemOpQueryInformation(FSP_FILE_SYSTEM *FileSystem,
@ -858,8 +962,8 @@ FSP_API NTSTATUS FspFileSystemOpQueryInformation(FSP_FILE_SYSTEM *FileSystem,
return STATUS_INVALID_DEVICE_REQUEST;
memset(&FileInfo, 0, sizeof FileInfo);
Result = FileSystem->Interface->GetFileInfo(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.QueryInformation), &FileInfo);
Result = FileSystem->Interface->GetFileInfo(FileSystem,
(PVOID)ValOfFileContext(Request->Req.QueryInformation), &FileInfo);
if (!NT_SUCCESS(Result))
return Result;
@ -879,8 +983,8 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
{
case 4/*FileBasicInformation*/:
if (0 != FileSystem->Interface->SetBasicInfo)
Result = FileSystem->Interface->SetBasicInfo(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.SetInformation),
Result = FileSystem->Interface->SetBasicInfo(FileSystem,
(PVOID)ValOfFileContext(Request->Req.SetInformation),
Request->Req.SetInformation.Info.Basic.FileAttributes,
Request->Req.SetInformation.Info.Basic.CreationTime,
Request->Req.SetInformation.Info.Basic.LastAccessTime,
@ -889,23 +993,23 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
break;
case 19/*FileAllocationInformation*/:
if (0 != FileSystem->Interface->SetFileSize)
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.SetInformation),
Result = FileSystem->Interface->SetFileSize(FileSystem,
(PVOID)ValOfFileContext(Request->Req.SetInformation),
Request->Req.SetInformation.Info.Allocation.AllocationSize, TRUE,
&FileInfo);
break;
case 20/*FileEndOfFileInformation*/:
if (0 != FileSystem->Interface->SetFileSize)
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.SetInformation),
Result = FileSystem->Interface->SetFileSize(FileSystem,
(PVOID)ValOfFileContext(Request->Req.SetInformation),
Request->Req.SetInformation.Info.EndOfFile.FileSize, FALSE,
&FileInfo);
break;
case 13/*FileDispositionInformation*/:
if (0 != FileSystem->Interface->GetFileInfo)
{
Result = FileSystem->Interface->GetFileInfo(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.SetInformation), &FileInfo);
Result = FileSystem->Interface->GetFileInfo(FileSystem,
(PVOID)ValOfFileContext(Request->Req.SetInformation), &FileInfo);
if (NT_SUCCESS(Result) && 0 != (FileInfo.FileAttributes & FILE_ATTRIBUTE_READONLY))
{
Result = STATUS_CANNOT_DELETE;
@ -914,8 +1018,8 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
}
if (0 != FileSystem->Interface->CanDelete)
if (Request->Req.SetInformation.Info.Disposition.Delete)
Result = FileSystem->Interface->CanDelete(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.SetInformation),
Result = FileSystem->Interface->CanDelete(FileSystem,
(PVOID)ValOfFileContext(Request->Req.SetInformation),
(PWSTR)Request->Buffer);
else
Result = STATUS_SUCCESS;
@ -931,8 +1035,8 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
STATUS_OBJECT_NAME_NOT_FOUND != Result)
break;
}
Result = FileSystem->Interface->Rename(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.SetInformation),
Result = FileSystem->Interface->Rename(FileSystem,
(PVOID)ValOfFileContext(Request->Req.SetInformation),
(PWSTR)Request->Buffer,
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
0 != Request->Req.SetInformation.Info.Rename.AccessToken);
@ -957,7 +1061,7 @@ FSP_API NTSTATUS FspFileSystemOpQueryVolumeInformation(FSP_FILE_SYSTEM *FileSyst
return STATUS_INVALID_DEVICE_REQUEST;
memset(&VolumeInfo, 0, sizeof VolumeInfo);
Result = FileSystem->Interface->GetVolumeInfo(FileSystem, Request, &VolumeInfo);
Result = FileSystem->Interface->GetVolumeInfo(FileSystem, &VolumeInfo);
if (!NT_SUCCESS(Result))
return Result;
@ -977,7 +1081,7 @@ FSP_API NTSTATUS FspFileSystemOpSetVolumeInformation(FSP_FILE_SYSTEM *FileSystem
{
case 2/*FileFsLabelInformation*/:
if (0 != FileSystem->Interface->SetVolumeLabel)
Result = FileSystem->Interface->SetVolumeLabel(FileSystem, Request,
Result = FileSystem->Interface->SetVolumeLabel(FileSystem,
(PWSTR)Request->Buffer,
&VolumeInfo);
break;
@ -1000,8 +1104,8 @@ FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
return STATUS_INVALID_DEVICE_REQUEST;
BytesTransferred = 0;
Result = FileSystem->Interface->ReadDirectory(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.QueryDirectory),
Result = FileSystem->Interface->ReadDirectory(FileSystem,
(PVOID)ValOfFileContext(Request->Req.QueryDirectory),
(PVOID)Request->Req.QueryDirectory.Address,
Request->Req.QueryDirectory.Offset,
Request->Req.QueryDirectory.Length,
@ -1034,8 +1138,8 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
memset(ReparseData, 0, sizeof *ReparseData);
Size = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
Result = FileSystem->Interface->GetReparsePoint(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.FileSystemControl),
Result = FileSystem->Interface->GetReparsePoint(FileSystem,
(PVOID)ValOfFileContext(Request->Req.FileSystemControl),
(PWSTR)Request->Buffer, ReparseData, &Size);
if (NT_SUCCESS(Result))
{
@ -1051,8 +1155,8 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
ReparseData = (PREPARSE_DATA_BUFFER)
(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset);
Result = FileSystem->Interface->SetReparsePoint(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.FileSystemControl),
Result = FileSystem->Interface->SetReparsePoint(FileSystem,
(PVOID)ValOfFileContext(Request->Req.FileSystemControl),
(PWSTR)Request->Buffer,
ReparseData,
Request->Req.FileSystemControl.Buffer.Size);
@ -1064,8 +1168,8 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
ReparseData = (PREPARSE_DATA_BUFFER)
(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset);
Result = FileSystem->Interface->DeleteReparsePoint(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.FileSystemControl),
Result = FileSystem->Interface->DeleteReparsePoint(FileSystem,
(PVOID)ValOfFileContext(Request->Req.FileSystemControl),
(PWSTR)Request->Buffer,
ReparseData,
Request->Req.FileSystemControl.Buffer.Size);
@ -1086,8 +1190,8 @@ FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
return STATUS_INVALID_DEVICE_REQUEST;
SecurityDescriptorSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
Result = FileSystem->Interface->GetSecurity(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.QuerySecurity),
Result = FileSystem->Interface->GetSecurity(FileSystem,
(PVOID)ValOfFileContext(Request->Req.QuerySecurity),
Response->Buffer, &SecurityDescriptorSize);
if (!NT_SUCCESS(Result))
return STATUS_BUFFER_OVERFLOW != Result ? Result : STATUS_INVALID_SECURITY_DESCR;
@ -1104,8 +1208,8 @@ FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem,
if (0 == FileSystem->Interface->SetSecurity)
return STATUS_INVALID_DEVICE_REQUEST;
return FileSystem->Interface->SetSecurity(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.SetSecurity),
return FileSystem->Interface->SetSecurity(FileSystem,
(PVOID)ValOfFileContext(Request->Req.SetSecurity),
Request->Req.SetSecurity.SecurityInformation,
(PSECURITY_DESCRIPTOR)Request->Buffer);
}
@ -1120,8 +1224,8 @@ FSP_API NTSTATUS FspFileSystemOpQueryStreamInformation(FSP_FILE_SYSTEM *FileSyst
return STATUS_INVALID_DEVICE_REQUEST;
BytesTransferred = 0;
Result = FileSystem->Interface->GetStreamInfo(FileSystem, Request,
(PVOID)USERCONTEXT(Request->Req.QueryStreamInformation),
Result = FileSystem->Interface->GetStreamInfo(FileSystem,
(PVOID)ValOfFileContext(Request->Req.QueryStreamInformation),
Response->Buffer,
FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX,
&BytesTransferred);

View File

@ -524,7 +524,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
opt_data.VolumeParams.NamedStreams = FALSE;
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
opt_data.VolumeParams.PostCleanupOnDeleteOnly = TRUE;
opt_data.VolumeParams.UmFileNodeIsUserContext2 = TRUE;
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));

View File

@ -26,6 +26,7 @@ VOID fsp_fuse_op_enter_lock(FSP_FILE_SYSTEM *FileSystem,
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
if ((FspFsctlTransactCreateKind == Request->Kind &&
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
FspFsctlTransactOverwriteKind == Request->Kind ||
(FspFsctlTransactCleanupKind == Request->Kind &&
Request->Req.Cleanup.Delete) ||
(FspFsctlTransactSetInformationKind == Request->Kind &&
@ -69,6 +70,7 @@ VOID fsp_fuse_op_leave_unlock(FSP_FILE_SYSTEM *FileSystem,
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
if ((FspFsctlTransactCreateKind == Request->Kind &&
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
FspFsctlTransactOverwriteKind == Request->Kind ||
(FspFsctlTransactCleanupKind == Request->Kind &&
Request->Req.Cleanup.Delete) ||
(FspFsctlTransactSetInformationKind == Request->Kind &&
@ -143,8 +145,6 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
FileName = (PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset);
Token = (HANDLE)Request->Req.SetInformation.Info.Rename.AccessToken;
}
else if (FspFsctlTransactSetSecurityKind == Request->Kind)
Token = (HANDLE)Request->Req.SetSecurity.AccessToken;
if (0 != FileName)
{
@ -691,7 +691,6 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointByName(
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize);
static NTSTATUS fsp_fuse_intf_GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
{
struct fuse *f = FileSystem->UserContext;
@ -715,7 +714,6 @@ static NTSTATUS fsp_fuse_intf_GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
}
static NTSTATUS fsp_fuse_intf_SetVolumeLabel(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PWSTR VolumeLabel,
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
{
@ -758,8 +756,7 @@ exit:
}
static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PWSTR FileName, BOOLEAN CaseSensitive, UINT32 CreateOptions,
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo)
{
@ -914,8 +911,7 @@ exit:
}
static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PWSTR FileName, BOOLEAN CaseSensitive, UINT32 CreateOptions,
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;
@ -941,7 +937,7 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
}
memset(&fi, 0, sizeof fi);
switch (Request->Req.Create.DesiredAccess & (FILE_READ_DATA | FILE_WRITE_DATA))
switch (GrantedAccess & (FILE_READ_DATA | FILE_WRITE_DATA))
{
default:
case FILE_READ_DATA:
@ -1017,8 +1013,7 @@ exit:
}
static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes,
PVOID FileNode, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes, UINT64 AllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo)
{
struct fuse *f = FileSystem->UserContext;
@ -1055,7 +1050,6 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
}
static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PWSTR FileName, BOOLEAN Delete)
{
struct fuse *f = FileSystem->UserContext;
@ -1092,7 +1086,6 @@ static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem,
}
static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode)
{
struct fuse *f = FileSystem->UserContext;
@ -1126,7 +1119,6 @@ static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem,
}
static NTSTATUS fsp_fuse_intf_Read(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
PULONG PBytesTransferred)
{
@ -1161,7 +1153,6 @@ static NTSTATUS fsp_fuse_intf_Read(FSP_FILE_SYSTEM *FileSystem,
}
static NTSTATUS fsp_fuse_intf_Write(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
BOOLEAN WriteToEndOfFile, BOOLEAN ConstrainedIo,
PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo)
@ -1224,7 +1215,6 @@ success:
}
static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode)
{
struct fuse *f = FileSystem->UserContext;
@ -1264,7 +1254,6 @@ static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
}
static NTSTATUS fsp_fuse_intf_GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
FSP_FSCTL_FILE_INFO *FileInfo)
{
@ -1282,7 +1271,6 @@ static NTSTATUS fsp_fuse_intf_GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
}
static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, UINT32 FileAttributes,
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
FSP_FSCTL_FILE_INFO *FileInfo)
@ -1361,7 +1349,6 @@ static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
}
static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, UINT64 NewSize, BOOLEAN SetAllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo)
{
@ -1445,7 +1432,6 @@ static int fsp_fuse_intf_CanDeleteAddDirInfoOld(fuse_dirh_t dh, const char *name
}
static NTSTATUS fsp_fuse_intf_CanDelete(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PWSTR FileName)
{
struct fuse *f = FileSystem->UserContext;
@ -1479,7 +1465,6 @@ static NTSTATUS fsp_fuse_intf_CanDelete(FSP_FILE_SYSTEM *FileSystem,
}
static NTSTATUS fsp_fuse_intf_Rename(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
PWSTR FileName, PWSTR NewFileName, BOOLEAN ReplaceIfExists)
{
@ -1513,7 +1498,6 @@ static NTSTATUS fsp_fuse_intf_Rename(FSP_FILE_SYSTEM *FileSystem,
}
static NTSTATUS fsp_fuse_intf_GetSecurity(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
PSECURITY_DESCRIPTOR SecurityDescriptorBuf, SIZE_T *PSecurityDescriptorSize)
{
@ -1531,9 +1515,8 @@ static NTSTATUS fsp_fuse_intf_GetSecurity(FSP_FILE_SYSTEM *FileSystem,
}
static NTSTATUS fsp_fuse_intf_SetSecurity(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR Ignored)
SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileNode;
@ -1560,7 +1543,10 @@ static NTSTATUS fsp_fuse_intf_SetSecurity(FSP_FILE_SYSTEM *FileSystem,
if (!NT_SUCCESS(Result))
goto exit;
Result = FspSetSecurityDescriptor(FileSystem, Request, SecurityDescriptor,
Result = FspSetSecurityDescriptor(
SecurityDescriptor,
SecurityInformation,
ModificationDescriptor,
&NewSecurityDescriptor);
if (!NT_SUCCESS(Result))
goto exit;
@ -1663,7 +1649,6 @@ int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name,
}
static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
PWSTR Pattern,
PULONG PBytesTransferred)
@ -1748,6 +1733,15 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
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)
@ -1871,7 +1865,6 @@ exit:
}
static NTSTATUS fsp_fuse_intf_GetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
PWSTR FileName, PVOID Buffer, PSIZE_T PSize)
{
@ -1886,7 +1879,6 @@ static NTSTATUS fsp_fuse_intf_GetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
}
static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
PWSTR FileName, PVOID Buffer, SIZE_T Size)
{
@ -1971,6 +1963,8 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
if (0 == (ReparseData->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) &&
ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0])
{
FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request;
/* we do not support absolute paths that point outside this file system */
if (0 == Request->Req.FileSystemControl.TargetOnFileSystem)
return STATUS_ACCESS_DENIED;
@ -2081,7 +2075,6 @@ exit:
}
static NTSTATUS fsp_fuse_intf_DeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode,
PWSTR FileName, PVOID Buffer, SIZE_T Size)
{

View File

@ -107,7 +107,7 @@ static void fsp_fuse_opt_match_templ(
if ('%' == *p || '\0' == *p)
*pspec = p, *parg = q;
else
*parg = 0 == lstrcmpA(q, p) ?
*parg = 0 == invariant_strcmp(q, p) ?
fsp_fuse_opt_match_exact : fsp_fuse_opt_match_none;
}
else

View File

@ -66,4 +66,14 @@ static inline ULONG FspPathSuffixIndex(PWSTR FileName)
return Result;
}
static inline BOOLEAN FspPathIsDrive(PWSTR FileName)
{
return
(
(L'A' <= FileName[0] && FileName[0] <= L'Z') ||
(L'a' <= FileName[0] && FileName[0] <= L'z')
) &&
L':' == FileName[1] || L'\0' == FileName[2];
}
#endif

View File

@ -100,12 +100,7 @@ DWORD APIENTRY NPGetCaps(DWORD Index)
static inline BOOLEAN FspNpCheckLocalName(PWSTR LocalName)
{
return 0 != LocalName &&
(
(L'A' <= LocalName[0] && LocalName[0] <= L'Z') ||
(L'a' <= LocalName[0] && LocalName[0] <= L'z')
) &&
L':' == LocalName[1] || L'\0' == LocalName[2];
return 0 != LocalName && FspPathIsDrive(LocalName);
}
static inline BOOLEAN FspNpCheckRemoteName(PWSTR RemoteName)
@ -257,7 +252,7 @@ static WCHAR FspNpGetDriveLetter(PDWORD PLogicalDrives, PWSTR VolumeName)
LocalNameBuf[0] = Drive;
if (QueryDosDeviceW(LocalNameBuf, VolumeNameBuf, sizeof VolumeNameBuf / sizeof(WCHAR)))
{
if (0 == lstrcmpW(VolumeNameBuf, VolumeName))
if (0 == invariant_wcscmp(VolumeNameBuf, VolumeName))
{
*PLogicalDrives &= ~(1 << (Drive - 'A'));
return Drive;
@ -437,7 +432,7 @@ DWORD APIENTRY NPGetConnection(
{
if (L'\0' == *P)
{
if (0 == lstrcmpW(VolumeNameBuf, VolumeName))
if (0 == invariant_wcscmp(VolumeNameBuf, VolumeName))
{
/*
* Looks like this is a WinFsp device. Extract the VolumePrefix from the VolumeName.
@ -609,7 +604,7 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
RemoteNameSize = sizeof RemoteNameBuf / sizeof(WCHAR);
NpResult = NPGetConnection(LocalNameBuf, RemoteNameBuf, &RemoteNameSize);
if (WN_SUCCESS == NpResult)
NpResult = 0 == lstrcmpW(ExpectRemoteNameBuf, RemoteNameBuf) ? WN_SUCCESS : WN_NO_NETWORK;
NpResult = 0 == invariant_wcscmp(ExpectRemoteNameBuf, RemoteNameBuf) ? WN_SUCCESS : WN_NO_NETWORK;
else
NpResult = WN_NO_NETWORK;
}
@ -1041,9 +1036,7 @@ NTSTATUS FspNpRegister(VOID)
{
if (L',' == *P || '\0' == *P)
{
if (CSTR_EQUAL == CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE,
Part, (int)(P - Part),
L"" FSP_NP_NAME, (int)(sizeof L"" FSP_NP_NAME - sizeof(WCHAR)) / sizeof(WCHAR)))
if (0 == invariant_wcsncmp(Part, L"" FSP_NP_NAME, P - Part))
{
FoundProvider = TRUE;
break;
@ -1104,9 +1097,7 @@ NTSTATUS FspNpUnregister(VOID)
{
if (L',' == *P || '\0' == *P)
{
if (CSTR_EQUAL == CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE,
Part, (int)(P - Part),
L"" FSP_NP_NAME, (int)(sizeof L"" FSP_NP_NAME - sizeof(WCHAR)) / sizeof(WCHAR)))
if (0 == invariant_wcsncmp(Part, L"" FSP_NP_NAME, P - Part))
{
FoundProvider = TRUE;
break;

View File

@ -116,28 +116,43 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
}
if (Request->Req.Create.UserMode &&
AllowTraverseCheck && !Request->Req.Create.HasTraversePrivilege)
AllowTraverseCheck && !Request->Req.Create.HasTraversePrivilege &&
!(L'\\' == FileName[0] && L'\0' == FileName[1])/* no need to traverse check for root */)
{
Remain = (PWSTR)FileName;
Remain = FileName;
for (;;)
{
FspPathPrefix(Remain, &Prefix, &Remain, TraverseCheckRoot);
if (L'\0' == Remain[0])
while (L'\\' != *Remain)
{
FspPathCombine(FileName, Remain);
break;
if (L'\0' == *Remain || L':' == *Remain)
goto traverse_check_done;
Remain++;
}
*Remain = L'\0';
Prefix = Remain > FileName ? FileName : TraverseCheckRoot;
FileAttributes = 0;
Result = FspGetSecurityByName(FileSystem, Prefix, &FileAttributes,
&SecurityDescriptor, &SecurityDescriptorSize);
/* compute the ReparsePointIndex and place it in FileAttributes now */
/*
* We check to see if this is a reparse point and then compute the ReparsePointIndex
* and place it in FileAttributes. We do this check BEFORE the directory check,
* because contrary to NTFS we want to allow non-directory symlinks to directories.
*/
if (NT_SUCCESS(Result) && STATUS_REPARSE != Result &&
(FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
{
FileAttributes = FspPathSuffixIndex(Prefix);
Result = STATUS_REPARSE;
}
FspPathCombine(FileName, Remain);
*Remain = L'\\';
do
{
Remain++;
} while (L'\\' == *Remain);
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
{
@ -146,27 +161,6 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
goto exit;
}
/*
* We check to see if this is a reparse point and then immediately return
* STATUS_REPARSE. We do this check BEFORE the directory check, because
* contrary to NTFS we want to allow non-directory symlinks to directories.
*
* Note that this effectively turns off traverse checking a path comprised of
* reparse points even when the originating process does not have the Traverse
* privilege. [I am not sure what NTFS does in this case, but POSIX symlinks
* behave similarly.] We will still traverse check the reparsed path when
* the FSD sends it back to us though!
*
* Now if the reparse points are not symlinks (or symlink-like) things
* get even more complicated. Argh! Windows!
*/
if (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
{
/* ReparsePointIndex already computed after FspGetSecurityByName call above */
Result = STATUS_REPARSE;
goto exit;
}
/*
* Check if this is a directory, otherwise the path is invalid.
*/
@ -187,6 +181,8 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
goto exit;
}
}
traverse_check_done:
;
}
FileAttributes = 0;
@ -197,7 +193,9 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
if (Request->Req.Create.UserMode && 0 < SecurityDescriptorSize)
{
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess,
if (0 == DesiredAccess)
Result = STATUS_SUCCESS;
else if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess,
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
else
@ -400,16 +398,14 @@ FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
return STATUS_SUCCESS;
}
FSP_API NTSTATUS FspSetSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
FSP_API NTSTATUS FspSetSecurityDescriptor(
PSECURITY_DESCRIPTOR InputDescriptor,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR ModificationDescriptor,
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
{
*PSecurityDescriptor = 0;
if (FspFsctlTransactSetSecurityKind != Request->Kind)
return STATUS_INVALID_PARAMETER;
if (0 == InputDescriptor)
return STATUS_NO_SECURITY_ON_OBJECT;
@ -443,11 +439,11 @@ FSP_API NTSTATUS FspSetSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
InputDescriptor = CopiedDescriptor;
if (!SetPrivateObjectSecurity(
Request->Req.SetSecurity.SecurityInformation,
(PVOID)Request->Buffer,
SecurityInformation,
ModificationDescriptor,
&InputDescriptor,
&FspFileGenericMapping,
(HANDLE)Request->Req.SetSecurity.AccessToken))
0))
{
HeapFree(ProcessHeap, 0, CopiedDescriptor);
return FspNtStatusFromWin32(GetLastError());

View File

@ -27,7 +27,7 @@ BEGIN
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "winfsp.dll"
VALUE "ProductName", STR(MyProductName)
VALUE "ProductVersion", STR(MyVersion)
VALUE "ProductVersion", STR(MyProductVersion)
END
END
BLOCK "VarFileInfo"

View File

@ -27,7 +27,7 @@ BEGIN
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "launchctl.exe"
VALUE "ProductName", STR(MyProductName)
VALUE "ProductVersion", STR(MyVersion)
VALUE "ProductVersion", STR(MyProductVersion)
END
END
BLOCK "VarFileInfo"

View File

@ -227,7 +227,7 @@ int wmain(int argc, wchar_t **argv)
if (0 == argc)
usage();
if (0 == lstrcmpW(L"start", argv[0]))
if (0 == invariant_wcscmp(L"start", argv[0]))
{
if (3 > argc || argc > 12)
usage();
@ -236,7 +236,7 @@ int wmain(int argc, wchar_t **argv)
FALSE);
}
else
if (0 == lstrcmpW(L"startWithSecret", argv[0]))
if (0 == invariant_wcscmp(L"startWithSecret", argv[0]))
{
if (4 > argc || argc > 13)
usage();
@ -245,7 +245,7 @@ int wmain(int argc, wchar_t **argv)
TRUE);
}
else
if (0 == lstrcmpW(L"stop", argv[0]))
if (0 == invariant_wcscmp(L"stop", argv[0]))
{
if (3 != argc)
usage();
@ -253,7 +253,7 @@ int wmain(int argc, wchar_t **argv)
return stop(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2]);
}
else
if (0 == lstrcmpW(L"info", argv[0]))
if (0 == invariant_wcscmp(L"info", argv[0]))
{
if (3 != argc)
usage();
@ -261,7 +261,7 @@ int wmain(int argc, wchar_t **argv)
return getinfo(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2]);
}
else
if (0 == lstrcmpW(L"list", argv[0]))
if (0 == invariant_wcscmp(L"list", argv[0]))
{
if (1 != argc)
usage();
@ -269,7 +269,7 @@ int wmain(int argc, wchar_t **argv)
return list(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE);
}
else
if (0 == lstrcmpW(L"quit", argv[0]))
if (0 == invariant_wcscmp(L"quit", argv[0]))
{
if (1 != argc)
usage();

View File

@ -27,7 +27,7 @@ BEGIN
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "launcher.exe"
VALUE "ProductName", STR(MyProductName)
VALUE "ProductVersion", STR(MyVersion)
VALUE "ProductVersion", STR(MyProductVersion)
END
END
BLOCK "VarFileInfo"

View File

@ -157,8 +157,8 @@ static SVC_INSTANCE *SvcInstanceLookup(PWSTR ClassName, PWSTR InstanceName)
{
SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry);
if (0 == lstrcmpiW(ClassName, SvcInstance->ClassName) &&
0 == lstrcmpiW(InstanceName, SvcInstance->InstanceName))
if (0 == invariant_wcsicmp(ClassName, SvcInstance->ClassName) &&
0 == invariant_wcsicmp(InstanceName, SvcInstance->InstanceName))
return SvcInstance;
}

View File

@ -87,6 +87,41 @@ void *memmove(void *dst, const void *src, size_t siz)
return dst;
}
#define WINFSP_SHARED_MINIMAL_STRCMP(NAME, TYPE, CONV)\
static inline\
int NAME(const TYPE *s, const TYPE *t)\
{\
int v = 0;\
while (0 == (v = CONV(*s) - CONV(*t)) && *t)\
++s, ++t;\
return v;/*(0 < v) - (0 > v);*/\
}
#define WINFSP_SHARED_MINIMAL_STRNCMP(NAME, TYPE, CONV)\
static inline\
int NAME(const TYPE *s, const TYPE *t, size_t n)\
{\
int v = 0;\
const void *e = t + n;\
while (e > (const void *)t && 0 == (v = CONV(*s) - CONV(*t)) && *t)\
++s, ++t;\
return v;/*(0 < v) - (0 > v);*/\
}
static inline
unsigned invariant_toupper(unsigned c)
{
return ('a' <= c && c <= 'z') ? c & ~0x20 : c;
}
WINFSP_SHARED_MINIMAL_STRCMP(invariant_strcmp, char, (unsigned))
WINFSP_SHARED_MINIMAL_STRCMP(invariant_stricmp, char, invariant_toupper)
WINFSP_SHARED_MINIMAL_STRNCMP(invariant_strncmp, char, (unsigned))
WINFSP_SHARED_MINIMAL_STRNCMP(invariant_strnicmp, char, invariant_toupper)
WINFSP_SHARED_MINIMAL_STRCMP(invariant_wcscmp, wchar_t, (unsigned))
WINFSP_SHARED_MINIMAL_STRCMP(invariant_wcsicmp, wchar_t, invariant_toupper)
WINFSP_SHARED_MINIMAL_STRNCMP(invariant_wcsncmp, wchar_t, (unsigned))
WINFSP_SHARED_MINIMAL_STRNCMP(invariant_wcsnicmp, wchar_t, invariant_toupper)
#undef WINFSP_SHARED_MINIMAL_STRCMP
#undef WINFSP_SHARED_MINIMAL_STRNCMP
static inline void *MemAlloc(size_t Size)
{
return HeapAlloc(GetProcessHeap(), 0, Size);

View File

@ -175,6 +175,9 @@ static VOID FspFsvolCleanupRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Co
FspFileNodeReleaseOwner(FileNode, Pgio, Request);
FspFileNodeCleanupComplete(FileNode, FileObject);
if (!FileNode->IsDirectory)
FspFileNodeOplockCheck(FileNode, Irp);
SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
MainFileHandle = FileDesc->MainFileHandle;
FileDesc->MainFileHandle = 0;

View File

@ -74,7 +74,7 @@ static NTSTATUS FspFsvolClose(
Request->Req.Close.UserContext = FileNode->UserContext;
Request->Req.Close.UserContext2 = FileDesc->UserContext2;
FspFileNodeClose(FileNode, FileObject);
FspFileNodeClose(FileNode, 0, FALSE);
/* delete the FileDesc and deref the FileNode; order is important (FileDesc has FileNode ref) */
FspFileDescDelete(FileDesc); /* this will also close the MainFileObject if any */

View File

@ -35,6 +35,15 @@ static VOID FspFsvolCreatePostClose(FSP_FILE_DESC *FileDesc);
static FSP_IOP_REQUEST_FINI FspFsvolCreateRequestFini;
static FSP_IOP_REQUEST_FINI FspFsvolCreateTryOpenRequestFini;
static FSP_IOP_REQUEST_FINI FspFsvolCreateOverwriteRequestFini;
static NTSTATUS FspFsvolCreateSharingViolationOplock(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN CanWait);
static BOOLEAN FspFsvolCreateOpenOrOverwriteOplock(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
PNTSTATUS PResult);
static VOID FspFsvolCreateOpenOrOverwriteOplockPrepare(
PVOID Context, PIRP Irp);
static VOID FspFsvolCreateOpenOrOverwriteOplockComplete(
PVOID Context, PIRP Irp);
FSP_DRIVER_DISPATCH FspCreate;
#ifdef ALLOC_PRAGMA
@ -49,6 +58,10 @@ FSP_DRIVER_DISPATCH FspCreate;
#pragma alloc_text(PAGE, FspFsvolCreateRequestFini)
#pragma alloc_text(PAGE, FspFsvolCreateTryOpenRequestFini)
#pragma alloc_text(PAGE, FspFsvolCreateOverwriteRequestFini)
#pragma alloc_text(PAGE, FspFsvolCreateSharingViolationOplock)
#pragma alloc_text(PAGE, FspFsvolCreateOpenOrOverwriteOplock)
#pragma alloc_text(PAGE, FspFsvolCreateOpenOrOverwriteOplockPrepare)
#pragma alloc_text(PAGE, FspFsvolCreateOpenOrOverwriteOplockComplete)
#pragma alloc_text(PAGE, FspCreate)
#endif
@ -163,23 +176,27 @@ static NTSTATUS FspFsvolCreateNoLock(
ULONG SecurityDescriptorSize = 0;
UINT64 AllocationSize = Irp->Overlay.AllocationSize.QuadPart;
UINT64 AllocationUnit;
ACCESS_MASK DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
ACCESS_MASK DesiredAccess = AccessState->RemainingDesiredAccess;
ACCESS_MASK GrantedAccess = AccessState->PreviouslyGrantedAccess;
USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess;
PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer;
//ULONG EaLength = IrpSp->Parameters.Create.EaLength;
ULONG Flags = IrpSp->Flags;
KPROCESSOR_MODE RequestorMode =
FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode;
BOOLEAN CaseSensitiveRequested =
BooleanFlagOn(Flags, SL_CASE_SENSITIVE);
BOOLEAN CaseSensitive =
CaseSensitiveRequested || FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch;
//BooleanFlagOn(Flags, SL_CASE_SENSITIVE) ||
!!FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch;
BOOLEAN HasTraversePrivilege =
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE);
BOOLEAN HasBackupPrivilege =
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_BACKUP_PRIVILEGE);
BOOLEAN HasRestorePrivilege =
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE);
FSP_FILE_NODE *FileNode, *RelatedFileNode;
FSP_FILE_DESC *FileDesc;
UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 };
ULONG StreamType = FspUnicodePathStreamTypeNone;
ULONG StreamType = FspFileNameStreamTypeNone;
FSP_FSCTL_TRANSACT_REQ *Request;
/* cannot open files by fileid */
@ -276,7 +293,7 @@ static NTSTATUS FspFsvolCreateNoLock(
ASSERT(NT_SUCCESS(Result));
/* check filename validity */
if (!FspUnicodePathIsValid(&FileNode->FileName,
if (!FspFileNameIsValid(&FileNode->FileName,
FsvolDeviceExtension->VolumeParams.NamedStreams ? &StreamPart : 0,
&StreamType))
{
@ -297,7 +314,10 @@ static NTSTATUS FspFsvolCreateNoLock(
(0 == StreamPart.Length) * sizeof(WCHAR));
}
/* check and remove any volume prefix */
/*
* Check and remove any volume prefix. Only do this when RelatedFileObject is NULL,
* because the volume prefix has been removed already from the RelatedFileNode.
*/
if (0 == RelatedFileObject && 0 < FsvolDeviceExtension->VolumePrefix.Length)
{
if (!FspFsvolDeviceVolumePrefixInString(FsvolDeviceObject, &FileNode->FileName) ||
@ -334,7 +354,7 @@ static NTSTATUS FspFsvolCreateNoLock(
}
/* if a $DATA stream type, this cannot be a directory */
if (FspUnicodePathStreamTypeData == StreamType)
if (FspFileNameStreamTypeData == StreamType)
{
if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
{
@ -453,6 +473,7 @@ static NTSTATUS FspFsvolCreateNoLock(
FileDesc->FileNode = FileNode;
FileDesc->CaseSensitive = CaseSensitive;
FileDesc->HasTraversePrivilege = HasTraversePrivilege;
if (!MainFileOpen)
{
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
@ -470,13 +491,16 @@ static NTSTATUS FspFsvolCreateNoLock(
Request->Req.Create.AllocationSize = AllocationSize;
Request->Req.Create.AccessToken = 0;
Request->Req.Create.DesiredAccess = DesiredAccess;
Request->Req.Create.GrantedAccess = GrantedAccess;
Request->Req.Create.ShareAccess = ShareAccess;
Request->Req.Create.Ea.Offset = 0;
Request->Req.Create.Ea.Size = 0;
Request->Req.Create.UserMode = UserMode == RequestorMode;
Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege;
Request->Req.Create.HasBackupPrivilege = HasBackupPrivilege;
Request->Req.Create.HasRestorePrivilege = HasRestorePrivilege;
Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY);
Request->Req.Create.CaseSensitive = CaseSensitiveRequested;
Request->Req.Create.CaseSensitive = CaseSensitive;
Request->Req.Create.NamedStream = MainFileName.Length;
ASSERT(
@ -488,6 +512,18 @@ static NTSTATUS FspFsvolCreateNoLock(
RtlCopyMemory(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset,
SecurityDescriptor, SecurityDescriptorSize);
/* fix FileNode->FileName if we are doing SL_OPEN_TARGET_DIRECTORY */
if (Request->Req.Create.OpenTargetDirectory)
{
UNICODE_STRING Suffix;
FspFileNameSuffix(&FileNode->FileName, &FileNode->FileName, &Suffix);
}
/* zero Irp->IoStatus, because we now use it to maintain state in FspFsvolCreateComplete */
Irp->IoStatus.Status = 0;
Irp->IoStatus.Information = 0;
return FSP_STATUS_IOQ_POST;
}
@ -552,9 +588,20 @@ NTSTATUS FspFsvolCreatePrepare(
FileObject = FspIopRequestContext(Request, RequestFileObject);
/* lock the FileNode for overwriting */
Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusive(FileNode, Full);
Result = STATUS_SUCCESS;
Success = DEBUGTEST(90) &&
FspFileNodeTryAcquireExclusive(FileNode, Full) &&
FspFsvolCreateOpenOrOverwriteOplock(Irp, 0, &Result);
if (!Success)
{
if (STATUS_PENDING == Result)
return Result;
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
return Result;
}
FspIopRetryPrepareIrp(Irp, &Result);
return Result;
}
@ -592,11 +639,14 @@ NTSTATUS FspFsvolCreateComplete(
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
FSP_FILE_NODE *OpenedFileNode;
ULONG SharingViolationReason;
UNICODE_STRING NormalizedName;
PREPARSE_DATA_BUFFER ReparseData;
UNICODE_STRING ReparseTargetPrefix0, ReparseTargetPrefix1, ReparseTargetPath;
@ -605,7 +655,8 @@ NTSTATUS FspFsvolCreateComplete(
/* did the user-mode file system sent us a failure code? */
if (!NT_SUCCESS(Response->IoStatus.Status))
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Information = STATUS_SHARING_VIOLATION == Response->IoStatus.Status ?
Response->IoStatus.Information : 0;
Result = Response->IoStatus.Status;
FSP_RETURN();
}
@ -751,15 +802,36 @@ NTSTATUS FspFsvolCreateComplete(
}
}
/* fix FileNode->FileName if we were doing SL_OPEN_TARGET_DIRECTORY */
if (Request->Req.Create.OpenTargetDirectory)
{
UNICODE_STRING Suffix;
FspUnicodePathSuffix(&FileNode->FileName, &FileNode->FileName, &Suffix);
}
/* populate the FileNode/FileDesc fields from the Response */
if (!FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch)
{
/* is there a normalized file name as part of the response? */
if (0 == Response->Rsp.Create.Opened.FileName.Size)
{
/* if not, the default is to upper case the name */
FspFileNameUpcase(&FileNode->FileName, &FileNode->FileName, 0);
}
else
{
/* if yes, verify it and then set it */
if (Response->Buffer + Response->Rsp.Create.Opened.FileName.Size >
(PUINT8)Response + Response->Size)
FSP_RETURN(Result = STATUS_OBJECT_NAME_INVALID);
NormalizedName.Length = NormalizedName.MaximumLength =
Response->Rsp.Create.Opened.FileName.Size;
NormalizedName.Buffer = (PVOID)Response->Buffer;
/* normalized file name can only differ in case from requested one */
if (0 != FspFileNameCompare(&FileNode->FileName, &NormalizedName, TRUE, 0))
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,
@ -770,11 +842,41 @@ NTSTATUS FspFsvolCreateComplete(
FileDesc->DeleteOnClose = BooleanFlagOn(IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE);
/* open the FileNode */
OpenedFileNode = FspFileNodeOpen(FileNode, FileObject,
Result = FspFileNodeOpen(FileNode, FileObject,
Response->Rsp.Create.Opened.GrantedAccess, IrpSp->Parameters.Create.ShareAccess,
&Result);
if (0 == OpenedFileNode)
&OpenedFileNode, &SharingViolationReason);
if (!NT_SUCCESS(Result))
{
if (STATUS_SHARING_VIOLATION == Result)
{
ASSERT(0 != OpenedFileNode);
if (STATUS_SHARING_VIOLATION != Irp->IoStatus.Status)
{
ASSERT(0 == Irp->IoStatus.Information ||
FILE_OPBATCH_BREAK_UNDERWAY == Irp->IoStatus.Information);
FspIopSetIrpResponse(Irp, Response);
FspIopRequestContext(Request, FspIopRequestExtraContext) = OpenedFileNode;
/* HACK: We have run out of Contexts. Store the sharing violation reason in the IRP. */
Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
Irp->IoStatus.Information = SharingViolationReason;
Result = FspFsvolCreateSharingViolationOplock(
FsvolDeviceObject, Irp, IrpSp, FALSE);
if (STATUS_PENDING == Result)
FSP_RETURN();
}
else
{
FspFileNodeClose(OpenedFileNode, 0, TRUE);
FspFileNodeDereference(OpenedFileNode);
}
}
else
ASSERT(0 == OpenedFileNode);
/* unable to open the FileNode; post a Close request */
FspFsvolCreatePostClose(FileDesc);
@ -787,6 +889,10 @@ NTSTATUS FspFsvolCreateComplete(
FileDesc->FileNode = FileNode = OpenedFileNode;
}
/* set up the AccessState */
AccessState->RemainingDesiredAccess = 0;
AccessState->PreviouslyGrantedAccess = Response->Rsp.Create.Opened.GrantedAccess;
/* set up the FileObject */
if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
#pragma prefast(disable:28175, "We are a filesystem: ok to access Vpb")
@ -796,7 +902,8 @@ NTSTATUS FspFsvolCreateComplete(
FileObject->FsContext = FileNode;
FileObject->FsContext2 = FileDesc;
if (FspTimeoutInfinity32 == FsvolDeviceExtension->VolumeParams.FileInfoTimeout &&
!FlagOn(IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING))
!FlagOn(IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING) &&
!Response->Rsp.Create.Opened.DisableCache)
/* enable caching! */
SetFlag(FileObject->Flags, FO_CACHE_SUPPORTED);
@ -826,6 +933,7 @@ NTSTATUS FspFsvolCreateComplete(
*/
USHORT FileAttributes = IrpSp->Parameters.Create.FileAttributes;
UINT64 AllocationSize = Request->Req.Create.AllocationSize;
ClearFlag(FileAttributes, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
if (FileNode->IsDirectory)
@ -850,6 +958,7 @@ NTSTATUS FspFsvolCreateComplete(
Request->Req.Overwrite.UserContext = FileNode->UserContext;
Request->Req.Overwrite.UserContext2 = FileDesc->UserContext2;
Request->Req.Overwrite.FileAttributes = FileAttributes;
Request->Req.Overwrite.AllocationSize = AllocationSize;
Request->Req.Overwrite.Supersede = FILE_SUPERSEDED == Response->IoStatus.Information;
/*
@ -887,6 +996,8 @@ NTSTATUS FspFsvolCreateComplete(
}
/* file was successfully overwritten/superseded */
if (0 == FileNode->MainFileNode)
FspFileNodeOverwriteStreams(FileNode);
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Overwrite.FileInfo);
FspFileNodeNotifyChange(FileNode,
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE,
@ -897,7 +1008,7 @@ NTSTATUS FspFsvolCreateComplete(
/* SUCCESS! */
FspIopRequestContext(Request, RequestFileDesc) = 0;
Irp->IoStatus.Information = Request->Req.Overwrite.Supersede ? FILE_SUPERSEDED : FILE_OVERWRITTEN;
Result = STATUS_SUCCESS;
Result = Irp->IoStatus.Status; /* get success value from oplock processing */
}
else
ASSERT(0);
@ -914,34 +1025,42 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
PAGED_CODE();
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
NTSTATUS Result;
BOOLEAN Success;
Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusive(FileNode, Main);
if (FspFsctlTransactCreateKind == Request->Kind)
{
PVOID RequestDeviceObjectValue = FspIopRequestContext(Request, RequestDeviceObject);
/* disassociate the FileDesc momentarily from the Request */
Request = FspIrpRequest(Irp);
FspIopRequestContext(Request, RequestDeviceObject) = 0;
FspIopRequestContext(Request, RequestFileDesc) = 0;
/* reset the Request and reassociate the FileDesc and FileObject with it */
Request->Kind = FspFsctlTransactReservedKind;
FspIopResetRequest(Request, FspFsvolCreateTryOpenRequestFini);
FspIopRequestContext(Request, RequestDeviceObject) = RequestDeviceObjectValue;
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
FspIopRequestContext(Request, RequestFileObject) = FileObject;
FspIopRequestContext(Request, RequestState) = (PVOID)(UINT_PTR)FlushImage;
}
Result = STATUS_SUCCESS;
Success = DEBUGTEST(90) &&
FspFileNodeTryAcquireExclusive(FileNode, Main) &&
FspFsvolCreateOpenOrOverwriteOplock(Irp, Response, &Result);
if (!Success)
{
/* repost the IRP to retry later */
NTSTATUS Result;
if (FspFsctlTransactCreateKind == Request->Kind)
if (STATUS_PENDING == Result)
return Result;
if (!NT_SUCCESS(Result))
{
PVOID RequestDeviceObjectValue = FspIopRequestContext(Request, RequestDeviceObject);
/* disassociate the FileDesc momentarily from the Request */
Request = FspIrpRequest(Irp);
FspIopRequestContext(Request, RequestDeviceObject) = 0;
FspIopRequestContext(Request, RequestFileDesc) = 0;
/* reset the Request and reassociate the FileDesc and FileObject with it */
Request->Kind = FspFsctlTransactReservedKind;
FspIopResetRequest(Request, FspFsvolCreateTryOpenRequestFini);
FspIopRequestContext(Request, RequestDeviceObject) = RequestDeviceObjectValue;
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
FspIopRequestContext(Request, RequestFileObject) = FileObject;
FspIopRequestContext(Request, RequestState) = (PVOID)(UINT_PTR)FlushImage;
FspFileNodeRelease(FileNode, Main);
return Result;
}
FspIopRetryCompleteIrp(Irp, Response, &Result);
return Result;
}
@ -961,9 +1080,10 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
if (0 == Request)
{
FspFsvolCreatePostClose(FileDesc);
FspFileNodeClose(FileNode, FileObject);
FspFileNodeClose(FileNode, FileObject, TRUE);
}
Irp->IoStatus.Information = 0;
return DeleteOnClose ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION;
}
}
@ -978,7 +1098,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
/* SUCCESS! */
FspIopRequestContext(Request, RequestFileDesc) = 0;
Irp->IoStatus.Information = Response->IoStatus.Information;
return STATUS_SUCCESS;
return Irp->IoStatus.Status; /* get success value from oplock processing */
}
static VOID FspFsvolCreatePostClose(FSP_FILE_DESC *FileDesc)
@ -1019,6 +1139,14 @@ static VOID FspFsvolCreateRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Con
FSP_FILE_DESC *FileDesc = Context[RequestFileDesc];
HANDLE AccessToken = Context[RequestAccessToken];
PEPROCESS Process = Context[RequestProcess];
FSP_FILE_NODE *ExtraFileNode = FspIopRequestContext(Request, FspIopRequestExtraContext);
if (0 != ExtraFileNode)
{
ASSERT(FspFileNodeIsValid(ExtraFileNode));
FspFileNodeClose(ExtraFileNode, 0, TRUE);
FspFileNodeDereference(ExtraFileNode);
}
if (0 != FileDesc)
{
@ -1061,13 +1189,21 @@ static VOID FspFsvolCreateTryOpenRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PV
PDEVICE_OBJECT FsvolDeviceObject = Context[RequestDeviceObject];
FSP_FILE_DESC *FileDesc = Context[RequestFileDesc];
PFILE_OBJECT FileObject = Context[RequestFileObject];
PIRP OplockIrp = FspIopRequestContext(Request, FspIopRequestExtraContext);
if (0 != FileDesc)
{
ASSERT(0 != FileObject);
if (OplockIrp)
{
ASSERT(IO_TYPE_IRP == OplockIrp->Type);
FspFileNodeOplockCheckEx(FileDesc->FileNode, OplockIrp,
OPLOCK_FLAG_BACK_OUT_ATOMIC_OPLOCK);
}
FspFsvolCreatePostClose(FileDesc);
FspFileNodeClose(FileDesc->FileNode, FileObject);
FspFileNodeClose(FileDesc->FileNode, FileObject, TRUE);
FspFileNodeDereference(FileDesc->FileNode);
FspFileDescDelete(FileDesc);
}
@ -1084,6 +1220,7 @@ static VOID FspFsvolCreateOverwriteRequestFini(FSP_FSCTL_TRANSACT_REQ *Request,
FSP_FILE_DESC *FileDesc = Context[RequestFileDesc];
PFILE_OBJECT FileObject = Context[RequestFileObject];
ULONG State = (ULONG)(UINT_PTR)Context[RequestState];
PIRP OplockIrp = FspIopRequestContext(Request, FspIopRequestExtraContext);
if (0 != FileDesc)
{
@ -1094,7 +1231,14 @@ static VOID FspFsvolCreateOverwriteRequestFini(FSP_FSCTL_TRANSACT_REQ *Request,
else if (RequestProcessing == State)
FspFileNodeReleaseOwner(FileDesc->FileNode, Full, Request);
FspFileNodeClose(FileDesc->FileNode, FileObject);
if (OplockIrp)
{
ASSERT(IO_TYPE_IRP == OplockIrp->Type);
FspFileNodeOplockCheckEx(FileDesc->FileNode, OplockIrp,
OPLOCK_FLAG_BACK_OUT_ATOMIC_OPLOCK);
}
FspFileNodeClose(FileDesc->FileNode, FileObject, TRUE);
FspFileNodeDereference(FileDesc->FileNode);
FspFileDescDelete(FileDesc);
}
@ -1103,6 +1247,258 @@ static VOID FspFsvolCreateOverwriteRequestFini(FSP_FSCTL_TRANSACT_REQ *Request,
FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, Request);
}
static NTSTATUS FspFsvolCreateSharingViolationOplock(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN CanWait)
{
PAGED_CODE();
/*
* Perform oplock checks in the case that we received STATUS_SHARING_VIOLATION.
* The logic below is rather tortured, because it tries to mimic what FastFat
* does in Win7 when a sharing violation happens. Here is an explanation.
*
* When this routine first gets called the CanWait parameter is FALSE. This is
* because it gets called in the context of a completion thread, which belongs
* to the user mode file system. This means that we cannot block this thread
* because the user mode file system may have a limited number of threads to
* service file system requests.
*
* When CanWait is FALSE the routine checks whether there are any oplocks on
* this file. If there are none it simply returns STATUS_SHARING_VIOLATION.
* Otherwise it posts a work item so that the routine can be executed in the
* context of a worker thread. When executed in the context of a worker thread
* the CanWait parameter is TRUE.
*
* When CanWait is TRUE the routine is free to wait for any oplocks breaks. We
* try to break both Batch and Handle oplocks and return the appropriate status
* code.
*
* We acquire the FileNode shared to allow oplock breaks to happen concurrently.
* See https://www.osronline.com/showthread.cfm?link=248984
*/
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
FSP_FSCTL_TRANSACT_RSP *Response;
FSP_FILE_NODE *ExtraFileNode = FspIopRequestContext(Request, FspIopRequestExtraContext);
ULONG SharingViolationReason = (ULONG)Irp->IoStatus.Information;
NTSTATUS Result;
BOOLEAN Success;
ASSERT(FspFsctlTransactCreateKind == Request->Kind);
ASSERT(
FspFileNodeSharingViolationGeneral == SharingViolationReason ||
FspFileNodeSharingViolationMainFile == SharingViolationReason ||
FspFileNodeSharingViolationStream == SharingViolationReason);
Success = DEBUGTEST(90) &&
FspFileNodeTryAcquireSharedF(ExtraFileNode, FspFileNodeAcquireMain, CanWait);
if (!Success)
return FspWqRepostIrpWorkItem(Irp,
FspFsvolCreateSharingViolationOplock, FspFsvolCreateRequestFini);
if (!CanWait)
{
/*
* If there is no Batch or Handle oplock we are done; else retry in a
* worker thread to break the oplocks.
*/
Success = DEBUGTEST(90) &&
!(FspFileNodeSharingViolationMainFile == SharingViolationReason) &&
!(FspFileNodeSharingViolationStream == SharingViolationReason) &&
!(FspFileNodeOplockIsBatch(ExtraFileNode)) &&
!(!FlagOn(IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED) &&
FspFileNodeOplockIsHandle(ExtraFileNode));
FspFileNodeRelease(ExtraFileNode, Main);
if (!Success)
return FspWqRepostIrpWorkItem(Irp,
FspFsvolCreateSharingViolationOplock, FspFsvolCreateRequestFini);
Irp->IoStatus.Information = 0;
return STATUS_SHARING_VIOLATION;
}
else
{
Irp->IoStatus.Information = 0;
Result = STATUS_SHARING_VIOLATION;
if (FspFileNodeSharingViolationMainFile == SharingViolationReason)
{
/*
* If a SUPERSEDE, OVERWRITE or OVERWRITE_IF operation is performed
* on an alternate data stream and FILE_SHARE_DELETE is not specified
* and there is a Batch or Filter oplock on the primary data stream,
* request a break of the Batch or Filter oplock on the primary data
* stream.
*/
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
/* break Batch oplocks on the main file and this stream */
Result = FspFileNodeCheckBatchOplocksOnAllStreams(FsvolDeviceObject, Irp,
ExtraFileNode, FspFileNodeAcquireMain, &FileNode->FileName);
if (STATUS_SUCCESS != Result)
Result = STATUS_SHARING_VIOLATION;
}
else
if (FspFileNodeSharingViolationStream == SharingViolationReason)
{
/*
* If a SUPERSEDE, OVERWRITE or OVERWRITE_IF operation is performed
* on the primary data stream and DELETE access has been requested
* and there are Batch or Filter oplocks on any alternate data stream,
* request a break of the Batch or Filter oplocks on all alternate data
* streams that have them.
*/
/* break Batch oplocks on the main file and all our streams */
Result = FspFileNodeCheckBatchOplocksOnAllStreams(FsvolDeviceObject, Irp,
ExtraFileNode, FspFileNodeAcquireMain, 0);
if (STATUS_SUCCESS != Result)
Result = STATUS_SHARING_VIOLATION;
}
else
if (FspFileNodeOplockIsBatch(ExtraFileNode))
{
FspFileNodeRelease(ExtraFileNode, Main);
/* wait for Batch oplock break to complete */
Result = FspFileNodeOplockCheck(ExtraFileNode, Irp);
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result);
if (STATUS_SUCCESS != Result)
Result = STATUS_SHARING_VIOLATION;
else
Irp->IoStatus.Information = FILE_OPBATCH_BREAK_UNDERWAY;
}
else
if (!FlagOn(IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED) &&
FspFileNodeOplockIsHandle(ExtraFileNode))
{
FspFileNodeRelease(ExtraFileNode, Main);
/* wait for Handle oplock break to complete */
Result = FspFileNodeOplockBreakHandle(ExtraFileNode, Irp, 0);
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result);
if (STATUS_SUCCESS != Result)
Result = STATUS_SHARING_VIOLATION;
}
else
FspFileNodeRelease(ExtraFileNode, Main);
Response = FspIopIrpResponse(Irp);
if (STATUS_SUCCESS == Result)
{
FspFileNodeClose(ExtraFileNode, 0, TRUE);
FspFileNodeDereference(ExtraFileNode);
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
}
else
{
Response->IoStatus.Status = (UINT32)Result;
Response->IoStatus.Information = (UINT32)Irp->IoStatus.Information;
}
FspIopRetryCompleteIrp(Irp, Response, &Result);
return Result;
}
}
static BOOLEAN FspFsvolCreateOpenOrOverwriteOplock(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
PNTSTATUS PResult)
{
PAGED_CODE();
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject;
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
UINT32 RequestKind = FspIrpRequest(Irp)->Kind;
ULONG OplockCount = 0;
NTSTATUS Result;
ASSERT(
FspFsctlTransactReservedKind == RequestKind ||
FspFsctlTransactOverwriteKind == RequestKind);
/* add oplock key to the file object */
Result = FspFileNodeOplockCheckEx(FileNode, Irp,
OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY);
if (!NT_SUCCESS(Result))
{
*PResult = Result;
return FALSE;
}
/* get current handle count */
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
OplockCount = FileNode->HandleCount;
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
/* if there are more than one handles, perform oplock check */
if (1 < OplockCount)
{
Result = FspFileNodeOplockCheckAsyncEx(
FileNode,
FspFsctlTransactReservedKind == RequestKind ? FspFileNodeAcquireMain : FspFileNodeAcquireFull,
(PVOID)Response,
Irp,
FspFsvolCreateOpenOrOverwriteOplockComplete,
FspFsvolCreateOpenOrOverwriteOplockPrepare);
if (STATUS_PENDING == Result)
{
*PResult = Result;
return FALSE;
}
}
/* is an oplock requested during Create? */
if (STATUS_SUCCESS == Result &&
FlagOn(IrpSp->Parameters.Create.Options, FILE_OPEN_REQUIRING_OPLOCK))
{
Result = FspFileNodeOplockFsctl(FileNode, Irp, OplockCount);
ASSERT(STATUS_PENDING != Result);
if (STATUS_SUCCESS == Result)
/* if we added an oplock, remember to remove it later in case of failure */
FspIopRequestContext(FspIrpRequest(Irp), FspIopRequestExtraContext) = Irp;
}
*PResult = Irp->IoStatus.Status = Result;
return STATUS_SUCCESS == Result || STATUS_OPLOCK_BREAK_IN_PROGRESS == Result;
}
static VOID FspFsvolCreateOpenOrOverwriteOplockPrepare(
PVOID Context, PIRP Irp)
{
PAGED_CODE();
FSP_FSCTL_TRANSACT_RSP *Response = FspFileNodeReleaseForOplock(Context);
if (0 != Response)
FspIopSetIrpResponse(Irp, Response);
}
static VOID FspFsvolCreateOpenOrOverwriteOplockComplete(
PVOID Context, PIRP Irp)
{
PAGED_CODE();
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
NTSTATUS Result;
if (FspFsctlTransactReservedKind == Request->Kind)
FspIopRetryCompleteIrp(Irp, FspIopIrpResponse(Irp), &Result);
else
if (FspFsctlTransactOverwriteKind == Request->Kind)
FspIopRetryPrepareIrp(Irp, &Result);
else
ASSERT(0);
}
NTSTATUS FspCreate(
PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
@ -1131,7 +1527,7 @@ NTSTATUS FspCreate(
"Ea=%p, EaLength=%ld",
IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName,
IrpSp->Flags,
IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
IrpSp->Parameters.Create.SecurityContext->AccessState->OriginalDesiredAccess,
IrpSp->Parameters.Create.ShareAccess,
IrpSp->Parameters.Create.Options,
IrpSp->Parameters.Create.FileAttributes,

View File

@ -590,7 +590,9 @@ NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
*PContextCount = 0;
ContextCount = RtlNumberGenericTableElementsAvl(&FsvolDeviceExtension->ContextByNameTable);
Contexts = FspAlloc(sizeof(PVOID) * ContextCount);
/* if ContextCount == 0 allocate an empty Context list */
Contexts = FspAlloc(sizeof(PVOID) * (0 != ContextCount ? ContextCount : 1));
if (0 == Contexts)
return STATUS_INSUFFICIENT_RESOURCES;
@ -631,9 +633,10 @@ PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE
0, 0, NextFlag, &RestartKey->RestartKey, &RestartKey->DeleteCount, &FileName);
if (0 != Result &&
RtlPrefixUnicodeString(FileName, Result->FileName, CaseInsensitive) &&
FileName->Length < Result->FileName->Length &&
'\\' == Result->FileName->Buffer[FileName->Length / sizeof(WCHAR)])
FspFileNameIsPrefix(FileName, Result->FileName, CaseInsensitive, 0) &&
(FileName->Length == Result->FileName->Length ||
(L'\\' == Result->FileName->Buffer[FileName->Length / sizeof(WCHAR)] ||
L':' == Result->FileName->Buffer[FileName->Length / sizeof(WCHAR)])))
return Result->Context;
else
return 0;
@ -699,7 +702,12 @@ static RTL_GENERIC_COMPARE_RESULTS NTAPI FspFsvolDeviceCompareContextByName(
PUNICODE_STRING SecondFileName = *(PUNICODE_STRING *)SecondElement;
LONG ComparisonResult;
ComparisonResult = RtlCompareUnicodeString(FirstFileName, SecondFileName, CaseInsensitive);
/*
* Since FileNode FileName's are now always normalized, we could perhaps get away
* with using CaseInsensitive == FALSE at all times. For safety reasons we avoid
* doing so here.
*/
ComparisonResult = FspFileNameCompare(FirstFileName, SecondFileName, CaseInsensitive, 0);
if (0 > ComparisonResult)
return GenericLessThan;

View File

@ -17,6 +17,15 @@
#include <sys/driver.h>
/*
* NOTE:
*
* FspIopCompleteIrpEx does some special processing for IRP_MJ_DIRECTORY_CONTROL /
* IRP_MN_QUERY_DIRECTORY IRP's that come from SRV2. If the processing of this IRP
* changes substantially (in particular if we eliminate our use of
* Irp->AssociatedIrp.SystemBuffer) we should also revisit FspIopCompleteIrpEx.
*/
static NTSTATUS FspFsvolQueryDirectoryCopy(
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
UINT64 DirectoryOffset, PUINT64 PDirectoryOffset,
@ -71,7 +80,7 @@ FSP_DRIVER_DISPATCH FspDirectoryControl;
enum
{
/* QueryDirectory */
RequestFileNode = 0,
RequestIrp = 0,
RequestMdl = 1,
RequestAddress = 2,
RequestProcess = 3,
@ -118,7 +127,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
PAGED_CODE();
NTSTATUS Result = STATUS_SUCCESS;
BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer;
BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer, Match;
BOOLEAN Loop = TRUE, DirectoryOffsetFound = FALSE;
FSP_FSCTL_DIR_INFO *DirInfo = *PDirInfo;
PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize;
@ -182,7 +191,15 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
CopyLength = FileName.Length;
if (MatchAll || FsRtlIsNameInExpression(DirectoryPattern, &FileName, CaseInsensitive, 0))
Match = MatchAll;
if (!Match)
{
Result = FspFileNameInExpression(DirectoryPattern, &FileName, CaseInsensitive, 0, &Match);
if (!NT_SUCCESS(Result))
return Result;
}
if (Match)
{
if ((PUINT8)DestBuf + BaseInfoLen + CopyLength > DestBufEnd)
{
@ -340,7 +357,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
UINT64 DirectoryOffset = FileDesc->DirectoryOffset;
ASSERT(DirInfo == DestBuf);
static_assert(
FSP_FSCTL_STATIC_ASSERT(
FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) >=
FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName),
"FSP_FSCTL_DIR_INFO must be bigger than FILE_ID_BOTH_DIR_INFORMATION");
@ -567,6 +584,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
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)
{
@ -580,7 +598,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
}
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
FspIopRequestContext(Request, RequestIrp) = Irp;
return FSP_STATUS_IOQ_POST;
@ -618,7 +636,7 @@ static NTSTATUS FspFsvolQueryDirectory(
return STATUS_INVALID_PARAMETER;
/* check that FileName is valid (if supplied) */
if (0 != FileName && !FspUnicodePathIsValidPattern(FileName))
if (0 != FileName && !FspFileNameIsValidPattern(FileName))
return STATUS_INVALID_PARAMETER;
/* is this an allowed file information class? */
@ -847,6 +865,10 @@ NTSTATUS FspFsvolDirectoryControlComplete(
}
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
if (Response->IoStatus.Information > Request->Req.QueryDirectory.Length)
FSP_RETURN(Result = STATUS_INTERNAL_ERROR);
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
@ -930,7 +952,7 @@ NTSTATUS FspFsvolDirectoryControlComplete(
Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset;
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
FspIopRequestContext(Request, RequestIrp) = Irp;
FspIoqPostIrp(FsvolDeviceExtension->Ioq, Irp, &Result);
}
@ -952,7 +974,7 @@ static VOID FspFsvolQueryDirectoryRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
{
PAGED_CODE();
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
PIRP Irp = Context[RequestIrp];
PMDL Mdl = Context[RequestMdl];
PVOID Address = Context[RequestAddress];
PEPROCESS Process = Context[RequestProcess];
@ -977,8 +999,13 @@ static VOID FspFsvolQueryDirectoryRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
if (0 != Mdl)
IoFreeMdl(Mdl);
if (0 != FileNode)
if (0 != Irp)
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
FSP_FILE_NODE *FileNode = IrpSp->FileObject->FsContext;
FspFileNodeReleaseOwner(FileNode, Full, Request);
}
}
NTSTATUS FspDirectoryControl(

View File

@ -120,7 +120,6 @@ NTSTATUS DriverEntry(
FspIopCompleteFunction[IRP_MJ_LOCK_CONTROL] = FspFsvolLockControlComplete;
FspIopCompleteFunction[IRP_MJ_CLEANUP] = FspFsvolCleanupComplete;
FspIopCompleteFunction[IRP_MJ_QUERY_SECURITY] = FspFsvolQuerySecurityComplete;
FspIopPrepareFunction[IRP_MJ_SET_SECURITY] = FspFsvolSetSecurityPrepare;
FspIopCompleteFunction[IRP_MJ_SET_SECURITY] = FspFsvolSetSecurityComplete;
/* setup fast I/O and resource acquisition */
@ -177,6 +176,8 @@ NTSTATUS DriverEntry(
static VOID FspDriverMultiVersionInitialize(VOID)
{
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
if (RtlIsNtDdiVersionAvailable(NTDDI_WIN7))
{
UNICODE_STRING Name;

View File

@ -19,6 +19,8 @@
#define WINFSP_SYS_DRIVER_H_INCLUDED
#define WINFSP_SYS_INTERNAL
#define POOL_NX_OPTIN 1
#include <ntifs.h>
#include <ntstrsafe.h>
#include <wdmsec.h>
@ -33,8 +35,8 @@
/* IoCreateDeviceSecure default SDDL's */
#define FSP_FSCTL_DEVICE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;WD)"
/* System:GENERIC_ALL, Administrators:GENERIC_ALL, World:GENERIC_READ */
#define FSP_FSVRT_DEVICE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;WD)"
/* System:GENERIC_ALL, Administrators:GENERIC_ALL, World:GENERIC_READ */
#define FSP_FSVRT_DEVICE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGX;;;WD)"
/* System:GENERIC_ALL, Administrators:GENERIC_ALL, World:GENERIC_READ|GENERIC_EXECUTE */
/* private NTSTATUS codes */
#define FSP_STATUS_PRIVATE_BIT (0x20000000)
@ -45,7 +47,6 @@
#define FSP_ALLOC_INTERNAL_TAG 'IpsF'
#define FSP_ALLOC_EXTERNAL_TAG 'XpsF'
#define FSP_IO_INCREMENT IO_NETWORK_INCREMENT
#define FSP_VOLUME_PREFIX_CASE_INS TRUE
/* debug */
#if DBG
@ -123,8 +124,11 @@ VOID FspDebugLogIrp(const char *func, PIRP Irp, NTSTATUS Result);
#if DBG
#define DEBUGTEST(Percent) \
(0 == (fsp_debug & fsp_debug_dt) || DebugRandom() <= (Percent) * 0x7fff / 100)
#define DEBUGTEST_EX(C, Percent, Deflt) \
(0 != (fsp_debug & fsp_debug_dt) && (C) ? (DebugRandom() <= (Percent) * 0x7fff / 100) : (Deflt))
#else
#define DEBUGTEST(Percent) (TRUE)
#define DEBUGTEST_EX(C, Percent, Deflt) (Deflt)
#endif
/* FSP_ENTER/FSP_LEAVE */
@ -319,7 +323,6 @@ FSP_IOCMPL_DISPATCH FspFsvolReadComplete;
FSP_IOCMPL_DISPATCH FspFsvolSetEaComplete;
FSP_IOPREP_DISPATCH FspFsvolSetInformationPrepare;
FSP_IOCMPL_DISPATCH FspFsvolSetInformationComplete;
FSP_IOPREP_DISPATCH FspFsvolSetSecurityPrepare;
FSP_IOCMPL_DISPATCH FspFsvolSetSecurityComplete;
FSP_IOCMPL_DISPATCH FspFsvolSetVolumeInformationComplete;
FSP_IOCMPL_DISPATCH FspFsvolShutdownComplete;
@ -428,17 +431,45 @@ BOOLEAN FspExpirationTimeValid2(UINT64 ExpirationTime, UINT64 CurrentTime)
return CurrentTime < ExpirationTime;
}
/* utility */
/* names */
enum
{
FspUnicodePathStreamTypeNone = 0,
FspUnicodePathStreamTypeData = 1,
FspFileNameStreamTypeNone = 0,
FspFileNameStreamTypeData = 1,
};
BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType);
BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Pattern);
VOID FspFileNameSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
#if 0
NTSTATUS FspFileNameUpcase(
PUNICODE_STRING DestinationName,
PUNICODE_STRING SourceName,
PCWCH UpcaseTable);
LONG FspFileNameCompare(
PUNICODE_STRING Name1,
PUNICODE_STRING Name2,
BOOLEAN IgnoreCase,
PCWCH UpcaseTable);
BOOLEAN FspFileNameIsPrefix(
PCUNICODE_STRING Name1,
PCUNICODE_STRING Name2,
BOOLEAN IgnoreCase,
PCWCH UpcaseTable);
#else
#define FspFileNameUpcase(D,S,U) (ASSERT(0 == (U)), RtlUpcaseUnicodeString(D,S,FALSE))
#define FspFileNameCompare(N1,N2,I,U) (ASSERT(0 == (U)), RtlCompareUnicodeString(N1,N2,I))
#define FspFileNameIsPrefix(N1,N2,I,U) (ASSERT(0 == (U)), RtlPrefixUnicodeString(N1,N2,I))
#endif
NTSTATUS FspFileNameInExpression(
PUNICODE_STRING Expression,
PUNICODE_STRING Name,
BOOLEAN IgnoreCase,
PWCH UpcaseTable,
PBOOLEAN PResult);
/* utility */
PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag);
PVOID FspAllocateIrpMustSucceed(CCHAR StackSize);
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType);
BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Pattern);
VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
NTSTATUS FspCreateGuid(GUID *Guid);
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject);
@ -487,18 +518,42 @@ NTSTATUS FspNotifyFullReportChange(
ULONG FilterMatch,
ULONG Action,
PVOID TargetContext);
NTSTATUS FspOplockBreakH(
POPLOCK Oplock,
PIRP Irp,
ULONG Flags,
PVOID Context,
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
POPLOCK_FS_PREPOST_IRP PostIrpRoutine);
NTSTATUS FspCheckOplock(
POPLOCK Oplock,
PIRP Irp,
PVOID Context,
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
POPLOCK_FS_PREPOST_IRP PostIrpRoutine);
NTSTATUS FspCheckOplockEx(
POPLOCK Oplock,
PIRP Irp,
ULONG Flags,
PVOID Context,
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
POPLOCK_FS_PREPOST_IRP PostIrpRoutine);
NTSTATUS FspOplockFsctrl(
POPLOCK Oplock,
PIRP Irp,
ULONG OpenCount);
#define FspNotifyUninitializeSync(NS)\
FsRtlNotifyUninitializeSync(NS)
#define FspNotifyCleanupAll(NS, NL)\
FsRtlNotifyCleanupAll(NS, NL)
#define FspNotifyChangeDirectory(NS, NL, FC, FN, WT, CF, I)\
FspNotifyFullChangeDirectory(NS, NL, FC, (PSTRING)FN, WT, FALSE, CF, I, 0, 0)
FspNotifyFullChangeDirectory(NS, NL, FC, (PSTRING)(FN), WT, FALSE, CF, I, 0, 0)
#define FspNotifyCleanup(NS, NL, FC)\
FsRtlNotifyCleanup(NS, NL, FC)
#define FspNotifyDeletePending(NS, NL, FC)\
FspNotifyFullChangeDirectory(NS, NL, FC, 0, 0, FALSE, 0, 0, 0, 0)
#define FspNotifyReportChange(NS, NL, FN, FO, SN, F, A)\
FspNotifyFullReportChange(NS, NL, (PSTRING)FN, FO, (PSTRING)SN, 0, F, A, 0)
#define FspNotifyReportChange(NS, NL, FN, FO, NP, F, A)\
FspNotifyFullReportChange(NS, NL, (PSTRING)(FN), FO, 0, (PSTRING)(NP), F, A, 0)
/* utility: synchronous work queue */
typedef struct
@ -585,7 +640,151 @@ VOID FspIrpSetTopFlags(PIRP Irp, ULONG Flags)
Irp->Tail.Overlay.DriverContext[2] = (PVOID)((UINT_PTR)Request | (Flags << 2));
}
/*
* Queued Events
*
* Queued Events are an implementation of SynchronizationEvent's using
* a KQUEUE. The reason we do this is because a KQUEUE has some desirable
* properties:
*
* - It has a LIFO wait discipline, which is advantageous in many situations.
* - It can limit the numbers of threads that can be satisfied concurrently.
*
* Queued Events must always be allocated in non-paged storage.
*
* Here is how Queued Events work. A queued event consists of a KQUEUE and a
* spin lock. There is also a LIST_ENTRY which is used as a dummy item to
* place in the KQUEUE.
*
* The KQUEUE is guaranteed to contain either 0 or 1 items. When the KQUEUE
* contains 0 items the queued event is considered non-signaled. When the
* KQUEUE contains 1 items the queued event is considered signaled.
*
* To transition from the non-signaled to the signaled state, we acquire the
* spin lock and then insert the dummy item in the KQUEUE using KeInsertQueue.
* To transition from the signaled to the non-signaled state, we simply (wait
* and) remove the dummy item from the KQUEUE using KeRemoveQueue (without
* the use of the spin lock).
*
* EventSet:
* AcquireSpinLock
* if (0 == KeReadState()) // if KQUEUE is empty
* KeInsertQueue(DUMMY);
* ReleaseSpinLock
*
* EventWait:
* KeRemoveQueue(); // (wait and) remove item
*
* First notice that EventSet is serialized by the use of the spin lock. This
* guarantees that the dummy item can be only inserted ONCE in the KQUEUE
* and that the only possible signaled state transitions for EventSet are 0->1
* and 1->1. This is how KeSetEvent works for a SynchronizationEvent.
*
* Second notice that EventWait is not protected by the spin lock, which means
* that it can happen at any time including concurrently with EventSet or
* another EventWait. Notice also that for EventWait the only possible
* transitions are 1->0 or 0->0 (0->block->0). This is how
* KeWaitForSingleObject works for a SynchronizationEvent.
*
* We now have to consider what happens when we have one EventSet concurrently
* with one or more EventWait's:
*
* 1. The EventWait(s) happen before KeReadState. If the KQUEUE has an
* item one EventWait gets satisfied, otherwise it blocks. In this case
* KeReadState will read the KQUEUE's state as 0 and KeInsertQueue will
* insert the dummy item, which will unblock the EventWait.
*
* 2. The EventWait(s) happen after KeReadState, but before KeInsertQueue.
* If the dummy item was already in the KQUEUE the KeReadState test will
* fail and KeInsertQueue will not be executed, but EventWait will be
* satisfied immediately. If the dummy item was not in the KQUEUE the
* KeReadState will succeed and EventWait will momentarily block until
* KeInsertQueue releases it.
*
* 3. The EventWait(s) happen after KeInsertQueue. In this case the dummy
* item in is the KQUEUE already and one EventWait will be satisfied
* immediately.
*
* A final note: Queued Events cannot cleanly support an EventClear operation.
* The obvious choice of using KeRemoveQueue with a 0 timeout is insufficient
* because it would associate the current thread with the KQUEUE and that is
* not desirable. KeRundownQueue cannot be used either because it
* disassociates all threads from the KQUEUE.
*/
typedef struct
{
KQUEUE Queue;
LIST_ENTRY DummyEntry;
KSPIN_LOCK SpinLock;
} FSP_QEVENT;
static inline
VOID FspQeventInitialize(FSP_QEVENT *Qevent, ULONG ThreadCount)
{
KeInitializeQueue(&Qevent->Queue, ThreadCount);
RtlZeroMemory(&Qevent->DummyEntry, sizeof Qevent->DummyEntry);
KeInitializeSpinLock(&Qevent->SpinLock);
}
static inline
VOID FspQeventFinalize(FSP_QEVENT *Qevent)
{
KeRundownQueue(&Qevent->Queue);
}
static inline
VOID FspQeventSetNoLock(FSP_QEVENT *Qevent)
{
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
if (0 == KeReadStateQueue(&Qevent->Queue))
KeInsertQueue(&Qevent->Queue, &Qevent->DummyEntry);
}
static inline
VOID FspQeventSet(FSP_QEVENT *Qevent)
{
KIRQL Irql;
KeAcquireSpinLock(&Qevent->SpinLock, &Irql);
FspQeventSetNoLock(Qevent);
KeReleaseSpinLock(&Qevent->SpinLock, Irql);
}
static inline
NTSTATUS FspQeventWait(FSP_QEVENT *Qevent,
KPROCESSOR_MODE WaitMode, BOOLEAN Alertable, PLARGE_INTEGER PTimeout)
{
PLIST_ENTRY ListEntry;
KeRemoveQueueEx(&Qevent->Queue, WaitMode, Alertable, PTimeout, &ListEntry, 1);
if (ListEntry == &Qevent->DummyEntry)
return STATUS_SUCCESS;
return (NTSTATUS)(UINT_PTR)ListEntry;
}
static inline
NTSTATUS FspQeventCancellableWait(FSP_QEVENT *Qevent,
PLARGE_INTEGER PTimeout, PIRP Irp)
{
NTSTATUS Result;
UINT64 ExpirationTime = 0, InterruptTime;
if (0 != PTimeout && 0 > PTimeout->QuadPart)
ExpirationTime = KeQueryInterruptTime() - PTimeout->QuadPart;
retry:
Result = FspQeventWait(Qevent, KernelMode, TRUE, PTimeout);
if (STATUS_ALERTED == Result)
{
if (PsIsThreadTerminating(PsGetCurrentThread()))
return STATUS_THREAD_IS_TERMINATING;
if (0 != Irp && Irp->Cancel)
return STATUS_CANCELLED;
if (0 != ExpirationTime)
{
InterruptTime = KeQueryInterruptTime();
if (ExpirationTime <= InterruptTime)
return STATUS_TIMEOUT;
PTimeout->QuadPart = (INT64)InterruptTime - (INT64)ExpirationTime;
}
goto retry;
}
return Result;
}
/* I/O queue */
#define FSP_IOQ_USE_QEVENT
#define FSP_IOQ_PROCESS_NO_CANCEL
#define FspIoqTimeout ((PIRP)1)
#define FspIoqCancelled ((PIRP)2)
#define FspIoqPostIrp(Q, I, R) FspIoqPostIrpEx(Q, I, FALSE, R)
@ -594,7 +793,11 @@ typedef struct
{
KSPIN_LOCK SpinLock;
BOOLEAN Stopped;
#if defined(FSP_IOQ_USE_QEVENT)
FSP_QEVENT PendingIrpEvent;
#else
KEVENT PendingIrpEvent;
#endif
LIST_ENTRY PendingIrpList, ProcessIrpList, RetriedIrpList;
IO_CSQ PendingIoCsq, ProcessIoCsq, RetriedIoCsq;
ULONG IrpTimeout;
@ -649,45 +852,53 @@ VOID FspMetaCacheInvalidateItem(FSP_META_CACHE *MetaCache, UINT64 ItemIndex);
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'W', METHOD_NEITHER, FILE_ANY_ACCESS)
#define FSP_FSCTL_WORK_BEST_EFFORT \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'w', METHOD_NEITHER, FILE_ANY_ACCESS)
#define FSP_FSCTL_TRANSACT_REQ_ALIGNMENT 16
enum
{
FspIopRequestMustSucceed = 0x01,
FspIopRequestNonPaged = 0x02,
FspIopCreateRequestMustSucceedFlag = 0x01,
FspIopCreateRequestNonPagedFlag = 0x02,
FspIopCreateRequestWorkItemFlag = 0x04,
};
enum
{
FspIopRequestExtraContext = 4,
};
#define FspIopCreateRequest(I, F, E, P) \
FspIopCreateRequestFunnel(I, F, E, 0, 0, P)
#define FspIopCreateRequestMustSucceed(I, F, E, P)\
FspIopCreateRequestFunnel(I, F, E, 0, FspIopRequestMustSucceed, P)
#define FspIopCreateRequestEx(I, F, E, RF, P)\
FspIopCreateRequestFunnel(I, F, E, RF, 0, P)
#define FspIopCreateRequestMustSucceedEx(I, F, E, RF, P)\
FspIopCreateRequestFunnel(I, F, E, RF, FspIopRequestMustSucceed, P)
#define FspIopCreateRequestWorkItem(I, E, RF, P)\
FspIopCreateRequestFunnel(I, 0, E, RF, FspIopRequestNonPaged, P)
#define FspIopRequestContext(Request, I)\
(*FspIopRequestContextAddress(Request, I))
#define FspIopPostWorkRequest(D, R) FspIopPostWorkRequestFunnel(D, R, FALSE)
#define FspIopPostWorkRequestBestEffort(D, R)\
FspIopPostWorkRequestFunnel(D, R, TRUE)
#define FspIopCompleteIrp(I, R) FspIopCompleteIrpEx(I, R, TRUE)
#define REQ_ALIGN_SIZE 16
typedef VOID FSP_IOP_REQUEST_FINI(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4]);
typedef NTSTATUS FSP_IOP_REQUEST_WORK(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN CanWait);
typedef struct
{
FSP_IOP_REQUEST_WORK *WorkRoutine;
WORK_QUEUE_ITEM WorkQueueItem;
} FSP_FSCTL_TRANSACT_REQ_WORK_ITEM;
typedef struct
{
FSP_IOP_REQUEST_FINI *RequestFini;
PVOID Context[4];
PVOID Context[4 + 1/*FspIopRequestExtraContext*/];
FSP_FSCTL_TRANSACT_RSP *Response;
__declspec(align(REQ_ALIGN_SIZE)) UINT8 RequestBuf[];
FSP_FSCTL_TRANSACT_REQ_WORK_ITEM *WorkItem;
__declspec(align(FSP_FSCTL_TRANSACT_REQ_ALIGNMENT)) UINT8 RequestBuf[];
} FSP_FSCTL_TRANSACT_REQ_HEADER;
FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FSCTL_TRANSACT_REQ_HEADER) <= 64,
"sizeof(FSP_FSCTL_TRANSACT_REQ_HEADER) assumed less or equal to 64; "
"see FSP_FSCTL_TRANSACT_REQ_SIZEMAX");
static inline
PVOID *FspIopRequestContextAddress(FSP_FSCTL_TRANSACT_REQ *Request, ULONG I)
{
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader = (PVOID)((PUINT8)Request - sizeof *RequestHeader);
return &RequestHeader->Context[I];
}
static inline
FSP_FSCTL_TRANSACT_REQ_WORK_ITEM *FspIopRequestWorkItem(FSP_FSCTL_TRANSACT_REQ *Request)
{
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader = (PVOID)((PUINT8)Request - sizeof *RequestHeader);
return RequestHeader->WorkItem;
}
NTSTATUS FspIopCreateRequestFunnel(
PIRP Irp, PUNICODE_STRING FileName, ULONG ExtraSize, FSP_IOP_REQUEST_FINI *RequestFini,
ULONG Flags, FSP_FSCTL_TRANSACT_REQ **PRequest);
NTSTATUS FspIopCreateRequestWorkItem(FSP_FSCTL_TRANSACT_REQ *Request);
VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request);
VOID FspIopResetRequest(FSP_FSCTL_TRANSACT_REQ *Request, FSP_IOP_REQUEST_FINI *RequestFini);
NTSTATUS FspIopPostWorkRequestFunnel(PDEVICE_OBJECT DeviceObject,
@ -696,6 +907,7 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceDereference);
VOID FspIopCompleteCanceledIrp(PIRP Irp);
BOOLEAN FspIopRetryPrepareIrp(PIRP Irp, NTSTATUS *PResult);
BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response, NTSTATUS *PResult);
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);
@ -709,17 +921,26 @@ VOID FspIrpDeleteRequest(PIRP Irp)
FspIrpSetRequest(Irp, 0);
}
}
#define FspIopCreateRequest(I, F, E, P) \
FspIopCreateRequestFunnel(I, F, E, 0, 0, P)
#define FspIopCreateRequestMustSucceed(I, F, E, P)\
FspIopCreateRequestFunnel(I, F, E, 0, FspIopCreateRequestMustSucceedFlag, P)
#define FspIopCreateRequestEx(I, F, E, RF, P)\
FspIopCreateRequestFunnel(I, F, E, RF, 0, P)
#define FspIopCreateRequestMustSucceedEx(I, F, E, RF, P)\
FspIopCreateRequestFunnel(I, F, E, RF, FspIopCreateRequestMustSucceedFlag, P)
#define FspIopCreateRequestAndWorkItem(I, E, RF, P)\
FspIopCreateRequestFunnel(I, 0, E, RF, FspIopCreateRequestWorkItemFlag, P)
#define FspIopRequestContext(Request, I)\
(*FspIopRequestContextAddress(Request, I))
#define FspIopPostWorkRequest(D, R) FspIopPostWorkRequestFunnel(D, R, FALSE)
#define FspIopPostWorkRequestBestEffort(D, R)\
FspIopPostWorkRequestFunnel(D, R, TRUE)
#define FspIopCompleteIrp(I, R) FspIopCompleteIrpEx(I, R, TRUE)
/* work queue processing */
enum
{
FspWqRequestWorkRoutine = 3,
};
typedef NTSTATUS FSP_WQ_REQUEST_WORK(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN CanWait);
NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp,
FSP_WQ_REQUEST_WORK *WorkRoutine, FSP_IOP_REQUEST_FINI *RequestFini,
FSP_IOP_REQUEST_WORK *WorkRoutine, FSP_IOP_REQUEST_FINI *RequestFini,
BOOLEAN CreateAndPost);
VOID FspWqPostIrpWorkItem(PIRP Irp);
#define FspWqCreateIrpWorkItem(I, RW, RF)\
@ -842,7 +1063,7 @@ static inline
BOOLEAN FspFsvolDeviceVolumePrefixInString(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING String)
{
return RtlPrefixUnicodeString(&FspFsvolDeviceExtension(DeviceObject)->VolumePrefix, String,
FSP_VOLUME_PREFIX_CASE_INS);
TRUE);
}
NTSTATUS FspDeviceCopyList(
PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount);
@ -897,6 +1118,12 @@ enum
FspFileNodeFileKind = 'BZ',
};
enum
{
FspFileNodeSharingViolationGeneral = 'G',
FspFileNodeSharingViolationMainFile = 'M',
FspFileNodeSharingViolationStream = 'S',
};
enum
{
FspFileNodeAcquireMain = 1,
FspFileNodeAcquirePgio = 2,
@ -944,6 +1171,9 @@ typedef struct FSP_FILE_NODE
ULONG StreamInfoChangeNumber;
BOOLEAN TruncateOnClose;
FILE_LOCK FileLock;
#if (NTDDI_VERSION < NTDDI_WIN8)
OPLOCK Oplock;
#endif
struct
{
PVOID LazyWriteThread;
@ -1004,17 +1234,49 @@ VOID FspFileNodeConvertExclusiveToSharedF(FSP_FILE_NODE *FileNode, ULONG Flags);
VOID FspFileNodeSetOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
VOID FspFileNodeReleaseF(FSP_FILE_NODE *FileNode, ULONG Flags);
VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
UINT32 GrantedAccess, UINT32 ShareAccess, NTSTATUS *PResult);
static inline
VOID FspFileNodeAcquireSharedForeign(FSP_FILE_NODE *FileNode)
{
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
ExAcquireResourceSharedLite(FileNode->Header.Resource, TRUE);
}
static inline
VOID FspFileNodeAcquireExclusiveForeign(FSP_FILE_NODE *FileNode)
{
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
ExAcquireResourceExclusiveLite(FileNode->Header.Resource, TRUE);
}
static inline
VOID FspFileNodeReleaseForeign(FSP_FILE_NODE *FileNode)
{
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
ExReleaseResourceLite(FileNode->Header.Resource);
}
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 FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
PFILE_OBJECT FileObject, /* non-0 to remove share access */
BOOLEAN HandleCleanup); /* TRUE to decrement handle count */
NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
UINT64 FlushOffset64, ULONG FlushLength, BOOLEAN FlushAndPurge);
VOID FspFileNodeOverwriteStreams(FSP_FILE_NODE *FileNode);
NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
PDEVICE_OBJECT FsvolDeviceObject,
PIRP OplockIrp,
FSP_FILE_NODE *FileNode,
ULONG AcquireFlags,
PUNICODE_STRING StreamFileName);
NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
FSP_FILE_NODE *FileNode, ULONG AcquireFlags,
PUNICODE_STRING FileName, BOOLEAN CheckingOldName);
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject,
PUNICODE_STRING FileName, BOOLEAN SubpathOnly);
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,
@ -1113,6 +1375,90 @@ BOOLEAN FspMainFileOpenCheck(PIRP Irp)
#define FspFileNodeDereferenceDirInfo(P) FspMetaCacheDereferenceItemBuffer(P)
#define FspFileNodeDereferenceStreamInfo(P) FspMetaCacheDereferenceItemBuffer(P)
#define FspFileNodeUnlockAll(N,F,P) FsRtlFastUnlockAll(&(N)->FileLock, F, P, N)
#if (NTDDI_VERSION < NTDDI_WIN8)
#define FspFileNodeAddrOfOplock(N) (&(N)->Oplock)
#else
#define FspFileNodeAddrOfOplock(N) (&(N)->Header.Oplock)
#endif
/* oplock support */
typedef struct
{
FSP_FILE_NODE *FileNode;
ULONG AcquireFlags;
PVOID PrepareContext;
} FSP_FILE_NODE_OPLOCK_CONTEXT;
static inline
NTSTATUS FspFileNodeOplockFsctl(FSP_FILE_NODE *FileNode, PIRP Irp, ULONG OpenCount)
{
return FspOplockFsctrl(FspFileNodeAddrOfOplock(FileNode), Irp, OpenCount);
}
static inline
BOOLEAN FspFileNodeOplockIsBatch(FSP_FILE_NODE *FileNode)
{
return FsRtlCurrentBatchOplock(FspFileNodeAddrOfOplock(FileNode));
}
static inline
BOOLEAN FspFileNodeOplockIsHandle(FSP_FILE_NODE *FileNode)
{
return FsRtlCurrentOplockH(FspFileNodeAddrOfOplock(FileNode));
}
static inline
NTSTATUS FspFileNodeOplockCheck(FSP_FILE_NODE *FileNode, PIRP Irp)
{
return FspCheckOplock(FspFileNodeAddrOfOplock(FileNode), Irp, 0, 0, 0);
}
static inline
NTSTATUS FspFileNodeOplockCheckEx(FSP_FILE_NODE *FileNode, PIRP Irp, ULONG Flags)
{
return FspCheckOplockEx(FspFileNodeAddrOfOplock(FileNode), Irp, Flags, 0, 0, 0);
}
static inline
NTSTATUS FspFileNodeOplockBreakHandle(FSP_FILE_NODE *FileNode, PIRP Irp, ULONG Flags)
{
return FspOplockBreakH(FspFileNodeAddrOfOplock(FileNode), Irp, Flags, 0, 0, 0);
}
static inline
NTSTATUS FspFileNodeOplockCheckAsyncEx(
FSP_FILE_NODE *FileNode, ULONG AcquireFlags, PVOID PrepareContext,
PIRP Irp,
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
POPLOCK_FS_PREPOST_IRP PostIrpRoutine)
{
FSP_FILE_NODE_OPLOCK_CONTEXT OplockContext;
NTSTATUS Result;
OplockContext.FileNode = FileNode;
OplockContext.AcquireFlags = AcquireFlags;
OplockContext.PrepareContext = PrepareContext;
Result = FspCheckOplock(
FspFileNodeAddrOfOplock(FileNode),
Irp,
&OplockContext,
CompletionRoutine,
PostIrpRoutine);
#if DBG
if (STATUS_SUCCESS == Result && DEBUGTEST(10))
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
PostIrpRoutine(&OplockContext, Irp);
CompletionRoutine(&OplockContext, Irp);
Result = STATUS_PENDING;
}
#endif
return Result;
}
static inline
PVOID FspFileNodeReleaseForOplock(FSP_FILE_NODE_OPLOCK_CONTEXT *OplockContext)
{
FspFileNodeReleaseF(OplockContext->FileNode, OplockContext->AcquireFlags);
return OplockContext->PrepareContext;
}
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp);
VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
#define FspFileNodeOplockCheckAsync(FileNode, AcquireFlags, PrepareContext, Irp)\
FspFileNodeOplockCheckAsyncEx(FileNode, AcquireFlags, (PVOID)(UINT_PTR)PrepareContext, Irp,\
FspFileNodeOplockComplete,FspFileNodeOplockPrepare)
/* multiversion support */
typedef
@ -1144,16 +1490,6 @@ extern ULONG FspMvMdlMappingNoWrite;
* Fixes
*/
/* ObCloseHandle: add missing prototype */
#if (NTDDI_VERSION < NTDDI_WIN7)
NTKERNELAPI
NTSTATUS
ObCloseHandle(
_In_ HANDLE Handle,
_In_ KPROCESSOR_MODE PreviousMode
);
#endif
/* RtlEqualMemory: this is defined as memcmp, which does not exist on Win7 x86! */
#undef RtlEqualMemory
static inline

View File

@ -31,17 +31,28 @@ VOID FspFileNodeConvertExclusiveToSharedF(FSP_FILE_NODE *FileNode, ULONG Flags);
VOID FspFileNodeSetOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
VOID FspFileNodeReleaseF(FSP_FILE_NODE *FileNode, ULONG Flags);
VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
UINT32 GrantedAccess, UINT32 ShareAccess, NTSTATUS *PResult);
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 FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
PFILE_OBJECT FileObject, /* non-0 to remove share access */
BOOLEAN HandleCleanup); /* TRUE to decrement handle count */
NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
UINT64 FlushOffset64, ULONG FlushLength, BOOLEAN FlushAndPurge);
VOID FspFileNodeOverwriteStreams(FSP_FILE_NODE *FileNode);
NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
PDEVICE_OBJECT FsvolDeviceObject,
PIRP OplockIrp,
FSP_FILE_NODE *FileNode,
ULONG AcquireFlags,
PUNICODE_STRING StreamFileName);
NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
FSP_FILE_NODE *FileNode, ULONG AcquireFlags,
PUNICODE_STRING FileName, BOOLEAN CheckingOldName);
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject,
PUNICODE_STRING FileName, BOOLEAN SubpathOnly);
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,
@ -82,6 +93,8 @@ NTSTATUS FspMainFileOpen(
NTSTATUS FspMainFileClose(
HANDLE MainFileHandle,
PFILE_OBJECT MainFileObject);
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp);
VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFileNodeCopyList)
@ -101,8 +114,10 @@ NTSTATUS FspMainFileClose(
#pragma alloc_text(PAGE, FspFileNodeCleanupComplete)
#pragma alloc_text(PAGE, FspFileNodeClose)
#pragma alloc_text(PAGE, FspFileNodeFlushAndPurgeCache)
#pragma alloc_text(PAGE, FspFileNodeOverwriteStreams)
#pragma alloc_text(PAGE, FspFileNodeCheckBatchOplocksOnAllStreams)
#pragma alloc_text(PAGE, FspFileNodeRenameCheck)
#pragma alloc_text(PAGE, FspFileNodeRename)
#pragma alloc_text(PAGE, FspFileNodeHasOpenHandles)
#pragma alloc_text(PAGE, FspFileNodeGetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeSetFileInfo)
@ -126,6 +141,8 @@ NTSTATUS FspMainFileClose(
#pragma alloc_text(PAGE, FspFileDescResetDirectoryPattern)
#pragma alloc_text(PAGE, FspMainFileOpen)
#pragma alloc_text(PAGE, FspMainFileClose)
#pragma alloc_text(PAGE, FspFileNodeOplockPrepare)
#pragma alloc_text(PAGE, FspFileNodeOplockComplete)
#endif
#define FSP_FILE_NODE_GET_FLAGS() \
@ -217,6 +234,7 @@ NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
RtlInitEmptyUnicodeString(&FileNode->FileName, FileNode->FileNameBuf, (USHORT)ExtraSize);
FsRtlInitializeFileLock(&FileNode->FileLock, FspFileNodeCompleteLockIrp, 0);
FsRtlInitializeOplock(FspFileNodeAddrOfOplock(FileNode));
*PFileNode = FileNode;
@ -230,6 +248,7 @@ VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode)
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
FsRtlUninitializeOplock(FspFileNodeAddrOfOplock(FileNode));
FsRtlUninitializeFileLock(&FileNode->FileLock);
FsRtlTeardownPerStreamContexts(&FileNode->Header);
@ -444,8 +463,9 @@ VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
FSP_FILE_NODE_CLR_FLAGS();
}
FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
UINT32 GrantedAccess, UINT32 ShareAccess, NTSTATUS *PResult)
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
UINT32 GrantedAccess, UINT32 ShareAccess,
FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason)
{
/*
* Attempt to insert our FileNode into the volume device's generic table.
@ -462,6 +482,8 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
BOOLEAN Inserted, DeletePending;
NTSTATUS Result;
*PSharingViolationReason = FspFileNodeSharingViolationGeneral;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
/*
@ -489,6 +511,8 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
FlagOn(GrantedAccess,
FILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE))
{
OpenedFileNode = FileNode->MainFileNode;
*PSharingViolationReason = FspFileNodeSharingViolationMainFile;
Result = STATUS_SHARING_VIOLATION;
goto exit;
}
@ -539,6 +563,7 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
if (FlagOn(GrantedAccess, DELETE))
{
*PSharingViolationReason = FspFileNodeSharingViolationStream;
Result = STATUS_SHARING_VIOLATION;
goto exit;
}
@ -593,13 +618,8 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
{
if (0 != PResult)
*PResult = Result;
if (!NT_SUCCESS(Result) && STATUS_SHARING_VIOLATION != Result)
OpenedFileNode = 0;
}
if (0 != OpenedFileNode)
{
@ -610,7 +630,9 @@ exit:
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
return OpenedFileNode;
*POpenedFileNode = OpenedFileNode;
return Result;
}
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
@ -695,9 +717,11 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
{
PTruncateSize = &TruncateSize;
if (0 == --FileNode->OpenCount)
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName,
&DeletedFromContextTable);
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName,
&DeletedFromContextTable);
ASSERT(DeletedFromContextTable);
FileNode->OpenCount = 0;
}
else if (FileNode->TruncateOnClose && FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
{
@ -718,7 +742,9 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
FspFileNodeDereference(FileNode);
}
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject)
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
PFILE_OBJECT FileObject, /* non-0 to remove share access */
BOOLEAN HandleCleanup) /* TRUE to decrement handle count */
{
/*
* Close the FileNode. If the OpenCount becomes zero remove it
@ -734,9 +760,36 @@ VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject)
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
if (0 != FileObject)
{
/*
* Sharing violations between main file and streams were determined
* through experimentation with NTFS. They may be wrong!
*/
if (0 == FileNode->MainFileNode)
{
if (FileObject->DeleteAccess)
FileNode->MainFileDenyDeleteCount--;
}
else
{
if ((FileObject->ReadAccess || FileObject->WriteAccess || FileObject->DeleteAccess) &&
!FileObject->SharedDelete)
FileNode->MainFileNode->StreamDenyDeleteCount--;
}
IoRemoveShareAccess(FileObject, &FileNode->ShareAccess);
}
if (HandleCleanup)
FileNode->HandleCount--;
if (0 < FileNode->OpenCount && 0 == --FileNode->OpenCount)
{
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName,
&DeletedFromContextTable);
ASSERT(DeletedFromContextTable);
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
@ -801,57 +854,440 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
return IoStatus.Status;
}
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
#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)
{
/*
* Called during Create processing. The device rename resource has been acquired shared.
* No concurrent renames are allowed.
*/
PAGED_CODE();
ASSERT(0 == FileNode->MainFileNode);
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
USHORT FileNameLength = FileNode->FileName.Length;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
GATHER_DESCENDANTS(&FileNode->FileName, FALSE,
if (DescendantFileNode->FileName.Length > FileNameLength &&
L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)])
break;
if (FileNode == DescendantFileNode || 0 >= DescendantFileNode->HandleCount)
continue;
);
/* mark any open named streams as DeletePending */
for (
DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
DescendantFileNode->DeletePending = TRUE;
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
SCATTER_DESCENDANTS(FALSE);
}
NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
PDEVICE_OBJECT FsvolDeviceObject,
PIRP OplockIrp,
FSP_FILE_NODE *FileNode,
ULONG AcquireFlags,
PUNICODE_STRING StreamFileName)
{
/*
* Called during Create processing. The device rename resource has been acquired shared.
* No concurrent renames are allowed.
*/
PAGED_CODE();
ASSERT(0 == FileNode->MainFileNode);
USHORT FileNameLength = FileNode->FileName.Length;
BOOLEAN CaseInsensitive = !FspFsvolDeviceExtension(FsvolDeviceObject)->
VolumeParams.CaseSensitiveSearch;
ULONG IsBatchOplock, IsHandleOplock;
NTSTATUS Result;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
GATHER_DESCENDANTS(&FileNode->FileName, TRUE,
if (DescendantFileNode->FileName.Length > FileNameLength &&
L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)])
break;
if (0 >= DescendantFileNode->HandleCount)
continue;
if (0 != StreamFileName)
{
if (DescendantFileNode != FileNode &&
0 != FspFileNameCompare(&DescendantFileNode->FileName, StreamFileName,
CaseInsensitive, 0))
continue;
});
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
/* break any Batch or Handle oplocks on descendants */
Result = STATUS_SUCCESS;
for (
DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
if (FspFileNodeOplockIsBatch(DescendantFileNode))
{
NTSTATUS Result0 = FspFileNodeOplockCheckEx(DescendantFileNode, OplockIrp,
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
if (STATUS_SUCCESS == Result0)
OplockIrp->IoStatus.Information = FILE_OPBATCH_BREAK_UNDERWAY;
else
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result0)
{
OplockIrp->IoStatus.Information = FILE_OPBATCH_BREAK_UNDERWAY;
DescendantFileNodes[DescendantFileNodeIndex] =
(PVOID)((UINT_PTR)DescendantFileNode | 2);
}
else
Result = STATUS_SHARING_VIOLATION;
}
else
if (FspFileNodeOplockIsHandle(DescendantFileNode))
{
NTSTATUS Result0 = FspFileNodeOplockBreakHandle(DescendantFileNode, OplockIrp,
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
if (STATUS_SUCCESS == Result0)
;
else
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result0)
DescendantFileNodes[DescendantFileNodeIndex] =
(PVOID)((UINT_PTR)DescendantFileNode | 4);
else
Result = STATUS_SHARING_VIOLATION;
}
}
/* release the FileNode so that we can safely wait without deadlocks */
FspFileNodeReleaseF(FileNode, AcquireFlags);
/* wait for oplock breaks to finish */
Result = STATUS_SUCCESS;
for (
DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
IsBatchOplock = (UINT_PTR)DescendantFileNode & 2;
IsHandleOplock = (UINT_PTR)DescendantFileNode & 4;
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
if (IsBatchOplock)
{
NTSTATUS Result0 = FspFileNodeOplockCheck(DescendantFileNode, OplockIrp);
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result0);
if (STATUS_SUCCESS != Result0)
Result = STATUS_SHARING_VIOLATION;
}
else
if (IsHandleOplock)
{
NTSTATUS Result0 = FspFileNodeOplockBreakHandle(DescendantFileNode, OplockIrp, 0);
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result0);
if (STATUS_SUCCESS != Result0)
Result = STATUS_SHARING_VIOLATION;
}
}
SCATTER_DESCENDANTS(TRUE);
return Result;
}
NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
FSP_FILE_NODE *FileNode, ULONG AcquireFlags,
PUNICODE_STRING FileName, BOOLEAN CheckingOldName)
{
PAGED_CODE();
NTSTATUS Result;
ULONG HasHandles, IsBatchOplock, IsHandleOplock;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
if (CheckingOldName && !FileNode->IsDirectory && 1 == FileNode->HandleCount)
{
/* quick exit */
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
return STATUS_SUCCESS;
}
GATHER_DESCENDANTS(FileName, TRUE,
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode |
(0 < DescendantFileNode->HandleCount)));
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (0 == DescendantFileNodeCount)
{
Result = STATUS_SUCCESS;
goto exit;
}
/*
* At this point all descendant FileNode's are enumerated and referenced.
* There can be no new FileNode's because Rename has acquired the device's
* "rename" resource exclusively, which disallows new Opens.
*/
if (!CheckingOldName)
{
/* replaced file cannot be a directory or mapped as an image */
for (
DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
/*
* Windows file systems do not allow the replaced file to be a directory.
* However POSIX allows this (when the directory is empty).
*
* For this reason we will allow the case where the replaced file is a directory
* (without any open files within it). The user mode file system can always fail
* such requests if it wants.
*/
if ((DescendantFileNode->FileName.Length > FileName->Length &&
L'\\' == DescendantFileNode->FileName.Buffer[FileName->Length / sizeof(WCHAR)]) ||
(0 != DescendantFileNode->NonPaged->SectionObjectPointers.ImageSectionObject &&
!MmFlushImageSection(&DescendantFileNode->NonPaged->SectionObjectPointers,
MmFlushForDelete)))
{
/* release the FileNode in case of failure! */
FspFileNodeReleaseF(FileNode, AcquireFlags);
Result = STATUS_ACCESS_DENIED;
goto exit;
}
}
}
/* break any Batch or Handle oplocks on descendants */
Result = STATUS_SUCCESS;
for (
DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
HasHandles = (UINT_PTR)DescendantFileNode & 1;
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
if (!HasHandles)
continue;
if (FspFileNodeOplockIsBatch(DescendantFileNode))
{
NTSTATUS Result0 = FspFileNodeOplockCheckEx(DescendantFileNode, OplockIrp,
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
if (STATUS_SUCCESS == Result0)
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
else
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result0)
{
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
DescendantFileNodes[DescendantFileNodeIndex] =
(PVOID)((UINT_PTR)DescendantFileNode | 2);
}
else
Result = STATUS_ACCESS_DENIED;
}
else
if (FspFileNodeOplockIsHandle(DescendantFileNode))
{
NTSTATUS Result0 = FspFileNodeOplockBreakHandle(DescendantFileNode, OplockIrp,
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
if (STATUS_SUCCESS == Result0)
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
else
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result0)
{
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
DescendantFileNodes[DescendantFileNodeIndex] =
(PVOID)((UINT_PTR)DescendantFileNode | 2);
}
else
Result = STATUS_ACCESS_DENIED;
}
}
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result || !NT_SUCCESS(Result))
{
/* release the FileNode so that we can safely wait without deadlocks */
FspFileNodeReleaseF(FileNode, AcquireFlags);
/* wait for oplock breaks to finish */
for (
DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
IsBatchOplock = (UINT_PTR)DescendantFileNode & 2;
IsHandleOplock = (UINT_PTR)DescendantFileNode & 4;
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
if (IsBatchOplock)
{
NTSTATUS Result0 = FspFileNodeOplockCheck(DescendantFileNode, OplockIrp);
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result0);
if (STATUS_SUCCESS != Result0)
Result = STATUS_ACCESS_DENIED;
}
else
if (IsHandleOplock)
{
NTSTATUS Result0 = FspFileNodeOplockBreakHandle(DescendantFileNode, OplockIrp, 0);
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result0);
if (STATUS_SUCCESS != Result0)
Result = STATUS_ACCESS_DENIED;
}
}
goto exit;
}
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
/* recheck whether there are still files with open handles */
memset(&RestartKey, 0, sizeof RestartKey);
for (;;)
{
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
FileName, FALSE, &RestartKey);
if (0 == DescendantFileNode)
break;
/* if this is the FileNode being renamed then HandleCount must be 1, else 0 */
if ((DescendantFileNode == FileNode) < DescendantFileNode->HandleCount)
{
/* release the FileNode in case of failure! */
FspFileNodeReleaseF(FileNode, AcquireFlags);
Result = STATUS_ACCESS_DENIED;
break;
}
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
exit:
SCATTER_DESCENDANTS(TRUE);
return Result;
}
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
{
/*
* FspFileNodeRename may block, because it attempts to acquire the Main
* resource of descendant file nodes. FspFileNodeRename is called at the
* completion path of IRP_MJ_SET_INFORMATION[Rename] and an IRP completion
* path should not block, with the notable exception of Rename.
*
* The original reason that Rename completion is allowed to block was that
* it was observed that IoCompleteRequest of a Rename could sometimes
* trigger a recursive call into the FSD (likely due to a filter). WinFsp
* was modified to accommodate this by allowing this recursive call to
* proceed on a different thread.
*
* Since WinFsp can already accommodate blocking on Rename completions,
* it is safe to acquire the Main resource of descendant file nodes.
*
* Note also that there can only be one rename at a time because of the
* device's FileRenameResource.
*/
PAGED_CODE();
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FILE_NODE *DescendantFileNode;
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;
BOOLEAN Deleted, Inserted;
BOOLEAN Deleted, Inserted, AcquireForeign;
FSP_FILE_NODE *InsertedFileNode;
USHORT FileNameLength;
PWSTR ExternalFileName;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
DescendantFileNodes = DescendantFileNodeArray;
DescendantFileNodes[0] = FileNode;
DescendantFileNodeCount = 1;
memset(&RestartKey, 0, sizeof RestartKey);
for (;;)
{
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
&FileNode->FileName, TRUE, &RestartKey);
if (0 == DescendantFileNode)
break;
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;
DescendantFileNodeCount++;
}
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount)
{
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));
DescendantFileNodes[0] = FileNode;
DescendantFileNodeIndex = 1;
memset(&RestartKey, 0, sizeof RestartKey);
for (;;)
{
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
&FileNode->FileName, TRUE, &RestartKey);
if (0 == DescendantFileNode)
break;
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode;
DescendantFileNodeIndex++;
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);
}
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);
}
GATHER_DESCENDANTS(&FileNode->FileName, FALSE, {});
FileNameLength = FileNode->FileName.Length;
for (
@ -862,6 +1298,11 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
ASSERT(DescendantFileNode->FileName.Length >= FileNameLength);
AcquireForeign = DescendantFileNode->FileName.Length > FileNameLength &&
L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)];
if (AcquireForeign)
FspFileNodeAcquireExclusiveForeign(DescendantFileNode);
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &DescendantFileNode->FileName, &Deleted);
ASSERT(Deleted);
@ -885,38 +1326,41 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
if (0 != ExternalFileName)
FspFree(ExternalFileName);
FspFsvolDeviceInsertContextByName(FsvolDeviceObject, &DescendantFileNode->FileName, DescendantFileNode,
InsertedFileNode = FspFsvolDeviceInsertContextByName(
FsvolDeviceObject, &DescendantFileNode->FileName, DescendantFileNode,
&DescendantFileNode->ContextByNameElementStorage, &Inserted);
ASSERT(Inserted);
if (!Inserted)
{
/*
* Handle files that have been Cleanup'ed but not Close'd.
* For example, this can happen when the user has mapped and closed a file
* or immediately after breaking a Batch oplock.
*/
ASSERT(FspFileNodeIsValid(InsertedFileNode));
ASSERT(DescendantFileNode != InsertedFileNode);
ASSERT(0 == InsertedFileNode->HandleCount);
ASSERT(0 != InsertedFileNode->OpenCount);
InsertedFileNode->OpenCount = 0;
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &InsertedFileNode->FileName, &Deleted);
ASSERT(Deleted);
FspFileNodeDereference(InsertedFileNode);
FspFsvolDeviceInsertContextByName(
FsvolDeviceObject, &DescendantFileNode->FileName, DescendantFileNode,
&DescendantFileNode->ContextByNameElementStorage, &Inserted);
ASSERT(Inserted);
}
if (AcquireForeign)
FspFileNodeReleaseForeign(DescendantFileNode);
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (DescendantFileNodeArray != DescendantFileNodes)
FspFree(DescendantFileNodes);
}
BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject,
PUNICODE_STRING FileName, BOOLEAN SubpathOnly)
{
/*
* The ContextByNameTable must be already locked.
*/
PAGED_CODE();
FSP_FILE_NODE *FileNode;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey = { 0 };
for (;;)
{
FileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject, FileName, SubpathOnly,
&RestartKey);
if (0 == FileNode)
return FALSE;
if (0 < FileNode->HandleCount)
return TRUE;
}
SCATTER_DESCENDANTS(FALSE);
}
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo)
@ -1009,9 +1453,52 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
CcFileObject, (PCC_FILE_SIZES)&FileNode->Header.AllocationSize);
if (!NT_SUCCESS(Result))
{
DEBUGLOG("FspCcSetFileSizes error: %s", NtStatusSym(Result));
DEBUGBREAK_CRIT();
CcUninitializeCacheMap(CcFileObject, 0, 0);
/*
* CcSetFileSizes failed. This is a hard case to handle, because it is
* usually late in IRP processing. So we have the following strategy.
*
* Our goal is to completely stop all caching for this FileNode. The idea
* is that if some I/O arrives later for this FileNode, CcInitializeCacheMap
* will be executed (and possibly fail safely there). In fact we may decide
* later to make such CcInitializeCacheMap failures benign (by not using the
* cache when we cannot).
*
* In order to completely stop caching for the FileNode we do the following:
*
* - We flush the cache using CcFlushCache.
* - We purge the cache and uninitialize all PrivateCacheMap's using
* CcPurgeCacheSection with UninitializeCacheMaps==TRUE.
* - If the SharedCacheMap is still around, we perform an additional
* CcUninitializeCacheMap with an UninitializeEvent. At this point
* CcUninitializeCacheMap should delete the SharedCacheMap and
* signal the UninitializeEvent.
*
* One potential gotcha is whether there is any possibility for another
* system component to delay deletion of the SharedCacheMap and signaling
* of the UninitializeEvent. This could result in a deadlock, because we
* are already holding the FileNode exclusive and waiting for the
* UninitializeEvent. But the thread that would signal our event would have
* to first acquire our FileNode. Classic deadlock.
*
* I believe (but cannot prove) that this deadlock cannot happen. The reason
* is that we have flushed and purged the cache and we have closed all
* PrivateCacheMap's using this SharedCacheMap. There should be no reason for
* any system component to keep the SharedCacheMap around (famous last words).
*/
IO_STATUS_BLOCK IoStatus;
CACHE_UNINITIALIZE_EVENT UninitializeEvent;
FspCcFlushCache(CcFileObject->SectionObjectPointer, 0, 0, &IoStatus);
CcPurgeCacheSection(CcFileObject->SectionObjectPointer, 0, 0, TRUE);
if (0 != CcFileObject->SectionObjectPointer->SharedCacheMap)
{
UninitializeEvent.Next = 0;
KeInitializeEvent(&UninitializeEvent.Event, NotificationEvent, FALSE);
BOOLEAN CacheStopped = CcUninitializeCacheMap(CcFileObject, 0, &UninitializeEvent);
(VOID)CacheStopped; ASSERT(CacheStopped);
KeWaitForSingleObject(&UninitializeEvent.Event, Executive, KernelMode, FALSE, 0);
}
}
}
}
@ -1231,7 +1718,7 @@ VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
UNICODE_STRING Parent, Suffix;
FSP_FILE_NODE *ParentNode;
FspUnicodePathSuffix(&FileNode->FileName, &Parent, &Suffix);
FspFileNameSuffix(&FileNode->FileName, &Parent, &Suffix);
switch (Action)
{
@ -1428,7 +1915,7 @@ NTSTATUS FspMainFileOpen(
PFILE_OBJECT MainFileObject;
/* assert that the supplied name is actually a main file name */
ASSERT(FspUnicodePathIsValid(MainFileName, 0, 0));
ASSERT(FspFileNameIsValid(MainFileName, 0, 0));
*PMainFileHandle = 0;
*PMainFileObject = 0;
@ -1570,6 +2057,36 @@ NTSTATUS FspMainFileClose(
return Result;
}
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp)
{
PAGED_CODE();
FSP_IOP_REQUEST_WORK *WorkRoutine = (FSP_IOP_REQUEST_WORK *)(UINT_PTR)
FspFileNodeReleaseForOplock(Context);
NTSTATUS Result;
FSP_FSCTL_STATIC_ASSERT(sizeof(PVOID) == sizeof(VOID (*)(VOID)),
"Data and code pointers must have same size!");
Result = FspWqCreateIrpWorkItem(Irp, WorkRoutine, 0);
if (!NT_SUCCESS(Result))
/*
* Only way to communicate failure is through ExRaiseStatus.
* We will catch it in FspCheckOplock, etc.
*/
ExRaiseStatus(Result);
}
VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp)
{
PAGED_CODE();
if (STATUS_SUCCESS == Irp->IoStatus.Status)
FspWqPostIrpWorkItem(Irp);
else
FspIopCompleteIrp(Irp, Irp->IoStatus.Status);
}
WCHAR FspFileDescDirectoryPatternMatchAll[] = L"*";
// {904862B4-EB3F-461E-ACB2-4DF2B3FC898B}

View File

@ -26,6 +26,8 @@ static NTSTATUS FspFsvolQueryAttributeTagInformation(PFILE_OBJECT FileObject,
static NTSTATUS FspFsvolQueryBasicInformation(PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd,
const FSP_FSCTL_FILE_INFO *FileInfo);
static NTSTATUS FspFsvolQueryEaInformation(PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd);
static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd);
static NTSTATUS FspFsvolQueryNameInformation(PFILE_OBJECT FileObject,
@ -80,6 +82,7 @@ FSP_DRIVER_DISPATCH FspSetInformation;
#pragma alloc_text(PAGE, FspFsvolQueryAllInformation)
#pragma alloc_text(PAGE, FspFsvolQueryAttributeTagInformation)
#pragma alloc_text(PAGE, FspFsvolQueryBasicInformation)
#pragma alloc_text(PAGE, FspFsvolQueryEaInformation)
#pragma alloc_text(PAGE, FspFsvolQueryInternalInformation)
#pragma alloc_text(PAGE, FspFsvolQueryNameInformation)
#pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation)
@ -119,7 +122,7 @@ enum
//RequestFileNode = 0,
RequestDeviceObject = 1,
/* Rename */
RequestAccessToken = 2,
RequestSubjectContextOrAccessToken = 2,
RequestProcess = 3,
};
@ -216,6 +219,27 @@ static NTSTATUS FspFsvolQueryBasicInformation(PFILE_OBJECT FileObject,
return STATUS_SUCCESS;
}
static NTSTATUS FspFsvolQueryEaInformation(PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd)
{
PAGED_CODE();
PFILE_EA_INFORMATION Info = (PFILE_EA_INFORMATION)*PBuffer;
if ((PVOID)(Info + 1) > BufferEnd)
return STATUS_BUFFER_TOO_SMALL;
/*
* No EA support currently. We must nevertheless respond to this query
* or SRV2 gets unhappy. Just tell them that we have 0 EA's.
*/
Info->EaSize = 0;
*PBuffer = (PVOID)(Info + 1);
return STATUS_SUCCESS;
}
static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd)
{
@ -546,7 +570,7 @@ static NTSTATUS FspFsvolQueryStreamInformationSuccess(
(PUINT8)Response + Response->Size)
{
Irp->IoStatus.Information = 0;
return STATUS_INFO_LENGTH_MISMATCH; /* ???: what is the best code to return here? */
return STATUS_INTERNAL_ERROR;
}
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)
@ -635,7 +659,8 @@ static NTSTATUS FspFsvolQueryInformation(
Result = STATUS_INVALID_PARAMETER; /* no compression support */
return Result;
case FileEaInformation:
Result = STATUS_INVALID_PARAMETER; /* no EA support currently */
Result = FspFsvolQueryEaInformation(FileObject, &Buffer, BufferEnd);
Irp->IoStatus.Information = (UINT_PTR)((PUINT8)Buffer - (PUINT8)Irp->AssociatedIrp.SystemBuffer);
return Result;
case FileHardLinkInformation:
Result = STATUS_INVALID_PARAMETER; /* no hard link support */
@ -871,6 +896,9 @@ static NTSTATUS FspFsvolSetAllocationInformation(PFILE_OBJECT FileObject,
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetInformation.FileInfo);
FileNode->TruncateOnClose = TRUE;
/* mark the file object as modified */
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
}
@ -971,6 +999,9 @@ static NTSTATUS FspFsvolSetEndOfFileInformation(PFILE_OBJECT FileObject,
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetInformation.FileInfo);
FileNode->TruncateOnClose = 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);
}
@ -1019,10 +1050,37 @@ static NTSTATUS FspFsvolSetDispositionInformation(
/* cannot delete root directory */
return STATUS_CANNOT_DELETE;
retry:
FspFileNodeAcquireExclusive(FileNode, Full);
if (Info->DeleteFile)
{
/*
* Perform oplock check.
*
* It is ok to block our thread during receipt of the SetInformation IRP.
* However we cannot acquire the FileNode exclusive and wait for oplock
* breaks to complete, because oplock break processing acquires the FileNode
* shared.
*
* Instead we initiate the oplock breaks and then check if any are in progress.
* If that is the case we release the FileNode and wait for the oplock breaks
* to complete. Once they are complete we retry the whole thing.
*/
Result = FspFileNodeOplockCheckEx(FileNode, Irp,
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result ||
DEBUGTEST_EX(NT_SUCCESS(Result), 10, FALSE))
{
FspFileNodeRelease(FileNode, Full);
Result = FspFileNodeOplockCheck(FileNode, Irp);
if (!NT_SUCCESS(Result))
return Result;
goto retry;
}
if (!NT_SUCCESS(Result))
goto unlock_exit;
/* make sure no process is mapping the file as an image */
Success = MmFlushImageSection(FileObject->SectionObjectPointer, MmFlushForDelete);
if (!Success)
@ -1095,17 +1153,19 @@ static NTSTATUS FspFsvolSetRenameInformation(
NTSTATUS Result;
PFILE_OBJECT FileObject = IrpSp->FileObject;
PFILE_OBJECT TargetFileObject = IrpSp->Parameters.SetFile.FileObject;
BOOLEAN ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
PFILE_RENAME_INFORMATION Info = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
ULONG Length = IrpSp->Parameters.SetFile.Length;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
FSP_FILE_NODE *TargetFileNode = 0 != TargetFileObject ?
TargetFileObject->FsContext : 0;
FSP_FSCTL_TRANSACT_REQ *Request;
FSP_FSCTL_TRANSACT_REQ *Request = 0;
UNICODE_STRING Remain, Suffix;
UNICODE_STRING NewFileName;
PUINT8 NewFileNameBuffer;
BOOLEAN AppendBackslash;
PSECURITY_SUBJECT_CONTEXT SecuritySubjectContext = 0;
ASSERT(FileNode == FileDesc->FileNode);
@ -1116,7 +1176,7 @@ static NTSTATUS FspFsvolSetRenameInformation(
if (FileNode->IsRootDirectory)
/* cannot rename root directory */
return STATUS_INVALID_PARAMETER;
if (!FspUnicodePathIsValid(&FileNode->FileName, 0, 0))
if (!FspFileNameIsValid(&FileNode->FileName, 0, 0))
/* cannot rename streams (WinFsp limitation) */
return STATUS_INVALID_PARAMETER;
@ -1129,56 +1189,61 @@ static NTSTATUS FspFsvolSetRenameInformation(
}
FspFsvolDeviceFileRenameAcquireExclusive(FsvolDeviceObject);
retry:
FspFileNodeAcquireExclusive(FileNode, Full);
if (0 != TargetFileNode)
Remain = TargetFileNode->FileName;
else
FspUnicodePathSuffix(&FileNode->FileName, &Remain, &Suffix);
Suffix.Length = Suffix.MaximumLength = (USHORT)Info->FileNameLength;
Suffix.Buffer = Info->FileName;
if (L'\\' == Suffix.Buffer[0])
FspUnicodePathSuffix(&Suffix, &NewFileName, &Suffix);
if (!FspUnicodePathIsValid(&Remain, 0, 0) || !FspUnicodePathIsValid(&Suffix, 0, 0))
if (0 == Request)
{
/* cannot rename streams (WinFsp limitation) */
Result = STATUS_INVALID_PARAMETER;
goto unlock_exit;
if (0 != TargetFileNode)
Remain = TargetFileNode->FileName;
else
FspFileNameSuffix(&FileNode->FileName, &Remain, &Suffix);
Suffix.Length = (USHORT)Info->FileNameLength;
Suffix.Buffer = Info->FileName;
/* if there is a backslash anywhere in the NewFileName get its suffix */
for (PWSTR P = Suffix.Buffer, EndP = P + Suffix.Length / sizeof(WCHAR); EndP > P; P++)
if (L'\\' == *P)
{
Suffix.Length = (USHORT)((EndP - P - 1) * sizeof(WCHAR));
Suffix.Buffer = P + 1;
}
Suffix.MaximumLength = Suffix.Length;
if (!FspFileNameIsValid(&Remain, 0, 0) || !FspFileNameIsValid(&Suffix, 0, 0))
{
/* cannot rename streams (WinFsp limitation) */
Result = STATUS_INVALID_PARAMETER;
goto unlock_exit;
}
AppendBackslash = sizeof(WCHAR) < Remain.Length;
NewFileName.Length = NewFileName.MaximumLength =
Remain.Length + AppendBackslash * sizeof(WCHAR) + Suffix.Length;
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName,
NewFileName.Length + sizeof(WCHAR),
FspFsvolSetInformationRequestFini, &Request);
if (!NT_SUCCESS(Result))
goto unlock_exit;
NewFileNameBuffer = Request->Buffer + Request->FileName.Size;
NewFileName.Buffer = (PVOID)NewFileNameBuffer;
RtlCopyMemory(NewFileNameBuffer, Remain.Buffer, Remain.Length);
*(PWSTR)(NewFileNameBuffer + Remain.Length) = L'\\';
RtlCopyMemory(NewFileNameBuffer + Remain.Length + AppendBackslash * sizeof(WCHAR),
Suffix.Buffer, Suffix.Length);
*(PWSTR)(NewFileNameBuffer + NewFileName.Length) = L'\0';
Request->Kind = FspFsctlTransactSetInformationKind;
Request->Req.SetInformation.UserContext = FileNode->UserContext;
Request->Req.SetInformation.UserContext2 = FileDesc->UserContext2;
Request->Req.SetInformation.FileInformationClass = FileRenameInformation;
Request->Req.SetInformation.Info.Rename.NewFileName.Offset = Request->FileName.Size;
Request->Req.SetInformation.Info.Rename.NewFileName.Size = NewFileName.Length + sizeof(WCHAR);
}
AppendBackslash = sizeof(WCHAR) < Remain.Length;
NewFileName.Length = NewFileName.MaximumLength =
Remain.Length + AppendBackslash * sizeof(WCHAR) + Suffix.Length;
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName,
NewFileName.Length + sizeof(WCHAR),
FspFsvolSetInformationRequestFini, &Request);
if (!NT_SUCCESS(Result))
goto unlock_exit;
NewFileNameBuffer = Request->Buffer + Request->FileName.Size;
NewFileName.Buffer = (PVOID)NewFileNameBuffer;
RtlCopyMemory(NewFileNameBuffer, Remain.Buffer, Remain.Length);
*(PWSTR)(NewFileNameBuffer + Remain.Length) = L'\\';
RtlCopyMemory(NewFileNameBuffer + Remain.Length + AppendBackslash * sizeof(WCHAR),
Suffix.Buffer, Suffix.Length);
*(PWSTR)(NewFileNameBuffer + NewFileName.Length) = L'\0';
Request->Kind = FspFsctlTransactSetInformationKind;
Request->Req.SetInformation.UserContext = FileNode->UserContext;
Request->Req.SetInformation.UserContext2 = FileDesc->UserContext2;
Request->Req.SetInformation.FileInformationClass = FileRenameInformation;
Request->Req.SetInformation.Info.Rename.NewFileName.Offset = Request->FileName.Size;
Request->Req.SetInformation.Info.Rename.NewFileName.Size = NewFileName.Length + sizeof(WCHAR);
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
/*
* Special rules for renaming open files:
* - A file cannot be renamed if it has any open handles,
@ -1190,21 +1255,72 @@ static NTSTATUS FspFsvolSetRenameInformation(
* that has open handles (except in the batch-oplock case described earlier).
*/
Result = STATUS_SUCCESS;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
if (1 < FileNode->HandleCount ||
(FileNode->IsDirectory &&
FspFileNodeHasOpenHandles(FsvolDeviceObject, &FileNode->FileName, TRUE)) ||
FspFileNodeHasOpenHandles(FsvolDeviceObject, &NewFileName, FALSE))
Result = STATUS_ACCESS_DENIED;
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
Result = FspFileNodeRenameCheck(FsvolDeviceObject, Irp,
FileNode, FspFileNodeAcquireFull,
&FileNode->FileName, TRUE);
/* FspFileNodeRenameCheck releases FileNode with STATUS_OPLOCK_BREAK_IN_PROGRESS or failure */
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result)
goto retry;
if (!NT_SUCCESS(Result))
return Result;
{
Result = STATUS_ACCESS_DENIED;
goto rename_unlock_exit;
}
if (0 != FspFileNameCompare(&FileNode->FileName, &NewFileName, !FileDesc->CaseSensitive, 0))
{
Result = FspFileNodeRenameCheck(FsvolDeviceObject, Irp,
FileNode, FspFileNodeAcquireFull,
&NewFileName, FALSE);
/* FspFileNodeRenameCheck releases FileNode with STATUS_OPLOCK_BREAK_IN_PROGRESS or failure */
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result)
goto retry;
if (!NT_SUCCESS(Result))
{
Result = STATUS_ACCESS_DENIED;
goto rename_unlock_exit;
}
}
else
{
/*
* If the new file name is *exactly* the same (including case) as the old one,
* there is no need to go to the user mode file system. Just return STATUS_SUCCESS.
* Our RequestFini will do any cleanup necessary.
*
* This check needs to be done *after* the open handle test above. This is what FASTFAT
* and NTFS do.
*/
if (0 == FspFileNameCompare(&FileNode->FileName, &NewFileName, FALSE, 0))
{
Result = STATUS_SUCCESS;
goto unlock_exit;
}
}
/* capture the security context */
if (ReplaceIfExists)
{
SecuritySubjectContext = FspAlloc(sizeof *SecuritySubjectContext);
if (0 == SecuritySubjectContext)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto unlock_exit;
}
SeCaptureSubjectContext(SecuritySubjectContext);
}
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
FspIopRequestContext(Request, RequestSubjectContextOrAccessToken) = SecuritySubjectContext;
return FSP_STATUS_IOQ_POST;
unlock_exit:
FspFileNodeRelease(FileNode, Full);
rename_unlock_exit:
FspFsvolDeviceFileRenameRelease(FsvolDeviceObject);
return Result;
@ -1308,16 +1424,54 @@ static NTSTATUS FspFsvolSetInformation(
ASSERT(FileNode == FileDesc->FileNode);
retry:
FspFileNodeAcquireExclusive(FileNode, Full);
if (FileAllocationInformation == FileInformationClass ||
FileEndOfFileInformation == FileInformationClass)
{
/*
* Perform oplock check.
*
* It is ok to block our thread during receipt of the SetInformation IRP.
* However we cannot acquire the FileNode exclusive and wait for oplock
* breaks to complete, because oplock break processing acquires the FileNode
* shared.
*
* Instead we initiate the oplock breaks and then check if any are in progress.
* If that is the case we release the FileNode and wait for the oplock breaks
* to complete. Once they are complete we retry the whole thing.
*/
Result = FspFileNodeOplockCheckEx(FileNode, Irp,
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result ||
DEBUGTEST_EX(NT_SUCCESS(Result), 10, FALSE))
{
FspFileNodeRelease(FileNode, Full);
Result = FspFileNodeOplockCheck(FileNode, Irp);
if (!NT_SUCCESS(Result))
return Result;
goto retry;
}
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
return Result;
}
}
Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolSetInformationRequestFini, &Request);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
return Result;
}
Request->Kind = FspFsctlTransactSetInformationKind;
Request->Req.SetInformation.UserContext = FileNode->UserContext;
Request->Req.SetInformation.UserContext2 = FileDesc->UserContext2;
Request->Req.SetInformation.FileInformationClass = FileInformationClass;
FspFileNodeAcquireExclusive(FileNode, Full);
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
@ -1352,32 +1506,36 @@ NTSTATUS FspFsvolSetInformationPrepare(
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
if (FileRenameInformation != IrpSp->Parameters.SetFile.FileInformationClass ||
!IrpSp->Parameters.SetFile.ReplaceIfExists)
0 == FspIopRequestContext(Request, RequestSubjectContextOrAccessToken))
return STATUS_SUCCESS;
NTSTATUS Result;
SECURITY_SUBJECT_CONTEXT SecuritySubjectContext;
PSECURITY_SUBJECT_CONTEXT SecuritySubjectContext;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
SECURITY_CLIENT_CONTEXT SecurityClientContext;
HANDLE UserModeAccessToken;
PEPROCESS Process;
SecuritySubjectContext = FspIopRequestContext(Request, RequestSubjectContextOrAccessToken);
/* duplicate the subject context access token into an impersonation token */
SecurityQualityOfService.Length = sizeof SecurityQualityOfService;
SecurityQualityOfService.ImpersonationLevel = SecurityIdentification;
SecurityQualityOfService.ContextTrackingMode = SECURITY_STATIC_TRACKING;
SecurityQualityOfService.EffectiveOnly = FALSE;
SeCaptureSubjectContext(&SecuritySubjectContext);
SeLockSubjectContext(&SecuritySubjectContext);
Result = SeCreateClientSecurityFromSubjectContext(&SecuritySubjectContext,
SeLockSubjectContext(SecuritySubjectContext);
Result = SeCreateClientSecurityFromSubjectContext(SecuritySubjectContext,
&SecurityQualityOfService, FALSE, &SecurityClientContext);
SeUnlockSubjectContext(&SecuritySubjectContext);
SeReleaseSubjectContext(&SecuritySubjectContext);
SeUnlockSubjectContext(SecuritySubjectContext);
if (!NT_SUCCESS(Result))
return Result;
ASSERT(TokenImpersonation == SeTokenType(SecurityClientContext.ClientToken));
SeReleaseSubjectContext(SecuritySubjectContext);
FspFree(SecuritySubjectContext);
FspIopRequestContext(Request, RequestSubjectContextOrAccessToken) = 0;
/* get a user-mode handle to the impersonation token */
Result = ObOpenObjectByPointer(SecurityClientContext.ClientToken,
0, 0, TOKEN_QUERY, *SeTokenObjectType, UserMode, &UserModeAccessToken);
@ -1390,7 +1548,7 @@ NTSTATUS FspFsvolSetInformationPrepare(
ObReferenceObject(Process);
/* send the user-mode handle to the user-mode file system */
FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken;
FspIopRequestContext(Request, RequestSubjectContextOrAccessToken) = UserModeAccessToken;
FspIopRequestContext(Request, RequestProcess) = Process;
Request->Req.SetInformation.Info.Rename.AccessToken = (UINT_PTR)UserModeAccessToken;
@ -1456,7 +1614,7 @@ static VOID FspFsvolSetInformationRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
PDEVICE_OBJECT FsvolDeviceObject = Context[RequestDeviceObject];
HANDLE AccessToken = Context[RequestAccessToken];
PVOID SubjectContextOrAccessToken = Context[RequestSubjectContextOrAccessToken];
PEPROCESS Process = Context[RequestProcess];
if (0 != FileNode)
@ -1465,8 +1623,9 @@ static VOID FspFsvolSetInformationRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
if (0 != FsvolDeviceObject)
FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, Request);
if (0 != AccessToken)
if (0 != SubjectContextOrAccessToken && 0 != Process)
{
HANDLE AccessToken = SubjectContextOrAccessToken;
KAPC_STATE ApcState;
BOOLEAN Attach;
@ -1488,6 +1647,13 @@ static VOID FspFsvolSetInformationRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
ObDereferenceObject(Process);
}
else if (0 != SubjectContextOrAccessToken)
{
PSECURITY_SUBJECT_CONTEXT SecuritySubjectContext = SubjectContextOrAccessToken;
SeReleaseSubjectContext(SecuritySubjectContext);
FspFree(SecuritySubjectContext);
}
}
NTSTATUS FspQueryInformation(

View File

@ -25,6 +25,10 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
BOOLEAN IsWrite);
static NTSTATUS FspFsvolFileSystemControlOplock(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static IO_COMPLETION_ROUTINE FspFsvolFileSystemControlOplockCompletion;
static WORKER_THREAD_ROUTINE FspFsvolFileSystemControlOplockCompletionWork;
static NTSTATUS FspFsvolFileSystemControl(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
@ -35,6 +39,9 @@ FSP_DRIVER_DISPATCH FspFileSystemControl;
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePoint)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePointComplete)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplock)
// !#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplockCompletion)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplockCompletionWork)
#pragma alloc_text(PAGE, FspFsvolFileSystemControl)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlComplete)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlRequestFini)
@ -205,9 +212,7 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
TargetFileNameIndex += FsvolDeviceExtension->VolumePrefix.Length;
if (TargetFileNameIndex < ReparseTargetPathLength &&
RtlEqualUnicodeString(&FsvolDeviceExtension->VolumePrefix,
&TargetObjectName,
FSP_VOLUME_PREFIX_CASE_INS))
FspFsvolDeviceVolumePrefixInString(FsvolDeviceObject, &TargetObjectName))
TargetOnFileSystem = (UINT16)TargetFileNameIndex;
}
}
@ -298,6 +303,176 @@ static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
return STATUS_SUCCESS;
}
typedef struct
{
PDEVICE_OBJECT FsvolDeviceObject;
WORK_QUEUE_ITEM WorkItem;
} FSP_FSVOL_FILESYSTEM_CONTROL_OPLOCK_COMPLETION_CONTEXT;
static NTSTATUS FspFsvolFileSystemControlOplock(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
PFILE_OBJECT FileObject = IrpSp->FileObject;
/* is this a valid FileObject? */
if (!FspFileNodeIsValid(FileObject->FsContext))
return STATUS_INVALID_DEVICE_REQUEST;
NTSTATUS Result;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
ULONG FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
ULONG OplockCount;
FSP_FSVOL_FILESYSTEM_CONTROL_OPLOCK_COMPLETION_CONTEXT *CompletionContext;
if (FileNode->IsDirectory)
return STATUS_INVALID_PARAMETER;
/*
* As per FastFat:
*
* We grab the Fcb exclusively for oplock requests, shared for oplock
* break acknowledgement.
*/
switch (FsControlCode)
{
case FSCTL_REQUEST_OPLOCK:
if (sizeof(REQUEST_OPLOCK_INPUT_BUFFER) > InputBufferLength ||
sizeof(REQUEST_OPLOCK_OUTPUT_BUFFER) > OutputBufferLength)
return STATUS_BUFFER_TOO_SMALL;
if (FlagOn(((PREQUEST_OPLOCK_INPUT_BUFFER)InputBuffer)->Flags,
REQUEST_OPLOCK_INPUT_FLAG_REQUEST))
goto exclusive;
if (FlagOn(((PREQUEST_OPLOCK_INPUT_BUFFER)InputBuffer)->Flags,
REQUEST_OPLOCK_INPUT_FLAG_ACK))
goto shared;
/* one of REQUEST_OPLOCK_INPUT_FLAG_REQUEST or REQUEST_OPLOCK_INPUT_FLAG_ACK required */
return STATUS_INVALID_PARAMETER;
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
case FSCTL_REQUEST_BATCH_OPLOCK:
case FSCTL_REQUEST_FILTER_OPLOCK:
exclusive:
FspFileNodeAcquireExclusive(FileNode, Main);
if (!FsRtlOplockIsSharedRequest(Irp))
{
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
OplockCount = FileNode->HandleCount;
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
}
else
OplockCount = FsRtlAreThereCurrentOrInProgressFileLocks(&FileNode->FileLock);
break;
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
case FSCTL_OPLOCK_BREAK_NOTIFY:
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
shared:
FspFileNodeAcquireShared(FileNode, Main);
OplockCount = 0;
break;
default:
ASSERT(0);
return STATUS_INVALID_DEVICE_REQUEST;
}
/*
* The FileNode is acquired exclusive or shared.
* Make sure to release it before exiting!
*/
if (FSCTL_REQUEST_FILTER_OPLOCK == FsControlCode ||
FSCTL_REQUEST_BATCH_OPLOCK == FsControlCode ||
(FSCTL_REQUEST_OPLOCK == FsControlCode &&
FlagOn(((PREQUEST_OPLOCK_INPUT_BUFFER)InputBuffer)->RequestedOplockLevel,
OPLOCK_LEVEL_CACHE_HANDLE)))
{
BOOLEAN DeletePending;
DeletePending = 0 != FileNode->DeletePending;
MemoryBarrier();
if (DeletePending)
{
Result = STATUS_DELETE_PENDING;
goto unlock_exit;
}
}
/*
* This IRP will be completed by the FSRTL package and therefore
* we will have no chance to do our normal IRP completion processing.
* Hook the IRP completion and perform the IRP completion processing
* there.
*/
CompletionContext = FspAllocNonPaged(sizeof *CompletionContext);
if (0 == CompletionContext)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto unlock_exit;
}
CompletionContext->FsvolDeviceObject = FsvolDeviceObject;
ExInitializeWorkItem(&CompletionContext->WorkItem,
FspFsvolFileSystemControlOplockCompletionWork, CompletionContext);
Result = FspIrpHook(Irp, FspFsvolFileSystemControlOplockCompletion, CompletionContext);
if (!NT_SUCCESS(Result))
{
FspFree(CompletionContext);
goto unlock_exit;
}
/*
* 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;
unlock_exit:
FspFileNodeRelease(FileNode, Main);
return Result;
}
static NTSTATUS FspFsvolFileSystemControlOplockCompletion(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
// !PAGED_CODE();
FSP_FSVOL_FILESYSTEM_CONTROL_OPLOCK_COMPLETION_CONTEXT *CompletionContext =
FspIrpHookContext(Context);
ExQueueWorkItem(&CompletionContext->WorkItem, DelayedWorkQueue);
return FspIrpHookNext(DeviceObject, Irp, Context);
}
static VOID FspFsvolFileSystemControlOplockCompletionWork(PVOID Context)
{
PAGED_CODE();
FSP_FSVOL_FILESYSTEM_CONTROL_OPLOCK_COMPLETION_CONTEXT *CompletionContext = Context;
FspDeviceDereference(CompletionContext->FsvolDeviceObject);
FspFree(CompletionContext);
}
static NTSTATUS FspFsvolFileSystemControl(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
@ -320,6 +495,17 @@ static NTSTATUS FspFsvolFileSystemControl(
case FSCTL_DELETE_REPARSE_POINT:
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, TRUE);
break;
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
case FSCTL_REQUEST_BATCH_OPLOCK:
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
case FSCTL_OPLOCK_BREAK_NOTIFY:
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
case FSCTL_REQUEST_FILTER_OPLOCK:
case FSCTL_REQUEST_OPLOCK:
Result = FspFsvolFileSystemControlOplock(FsvolDeviceObject, Irp, IrpSp);
break;
}
break;
}

View File

@ -100,7 +100,7 @@ SYM(FSCTL_TXFS_READ_BACKUP_INFORMATION2)
//SYM(FSCTL_GET_RETRIEVAL_POINTER_BASE)
//SYM(FSCTL_SET_PERSISTENT_VOLUME_STATE)
//SYM(FSCTL_QUERY_PERSISTENT_VOLUME_STATE)
//SYM(FSCTL_REQUEST_OPLOCK)
SYM(FSCTL_REQUEST_OPLOCK)
//SYM(FSCTL_CSV_TUNNEL_REQUEST)
//SYM(FSCTL_IS_CSV_FILE)
//SYM(FSCTL_QUERY_FILE_SYSTEM_RECOGNITION)
@ -185,7 +185,7 @@ SYM(FSCTL_PIPE_SET_CONNECTION_ATTRIBUTE)
SYM(FSCTL_PIPE_GET_HANDLE_ATTRIBUTE)
SYM(FSCTL_PIPE_SET_HANDLE_ATTRIBUTE)
SYM(FSCTL_PIPE_FLUSH)
SYM(FSCTL_PIPE_SET_CONTAINER_AWARE)
//SYM(FSCTL_PIPE_SET_CONTAINER_AWARE)
SYM(FSCTL_PIPE_INTERNAL_READ)
SYM(FSCTL_PIPE_INTERNAL_WRITE)
SYM(FSCTL_PIPE_INTERNAL_TRANSCEIVE)

View File

@ -20,6 +20,7 @@
NTSTATUS FspIopCreateRequestFunnel(
PIRP Irp, PUNICODE_STRING FileName, ULONG ExtraSize, FSP_IOP_REQUEST_FINI *RequestFini,
ULONG Flags, FSP_FSCTL_TRANSACT_REQ **PRequest);
NTSTATUS FspIopCreateRequestWorkItem(FSP_FSCTL_TRANSACT_REQ *Request);
VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request);
VOID FspIopResetRequest(FSP_FSCTL_TRANSACT_REQ *Request, FSP_IOP_REQUEST_FINI *RequestFini);
NTSTATUS FspIopPostWorkRequestFunnel(PDEVICE_OBJECT DeviceObject,
@ -29,12 +30,14 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceDereference);
VOID FspIopCompleteCanceledIrp(PIRP Irp);
BOOLEAN FspIopRetryPrepareIrp(PIRP Irp, NTSTATUS *PResult);
BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response, NTSTATUS *PResult);
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);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspIopCreateRequestFunnel)
#pragma alloc_text(PAGE, FspIopCreateRequestWorkItem)
#pragma alloc_text(PAGE, FspIopDeleteRequest)
#pragma alloc_text(PAGE, FspIopResetRequest)
#pragma alloc_text(PAGE, FspIopPostWorkRequestFunnel)
@ -42,17 +45,18 @@ NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response
#pragma alloc_text(PAGE, FspIopCompleteCanceledIrp)
#pragma alloc_text(PAGE, FspIopRetryPrepareIrp)
#pragma alloc_text(PAGE, FspIopRetryCompleteIrp)
#pragma alloc_text(PAGE, FspIopSetIrpResponse)
#pragma alloc_text(PAGE, FspIopIrpResponse)
#pragma alloc_text(PAGE, FspIopDispatchPrepare)
#pragma alloc_text(PAGE, FspIopDispatchComplete)
#endif
/* Requests (and RequestHeaders) must be 16-byte aligned, because we use the low 4 bits for flags */
#if REQ_ALIGN_SIZE <= MEMORY_ALLOCATION_ALIGNMENT
#if FSP_FSCTL_TRANSACT_REQ_ALIGNMENT <= MEMORY_ALLOCATION_ALIGNMENT
#define REQ_HEADER_ALIGN_MASK 0
#define REQ_HEADER_ALIGN_OVERHEAD 0
#else
#define REQ_HEADER_ALIGN_MASK (REQ_ALIGN_SIZE - 1)
#define REQ_HEADER_ALIGN_MASK (FSP_FSCTL_TRANSACT_REQ_ALIGNMENT - 1)
#define REQ_HEADER_ALIGN_OVERHEAD (sizeof(PVOID) + REQ_HEADER_ALIGN_MASK)
#endif
@ -63,6 +67,7 @@ NTSTATUS FspIopCreateRequestFunnel(
PAGED_CODE();
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader;
FSP_FSCTL_TRANSACT_REQ_WORK_ITEM *RequestWorkItem = 0;
FSP_FSCTL_TRANSACT_REQ *Request;
*PRequest = 0;
@ -73,19 +78,41 @@ NTSTATUS FspIopCreateRequestFunnel(
if (FSP_FSCTL_TRANSACT_REQ_SIZEMAX < sizeof *Request + ExtraSize)
return STATUS_INVALID_PARAMETER;
if (FlagOn(Flags, FspIopRequestMustSucceed))
if (FlagOn(Flags, FspIopCreateRequestMustSucceedFlag))
{
RequestHeader = FspAllocatePoolMustSucceed(
FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool,
FlagOn(Flags, FspIopCreateRequestNonPagedFlag) ? NonPagedPool : PagedPool,
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGN_OVERHEAD,
FSP_ALLOC_INTERNAL_TAG);
if (FlagOn(Flags, FspIopCreateRequestWorkItemFlag))
{
RequestWorkItem = FspAllocatePoolMustSucceed(
NonPagedPool, sizeof *RequestWorkItem, FSP_ALLOC_INTERNAL_TAG);
RtlZeroMemory(RequestWorkItem, sizeof *RequestWorkItem);
}
}
else
{
RequestHeader = ExAllocatePoolWithTag(
FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool,
FlagOn(Flags, FspIopCreateRequestNonPagedFlag) ? NonPagedPool : PagedPool,
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGN_OVERHEAD,
FSP_ALLOC_INTERNAL_TAG);
if (0 == RequestHeader)
return STATUS_INSUFFICIENT_RESOURCES;
if (FlagOn(Flags, FspIopCreateRequestWorkItemFlag))
{
RequestWorkItem = FspAllocNonPaged(sizeof *RequestWorkItem);
if (0 == RequestWorkItem)
{
FspFree(RequestHeader);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(RequestWorkItem, sizeof *RequestWorkItem);
}
}
#if 0 != REQ_HEADER_ALIGN_MASK
@ -97,6 +124,7 @@ NTSTATUS FspIopCreateRequestFunnel(
RtlZeroMemory(RequestHeader, sizeof *RequestHeader + sizeof *Request + ExtraSize);
RequestHeader->RequestFini = RequestFini;
RequestHeader->WorkItem = RequestWorkItem;
Request = (PVOID)RequestHeader->RequestBuf;
Request->Size = (UINT16)(sizeof *Request + ExtraSize);
@ -110,6 +138,8 @@ NTSTATUS FspIopCreateRequestFunnel(
Request->FileName.Size = FileName->Length + sizeof(WCHAR);
}
ASSERT(0 == ((UINT_PTR)Request & (FSP_FSCTL_TRANSACT_REQ_ALIGNMENT - 1)));
if (0 != Irp)
{
ASSERT(0 == FspIrpRequest(Irp));
@ -120,6 +150,26 @@ NTSTATUS FspIopCreateRequestFunnel(
return STATUS_SUCCESS;
}
NTSTATUS FspIopCreateRequestWorkItem(FSP_FSCTL_TRANSACT_REQ *Request)
{
PAGED_CODE();
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader = (PVOID)((PUINT8)Request - sizeof *RequestHeader);
FSP_FSCTL_TRANSACT_REQ_WORK_ITEM *RequestWorkItem;
if (0 == RequestHeader->WorkItem)
{
RequestWorkItem = FspAllocNonPaged(sizeof *RequestWorkItem);
if (0 == RequestWorkItem)
return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(RequestWorkItem, sizeof *RequestWorkItem);
RequestHeader->WorkItem = RequestWorkItem;
}
return STATUS_SUCCESS;
}
VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request)
{
PAGED_CODE();
@ -132,6 +182,9 @@ VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request)
if (0 != RequestHeader->Response)
FspFree(RequestHeader->Response);
if (0 != RequestHeader->WorkItem)
FspFree(RequestHeader->WorkItem);
#if 0 != REQ_HEADER_ALIGN_MASK
RequestHeader = ((PVOID *)RequestHeader)[-1];
#endif
@ -225,9 +278,55 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceDereference)
}
/* get the device object out of the IRP before completion */
PDEVICE_OBJECT DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_OBJECT DeviceObject = IrpSp->DeviceObject;
if (STATUS_SUCCESS != Result && STATUS_REPARSE != Result && STATUS_BUFFER_OVERFLOW != Result)
/*
* HACK:
*
* Turns out that SRV2 sends an undocumented flavor of IRP_MJ_DIRECTORY_CONTROL /
* IRP_MN_QUERY_DIRECTORY. These IRP's have a non-NULL Irp->MdlAddress. They expect
* the FSD to fill the buffer pointed by Irp->MdlAddress and they cannot handle
* completed IRP's with a non-NULL Irp->AssociatedIrp.SystemBuffer. So we have to
* provide special support for these IRPs.
*
* While this processing is IRP_MJ_DIRECTORY_CONTROL specific, we do this here for
* these reasons:
*
* 1. There may be other IRP's that have similar completion requirements under SRV2.
* If/when such IRP's are discovered the completion processing can be centralized
* here.
* 2. IRP_MJ_DIRECTORY_CONTROL has a few different ways that it can complete IRP's.
* It is far simpler to do this processing here, even if not academically correct.
*
* This will have to be revisited if IRP_MJ_DIRECTORY_CONTROL processing changes
* substantially (e.g. to no longer use Irp->AssociatedIrp.SystemBuffer).
*/
if (IRP_MJ_DIRECTORY_CONTROL == IrpSp->MajorFunction &&
IRP_MN_QUERY_DIRECTORY == IrpSp->MinorFunction &&
0 != Irp->MdlAddress && /* SRV2 queries have this set */
0 != Irp->AssociatedIrp.SystemBuffer &&
FlagOn(Irp->Flags, IRP_BUFFERED_IO))
{
if (STATUS_SUCCESS == Result)
{
PVOID Address = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
if (0 != Address)
RtlCopyMemory(Address, Irp->AssociatedIrp.SystemBuffer, Irp->IoStatus.Information);
else
Result = STATUS_INSUFFICIENT_RESOURCES;
}
FspFreeExternal(Irp->AssociatedIrp.SystemBuffer);
Irp->AssociatedIrp.SystemBuffer = 0;
ClearFlag(Irp->Flags, IRP_INPUT_OPERATION | IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
}
if (STATUS_SUCCESS != Result &&
STATUS_REPARSE != Result &&
STATUS_OPLOCK_BREAK_IN_PROGRESS != Result &&
STATUS_BUFFER_OVERFLOW != Result &&
STATUS_SHARING_VIOLATION != Result)
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = Result;
IoCompleteRequest(Irp, FSP_IO_INCREMENT);
@ -275,6 +374,16 @@ BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
PDEVICE_OBJECT DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
FspIopSetIrpResponse(Irp, Response);
return FspIoqRetryCompleteIrp(FsvolDeviceExtension->Ioq, Irp, PResult);
}
VOID FspIopSetIrpResponse(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
{
PAGED_CODE();
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader = (PVOID)((PUINT8)Request - sizeof *RequestHeader);
@ -288,8 +397,6 @@ BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
RtlCopyMemory(RequestHeader->Response, Response, Response->Size);
Response = RequestHeader->Response;
}
return FspIoqRetryCompleteIrp(FsvolDeviceExtension->Ioq, Irp, PResult);
}
FSP_FSCTL_TRANSACT_RSP *FspIopIrpResponse(PIRP Irp)

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