Compare commits

..

511 Commits
v0.9 ... v0.17

Author SHA1 Message Date
12e40f908d tst: winfsp-tests: stream_rename_flipflop_test 2016-10-13 00:17:48 -07:00
42745e2239 sys: FspFileNodeRename: correctly handle rename of closed by referenced descendant files 2016-10-12 23:52:54 -07:00
249c1a5cb8 sys: FspFsvolDeviceEnumerateContextByName: fix bug that manifested itself as hanging renames 2016-10-12 20:08:17 -07:00
233904fd51 dll: move STATUS_FILE_IS_A_DIRECTORY collision check to fsop.c from memfs 2016-10-12 12:15:19 -07:00
3e0f2316a7 dll: special case STATUS_OBJECT_NAME_NOT_FOUND and STATUS_OBJECT_NAME_COLLISION to handle open/create via symlink
tst: memfs: support reparse point functionality over a named stream and fix status return on create collision over directory
2016-10-12 11:18:55 -07:00
bd952253fb cosmetic fix 2016-10-11 11:39:17 -07:00
c7780cf7fa license: switch to GPLv3 from AGPLv3 2016-10-10 21:33:27 -07:00
31b54ecc47 dll: FspAccessCheckEx: fix DELETE access check for named streams 2016-10-10 18:04:55 -07:00
4084448bd5 sys,dll: properly implement stream create check 2016-10-10 17:29:16 -07:00
4dc1828e1f update submodules 2016-10-10 15:36:17 -07:00
79b7b66b62 update submodules 2016-10-10 14:46:25 -07:00
612c820630 tst: memfs: add -D option to specify debug log file 2016-10-10 13:25:47 -07:00
e13233ef32 tst: memfs: add -D option to specify debug log file 2016-10-10 13:21:20 -07:00
dd815f3c39 doc: update Changelog 2016-10-10 11:50:34 -07:00
5faafc4d11 doc: update Changelog 2016-10-10 11:49:22 -07:00
78e5d031c0 installer: add RC and GOLD banners 2016-10-09 18:10:52 -07:00
9ef562df15 installer: choose install banner based on MyDevStage project variable 2016-10-09 17:27:33 -07:00
a7cdc815d0 installer: choose install banner based on MyDevStage project variable 2016-10-09 17:10:23 -07:00
bd5e15fe24 sys: FspFileNodeNotifyChange: implement/test stream notifications 2016-10-09 16:08:11 -07:00
214a8406eb art: wix dialog banner 2016-10-08 23:55:52 -07:00
6bd6f0ee35 inc: fsctl: increase request/response size to 16K
dll: remove /Gs[size] switch, fix FspFileSystemResolveReparsePoints to not use more than 4K of stack space
2016-10-08 23:33:59 -07:00
f8cebd1f92 dll: FspDebugLogSetHandle 2016-10-08 18:49:28 -07:00
f8f6d0f1bc tools: run-tests: include stream tests 2016-10-07 12:22:19 -07:00
b06132cb6b tst: winfsp-tests: stream_create_related_test 2016-10-06 20:42:05 -07:00
748c9b6409 tst: winfsp-tests: stream_getstreaminfo_test 2016-10-06 17:20:23 -07:00
bfc7fc5dec tst: winfsp-tests: stream_getstreaminfo_test 2016-10-06 17:06:23 -07:00
03f906f966 sys: FspFsvolQueryDirectoryCopy: minor fix 2016-10-06 16:51:40 -07:00
4b1111fcc5 tst: winfsp-tests: stream_getstreaminfo_test 2016-10-06 15:36:33 -07:00
86ddeed129 tst: memfs: GetStreamInfo 2016-10-06 15:36:09 -07:00
e2d4b36057 sys: FspFsvolQueryStreamInformation* testing 2016-10-06 15:35:40 -07:00
ab2908a9ee sys: FspFileNodeTrySetSecurity, FspFileNodeTrySetDirInfo 2016-10-06 12:41:23 -07:00
fd7b12bb61 tst: memfs: minor fix 2016-10-06 12:13:34 -07:00
eb2000a194 sys: FSP_FILE_NODE: correctly handle FileInfo cache in the presence of streams 2016-10-06 12:13:16 -07:00
e4cabc50c5 tst: winfsp-tests: stream_setfileinfo_test 2016-10-05 18:18:57 -07:00
92dc2feecd sys: use main file security cache 2016-10-05 17:38:16 -07:00
43f333e8a6 sys: FSP_FILE_NODE: change number field access through inline functions 2016-10-05 17:30:50 -07:00
59eb40fd9b tst: winfsp-tests: stream_getsecurity_test 2016-10-05 16:59:54 -07:00
d85d36c94f tst: memfs: MemfsFileNodeMapHasChild: fix problems with streams on directory 2016-10-05 15:21:33 -07:00
27b841faf8 sys: FspFileNodeOpen: refine main file vs stream sharing violations 2016-10-05 14:55:37 -07:00
c6967c737a sys: FspUnicodePathIsValid: check and return stream type 2016-10-05 13:44:32 -07:00
4ccbd1bdf6 tst: winfsp-tests: stream_create_test 2016-10-05 10:48:33 -07:00
0a8b8e8444 sys: create: validate FileName only after FileNode->FileName has been constructed 2016-10-05 10:27:17 -07:00
352450d538 sys: FspMainFileOpen 2016-10-05 00:32:04 -07:00
7e1861a9f5 tst: memfs: GetSecurityByName: fix FileAttributes for streams on directories 2016-10-04 23:00:42 -07:00
860e9db8a7 sys: FspMainFileOpen, FspMainFileClose, FspMainFileOpenCheck 2016-10-04 22:19:41 -07:00
1d435269bd sys: create: correctly compute file name lengths when streams are involved 2016-10-04 11:35:39 -07:00
e58ac1fbde sys,dll: pass NULL security descriptor to user-mode file system during Create 2016-10-03 21:02:43 -07:00
1f0f2fe094 tst: winfsp-tests: stream testing 2016-10-03 20:15:17 -07:00
d7ec331c74 tst: winfsp-tests: stream testing 2016-10-03 20:14:22 -07:00
938c036387 tst: winfsp-tests: stream testing 2016-10-03 18:27:09 -07:00
16f5bd089d tst: winfsp-tests: stream testing 2016-10-03 17:30:30 -07:00
6afea44e31 tst: winfsp-tests: stream testing 2016-10-03 17:13:19 -07:00
2859355fd8 tst: winfsp-tests: stream testing 2016-10-03 16:52:44 -07:00
75012d1301 tst: winfsp-tests: stream testing 2016-10-03 16:40:03 -07:00
8e1512c067 tst: winfsp-tests: stream testing 2016-10-03 16:31:43 -07:00
fa6b621042 tst: winfsp-tests: stream testing 2016-10-03 16:16:09 -07:00
8ffb359f20 tst: winfsp-tests: stream testing 2016-10-03 16:13:17 -07:00
203873ef04 tst: winfsp-tests: stream testing 2016-10-03 16:08:45 -07:00
e73bda3926 tst: winfsp-tests: stream testing 2016-10-03 15:57:34 -07:00
0186b82fea tst: winfsp-tests: stream testing 2016-10-03 15:30:08 -07:00
db38d2f7f8 tst: winfsp-tests: stream testing 2016-10-03 15:19:18 -07:00
016d015fe6 sys: file, callbacks: acquire MainFileNode resources if exists 2016-10-03 14:21:34 -07:00
87b2d4ca4c tst: memfs: MEMFS_NAMED_STREAMS macro 2016-10-03 11:55:39 -07:00
dfd6cbbde1 tst: memfs: support named streams 2016-10-03 10:58:55 -07:00
6a126da51d sys: IRP_MJ_CREATE: handle security descriptor and file attributes correctly for named streams 2016-10-03 10:29:46 -07:00
03df0a9c26 sys: renamed "main stream" to "main file" 2016-10-02 16:57:15 -07:00
5c3a82a074 tst: memfs: Cleanup: remove all named streams on delete 2016-09-28 17:11:30 -07:00
b591015b28 tst: memfs: Cleanup: remove all named streams on delete 2016-09-28 16:59:39 -07:00
fb9b798d3d tst: memfs: implement GetStreamInfo 2016-09-28 16:17:50 -07:00
cc408b71e1 sys: FspFsvolQueryStreamInformationCopy: add stream type ($DATA) to stream names 2016-09-28 16:17:10 -07:00
19a73ca01d update submodules 2016-09-27 17:01:40 -07:00
3992b9ebb1 update submodules 2016-09-27 15:56:29 -07:00
a46c0610c4 tst: memfs: MemfsFileNameHasPrefix: work to support named streams 2016-09-27 15:35:26 -07:00
495fc7a5dc sys: implement named stream open/close and related delete/share access issues 2016-09-27 14:53:59 -07:00
2ba46fdb71 ensure that all source files use UNIX newlines 2016-09-25 21:50:44 -07:00
7cb56bb132 sys: FspUnicodePathIsValid: improvements 2016-09-25 21:38:41 -07:00
687b02c1e6 tools: ntstatus,winerror: lookup status/error codes 2016-09-24 23:55:15 -07:00
218b162d75 update submodules 2016-09-24 22:46:49 -07:00
5e13c8750e sys: FspUnicodePathIsValid, FspUnicodePathIsValidPattern 2016-09-24 22:21:05 -07:00
2e71d2fe14 sys: FspFsvolQueryStreamInformationCopy: improvements 2016-09-24 17:32:35 -07:00
866e4abe10 sys: IRP_MN_QUERY_DIRECTORY: correctly handle STATUS_BUFFER_OVERFLOW cases 2016-09-24 17:16:58 -07:00
7894cc8b7b sys: fileinfo.c: minor comment change 2016-09-24 15:09:15 -07:00
0c810c52fa sys: IRP_MJ_QUERY_INFORMATION: FileStreamInformation 2016-09-24 13:59:02 -07:00
b06e947e0e tst: winfsp-tests: troubleshoot appveyor dirnotify failure 2016-09-21 15:07:51 -07:00
aed134080c inc: fsctl: PostCleanupOnDeleteOnly 2016-09-21 14:22:08 -07:00
3ce490d405 inc: fsctl: UmFileNodeIsUserContext2 2016-09-21 10:40:18 -07:00
76aabecbfb dll: fuse: fstypename, FileSystemName command line options 2016-09-20 21:27:48 -07:00
8eebfe811d sys: FspFsvolQueryFsAttributeInformation: fix buffer overrun error 2016-09-20 20:55:10 -07:00
5798527237 sys: FspFsvolQueryFsAttributeInformation: return full file system name 2016-09-20 16:30:03 -07:00
817beebb63 inc: fsctl: FSP_FSCTL_VOLUME_PARAMS changes:
- increase size of VolumePrefix
- add FileSystemName field (currently unused)
2016-09-20 15:37:42 -07:00
b7a2b5e17a build: bump version to 0.17 2016-09-20 14:26:20 -07:00
20e547c6d0 Merge branch 'master' of https://github.com/billziss-gh/winfsp 2016-09-19 17:25:50 -07:00
d0d0f60033 doc: SSHFS Port Case Study: Step 5: POSIX special files 2016-09-19 17:29:56 -07:00
fbc3d3efce Update Changelog 2016-09-19 15:11:01 -07:00
2c3f177314 tst: winfsp-tests: disable HookCreateFileW for now 2016-09-16 17:34:32 -07:00
91e8bb1229 tst: winfsp-tests: HookCreateFileW 2016-09-16 10:08:16 -07:00
4b48502232 tools: run-tests: correctly test ERRORLEVEL 2016-09-15 21:18:52 -07:00
74af44e2e7 sys: create: FspFsvolCreateNoLock: fix open of network drive root 2016-09-15 20:23:21 -07:00
915279d41d Merge branch 'master' of https://bitbucket.org/billziss/winfsp 2016-09-15 15:30:50 -07:00
316a2940dc sys: write: FspFsvolWriteCached: fix simple but major bug when using FILE_APPEND_DATA 2016-09-15 15:28:55 -07:00
453c1753ab doc: update Changelog 2016-09-15 13:41:18 -07:00
b11b622fc2 doc: Changelog formatting fix 2016-09-15 13:25:59 -07:00
f1ba60e172 doc: update Changelog 2016-09-15 13:09:24 -07:00
7c1b592b84 installer: add public (stripped) symbols 2016-09-15 11:49:42 -07:00
1e88fedb19 src: sys: FspFsvolCreateComplete: minor comment fix 2016-09-15 00:16:25 -07:00
5ecc92f2ba update submodules 2016-09-14 23:46:05 -07:00
5771eedc45 sys,dll: FspFileSystemResolveReparsePoints: use IO_REPARSE_TAG_SYMLINK instead of IO_REPARSE for symlink resolution
- FspFsvolCreateComplete STATUS_REPARSE handling changed to support device-relative symlink reparse points
2016-09-14 22:16:40 -07:00
46a29f663a inc: fsctl: simplify FSP_FSCTL_TRANSACT_RSP Rsp.Create.Reparse 2016-09-14 17:18:59 -07:00
49cd11b34b tst: memfs: GetSecurityByName: reparse point fix 2016-09-14 16:20:21 -07:00
aeff3dc21e dll: debug: add diagnostic information for FileSystemControl requests/responses 2016-09-14 16:17:20 -07:00
b7368336d2 dll: debug: add diagnostic information for FileSystemControl requests/responses 2016-09-14 15:02:40 -07:00
5afe7a5315 tools: run-tests: include reparse point tests 2016-09-14 11:28:34 -07:00
7815b9e2eb dll: fuse: directory symlinks can now be deleted 2016-09-14 10:41:32 -07:00
cbcea380ef dll: fuse: correctly handle NFS_SPECFILE_LNK reparse points, which are in POSIX UTF-16 format 2016-09-14 10:36:52 -07:00
10635db99b dll: fuse: reparse point fixes
- symlinks to directories have the FILE_ATTRIBUTE_DIRECTORY added
- new symlinks/special files are now created with correct uid/gid in fuse_context
2016-09-13 22:17:31 -07:00
cb00f913cc appveyor.yml: the previous version of Visual Studio 2015 is hosed too, so remove :( 2016-09-13 15:49:24 -07:00
c406c89158 appveyor.yml: choose previous version of VS2015 so that AppVeyor builds can complete 2016-09-13 15:45:42 -07:00
f600d51ace dll: fuse: SetReparsePoint testing 2016-09-13 15:17:59 -07:00
7401481d42 dll: fuse: allow opening of reparse points 2016-09-13 14:36:40 -07:00
2d3d92fb2d dll: fuse: reparse point testing 2016-09-13 13:41:09 -07:00
eca93bbdb3 installer: add diag.bat file to installation 2016-09-13 10:24:14 -07:00
5fa0c36c8f dll: relative symbolic link resolution testing 2016-09-13 00:14:35 -07:00
ea2cc54677 dll: relative symbolic link resolution testing 2016-09-12 22:45:47 -07:00
ccec269dd6 dll: relative symbolic link resolution testing 2016-09-12 21:50:25 -07:00
5888e9ab05 dll: relative symbolic link resolution testing 2016-09-12 21:42:02 -07:00
c12b88286d dll: fuse: warning fix 2016-09-12 20:26:14 -07:00
e412d735ed tst: winfsp-tests: reparse_symlink_relative_test 2016-09-12 19:55:35 -07:00
582997b5a4 tst: winfsp-tests: reparse_symlink_large_test 2016-09-12 18:13:25 -07:00
1647702a65 tools: add diag.bat diagnostics batch file 2016-09-12 15:45:48 -07:00
ccf58122a2 sys: FspFsvolFileSystemControlReparsePoint: comments 2016-09-12 15:27:31 -07:00
be8c29114a sys: FspFsvolFileSystemControlReparsePoint: improve computation of TargetOnFileSystem field when MUP is being used 2016-09-12 15:11:45 -07:00
30f2807e2b sys: FspGetDeviceObjectByName: PAGED_CODE() macro 2016-09-11 21:45:32 -07:00
25a2873556 sys: symbolic link testing 2016-09-11 17:18:56 -07:00
bd0acf2289 sys,dll: symbolic link testing 2016-09-11 17:04:01 -07:00
997476f015 sys,launcher: MUP volume prefixes (share names) are now case insensitive 2016-09-11 14:35:56 -07:00
f89c91cd10 sys,dll: SYMLINK_FLAG_RELATIVE 2016-09-11 13:18:54 -07:00
af2cc10c15 sys,dll: reparse point testing 2016-09-10 23:00:55 -07:00
0d25e73364 Submodule secfs.test now pulled from github
- run `git submodule sync` after pull
2016-09-09 22:12:55 -07:00
86d74371aa doc: add Native API vs FUSE document 2016-09-09 21:54:51 -07:00
f32e335855 bump version to 0.16 and update Changelog 2016-09-09 21:45:19 -07:00
165f3ec45d sys,dll: symlink testing 2016-09-09 21:21:24 -07:00
811696d939 sys,dll: reparse point testing 2016-09-09 19:40:37 -07:00
0c07be9628 sys,dll: reparse point testing 2016-09-09 17:21:56 -07:00
5dcbbaa4e7 tst: winfsp-tests: NFS reparse point testing 2016-09-09 15:24:33 -07:00
12b70f661f dll: fuse: nfs reparse point fixes 2016-09-09 15:14:40 -07:00
9b4b5abe48 tst: winfsp-tests: reparse point testing 2016-09-09 14:55:15 -07:00
5cd0dfb1b9 sys: reparse point testing 2016-09-09 14:42:22 -07:00
46ce4b1a6c dll: fuse: properly acquire op guard for reparse point operations 2016-09-09 11:43:49 -07:00
28a20d5199 dll: FspFileSystemOpLeave: bug fix 2016-09-09 11:29:09 -07:00
10ea9a833f dll: fuse: fixes 2016-09-09 11:23:29 -07:00
d9713668aa dll: FspFileSystemCanReplaceReparsePoint: fix 2016-09-09 11:09:41 -07:00
00c0574f1f tst: memfs: minor fix 2016-09-08 11:42:05 -07:00
44c86ff9a4 dll: fuse: use NFS reparse points for POSIX special files 2016-09-08 10:43:01 -07:00
28931f4687 tst: reparse point testing 2016-09-04 12:38:12 -07:00
80e07cead6 sys,dll: reparse point implementation: DeleteReparsePoint 2016-08-26 07:43:25 -07:00
b88b2ec51d dll: acquire exclusive lock during flush volume 2016-08-22 01:04:07 -07:00
82e4dcb4a1 inc: winfsp.h: minor srcdoc fix 2016-08-22 00:54:15 -07:00
34e653a275 dll: fsop: implement FSCTL_DELETE_REPARSE_POINT parameter checking 2016-08-22 00:40:01 -07:00
981e60643f dll: reparse points: allow file system to provide directory symlink behavior 2016-08-22 00:04:49 -07:00
fee75590a8 sys,dll: rename VolumeParams::ReparsePoints* fields 2016-08-21 23:36:09 -07:00
1298dd842d update test submodule 2016-08-21 09:37:16 -07:00
8334daa048 update test submodule 2016-08-21 07:46:56 -07:00
2f73bfa069 dll: reparse point implementation: fixes 2016-08-20 02:47:14 -07:00
d2d2dd5099 inc: winfsp.h: srcdoc corrections 2016-08-20 01:19:07 -07:00
146570dd74 dll: FspFileSystemResolveReparsePoints: return STATUS_OBJECT_PATH_NOT_FOUND when appropriate 2016-08-20 01:11:46 -07:00
f509281be4 dll: fuse: reimplement reparse point support using FspFileSystemFindReparsePoint and FspFileSystemResolveReparsePoints 2016-08-20 01:06:52 -07:00
613a564ca2 tst: memfs: implement reparse points 2016-08-19 23:33:40 -07:00
7ffc60f512 dll: reparse point implementation: WIP 2016-08-19 10:24:03 -07:00
499a0cb866 dll: fuse: GetReparsePoint: return STATUS_NOT_A_REPARSE_POINT when appropriate 2016-08-15 08:05:09 -07:00
edff3054db dll: fuse: disallow deletion of reparse point (which we cannot support) 2016-08-15 07:21:05 -07:00
f7e0362350 sys,dll: reparse point implementation: WIP 2016-08-15 04:53:11 -07:00
7337f3c6cd sys,dll: symbolic link (reparse point) support: WIP 2016-08-04 11:25:35 -07:00
ab278d7b60 Merge branch 'master' into symlink 2016-07-31 00:16:38 -07:00
858df29ba2 Merge branch 'master' of https://github.com/billziss-gh/winfsp 2016-07-28 23:51:34 -07:00
4366866653 launcher: SvcInstanceStart: STATUS_TIMEOUT is not error; handle it correctly 2016-07-28 23:50:49 -07:00
e4b808806c Update README.md 2016-07-28 17:03:47 -07:00
13cee6e019 Update Changelog 2016-07-28 16:54:07 -07:00
35b9cb15a3 tst: do not test for read-only buffer during Write when not on Win8+ 2016-07-28 16:37:49 -07:00
0d8f0f9ac8 Merge branch 'master' of https://bitbucket.org/billziss/winfsp 2016-07-28 14:56:40 -07:00
a4e2ad9dd6 dll: FspFsctlStop: fix problem in call to DeviceIoControl
- The DeviceIoControl was invoked in an incorrect fashion that nevertheless worked in Win64, but not Win32.
2016-07-28 14:56:06 -07:00
9b4318c655 sys: fix request header alignment on 32-bit builds 2016-07-28 09:57:31 -07:00
5827b1fa9c sys: fixes for Win7 x86 2016-07-28 00:03:53 -07:00
913f7ac9cd dll: suppress compiler warning on x86 builds 2016-07-27 16:25:41 -07:00
0e2f46dc90 Define NTDDI_VERSION,_WIN32_WINNT; remove GetOverlappedResultEx
- Ensures that only Vista+ DDI/API's are used
- Project should now run on Win 7
2016-07-27 16:15:28 -07:00
a8d76d3e46 sys, dll: reparse point (symbolic link) support: WIP 2016-07-25 21:27:48 -07:00
380ec074ca sys: ioq: clarify comment 2016-07-23 18:43:02 -07:00
e7cba96c74 Update README 2016-07-21 14:08:00 -07:00
03db443406 Update README 2016-07-20 23:41:55 -07:00
0b65bc7e01 Update README 2016-07-19 21:08:02 -07:00
12e1caaa98 Update README 2016-07-19 21:02:14 -07:00
7a690a789b Update README 2016-07-19 12:21:21 -07:00
8ca419830c art: installer banners 2016-07-17 16:55:12 -07:00
c310d8ea1b art: installer banners 2016-07-17 16:46:54 -07:00
c3ddf73661 art: add installer banners 2016-07-17 16:26:47 -07:00
6b00b8e28a art: add winfsp icon and installer banners 2016-07-17 16:24:21 -07:00
35c722e91b appveyor: enable verifier for FSD 2016-07-15 23:10:44 -07:00
ae8802514b appveyor: enable verifier for FSD 2016-07-15 23:04:45 -07:00
e90aa46a27 build: bump version to 0.15 2016-07-15 22:43:40 -07:00
760cd5e46f opt: cygfuse: bump release number to 3 2016-07-15 17:58:17 -07:00
b36b6c60e2 inc: fuse: allow for future expansion of fsp_fuse_env 2016-07-15 17:52:24 -07:00
e4984bf675 doc: update Changelog 2016-07-15 17:49:08 -07:00
0c8bcd5d7d doc: update Changelog 2016-07-15 17:39:57 -07:00
b5d8cd3ea6 installer: wix: avoid using autogenerated GUID for INSTALLDIR component 2016-07-14 11:13:26 -07:00
af5f409233 dll: np: improve username/password prompts 2016-07-13 23:19:11 -07:00
cffb066d46 ext/test/winfstest: fix build with VS2015 Update 3 2016-07-11 21:21:05 -07:00
804434d836 dll: fuse: respect the uid,gid,umask options which were being ignored 2016-06-30 23:47:01 -07:00
f7595e40b6 dll: np: FSP_NP_CREDENTIAL_MANAGER 2016-06-29 23:31:07 -07:00
669dd07ce2 dll: np: credentials testing 2016-06-29 22:35:00 -07:00
b6fa54d301 update Changelog 2016-06-29 18:09:06 -07:00
342e7e39e2 tst: secret: small program to aid with testing launcher secrets 2016-06-29 16:27:01 -07:00
9dfdd19616 launcher: startWithSecret testing 2016-06-29 16:10:27 -07:00
2c651b1bd8 launcher: check Credentials registry value during svc instance creation 2016-06-29 15:02:15 -07:00
41764f7b41 launcher, launchctl: fixes 2016-06-29 13:05:15 -07:00
08e697c52c launcher: send the password to service instance as UTF-8 2016-06-29 12:34:06 -07:00
66cc043149 dll: np: credentials support 2016-06-29 12:18:53 -07:00
518cd0e8c0 launcher, launchctl: StartWithSecret 2016-06-28 23:09:10 -07:00
c0344f53b0 Merge branch 'master' into launchpass 2016-06-28 12:10:27 -07:00
76445a5403 bump version to 0.14 2016-06-28 12:10:08 -07:00
0577b8febb dll: posix: use the S-1-0-65534 <-> 65534 for the unmapped SID/UID 2016-06-28 11:45:35 -07:00
610a7ac2a6 dll: np: support launcher passwords: WIP 2016-06-28 11:26:25 -07:00
e33fda4d00 doc: Changelog 2016-06-25 16:26:56 -07:00
2151e193dc doc: Changelog 2016-06-25 16:25:14 -07:00
ccfaf04f76 opt: cygfuse: libfuse.dll.a symlink 2016-06-24 22:25:25 -07:00
7e8d9fb986 dll: posix: map unmapped UID to S-1-5-7 (Anonymous) 2016-06-24 16:28:38 -07:00
37b6936ad0 dll: posix: FspNullSid, FspNullUid 2016-06-24 00:19:20 -07:00
3683afe203 dll: posix: FspNullSid, FspNullUid 2016-06-23 23:42:37 -07:00
a3cfc84007 inc,dll: winfsp: FSP_FILE_SYSTEM_INTERFACE
Consolidate SetFileSize/SetAllocationSize
2016-06-23 14:30:01 -07:00
ee5c584614 inc: winfsp: FSP_FILE_SYSTEM_INTERFACE: ensure it has 64 entries 2016-06-23 00:33:18 -07:00
b8b15e8035 dll: FspFileSystemSetMountPoint, FspFileSystemRemoveMountPoint
Ensure that mapped drives get cleaned up even if file system dies
2016-06-22 23:16:22 -07:00
3db09be764 opt: cygfuse: minor fix in fuse.cygport 2016-06-22 11:45:11 -07:00
f2a0eb544e opt: cygfuse: rename cygfuse.cpp to cygfuse.c and fix fork problem 2016-06-22 11:12:33 -07:00
8c1c407b34 opt: cygfuse: undef _WIN32, _WIN64 symbols before including fuse*.h 2016-06-21 21:43:02 -07:00
8dc4225ea1 opt: cygfuse: can build cygport from working tree (make cygport) 2016-06-21 21:17:39 -07:00
ed0b83c84d opt: cygfuse: fuse.cygport now provides primary VERSION 2016-06-21 14:40:18 -07:00
71c68d1e17 opt: cygfuse: fuse.cygport and related changes 2016-06-21 14:16:52 -07:00
053a5f1e4b update README 2016-06-21 10:54:52 -07:00
e5d7f4ee9a opt: cygfuse 2016-06-21 10:50:19 -07:00
d6fb076cad opt: cygfuse 2016-06-21 00:35:36 -07:00
698b711df4 doc: SSHFS Port Case Study: Step 4 2016-06-17 18:17:54 -07:00
842f649f06 update README 2016-06-17 15:28:06 -07:00
b062df9c42 update README 2016-06-17 15:26:57 -07:00
f0385e3c7d update README 2016-06-17 15:24:51 -07:00
10ce221fcc update README and rename Contributors document 2016-06-17 15:20:41 -07:00
3f3092bdae build: update version to 0.13 2016-06-17 15:12:42 -07:00
29496a35be inc: fuse: use FSP_FUSE_SYM to define FUSE symbols 2016-06-17 14:24:15 -07:00
99a1e331b5 dll: eventlog: move source under Application and other improvements 2016-06-16 13:29:37 -07:00
68d79b0c3b dll: convert all initialization to the initonce pattern 2016-06-16 12:17:38 -07:00
b695ef8ad8 dll: fuse: only use the environment's malloc prior to fsp_fuse_loop
- this allows an environment like Cygwin to safely call fork prior to fuse_loop/fuse_loop_mt
2016-06-15 23:12:08 -07:00
b8ec5ba019 dll: fuse: improve signal handling under Cygwin 2016-06-15 11:21:41 -07:00
958f694b6f dll: fuse: Cygwin signal handling support 2016-06-14 21:36:08 -07:00
e227ae5751 inc: fuse: add fuse_flock definition 2016-06-13 17:21:40 -07:00
007ec8f360 dll: fuse: testing 2016-06-13 01:15:42 -07:00
00976b92b8 dll: fuse: remove PersistentAcls options; it is always enabled 2016-06-13 00:52:48 -07:00
9b56b3a420 dll: fuse: testing 2016-06-12 23:27:28 -07:00
adecc6fb25 dll: fuse: testing 2016-06-12 21:37:51 -07:00
b71d086ea7 dll: fuse: testing 2016-06-12 21:22:23 -07:00
382a6675da dll: fuse: testing 2016-06-12 16:47:40 -07:00
cbf8079324 dll: fuse: testing 2016-06-12 15:53:12 -07:00
1124e24a61 dll: fuse_intf: ReadDirectory reimplementation 2016-06-12 15:09:38 -07:00
c6bab18947 dll: fuse: testing 2016-06-11 17:10:27 -07:00
3310a4300e dll: fuse: testing 2016-06-11 15:47:28 -07:00
6347803392 dll: fuse: testing 2016-06-11 14:35:02 -07:00
259bd84cc9 dll: fuse: testing 2016-06-11 14:08:05 -07:00
6bc3ec7c8a dll: fuse: testing 2016-06-11 13:37:02 -07:00
cf66fc3931 dll: fuse_intf: eliminate <fcntl.h> dependency 2016-06-11 00:26:40 -07:00
8a5218b273 dll: fuse_intf: Flush implementation 2016-06-10 23:54:25 -07:00
e3ffa209eb dll: fuse_intf: Flush implementation 2016-06-10 23:51:21 -07:00
a8f0f58d35 dll: fuse_intf: Write implementation 2016-06-10 23:40:09 -07:00
beeae73c79 dll: fuse_intf: Write implementation 2016-06-10 23:36:19 -07:00
2aa683177e dll: fuse: rename fuseintf to fuse_intf 2016-06-10 23:19:13 -07:00
0437218691 dll: fuseintf: Read implementation 2016-06-10 23:13:46 -07:00
8a37cb9c36 dll: fuseintf: SetAllocationSize, SetFileSize 2016-06-10 22:59:28 -07:00
32912b587f dll: fuseintf: SetBasicInfo implementation 2016-06-10 22:14:23 -07:00
fb6a139c85 dll: fuseintf: CanDelete improvements 2016-06-10 21:30:59 -07:00
267ed97d36 dll: fuseintf: Rename implementation 2016-06-10 21:21:11 -07:00
53289f0c74 dll: fuseintf: SetVolumeLabel implementation 2016-06-10 18:44:34 -07:00
a4f687c635 dll: fuseintf: CanDelete implementation 2016-06-10 18:42:18 -07:00
55336e3dcf dll: fuseintf: Overwrite implementation 2016-06-10 17:32:51 -07:00
90d868c58f dll: fuseintf: GetVolumeInfo 2016-06-10 17:10:08 -07:00
e0386db270 dll: fuseintf: SetSecurity implementation 2016-06-10 17:00:42 -07:00
3490a379b0 dll: fuseintf: GetSecurity implementation 2016-06-10 16:18:49 -07:00
009728e2b7 dll: fuseintf: ReadDirectory implementation 2016-06-10 16:02:28 -07:00
240bdfeb39 dll: fuseintf: ReadDirectory implementation 2016-06-10 15:24:35 -07:00
ea8ed690f6 dll: fuseintf: ReadDirectory implementation 2016-06-10 00:41:30 -07:00
a94d41c6b4 inc: fuse.h: ensure compatibility with FUSE 2.8 fuse_operations 2016-06-09 22:28:27 -07:00
662df6544f dll: fuseintf: GetFileInfo implementation 2016-06-09 22:06:23 -07:00
15363e0256 dll: fuseintf: Cleanup implementation 2016-06-09 21:47:36 -07:00
c74f34eaf0 dll: fuseintf: Create implementation 2016-06-09 17:14:00 -07:00
bc777f2d91 dll: fuseintf: Open, Close implementation 2016-06-09 16:14:08 -07:00
a9868ba883 dll: fuse: implementation checkpoint 2016-06-09 16:03:40 -07:00
9d42c625cc dll: fuse: implementation checkpoint 2016-06-09 15:40:34 -07:00
afc498ba6e dll: fuse: include 0 -> STATUS_SUCCESS errno translation 2016-06-09 14:58:08 -07:00
e222c3ae72 dll: fuse: implementation checkpoint 2016-06-09 12:50:53 -07:00
90039ecd72 dll: fuse: implementation checkpoint 2016-06-09 10:16:20 -07:00
8f0f5b3d9e dll: fsp_fuse_op_enter, fsp_fuse_op_leave 2016-06-08 22:45:26 -07:00
0e8d694bdd dll: FSP_FILE_SYSTEM_OPERATION_GUARD now returns NTSTATUS 2016-06-08 22:15:24 -07:00
b0b15dff05 dll: fuse: refactor fuse_op to fuse_intf 2016-06-08 21:36:18 -07:00
0f63dddb32 dll: FspFileSystemOpEnter, FspFileSystemOpLeave 2016-06-08 20:43:52 -07:00
20fc185530 dll: fuse: fuse_operations WIP 2016-06-08 14:42:12 -07:00
6b99160625 dll: fuse: fsp_fuse_ntstatus_from_errno 2016-06-08 12:01:35 -07:00
1a406eb462 dll: FspNtStatusFromWin32: wrap unknown Win32 error codes as FACILITY_NTWIN32 status codes 2016-06-07 21:42:28 -07:00
70d5c095ca doc: SSHFS Port Case Study - Step 3 2016-06-07 17:36:23 -07:00
396997fb22 winfsp-tests: posix_map_path_test 2016-06-07 16:03:48 -07:00
8c8d80add3 dll: POSIX interop:
FspPosixMapPosixToWindowsPath, FspPosixMapWindowsToPosixPath
2016-06-07 13:00:15 -07:00
6bef445102 winfsp-tests: posix_map_sd_test 2016-06-07 00:39:43 -07:00
9edbe7012e winfsp-tests: posix_map_sd_test 2016-06-07 00:32:32 -07:00
bc5f5c02db winfsp-tests: posix_map_sd_test 2016-06-07 00:00:15 -07:00
326d6479ad winfsp-tests: posix_map_sd_test 2016-06-06 23:39:50 -07:00
54d343c4e4 winfsp-tests: posix_map_sd_test 2016-06-06 23:28:31 -07:00
96e048ec5e winfsp-tests: posix_map_sd_test 2016-06-06 23:11:03 -07:00
c46d8b2e0a winfsp-tests: posix_map_sd_test 2016-06-06 22:57:28 -07:00
bcfa4a326b dll: POSIX interop: minor fix 2016-06-06 12:15:28 -07:00
b451219bfc dll: POSIX interop: FspPosixMapSecurityDescriptorToPermissions 2016-06-06 12:10:30 -07:00
3286033191 dll: POSIX interop: FspPosixMapPermissionsToSecurityDescriptor 2016-06-06 00:33:26 -07:00
1432d711d8 dll: POSIX interop: FspPosixMapPermissionsToSecurityDescriptor 2016-06-06 00:24:45 -07:00
0d4aa15377 winfsp-tests: posix_map_sid_test 2016-06-05 11:45:18 -07:00
7fbaa8d37c winfsp-tests: posix_map_sid_test 2016-06-05 11:00:58 -07:00
229c3f81fa winfsp-tests: posix_map_sid_test 2016-06-05 00:34:44 -07:00
9ccb394b04 dll: POSIX interop 2016-06-04 23:46:29 -07:00
22da074ff7 dll: fuse: fuse_opt_parse: bugfix in handling templates of the form NAME=VALUE 2016-06-03 15:06:56 -07:00
e08b462566 dll: fuse: cosmetic fix 2016-06-03 14:13:30 -07:00
77e7147893 installer: fix message regarding memfs sample 2016-06-02 23:46:06 -07:00
7d4fc0f740 appveyor: build all branches 2016-06-02 23:32:17 -07:00
f0751f1fb3 dll: fuse: fixes 2016-06-02 23:35:11 -07:00
4e2aaa8a21 doc: add SSHFS Port Case Study document 2016-06-02 23:26:27 -07:00
8525c99d7a dll: fuse: minor fix 2016-06-02 20:49:34 -07:00
9b93c766c3 dll: fsctl, fuse: preflight check 2016-06-02 20:21:34 -07:00
7fef1b87f6 dll: fuse: fix usage message 2016-06-02 14:20:49 -07:00
190e2320c0 dll: fuse: ensure compatibility between winfsp and cygwin stat, etc. definitions 2016-06-02 14:07:29 -07:00
6910b67982 dll: fuse: implementation checkpoint 2016-06-02 13:24:44 -07:00
7e1906bad5 dll: 32-bit builds now include the MSVCRT default libraries (for __allmul symbol) 2016-06-02 13:21:28 -07:00
dddb55243b dll: fuse: implementation checkpoint 2016-06-02 12:11:37 -07:00
88b13082cb dll: fuse: implementation checkpoint 2016-06-02 09:49:55 -07:00
6d5abafdaa dll: fuse: implementation checkpoint 2016-06-02 09:40:56 -07:00
3f8e7273c3 dll: fuse: implementation checkpoint 2016-06-01 18:06:01 -07:00
8b8c567cf7 dll: fuse: remove extraneous newlines in log messages 2016-06-01 17:50:02 -07:00
da95f05b29 dll: fuse: fuseop.c 2016-06-01 16:44:11 -07:00
a53e79984a dll: fuse: implementation checkpoint 2016-06-01 16:05:30 -07:00
59a305b333 dll: fsp_fuse_opt_match: minor change 2016-06-01 12:15:59 -07:00
3620de44d1 dll: fuse: help system refactoring 2016-06-01 00:46:23 -07:00
3f3c02f3ce dll: fuse: help system refactoring 2016-06-01 00:39:27 -07:00
4b9945d9bf dll: fsp_fuse_main_real: implementation 2016-05-31 22:13:17 -07:00
19d400d251 dll: fsp_fuse_parse_cmdline, fsp_fuse_main_real: implementation checkpoint 2016-05-31 21:49:58 -07:00
b559c7405f dll: fuse_opt: support escaped options and related refactoring 2016-05-31 15:34:26 -07:00
765bb1e1a3 fuse: better handling of long (Cygwin64 vs Win64) 2016-05-31 11:12:01 -07:00
300ce8485b fuse: introduction of fsp_fuse_env and major refactoring 2016-05-31 10:53:22 -07:00
4a4dab14c5 inc: fuse: remove long references (as they have different size in Win64 and Cygwin64) 2016-05-31 09:46:02 -07:00
fd8a3ab786 dll: cygwin integration checkpoint 2016-05-31 00:02:45 -07:00
b7665478d9 dll: cygwin integration checkpoint 2016-05-30 22:33:27 -07:00
a938cb4fe6 dll, tst: fix 32-bit build 2016-05-30 15:19:36 -07:00
d12a256430 fuse_opt: fuse_opt_parse: remove backslash escaping for now 2016-05-30 00:17:58 -07:00
bcbba3e4cf fuse_opt: testing 2016-05-29 23:41:55 -07:00
10c3f6f507 fuse_opt: testing 2016-05-29 23:37:30 -07:00
ead273ae18 fuse_opt: testing 2016-05-29 23:31:53 -07:00
74a943d8d7 fuse_opt: implementation checkpoint 2016-05-29 23:05:54 -07:00
a40e7d8c56 fuse_opt: implementation checkpoint 2016-05-29 20:19:12 -07:00
187311bb5e fuse_opt: implementation checkpoint 2016-05-29 17:12:28 -07:00
e14a26b540 fuse_opt: implementation checkpoint 2016-05-29 15:56:19 -07:00
4850056bf6 tst: winfsp-tests: fuse_opt testing 2016-05-29 10:15:37 -07:00
3d3dcbe0c5 dll: fsp_fuse_opt_add_opt: testing 2016-05-28 17:53:11 -07:00
7ea13a967a dll: fsp_fuse_opt_insert_arg/fsp_fuse_opt_free_args: testing 2016-05-28 17:24:34 -07:00
c851e9c98e fuse_opt: implementation checkpoint 2016-05-28 16:07:20 -07:00
9e068049b3 fuse_opt: implementation checkpoint 2016-05-28 12:04:29 -07:00
f993cf7251 fuse_opt: implementation checkpoint 2016-05-28 11:41:12 -07:00
e8f35ac314 fuse_opt: implementation checkpoint 2016-05-28 11:02:55 -07:00
4d57a5c10e fuse_opt: implementation checkpoint 2016-05-27 00:04:50 -07:00
7db0f68dd7 fuse: implementation checkpoint 2016-05-25 18:34:36 -07:00
1f22bd3517 fuse: implementation checkpoint 2016-05-25 16:35:07 -07:00
91825106f1 fuse: implementation skeleton 2016-05-25 14:26:49 -07:00
9bceb577e3 dll: debug: minor fix: ensure that AccessToken is passed as a PVOID to FspDebugLog 2016-05-24 22:14:26 -07:00
2155cbadc3 ext/test: update submodule 2016-05-24 22:02:35 -07:00
71867f6779 sys, dll: IRP_MJ_SET_INFORMATION: perform access checks when replacing file during rename 2016-05-24 21:41:08 -07:00
214b43398f dll: FspAccessCheckEx: if the desired access includes DELETE or FILE_READ_ATTRIBUTES and access was denied, check with the parent 2016-05-24 15:37:16 -07:00
aa75d412ac sys: IRP_MJ_QUERY_VOLUME_INFORMATION: FileFsDeviceInformation: always return FILE_DEVICE_DISK to avoid problem with GetFileType failures 2016-05-23 22:23:47 -07:00
6be55aa515 memfs: allow empty VolumePrefix in command line 2016-05-23 17:16:06 -07:00
10c997ab6b dll: FspDebugLogRequest, FspDebugLoogResponse: improve log message consistency 2016-05-23 16:38:11 -07:00
1505b1f368 memfs: add -d (debug) switch 2016-05-23 13:47:07 -07:00
b004268583 src: dll: FspDebugLogRequest, FspDebugLogResponse 2016-05-23 12:36:49 -07:00
301e8fed62 src: dll: FspDebugLogRequest, FspDebugLogResponse 2016-05-23 11:40:23 -07:00
c2e38bcc97 src: dll: FspDebugLogRequest, FspDebugLogResponse 2016-05-23 11:09:24 -07:00
37b1dc440e tools: rename nmake-test.bat to nmake-ext-test.bat 2016-05-21 17:14:27 -07:00
c4b6e9bb47 appveyor.yml: improve build process 2016-05-21 14:49:25 -07:00
55f9053b1b appveyor.yml: build tests before running them 2016-05-21 14:26:53 -07:00
a53abe8ab6 appveyor.yml: explicitly clone submodules as AppVeyor does not do it automatically 2016-05-21 14:03:50 -07:00
5fa7ba3513 tools: run-tests: add fsx and winfstest tests 2016-05-21 13:31:18 -07:00
7e2c767997 ext: add secfs.test as submodule 2016-05-20 23:26:13 -07:00
d102edf1e9 tools: run-tests.bat: fix silly mistake 2016-05-20 21:27:40 -07:00
0412fac588 tools: run-tests 2016-05-20 21:14:11 -07:00
3935372956 update appveyor.yml: use appveyor command to add test output 2016-05-20 19:03:49 -07:00
d89baea193 memfs: do not update LastAccessTime on Open 2016-05-20 18:39:32 -07:00
599430e649 memfs: fix erroneous realloc 2016-05-20 18:17:00 -07:00
4f5e00474e memfs: handle FILE_ATTRIBUTE_ARCHIVE 2016-05-20 17:56:25 -07:00
16836c7cfb appveyor.yml: build on every push 2016-05-20 15:57:06 -07:00
ffded63c56 tst: lock-test: fix mistake in calling GetOverlappedResult when prior operation has returned error 2016-05-20 14:29:55 -07:00
0dba3ffe55 tools: add missing setlocal command to batch files 2016-05-20 10:58:12 -07:00
122592f332 update appveyor.yml 2016-05-20 10:25:48 -07:00
c4421bf3aa add appveyor.yml 2016-05-19 22:17:40 -07:00
222f015273 src: dll: FspFsctlStartService: return STATUS_NO_SUCH_DEVICE when WinFsp FSD does not exist 2016-05-19 19:17:07 -07:00
153eb42885 tools: build.bat: add setlocal command to avoid environment namespace polution 2016-05-19 16:31:02 -07:00
4d1aeeda4c tools: build.bat: better exit code handling to allow for CI 2016-05-19 13:28:13 -07:00
f2241fcee4 tools: build.bat: better exit code handling to allow for CI 2016-05-19 13:21:42 -07:00
f7adbaba92 dll: FspCallNamedPipeSecurely replaces CallNamedPipeW 2016-05-18 10:05:33 -07:00
fea92c4ae0 doc: add Service Architecture document 2016-05-17 18:59:16 -07:00
1e2f0930a2 inc: winfsp.h: add service related documentation 2016-05-17 16:21:18 -07:00
ab11ff2b39 dll: np: NPEnumResource: minor change 2016-05-17 13:01:20 -07:00
1e1b9cdda3 dll: NPOpenEnum, NPEnumResources, NPCloseEnum: testing 2016-05-17 11:49:31 -07:00
00ee25f904 dll: NPOpenEnum, NPEnumResources, NPCloseEnum: implementation 2016-05-17 00:39:26 -07:00
cf29bd5a58 dll: FspNpAddConnection3, FspNpCancelConnection: improve error handling 2016-05-16 21:35:52 -07:00
597dd43f23 launcher: fix bug in SvcInstanceCreate 2016-05-16 16:34:59 -07:00
1c3fc530f6 dll: np: NPAddConnection3, NPCancelConnection implementation 2016-05-16 15:48:27 -07:00
67c6cd453a dll: FspNpRegister: get NetworkProvider name from version info 2016-05-15 15:14:12 -07:00
7eec1649a4 installer: add requirement for VC++ redistributable to F.Developer feature description 2016-05-15 13:24:17 -07:00
9971472be7 launcher, launchctl: ensure that they build under all platforms/configurations 2016-05-15 11:22:19 -07:00
c1985bef6c installer: update installer to include launcher and launchctl and install launcher as a service 2016-05-15 10:05:39 -07:00
e4e2465bcb memfs: empty Mountpoint ("") now means autodetect (same as no MountPoint) 2016-05-14 23:52:37 -07:00
22d1f86ac1 launcher: AllocConsole if we are running as a service without one (DETACHED_PROCESS) 2016-05-14 23:18:43 -07:00
1a7d3b8f9e launcher: remove JOB_OBJECT_LIMIT_BREAKAWAY_OK, use JobControl=0 registry setting instead 2016-05-14 21:01:29 -07:00
768a393342 launcher, launchctl: add quit command on debug version of launcher 2016-05-14 21:00:02 -07:00
08a02d7b35 launcher:
- STOP_TIMEOUT vs KILL_TIMEOUT
    - JobControl registry value
2016-05-14 19:27:59 -07:00
3035ba2847 launcher: better handling of service instance stopping:
- instances are now launched in a job so that they get killed if the parent process dies
    - instances are killed after a timeout if they do not respond timely to console control events
2016-05-14 18:47:26 -07:00
147c90be9f launcher: minor bug fix 2016-05-13 15:25:31 -07:00
0822458238 launcher: SvcInstanceReplaceArguments 2016-05-13 14:30:54 -07:00
c322a4b14a launcher: testing 2016-05-13 13:13:08 -07:00
0c6300b97c launcher: testing 2016-05-13 12:38:30 -07:00
be952729c9 launcher, launchctl: testing 2016-05-13 12:07:30 -07:00
1802ac8878 launcher, launchctl: testing 2016-05-13 11:10:59 -07:00
5491187e1d launcher, launchctl: command line arguments are now numbered %1 to %9 2016-05-13 10:42:23 -07:00
ec2494433b launcher: fix deadlock when SvcPipeServer stops itself 2016-05-13 10:37:25 -07:00
0756649572 launchctl: fix usage string 2016-05-13 10:24:12 -07:00
8ccd44a1f7 launcher, launchctl: refactoring 2016-05-13 10:00:54 -07:00
2c51251cb7 launcher, launchctl: refactoring 2016-05-13 09:55:27 -07:00
35d2b3f626 launcher, launchctl: refactoring 2016-05-13 09:28:56 -07:00
26a9bb714b launchctl: major refactoring 2016-05-12 22:44:34 -07:00
13f2517a31 launchctl: major refactoring 2016-05-12 22:36:37 -07:00
da85f2aa08 launcher, launchctl: testing 2016-05-12 22:11:28 -07:00
22c324de69 launcher: testing 2016-05-12 17:19:48 -07:00
c42e2a5958 launcher: security model improvements 2016-05-12 15:31:35 -07:00
1c587dbcb7 version.properties: bump version to 0.11 2016-05-12 14:49:10 -07:00
bc2e87763e launcher, launchctl: add version info 2016-05-12 14:48:18 -07:00
724d177d0b launcher: security model improvements 2016-05-12 14:18:08 -07:00
6971f4d6ae launcher: access control 2016-05-12 13:44:07 -07:00
ceef2bf55e launcher: access check on client token 2016-05-11 21:35:12 -07:00
a81a766bbe launcher: named pipe SDDL 2016-05-11 20:37:44 -07:00
da839e39b8 launcher: SvcInstanceCreate improvements 2016-05-11 20:23:00 -07:00
ec21e830f1 launchctl: implementation 2016-05-11 17:40:49 -07:00
9ae28a5529 add launchctl project 2016-05-11 16:02:56 -07:00
1a14971911 launcher: improvements 2016-05-11 15:32:16 -07:00
ab48beb4ba launcher: List, Info command implementation 2016-05-11 15:20:23 -07:00
528cbd3295 launcher: named pipe implementation 2016-05-11 14:46:03 -07:00
c32d05c3b6 launcher: named pipe implementation 2016-05-11 13:31:07 -07:00
e82b06ae49 dll: FspServiceStop: early exit if service is already being stopped 2016-05-11 11:29:36 -07:00
457e151fa5 launcher: SvcInstance implementation 2016-05-10 16:48:21 -07:00
dc4109fc22 dll: refactor library.h into src/shared/minimal.h for reuse 2016-05-09 20:07:35 -07:00
2a69ad6710 add launcher project 2016-05-09 16:20:52 -07:00
d3ff12bf60 dll: FspServiceConsoleModeThread: fix stupid bug with command line argument handling 2016-05-09 14:51:30 -07:00
713ee8a917 memfs: add old memfs-main.c 2016-05-09 14:17:28 -07:00
f4744258a7 dll: FspServiceCtrlHandler: disable Shutdown handling 2016-05-09 13:50:36 -07:00
7e57edf72e dll: FspService: console mode further improvements with respect to console ctrl handling 2016-05-09 13:19:54 -07:00
89e4e8a96c dll: FspService: console mode testing 2016-05-09 12:35:51 -07:00
0c18b82cc2 dll: FspService: console mode improvements 2016-05-08 21:12:34 -07:00
57f9db6cc0 dll: FspService: console mode improvements 2016-05-08 17:57:08 -07:00
6da81be792 dll: FspService: console mode improvements 2016-05-08 17:46:09 -07:00
b77a749f93 dll: FspService: improve console mode handling 2016-05-08 17:23:12 -07:00
bb946d5a3a dll: streamline DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH handling 2016-05-08 16:22:07 -07:00
27a16e5c54 dll: service: testing 2016-05-07 22:37:17 -07:00
789222af68 dll: FspServiceRun 2016-05-07 17:25:49 -07:00
587fee93e9 dll, memfs: rename FspServiceRun to FspServiceLoop 2016-05-07 17:08:03 -07:00
077bbb0d65 memfs: convert to service 2016-05-07 17:00:58 -07:00
3d2a2dd90d dll: service: use FspServiceLog instead of FspEventLog 2016-05-07 14:57:39 -07:00
0b1bba36f8 dll: FspIsInteractive, FspServiceLog, FspServiceLogV 2016-05-07 14:55:19 -07:00
8dd5a03b51 dll: FSP_SERVICE: rename interactive mode to console mode 2016-05-07 13:30:12 -07:00
ac2e9f9882 dll: FSP_SERVICE 2016-05-07 12:56:32 -07:00
1017e7fda7 dll: FSP_SERVICE 2016-05-07 12:55:48 -07:00
125b612c9f winfsp-tests: eventlog-test.c 2016-05-06 15:58:33 -07:00
9addfa5899 dll: FspEventLogRegister, FspEventLogUnregister 2016-05-06 15:05:36 -07:00
12db7cf9dc dll: add eventlog.mc and related files 2016-05-06 13:15:29 -07:00
e53e915a72 dll: service, eventlog 2016-05-06 12:25:47 -07:00
d7a6f33d26 dll: add FSP_SERVICE and EventLog functionality 2016-05-06 11:41:45 -07:00
de973fa5ab dll: FspFileSystemRegister, FspFileSystemUnregister: rename and place in fsctl.c 2016-05-05 11:14:23 -07:00
4a4fba4670 build: bump version to 0.10 2016-05-04 16:32:17 -07:00
e45ac30b65 tools: build.bat: add friendly MSI name when signing (primarily for use in UAC dialog) 2016-05-04 16:25:49 -07:00
cbb7d943bd dll: fsctl: FspFsctlStartService 2016-05-04 16:06:14 -07:00
df5d2d6e87 installer: disallow major upgrades 2016-05-04 15:22:03 -07:00
b1b31b9017 dll: FspFileSystemRegister: fix WinFsp service security descriptor to allow Everyone to start the service 2016-05-04 13:29:34 -07:00
ff0b8bc3fe installer: only install memfs executables when developer build is selected! 2016-05-04 00:34:44 -07:00
a99e8ac9d2 dll: FspFileSystemRegister: handle the case where service already exists better 2016-05-03 22:53:51 -07:00
3f7ebe7996 tools: build.bat: sign MSI 2016-05-03 22:15:58 -07:00
030ef84c2e installer: check if ServiceRunning both on install and uninstall 2016-05-03 21:59:58 -07:00
ba5c670034 tools: build.bat 2016-05-03 15:13:21 -07:00
690e7662d6 dll: FspFileSystemRegister: now will correctly recreate the WinFsp service if it already exists 2016-05-02 21:54:59 -07:00
500db7b1cd installer: CustomActions: ServiceRunning 2016-05-02 20:47:24 -07:00
e43c5091e4 dll: FspFileSystemRegister, FspFileSystemUnregister: fix closing the wrong handle 2016-05-02 12:26:33 -07:00
9ffc3f03ed memfs: comment fix 2016-05-02 11:12:41 -07:00
14366f76c5 installer: simplify FSD/DLL registration by removing regsvr32 custom actions 2016-05-01 20:22:38 -07:00
b089b98afc dll: FspFileSystemRegister, FspFileSystemUnregister 2016-05-01 18:01:49 -07:00
26aadb0b72 installer: use regsvr32 to register FSD/DLL (Wix cannot register file system drivers or network provider DLL's) 2016-04-30 17:33:25 -07:00
9c11ca5bda installer: remember installation directory in registry 2016-04-29 16:33:55 -07:00
8ae2bb3bfc build: update version.properties 2016-04-29 14:22:53 -07:00
b0a2e4ff40 installer: add UI 2016-04-29 11:38:38 -07:00
0c75b58810 versioning: rename shared.properties to version.properties 2016-04-29 00:33:46 -07:00
b12e0aad47 versioning: add version resources to FSD and DLL; consolidate versioning to shared.properties 2016-04-29 00:23:55 -07:00
1264cae110 installer: reorg 2016-04-28 22:19:59 -07:00
5a7c7bb4f2 installer: automatic versioning scheme 2016-04-28 21:51:29 -07:00
acfd02c31d installer: add Package description 2016-04-28 19:22:21 -07:00
efa200aac4 installer: add memfs sample 2016-04-28 17:31:13 -07:00
3a1cba2442 installer: reorg 2016-04-28 17:19:07 -07:00
59698f5517 installer: reorg 2016-04-28 16:39:49 -07:00
1176114528 install: winfsp.wixproj 2016-04-28 15:55:05 -07:00
e0dde7349e sys,dll,tst: ensure that project compiles for x86 2016-04-28 15:02:00 -07:00
1bdfc8a579 install: winfsp.wixproj 2016-04-28 14:47:09 -07:00
2659effafb install: winfsp.wixproj 2016-04-28 13:04:46 -07:00
151 changed files with 21903 additions and 1220 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "ext/test"]
path = ext/test
url = https://github.com/billziss-gh/secfs.test.git

View File

@ -1,5 +1,7 @@
# WinFsp - Windows File System Proxy
![WinFsp Demo](http://www.secfs.net/winfsp/files/cap.gif)
WinFsp is a set of software components for Windows computers that allows the creation of user mode file systems. In this sense it is similar to FUSE (Filesystem in Userspace), which provides the same functionality on UNIX-like computers.
Some of the benefits and features of using WinFsp are listed below:
@ -20,19 +22,55 @@ 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: contains the WinFsp solution and project files.
* doc: contains the WinFsp license, contributor agreement and additional documentation. The WinFsp design document can be found here.
* ext/tlib: contains a small test library originally from the secfs (Secure Cloud File System) project.
* inc/winfsp: contains public include files to be used when developing a user mode file system.
* src/dll: contains the source code to the WinFsp DLL.
* src/sys: contains the source code to the WinFsp FSD.
* tst/memfs: contains the source code to an example file system written in C++ (memfs).
* tst/winfsp-tests: contains the WinFsp test suite.
* build/VStudio: WinFsp solution and project files.
* doc: WinFsp license, contributor agreement and additional documentation. The WinFsp design documents 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.
* inc/fuse: Public headers for the FUSE compatibility layer.
* src/dll: Source code to the WinFsp DLL.
* src/dll/fuse: Source code to the FUSE compatibility layer.
* src/launcher: Source code to the launcher service and the launchctl utility.
* src/sys: Source code to the WinFsp FSD.
* opt/cygfuse: Source code for the Cygwin FUSE package.
* tst/memfs: Source code to an example file system written in C++ (memfs).
* tst/winfsp-tests: WinFsp test suite.
## Building
## Building and Running
In order to build WinFsp you will need Windows 10 and Visual Studio 2015. You will also need the Windows Driver Kit (WDK) 10.
In order to build WinFsp you will need the following:
* Windows 10
* Visual Studio 2015
* Windows Driver Kit (WDK) 10
* [Wix toolset](http://wixtoolset.org)
If you build the driver yourself it will not be signed and Windows will refuse to load it unless you enable "testsigning". You can enable "testsigning" using the command `bcdedit.exe -set testsigning`. For more information see this [document](http://www.secfs.net/winfsp/develop/debug/).
WinFsp is designed to run on Vista and above. It has been tested on the following platforms so far:
* Windows 7 Enterprise
* Windows 8 Pro
* Windows 10 Pro
* Windows Server 2012
## How to Help
I am looking for help in the following areas:
* If you have a file system that runs on FUSE please consider porting it to WinFsp. WinFsp has a native API, but it also has a FUSE (high-level) API.
* If you are working with a language other than C/C++ (e.g. Delphi, C#, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you.
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues) ~~[BitBucket repository](https://bitbucket.org/billziss/winfsp/issues?status=new&status=open)~~. Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart. If you decide to tackle any of those please coordinate with me as I am actively working on that issue list.
In all cases I can provide ideas and/or support.
## Where to Discuss
If you wish to discuss WinFsp there are now two options:
- [WinFsp Google Group](https://groups.google.com/forum/#!forum/winfsp)
- [Author's Twitter](https://twitter.com/BZissimopoulos)
## License
WinFsp is available under the [AGPLv3](http://www.gnu.org/licenses/agpl-3.0.html) license. If you find the constraints of the AGPLv3 too onerous, a commercial license is also available. Please contact Bill Zissimopoulos <billziss at navimatics.com> for more details.
WinFsp is available under the [GPLv3](http://www.gnu.org/licenses/gpl-3.0.html) license. If you find the constraints of the GPLv3 too onerous, a commercial license is also available. Please contact Bill Zissimopoulos <billziss at navimatics.com> for more details.

23
appveyor.yml Normal file
View File

@ -0,0 +1,23 @@
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

BIN
art/winfsp-outln.afdesign Normal file

Binary file not shown.

BIN
art/winfsp-solid.afdesign Normal file

Binary file not shown.

BIN
art/winfsp-solid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
art/wixbanner.pxm Normal file

Binary file not shown.

BIN
art/wixdialog.pxm Normal file

Binary file not shown.

View File

@ -0,0 +1,83 @@
/**
* @file CustomActions.cpp
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <msiquery.h>
#include <wcautil.h>
#include <strutil.h>
UINT __stdcall ServiceRunning(MSIHANDLE MsiHandle)
{
#if 0
WCHAR MessageBuf[64];
wsprintfW(MessageBuf, L"PID=%ld", GetCurrentProcessId());
MessageBoxW(0, MessageBuf, L"" __FUNCTION__ " Break", MB_OK);
#endif
HRESULT hr = S_OK;
UINT err = ERROR_SUCCESS;
PWSTR ServiceName = 0;
SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0;
SERVICE_STATUS ServiceStatus;
int Result = 0;
hr = WcaInitialize(MsiHandle, __FUNCTION__);
ExitOnFailure(hr, "Failed to initialize");
WcaGetProperty(L"" __FUNCTION__, &ServiceName);
ExitOnFailure(hr, "Failed to get ServiceName");
WcaLog(LOGMSG_STANDARD, "Initialized: \"%S\"", ServiceName);
ScmHandle = OpenSCManagerW(0, 0, 0);
ExitOnNullWithLastError(ScmHandle, hr, "Failed to open SCM");
SvcHandle = OpenServiceW(ScmHandle, ServiceName, SERVICE_QUERY_STATUS);
if (0 != SvcHandle && QueryServiceStatus(SvcHandle, &ServiceStatus))
Result = SERVICE_STOPPED != ServiceStatus.dwCurrentState;
WcaSetIntProperty(L"" __FUNCTION__, Result);
LExit:
if (0 != SvcHandle)
CloseServiceHandle(SvcHandle);
if (0 != ScmHandle)
CloseServiceHandle(ScmHandle);
ReleaseStr(ServiceName);
err = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(err);
}
extern "C"
BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH:
WcaGlobalInitialize(Instance);
break;
case DLL_PROCESS_DETACH:
WcaGlobalFinalize();
break;
}
return TRUE;
}

View File

@ -0,0 +1,2 @@
EXPORTS
ServiceRunning

View File

@ -0,0 +1,112 @@
<?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>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{95C223E6-B5F1-4FD0-9376-41CDBC824445}</ProjectGuid>
<RootNamespace>CustomActions</RootNamespace>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.25123.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(WIX)sdk\VS2015\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(WIX)sdk\VS2015\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ModuleDefinitionFile>CustomActions.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(WIX)sdk\VS2015\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(WIX)sdk\VS2015\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ModuleDefinitionFile>CustomActions.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="CustomActions.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="CustomActions.def" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,19 @@
<?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="CustomActions.cpp">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="CustomActions.def">
<Filter>Source</Filter>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,424 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product
Id="*"
Name="$(var.MyProductName)"
Manufacturer="$(var.MyCompanyName)"
Version="$(var.MyVersion)"
Language="1033"
UpgradeCode="82F812D9-4083-4EF1-8BC8-0F1EDA05B46B">
<Package
Description="$(var.MyProductName) - $(var.MyDescription)"
InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine" />
<MajorUpgrade
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." />
<Media Id="1" Cabinet="WinFsp.cab" EmbedCab="yes" />
<Property Id="P.LauncherName">$(var.MyProductName).Launcher</Property>
<Property Id="P.LauncherRegistryKey">SYSTEM\\CurrentControlSet\\Services\\$(var.MyProductName).Launcher\\Services</Property>
<Property Id="P.RegistryKey">Software\$(var.MyProductName)</Property>
<Property Id="INSTALLDIR">
<RegistrySearch
Id="R.INSTALLDIR"
Root="HKLM"
Key="[P.RegistryKey]"
Name="InstallDir"
Type="raw" />
</Property>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="WinFsp">
<Directory Id="BINDIR" Name="bin" />
<Directory Id="INCDIR" Name="inc" />
<Directory Id="LIBDIR" Name="lib" />
<Directory Id="SMPDIR" Name="samples" />
<Directory Id="SYMDIR" Name="sym" />
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="INSTALLDIR">
<Component Id="C.INSTALLDIR" Guid="{F876F26E-5016-4AC6-93B3-653C0312A6CE}">
<RegistryValue
Root="HKLM"
Key="[P.RegistryKey]"
Name="InstallDir"
Type="string"
Value="[INSTALLDIR]"
KeyPath="yes" />
</Component>
</DirectoryRef>
<DirectoryRef Id="BINDIR" FileSource="..\build\$(var.Configuration)">
<Component Id="C.winfsp_x64.sys">
<File Name="winfsp-x64.sys" KeyPath="yes" />
</Component>
<Component Id="C.winfsp_x86.sys">
<File Name="winfsp-x86.sys" KeyPath="yes" />
</Component>
<!-- On Win64 register winfsp-x64.dll -->
<Component Id="C.winfsp_x64.dll.selfreg" Guid="F0A67746-1A9C-4976-8EC0-882E9407FA6D">
<File Id="FILE.winfsp_x64.dll.selfreg" Name="winfsp-x64.dll" KeyPath="yes" SelfRegCost="1" />
<Condition>VersionNT64</Condition>
</Component>
<Component Id="C.winfsp_x86.dll" Guid="950492FB-12F7-4E27-9124-8325A2BC9927">
<File Name="winfsp-x86.dll" KeyPath="yes" />
<Condition>VersionNT64</Condition>
</Component>
<!-- On Win32 register winfsp-x86.dll -->
<Component Id="C.winfsp_x64.dll" Guid="4D6E7A8E-0CA6-49BE-B312-1EDADE725756">
<File Name="winfsp-x64.dll" KeyPath="yes" />
<Condition>NOT VersionNT64</Condition>
</Component>
<Component Id="C.winfsp_x86.dll.selfreg" Guid="F0DEF7A6-AF55-419F-A58A-DF4018C6FA73">
<File Id="FILE.winfsp_x86.dll.selfreg" Name="winfsp-x86.dll" KeyPath="yes" SelfRegCost="1" />
<Condition>NOT VersionNT64</Condition>
</Component>
<!-- On Win64 ServiceInstall launcher-x64.exe -->
<Component Id="C.launcher_x64.exe.svcinst">
<File Id="launcher_x64.exe.svcinst" Name="launcher-x64.exe" KeyPath="yes" />
<ServiceInstall
Id="launcher_x64.exe.svcinst"
Name="[P.LauncherName]"
Description="$(var.MyDescription)"
Type="ownProcess"
Start="auto"
ErrorControl="ignore" />
<ServiceControl
Id="launcher_x64.exe.svcinst"
Name="[P.LauncherName]"
Start="install"
Stop="both"
Remove="uninstall" />
<Condition>VersionNT64</Condition>
</Component>
<Component Id="C.launcher_x86.exe">
<File Name="launcher-x86.exe" KeyPath="yes" />
<Condition>VersionNT64</Condition>
</Component>
<!-- On Win32 ServiceInstall launcher-x86.exe -->
<Component Id="C.launcher_x64.exe" Guid="88CDBE92-8B67-485A-838F-FA4AD37F306F">
<File Name="launcher-x64.exe" KeyPath="yes" />
<Condition>NOT VersionNT64</Condition>
</Component>
<Component Id="C.launcher_x86.exe.svcinst" Guid="E995D906-0273-4758-9B26-99A3A8CD143A">
<File Id="launcher_x86.exe.svcinst" Name="launcher-x86.exe" KeyPath="yes" />
<ServiceInstall
Id="launcher_x86.exe.svcinst"
Name="[P.LauncherName]"
Description="$(var.MyDescription)"
Type="ownProcess"
Start="auto"
ErrorControl="ignore" />
<ServiceControl
Id="launcher_x86.exe.svcinst"
Name="[P.LauncherName]"
Start="install"
Stop="both"
Remove="uninstall" />
<Condition>NOT VersionNT64</Condition>
</Component>
<Component Id="C.launchctl_x64.exe" Guid="2753623B-66F1-4514-B9C7-F879178DFF49">
<File Name="launchctl-x64.exe" KeyPath="yes" />
</Component>
<Component Id="C.launchctl_x86.exe" Guid="EBDEC4FB-07BB-47CA-BFFF-EB854CA2D22D">
<File Name="launchctl-x86.exe" KeyPath="yes" />
</Component>
<Component Id="C.diag.bat">
<File Name="diag.bat" Source="..\..\..\tools\diag.bat" KeyPath="yes" />
</Component>
<Component Id="C.memfs_x64.exe">
<File Name="memfs-x64.exe" KeyPath="yes" />
<RegistryKey
Root="HKLM"
Key="[P.LauncherRegistryKey]">
<RegistryKey
Key="memfs64">
<RegistryValue
Type="string"
Name="Executable"
Value="[BINDIR]memfs-x64.exe" />
<RegistryValue
Type="string"
Name="CommandLine"
Value="-u %1 -m %2" />
<RegistryValue
Type="string"
Name="Security"
Value="D:P(A;;RPWPLC;;;WD)" />
<RegistryValue
Type="integer"
Name="JobControl"
Value="1" />
</RegistryKey>
</RegistryKey>
</Component>
<Component Id="C.memfs_x86.exe">
<File Name="memfs-x86.exe" KeyPath="yes" />
<RegistryKey
Root="HKLM"
Key="[P.LauncherRegistryKey]">
<RegistryKey
Key="memfs32">
<RegistryValue
Type="string"
Name="Executable"
Value="[BINDIR]memfs-x86.exe" />
<RegistryValue
Type="string"
Name="CommandLine"
Value="-u %1 -m %2" />
<RegistryValue
Type="string"
Name="Security"
Value="D:P(A;;RPWPLC;;;WD)" />
<RegistryValue
Type="integer"
Name="JobControl"
Value="1" />
</RegistryKey>
</RegistryKey>
</Component>
</DirectoryRef>
<DirectoryRef Id="INCDIR" FileSource="..\..\..\inc">
<Directory Id="INCDIR.winfsp" Name="winfsp">
<Component Id="C.fsctl.h">
<File Name="fsctl.h" KeyPath="yes" />
</Component>
<Component Id="C.winfsp.h">
<File Name="winfsp.h" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="INCDIR.fuse" Name="fuse">
<Component Id="C.fuse.h">
<File Name="fuse.h" KeyPath="yes" />
</Component>
<Component Id="C.fuse_common.h">
<File Name="fuse_common.h" KeyPath="yes" />
</Component>
<Component Id="C.fuse_opt.h">
<File Name="fuse_opt.h" KeyPath="yes" />
</Component>
<Component Id="C.winfsp_fuse.h">
<File Name="winfsp_fuse.h" KeyPath="yes" />
</Component>
</Directory>
</DirectoryRef>
<DirectoryRef Id="LIBDIR" FileSource="..\build\$(var.Configuration)">
<Component Id="C.winfsp_x64.lib">
<File Name="winfsp-x64.lib" KeyPath="yes" />
</Component>
<Component Id="C.winfsp_x86.lib">
<File Name="winfsp-x86.lib" KeyPath="yes" />
</Component>
<!-- On Win64 copy fuse-x64.pc -->
<Component Id="C.fuse_x64.pc" Guid="407395D2-D076-411E-B1D0-D97E21E11A3C">
<File
Id="FILE.fuse_x64.pc"
Name="fuse.pc"
Source="..\build\$(var.Configuration)\fuse-x64.pc"
KeyPath="yes" />
<Condition>VersionNT64</Condition>
</Component>
<!-- On Win32 copy fuse-x86.pc -->
<Component Id="C.fuse_x86.pc" Guid="0568EBCB-782E-4C17-9B64-BAFCC43F64ED">
<File
Id="FILE.fuse_x86.pc"
Name="fuse.pc"
Source="..\build\$(var.Configuration)\fuse-x86.pc"
KeyPath="yes" />
<Condition>NOT VersionNT64</Condition>
</Component>
</DirectoryRef>
<DirectoryRef Id="SMPDIR" FileSource="..\..\..\tst">
<Directory Id="SMPDIR.memfs" Name="memfs">
<Component Id="C.memfs.h">
<File Name="memfs.h" KeyPath="yes" />
</Component>
<Component Id="C.memfs.cpp">
<File Name="memfs.cpp" KeyPath="yes" />
</Component>
<Component Id="C.memfs_main.c">
<File Name="memfs-main.c" KeyPath="yes" />
</Component>
</Directory>
</DirectoryRef>
<DirectoryRef Id="SYMDIR">
<Component Id="C.winfsp_x64.sys.pdb">
<File Name="winfsp-x64.sys.pdb" Source="..\build\$(var.Configuration)\winfsp-x64.sys.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.winfsp_x86.sys.pdb">
<File Name="winfsp-x86.sys.pdb" Source="..\build\$(var.Configuration)\winfsp-x86.sys.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.winfsp_x64.dll.pdb">
<File Name="winfsp-x64.dll.pdb" Source="..\build\$(var.Configuration)\winfsp-x64.dll.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.winfsp_x86.dll.pdb">
<File Name="winfsp-x86.dll.pdb" Source="..\build\$(var.Configuration)\winfsp-x86.dll.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.launcher_x64.pdb">
<File Name="launcher-x64.pdb" Source="..\build\$(var.Configuration)\launcher-x64.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.launcher_x86.pdb">
<File Name="launcher-x86.pdb" Source="..\build\$(var.Configuration)\launcher-x86.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.launchctl_x64.pdb">
<File Name="launchctl-x64.pdb" Source="..\build\$(var.Configuration)\launchctl-x64.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.launchctl_x86.pdb">
<File Name="launchctl-x86.pdb" Source="..\build\$(var.Configuration)\launchctl-x86.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.memfs_x64.pdb">
<File Name="memfs-x64.pdb" Source="..\build\$(var.Configuration)\memfs-x64.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.memfs_x86.pdb">
<File Name="memfs-x86.pdb" Source="..\build\$(var.Configuration)\memfs-x86.public.pdb" KeyPath="yes" />
</Component>
</DirectoryRef>
<ComponentGroup Id="C.WinFsp.bin">
<ComponentRef Id="C.winfsp_x64.sys" />
<ComponentRef Id="C.winfsp_x86.sys" />
<ComponentRef Id="C.winfsp_x64.dll.selfreg" />
<ComponentRef Id="C.winfsp_x86.dll" />
<ComponentRef Id="C.winfsp_x64.dll" />
<ComponentRef Id="C.winfsp_x86.dll.selfreg" />
<ComponentRef Id="C.launcher_x64.exe.svcinst" />
<ComponentRef Id="C.launcher_x86.exe" />
<ComponentRef Id="C.launcher_x64.exe" />
<ComponentRef Id="C.launcher_x86.exe.svcinst" />
<ComponentRef Id="C.launchctl_x64.exe" />
<ComponentRef Id="C.launchctl_x86.exe" />
<ComponentRef Id="C.diag.bat" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.inc">
<ComponentRef Id="C.fsctl.h" />
<ComponentRef Id="C.winfsp.h" />
<ComponentRef Id="C.fuse.h" />
<ComponentRef Id="C.fuse_common.h" />
<ComponentRef Id="C.fuse_opt.h" />
<ComponentRef Id="C.winfsp_fuse.h" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.lib">
<ComponentRef Id="C.winfsp_x64.lib" />
<ComponentRef Id="C.winfsp_x86.lib" />
<ComponentRef Id="C.fuse_x64.pc" />
<ComponentRef Id="C.fuse_x86.pc" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.smp">
<ComponentRef Id="C.memfs_x64.exe" />
<ComponentRef Id="C.memfs_x86.exe" />
<ComponentRef Id="C.memfs.h" />
<ComponentRef Id="C.memfs.cpp" />
<ComponentRef Id="C.memfs_main.c" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.sym">
<ComponentRef Id="C.winfsp_x64.sys.pdb" />
<ComponentRef Id="C.winfsp_x86.sys.pdb" />
<ComponentRef Id="C.winfsp_x86.dll.pdb" />
<ComponentRef Id="C.winfsp_x64.dll.pdb" />
<ComponentRef Id="C.launcher_x86.pdb" />
<ComponentRef Id="C.launcher_x64.pdb" />
<ComponentRef Id="C.launchctl_x64.pdb" />
<ComponentRef Id="C.launchctl_x86.pdb" />
<ComponentRef Id="C.memfs_x64.pdb" />
<ComponentRef Id="C.memfs_x86.pdb" />
</ComponentGroup>
<Feature
Id="F.Main"
Level="1"
Title="$(var.MyProductName) $(var.MyVersion)"
Description="$(var.MyDescription)"
Display="expand"
ConfigurableDirectory="INSTALLDIR"
AllowAdvertise="no"
InstallDefault="local"
Absent="disallow">
<ComponentRef Id="C.INSTALLDIR" />
<Feature
Id="F.User"
Level="1"
Title="Core"
Description="The core $(var.MyProductName) files."
AllowAdvertise="no"
InstallDefault="local"
Absent="disallow">
<ComponentGroupRef Id="C.WinFsp.bin" />
</Feature>
<Feature
Id="F.Developer"
Level="1000"
Title="Developer"
Description="Additional files needed for development."
AllowAdvertise="no"
InstallDefault="local"
Absent="allow">
<ComponentGroupRef Id="C.WinFsp.inc" />
<ComponentGroupRef Id="C.WinFsp.lib" />
<ComponentGroupRef Id="C.WinFsp.smp" />
<ComponentGroupRef Id="C.WinFsp.sym" />
</Feature>
</Feature>
<WixVariable Id="WixUIBannerBmp" Value="wixbanner.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="wixdialog-$(var.MyDevStage).bmp" />
<UI Id="FeatureTree">
<UIRef Id="WixUI_FeatureTree" />
<!-- skip the license agreement dialog; higher Order takes priority (weird) -->
<Publish
Dialog="WelcomeDlg"
Control="Next"
Event="NewDialog"
Value="CustomizeDlg"
Order="10">NOT Installed</Publish>
<Publish
Dialog="CustomizeDlg"
Control="Back"
Event="NewDialog"
Value="WelcomeDlg"
Order="10">NOT Installed</Publish>
</UI>
<Binary Id="CustomActions" SourceFile="..\build\$(var.Configuration)\CustomActions.dll" />
<CustomAction
Id="Params.ServiceRunning"
Property="ServiceRunning"
Value="$(var.MyProductName)" />
<CustomAction
Id="Action.ServiceRunning"
BinaryKey="CustomActions"
DllEntry="ServiceRunning"
Execute="immediate"
Return="ignore" />
<CustomAction
Id="Action.ServiceRunning.Error"
Error="The $(var.MyProductName) service appears to be running. If you just uninstalled $(var.MyProductName) please restart your computer. If you are running a development version of $(var.MyProductName) please remove it before proceeding." />
<InstallExecuteSequence>
<Custom Action="Params.ServiceRunning" Before="Action.ServiceRunning" />
<Custom Action="Action.ServiceRunning" Before="LaunchConditions" />
<Custom Action="Action.ServiceRunning.Error" After="Action.ServiceRunning">
<![CDATA[NOT Installed AND (0 <> ServiceRunning)]]>
</Custom>
<ScheduleReboot After="RemoveFiles">
<![CDATA[(REMOVE ~= "ALL") AND (0 <> ServiceRunning)]]>
</ScheduleReboot>
</InstallExecuteSequence>
</Product>
</Wix>

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\version.properties" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>3.10</ProductVersion>
<ProjectGuid>d53aac39-4c57-4ca5-a4f3-c2b24888c594</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>winfsp-$(MyVersion)</OutputName>
<OutputType>Package</OutputType>
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
<Name>winfsp.msi</Name>
</PropertyGroup>
<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>
<SuppressAllWarnings>False</SuppressAllWarnings>
<Pedantic>True</Pedantic>
<SuppressPdbOutput>True</SuppressPdbOutput>
<SuppressIces>ICE30</SuppressIces>
</PropertyGroup>
<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>
<SuppressAllWarnings>False</SuppressAllWarnings>
<Pedantic>True</Pedantic>
<SuppressPdbOutput>True</SuppressPdbOutput>
<SuppressIces>ICE30</SuppressIces>
</PropertyGroup>
<ItemGroup>
<Compile Include="Product.wxs" />
</ItemGroup>
<ItemGroup>
<WixExtension Include="WixUIExtension">
<HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
<Name>WixUIExtension</Name>
</WixExtension>
</ItemGroup>
<Import Project="$(WixTargetsPath)" />
<!--
To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Wix.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 KiB

View File

@ -0,0 +1,210 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\version.properties" />
<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>{73EAAEDA-557B-48D5-A137-328934720FB4}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>launchctl</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>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</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>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</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>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\launcher\launcher.h" />
<ClInclude Include="..\..\..\src\shared\minimal.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\launcher\launchctl.c" />
</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>
</ResourceCompile>
</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,33 @@
<?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="Include">
<UniqueIdentifier>{e650819b-355e-455c-81c9-10dc7debe109}</UniqueIdentifier>
</Filter>
<Filter Include="Include\shared">
<UniqueIdentifier>{744edf89-567a-40b7-b6f2-ee2bc7b9f0d9}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\shared\minimal.h">
<Filter>Include\shared</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\launcher\launcher.h">
<Filter>Source</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\launcher\launchctl.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\src\launcher\launchctl-version.rc">
<Filter>Source</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,214 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\version.properties" />
<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>{A5EFD487-0140-4184-8C54-FFAEC2F85E35}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>launcher</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>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</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>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</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>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\launcher\launcher.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\winfsp_dll.vcxproj">
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\launcher\launcher.h" />
<ClInclude Include="..\..\..\src\shared\minimal.h" />
</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>
</ResourceCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,33 @@
<?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="Include">
<UniqueIdentifier>{11e7c0f2-7782-43ee-84fa-9e56efbe39de}</UniqueIdentifier>
</Filter>
<Filter Include="Include\shared">
<UniqueIdentifier>{d83ea433-d9f7-494c-90b9-3a8997483cd9}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\launcher\launcher.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\shared\minimal.h">
<Filter>Include\shared</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\launcher\launcher.h">
<Filter>Source</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\src\launcher\launcher-version.rc">
<Filter>Source</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -103,11 +103,12 @@
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -119,11 +120,12 @@
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -137,13 +139,14 @@
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -157,13 +160,14 @@
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemGroup>

View File

@ -102,7 +102,7 @@
<PreprocessorDefinitions>__func__=__FUNCTION__;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\src;..\..\..\inc;..\..\..\ext</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -119,7 +119,7 @@
<PreprocessorDefinitions>__func__=__FUNCTION__;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\src;..\..\..\inc;..\..\..\ext</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -138,7 +138,7 @@
<PreprocessorDefinitions>__func__=__FUNCTION__;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\src;..\..\..\inc;..\..\..\ext</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -159,7 +159,7 @@
<PreprocessorDefinitions>__func__=__FUNCTION__;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\src;..\..\..\inc;..\..\..\ext</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -183,20 +183,27 @@
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp" />
<ClCompile Include="..\..\..\tst\winfsp-tests\create-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\dirctl-test.c" />
<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\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\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\security-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\winfsp-tests.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h" />
<ClInclude Include="..\..\..\tst\memfs\memfs.h" />
<ClInclude Include="..\..\..\tst\winfsp-tests\winfsp-tests.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\winfsp_dll.vcxproj">

View File

@ -52,6 +52,24 @@
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\posix-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\reparse-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\hook.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
@ -60,5 +78,8 @@
<ClInclude Include="..\..\..\tst\memfs\memfs.h">
<Filter>Source</Filter>
</ClInclude>
<ClInclude Include="..\..\..\tst\winfsp-tests\winfsp-tests.h">
<Filter>Source</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MyProductName>WinFsp</MyProductName>
<MyDescription>Windows File System Proxy</MyDescription>
<MyCompanyName>Navimatics Corporation</MyCompanyName>
<MyCopyright>2015-2016 Bill Zissimopoulos</MyCopyright>
<MyDevStage>Beta</MyDevStage>
<!-- build number: concat 2-digit year with 3-digit day of the year (16-bits until 2066) -->
<MyBuildNumber>$([System.DateTime]::Now.ToString(`yy`))$([System.DateTime]::Now.DayOfYear.ToString(`000`))</MyBuildNumber>
<MyVersion>0.17.$(MyBuildNumber)</MyVersion>
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>NTDDI_VERSION=0x06000000;_WIN32_WINNT=0x0600</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.23107.0
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winfsp.dll", "winfsp_dll.vcxproj", "{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}"
ProjectSection(ProjectDependencies) = postProject
@ -23,10 +23,36 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memfs", "testing\memfs.vcxp
{C85C26BA-8C22-4D30-83DA-46C3548E6332} = {C85C26BA-8C22-4D30-83DA-46C3548E6332}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "installer", "installer", "{B464EF06-42AE-4674-81BB-FDDE80204822}"
EndProject
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "winfsp_msi", "installer\winfsp_msi.wixproj", "{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}"
ProjectSection(ProjectDependencies) = postProject
{95C223E6-B5F1-4FD0-9376-41CDBC824445} = {95C223E6-B5F1-4FD0-9376-41CDBC824445}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomActions", "installer\CustomActions\CustomActions.vcxproj", "{95C223E6-B5F1-4FD0-9376-41CDBC824445}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "launcher", "launcher", "{FD28A504-431E-49B9-BB8C-DCA0E7019F66}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launcher", "launcher\launcher.vcxproj", "{A5EFD487-0140-4184-8C54-FFAEC2F85E35}"
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}") = "launchctl", "launcher\launchctl.vcxproj", "{73EAAEDA-557B-48D5-A137-328934720FB4}"
ProjectSection(ProjectDependencies) = postProject
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {A5EFD487-0140-4184-8C54-FFAEC2F85E35}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Installer.Debug|x64 = Installer.Debug|x64
Installer.Debug|x86 = Installer.Debug|x86
Installer.Release|x64 = Installer.Release|x64
Installer.Release|x86 = Installer.Release|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
@ -35,6 +61,10 @@ Global
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x64.Build.0 = Debug|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x86.ActiveCfg = Debug|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x86.Build.0 = Debug|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Debug|x64.ActiveCfg = Debug|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Release|x64.ActiveCfg = Release|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Release|x86.ActiveCfg = Release|Win32
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x64.ActiveCfg = Release|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x64.Build.0 = Release|x64
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x86.ActiveCfg = Release|Win32
@ -43,6 +73,10 @@ Global
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x64.Build.0 = Debug|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x86.ActiveCfg = Debug|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x86.Build.0 = Debug|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Debug|x64.ActiveCfg = Debug|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Release|x64.ActiveCfg = Release|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Release|x86.ActiveCfg = Release|Win32
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x64.ActiveCfg = Release|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x64.Build.0 = Release|x64
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x86.ActiveCfg = Release|Win32
@ -51,6 +85,10 @@ Global
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x64.Build.0 = Debug|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x86.ActiveCfg = Debug|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x86.Build.0 = Debug|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Debug|x64.ActiveCfg = Debug|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Release|x64.ActiveCfg = Release|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Release|x86.ActiveCfg = Release|Win32
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x64.ActiveCfg = Release|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x64.Build.0 = Release|x64
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x86.ActiveCfg = Release|Win32
@ -59,10 +97,62 @@ Global
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x64.Build.0 = Debug|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x86.ActiveCfg = Debug|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x86.Build.0 = Debug|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Debug|x64.ActiveCfg = Debug|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Release|x64.ActiveCfg = Release|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Release|x86.ActiveCfg = Release|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x64.ActiveCfg = Release|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x64.Build.0 = Release|x64
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x86.ActiveCfg = Release|Win32
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x86.Build.0 = Release|Win32
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Debug|x64.ActiveCfg = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Debug|x86.ActiveCfg = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x64.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x64.Build.0 = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x86.ActiveCfg = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x86.Build.0 = Debug|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x64.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x64.Build.0 = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x86.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x86.Build.0 = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Release|x64.ActiveCfg = Release|x86
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Release|x86.ActiveCfg = Release|x86
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Debug|x64.ActiveCfg = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Debug|x86.ActiveCfg = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x64.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x64.Build.0 = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x86.Build.0 = Debug|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x64.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x64.Build.0 = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x86.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x86.Build.0 = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x64.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x86.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.ActiveCfg = Debug|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.Build.0 = Debug|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x86.ActiveCfg = Debug|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x86.Build.0 = Debug|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|x64.ActiveCfg = Debug|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|x64.ActiveCfg = Release|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|x86.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x64.ActiveCfg = Release|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x64.Build.0 = Release|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x86.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x86.Build.0 = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x64.ActiveCfg = Debug|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x64.Build.0 = Debug|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x86.ActiveCfg = Debug|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x86.Build.0 = Debug|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|x64.ActiveCfg = Debug|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|x64.ActiveCfg = Release|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|x86.ActiveCfg = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.ActiveCfg = Release|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.Build.0 = Release|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.ActiveCfg = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -70,5 +160,9 @@ Global
GlobalSection(NestedProjects) = preSolution
{262DF8CC-E7A8-4460-A22C-683CBA322C32} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594} = {B464EF06-42AE-4674-81BB-FDDE80204822}
{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}
EndGlobalSection
EndGlobal

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="version.properties" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -19,12 +20,24 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\inc\fuse\fuse.h" />
<ClInclude Include="..\..\inc\fuse\fuse_common.h" />
<ClInclude Include="..\..\inc\fuse\fuse_opt.h" />
<ClInclude Include="..\..\inc\fuse\winfsp_fuse.h" />
<ClInclude Include="..\..\inc\winfsp\fsctl.h" />
<ClInclude Include="..\..\inc\winfsp\winfsp.h" />
<ClInclude Include="..\..\src\dll\fuse\library.h" />
<ClInclude Include="..\..\src\dll\library.h" />
<ClInclude Include="..\..\src\shared\minimal.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\dll\eventlog.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_main.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_opt.c" />
<ClCompile Include="..\..\src\dll\np.c" />
<ClCompile Include="..\..\src\dll\posix.c" />
<ClCompile Include="..\..\src\dll\security.c" />
<ClCompile Include="..\..\src\dll\debug.c" />
<ClCompile Include="..\..\src\dll\fsctl.c" />
@ -33,10 +46,43 @@
<ClCompile Include="..\..\src\dll\fs.c" />
<ClCompile Include="..\..\src\dll\ntstatus.c" />
<ClCompile Include="..\..\src\dll\path.c" />
<ClCompile Include="..\..\src\dll\service.c" />
<ClCompile Include="..\..\src\dll\util.c" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">echo arch=$(PlatformTarget) &gt;$(OutDir)fuse-$(PlatformTarget).pc
copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(PlatformTarget).pc &gt;nul</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Writing fuse-$(PlatformTarget).pc</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)fuse-$(PlatformTarget).pc</Outputs>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkObjects>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo arch=$(PlatformTarget) &gt;$(OutDir)fuse-$(PlatformTarget).pc
copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(PlatformTarget).pc &gt;nul</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Writing fuse-$(PlatformTarget).pc</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)fuse-$(PlatformTarget).pc</Outputs>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkObjects>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">echo arch=$(PlatformTarget) &gt;$(OutDir)fuse-$(PlatformTarget).pc
copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(PlatformTarget).pc &gt;nul</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Writing fuse-$(PlatformTarget).pc</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)fuse-$(PlatformTarget).pc</Outputs>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkObjects>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">echo arch=$(PlatformTarget) &gt;$(OutDir)fuse-$(PlatformTarget).pc
copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(PlatformTarget).pc &gt;nul</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Writing fuse-$(PlatformTarget).pc</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)fuse-$(PlatformTarget).pc</Outputs>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkObjects>
</CustomBuild>
<None Include="..\..\src\dll\library.def" />
<None Include="..\..\src\dll\ntstatus.i" />
</ItemGroup>
<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>
</ResourceCompile>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}</ProjectGuid>
@ -124,9 +170,11 @@
<SDLCheck>
</SDLCheck>
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -134,8 +182,10 @@
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -148,9 +198,11 @@
<SDLCheck>
</SDLCheck>
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -160,6 +212,8 @@
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -174,8 +228,10 @@
<SDLCheck>
</SDLCheck>
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -185,8 +241,10 @@
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -201,8 +259,10 @@
<SDLCheck>
</SDLCheck>
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AdditionalOptions>
</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -214,6 +274,8 @@
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -12,6 +12,15 @@
<Filter Include="Include\winfsp">
<UniqueIdentifier>{1d6501f4-cebd-4a00-a774-deb782b59fb5}</UniqueIdentifier>
</Filter>
<Filter Include="Include\shared">
<UniqueIdentifier>{c7b83307-0aa0-4593-b2d4-26ff2f1edfc6}</UniqueIdentifier>
</Filter>
<Filter Include="Include\fuse">
<UniqueIdentifier>{0e7ab1b1-bfca-4439-accb-45a909be9cad}</UniqueIdentifier>
</Filter>
<Filter Include="Source\fuse">
<UniqueIdentifier>{518cce17-85cd-489c-b4be-920a84c1d73c}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\inc\winfsp\fsctl.h">
@ -23,6 +32,24 @@
<ClInclude Include="..\..\src\dll\library.h">
<Filter>Source</Filter>
</ClInclude>
<ClInclude Include="..\..\src\shared\minimal.h">
<Filter>Include\shared</Filter>
</ClInclude>
<ClInclude Include="..\..\inc\fuse\fuse.h">
<Filter>Include\fuse</Filter>
</ClInclude>
<ClInclude Include="..\..\inc\fuse\fuse_common.h">
<Filter>Include\fuse</Filter>
</ClInclude>
<ClInclude Include="..\..\inc\fuse\fuse_opt.h">
<Filter>Include\fuse</Filter>
</ClInclude>
<ClInclude Include="..\..\inc\fuse\winfsp_fuse.h">
<Filter>Include\fuse</Filter>
</ClInclude>
<ClInclude Include="..\..\src\dll\fuse\library.h">
<Filter>Source\fuse</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\dll\library.c">
@ -52,13 +79,47 @@
<ClCompile Include="..\..\src\dll\np.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\service.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\eventlog.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\util.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\fuse\fuse.c">
<Filter>Source\fuse</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\fuse\fuse_opt.c">
<Filter>Source\fuse</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\fuse\fuse_main.c">
<Filter>Source\fuse</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\posix.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c">
<Filter>Source\fuse</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\src\dll\ntstatus.i">
<Filter>Source</Filter>
</None>
<None Include="..\..\src\dll\library.def">
<Filter>Source</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\dll\version.rc">
<Filter>Source</Filter>
</ResourceCompile>
<ResourceCompile Include="..\..\src\dll\eventlog\eventlog.rc">
<Filter>Source</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc">
<Filter>Source\fuse</Filter>
</CustomBuild>
</ItemGroup>
</Project>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="version.properties" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -33,6 +34,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries>
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>WDM</DriverType>
@ -40,6 +42,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries>
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>WDM</DriverType>
@ -47,6 +50,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries>
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>WDM</DriverType>
@ -54,6 +58,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries>
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>WDM</DriverType>
@ -104,6 +109,7 @@
<GenerateMapFile>true</GenerateMapFile>
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -116,6 +122,7 @@
<GenerateMapFile>true</GenerateMapFile>
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -128,6 +135,7 @@
<GenerateMapFile>true</GenerateMapFile>
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -140,6 +148,7 @@
<GenerateMapFile>true</GenerateMapFile>
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@ -177,6 +186,14 @@
<ClInclude Include="..\..\inc\winfsp\fsctl.h" />
<ClInclude Include="..\..\src\sys\driver.h" />
</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>
</ResourceCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -101,4 +101,9 @@
<Filter>Include\winfsp</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\sys\version.rc">
<Filter>Source</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

51
doc/Changelog.adoc Normal file
View File

@ -0,0 +1,51 @@
= Changelog
v0.17::
This release brings support for named streams.
- Named streams (or alternate data streams) are additional streams of data within a file. When a file gets opened the main (default, unnamed) data stream of a file gets accessed. However NTFS (and now WinFsp) supports multiple data streams per file accessible using the `filename:streamname` syntax.
- WinFsp handles a lot of the hairy details regarding named streams, including sharing checks, pending delete checks, conflicts between the main and named streams, etc.
- User mode file systems that wish to support named streams must set the `FSP_FSCTL_VOLUME_PARAMS::NamedStreams` flag and must also be prepared to handle named streams on `Create`, `Cleanup`, etc. They must also implement the new `FSP_FILE_SYSTEM_INTERFACE::GetStreamInfo` operation. For more information on how to correctly handle named streams refer to the MEMFS sample.
v0.16::
This release brings support for reparse points and symbolic links as well as other minor changes.
- Reparse points are a general mechanism for attaching special behavior to files. Symbolic links in Windows are implemented as reparse points. WinFsp supports any kind of reparse point including symbolic links.
- The WinFsp FUSE implementation supports symbolic links. It also supports POSIX special files (FIFO, SOCK, CHR, BLK) as NFS reparse points (see https://msdn.microsoft.com/en-us/library/dn617178.aspx).
- User mode file systems that wish to support reparse points will have to set the `FSP_FSCTL_VOLUME_PARAMS::ReparsePoints` flag and implement the `FSP_FILE_SYSTEM_INTERFACE` methods `ResolveReparsePoints`, `GetReparsePoint`, `SetReparsePoint`, `DeleteReparsePoint`. More information in this blog article: http://www.secfs.net/winfsp/blog/files/reparse-points-symlinks-api-changes.html
- The installation now includes public symbol files for all WinFsp components shipped.
v0.15::
This is a minor release that brings support for Windows 7 and 32-bit OS'es.
- Fixes a number of issues for Windows 7. Windows 7 is now officially supported.
- Fixes a number of issues with the 32-bit FSD and user mode components. 32-bit versions of Windows are now officially supported.
v0.14::
This release includes support for file systems protected by credentials.
- WinFsp now supports file systems that require username/password to be unlocked (e.g. sshfs/secfs). Such file systems must add a DWORD registry value with name "Credentials" and value 1 under their WinFsp.Launcher service entry. The WinFsp network provider will then prompt for credentials using the `CredUIPromptForWindowsCredentials` API. Credentials can optionally be saved with the Windows Credential Manager.
- WinFsp-FUSE now uses the S-1-0-65534 <--> 65534 mapping for unmapped SID/UID's. The Anonymous SID mapping from the previous release had security issues.
v0.13::
This release includes a Cygwin package, an API change and some other minor changes:
- New Cygwin package includes `cygfuse-2.8.dll` and `libfuse-2.8.dll.a` for easy use in the Cygwin environment. This is currently offered as a separate download.
- Minor but breaking API change: `SetFileSize`/`SetAllocationSize` have been consolidated. Please refer to the documentation for a description of the changes.
- File system drive symbolic links (`DefineDosDeviceW`) now automatically cleaned up even if user mode file system crashes or is terminated forcefully.
- WinFsp-FUSE now maps unmapped UID's to the Anonymous SID (S-1-5-7). See: https://cygwin.com/ml/cygwin/2016-06/msg00359.html
v0.12::
Prior changes are not recorded in this Changelog.

View File

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

View File

@ -1,9 +1,21 @@
web: web/winfsp-design.html web/winfsp.h.html
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,50 @@
= Native API vs FUSE
This document compares the "native" WinFsp API to the FUSE API and provides a rationale for the existence of both within WinFsp.
== Overview
WinFsp provides two different but conceptually similar API's for the same purpose of implementing a user mode file system:
- The WinFsp API, which is documented in the include file `inc/winfsp/winfsp.h` (and online at http://www.secfs.net/winfsp/apiref/). This API consists of the `FSP_FILE_SYSTEM_INTERFACE` "class" and the `FspFileSystem*` functions.
- The FUSE (high-level) API, which is the well understood API from the FUSE project originally by Miklos Szeredi.
Given the similarities between the two API's some questions naturally arise:
- What are the differences between the two API's?
- Why are both needed?
- What is the target audience for each API?
== Comparison
The primary difference between the two API's is that the WinFsp API is being designed to use all features available to a Windows file system, whereas the FUSE API is being designed (by the FUSE project) to better fit a POSIX file system. For example, a Windows file system can do the following, that cannot be (easily) made available to FUSE:
- Create and manage alternate data streams.
- Manage arbitrary security descriptors (SID's and ACL's vs POSIX permissions).
- Create and manage special files beyond what is supported through FUSE `mknod` (using reparse points).
- Support volume labels.
- Allow the file system to fulfill Read/Write requests using asynchronous I/O.
Furthermore there are other smaller, but still important differences:
- The file deletion model on Windows is different from the FUSE/POSIX model.
- The reparse mechanism (which supports symbolic links) on Windows is quite more powerful (and more complicated) than FUSE/POSIX symbolic links.
- Windows uses UTF-16 for file names, whereas FUSE uses UTF-8, requiring constant conversions between the two.
These and other differences make the creation of the WinFsp FUSE compatibility layer non-trivial and suggest that a native API that more closely resembles the Windows file system model is desirable. At the same time there are hundreds of FUSE (high-level) file systems and having a FUSE compatible API is also very desirable.
== Target Audiences
As mentioned WinFsp provides two different API's; to further complicate matters the FUSE API can be used from both a native Windows application and a Cygwin (POSIX) application. There are then 3 different audiences that the API's cater for:
- The WinFsp API audience. This consists of Windows-only file systems or cross-platform file systems that wish to provide maximum features and/or performance on Windows.
- The FUSE API for native Windows audience. This consists of FUSE file-systems that have had their core file system code ported to Windows, but have not yet been integrated into the operating system. It also includes cross-platform file systems that do not wish to include advanced (non-POSIX) Windows file system features.
- The FUSE API for Cygwin audience. This consists of FUSE file-systems that are ported to Windows/Cygwin with minimal work. For example, the author of this document has ported SSHFS to Cygwin using this API and a minimal SSHFS patch.
For the developer of a new or Windows exclusive file system the recommendation is to use the WinFsp API as it provides support for all features of the Windows file system.
For the developer of a FUSE file system that wishes to port their file system to Windows a natural process may be the following:
- Use the FUSE API for Cygwin to port the file system to Cygwin. In many cases little or no changes to the file system code are required.
- Use the FUSE API for native Windows to port the file system to native Windows. This would require porting the core file system code (i.e. those parts of the file system code that actually manage and organize files). Little to no changes should be required for the file system FUSE layer glue.
- Use the WinFsp API only if the file system requires maximum features and/or performance under Windows.

View File

@ -0,0 +1,47 @@
= WinFsp Service Architecture
This document discusses an architecture for writing user mode file systems as Windows services.
== Overview
There are a variety of reasons that user mode file systems should be written as Windows services. Chief among those are that a Windows service runs independently from user sessions. Therefore a user mode file system can provide its services to all processes in the system rather than those of the current user session. Furthermore a Windows service (usually) runs under an account with elevated privileges, which may be a requirement for some user mode file systems.
The Windows Service Control Manager provides a clean protocol for installing, configuring and controlling services. Unfortunately it also has a major deficiency in that it only allows a single instance of a particular service to be launched. The technique usually employed to work around this deficiency is to create multiple named instances of the same service (e.g. ServiceName #1, ServiceName #2). This technique assumes that there is a finite and well known set of instances, which may not always be the case.
Consider, for example, a network file system NETFS which can be used to provide a network based file system. NETFS connects to a particular server and uses its proprietary protocol to access files on that server, which it then presents to Windows as native files. Clearly there may be a very large number of NETFS servers, which makes the idea of creating separate named service instances for each server unworkable. One alternative for the NETFS developer is to create a service that manages multiple NETFS instances. Another one is to use the WinFsp service architecture described in this document.
== WinFsp Launcher
In order to overcome the issue with launching multiple instances of a particular service, WinFsp provides a generic launcher named WinFsp.Launcher. The WinFsp.Launcher is itself a Windows service that can be used to launch and control other services, provided that they fulfill the following requirements:
* That they are marked as console executables.
* That they can be parameterized using the command line.
* That they respond to the CTRL-BREAK console control event and terminate timely.
Services that wish to be controlled by the WinFsp.Launcher must add themselves under the following registry key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services
For example, the MEMFS sample adds the following registry entries under this key:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services\memfs32]
"Executable"="C:\\Program Files (x86)\\WinFsp\\bin\\memfs-x86.exe"
"CommandLine"="-u %1 -m %2"
"Security"="D:P(A;;RPWPLC;;;WD)"
"JobControl"=dword:00000001
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services\memfs64]
"Executable"="C:\\Program Files (x86)\\WinFsp\\bin\\memfs-x64.exe"
"CommandLine"="-u %1 -m %2"
"Security"="D:P(A;;RPWPLC;;;WD)"
"JobControl"=dword:00000001
When the WinFsp.Launcher starts up it creates a named pipe that applications can use to start, stop, get information about and list service instances. A small command line utility (`launchctl`) can be used to issue those commands. The CallNamedPipeW API can be used as well.
One final note regarding security. Notice the `Security` registry value in the example above. This registry value uses SDDL syntax to instruct WinFsp.Launcher to allow Everyone (`WD`) to start (`RP`), stop (`WP`) and get information (`LC`) about the service instance. If the `Security` registry value is missing the default is to allow only LocalSystem and Administrators to control the service instance.
== WinFsp Network Provider
WinFsp includes a Network Provider that integrates with Windows and can be used to start and stop user mode file systems from the Windows shell. To achieve this the Network Provider (implemented as part of the WinFsp DLL) works closely with the WinFsp.Launcher service.
For example, if a user uses the Windows Explorer to map `\\memfs64\share` to the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to start an instance of the memfs64 service with command line `-u \\memfs64\share -m Z:`. When the user disconnects the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to stop the previously started instance of the memfs64 service.

View File

@ -0,0 +1,266 @@
= SSHFS Port Case Study
This document is a case study in porting SSHFS to Windows and WinFsp. At the time that the document was started WinFsp had a native API, but no FUSE compatible API. The main purpose of the case study was to develop a FUSE compatible API for WinFsp.
== Step 1: Gather Information about SSHFS
The SSHFS project is one of the early FUSE projects. The project was originally written by Miklos Szeredi who is also the author of FUSE. SSHFS provides a file system interface on top of SFTP (Secure File Transfer Protocol).
The project's website is at https://github.com/libfuse/sshfs. A quick perusal of the source code shows that this is a POSIX program, the file `configure.ac` further shows that it depends on GLib and FUSE.
Luckily Cygwin on Windows provides a POSIX interface and it also includes GLib and pkg-config. We are missing FUSE of course. Let's try it anyway:
----
billziss@windows:~/Projects/ext$ git clone https://github.com/libfuse/sshfs.git
Cloning into 'sshfs'...
[snip]
billziss@windows:~/Projects/ext$ cd sshfs/
billziss@windows:~/Projects/ext/sshfs [master]$ autoreconf -i
[snip]
billziss@windows:~/Projects/ext/sshfs [master]$ ./configure
[snip]
configure: error: Package requirements (fuse >= 2.3 glib-2.0 gthread-2.0) were not met:
No package 'fuse' found
----
As expected we get an error because there is no package named FUSE. So let's create one.
== Step 2: Create a FUSE Compatible Package
After a few days of development there exists now an initial FUSE implementation within WinFsp. Most of the FUSE API's from the header files `fuse.h`, `fuse_common.h` and `fuse_opt.h` have been implemented. However none of the `fuse_operations` currently work as the necessary work to translate WinFsp requests to FUSE requests has not happened yet.
=== Challenges
- The FUSE API is old and somewhat hairy. There are multiple versions of it and choosing the right one was not easy. In the end version 2.8 of the API was chosen for implementation.
- The FUSE API uses a number of OS specific types (notably `struct stat`). Sometimes these types have multiple definitions even within the same OS (e.g. `struct stat` and `struct stat64`). For this reason it was decided to define our own `fuse_*` types (e.g. `struct fuse_stat`) instead of relying on the ones that come with MSVC. Care was taken to ensure that these types remain compatible with Cygwin as it is one of our primary target environments.
- The WinFsp DLL does *not* use the MSVCRT and uses its own memory allocator (`HeapAlloc`, `HeapFree`). Even if it used the MSVCRT `malloc`, it does not have access to the Cygwin `malloc`. The FUSE API has a few cases where users are expected to use `free` to deallocate memory (e.g. `fuse_opt_add_opt`). But which `free` is that for a Cygwin program? The Cygwin `free`, the MSVCRT `free` or our own `MemFree`?
+
To solve this problem we use the following pattern: every FUSE API is implemented as a `static inline` function that calls a WinFsp-FUSE API and passes it an extra argument that describes the environment:
+
----
static inline int fuse_opt_add_opt(char **opts, const char *opt)
{
return fsp_fuse_opt_add_opt(fsp_fuse_env(), opts, opt);
}
----
+
The `fsp_fuse_env` function is another `static inline` function that simply "captures" the current environment (things like the environment's `malloc` and `free`).
+
----
...
#elif defined(__CYGWIN__)
...
#define FSP_FUSE_ENV_INIT \
{ \
'C', \
malloc, free, \
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
fsp_fuse_remove_signal_handlers,\
}
...
#else
...
static inline struct fsp_fuse_env *fsp_fuse_env(void)
{
static struct fsp_fuse_env env = FSP_FUSE_ENV_INIT;
return &env;
}
----
- The implementation of `fuse_opt` proved an unexpected challenge. The function `fuse_opt_parse` is very flexible, but it also has a lot of quirks. It took a lot of trial and error to arrive at a clean reimplementation.
=== Things that worked rather nicely
- The pattern `fuse_new` / `fuse_loop` / `fuse_destroy` fits nicely to the WinFsp service model: `FspServiceCreate` / `FspServiceLoop` / `FspServiceDelete`. This means that every (high-level) FUSE file system can rather easily be converted into a Windows service if desired.
=== Integrating with Cygwin
It remains to show how to use the WinFsp-FUSE implementation from Cygwin and SSHFS. SSHFS uses `pkg-config` for its build configuration. `Pkg-config` requires a `fuse.pc` file:
----
arch=x64
prefix=${pcfiledir}/..
incdir=${prefix}/inc/fuse
implib=${prefix}/bin/winfsp-${arch}.dll
Name: fuse
Description: WinFsp FUSE compatible API
Version: 2.8
URL: http://www.secfs.net/winfsp/
Libs: "${implib}"
Cflags: -I"${incdir}"
----
The WinFsp installer has been modified to place this file within its installation directory. It remains to point `pkg-config` to the appropriate location (using `PKG_CONFIG_PATH`) and the SSHFS configuration process can now find the FUSE package.
=== SSHFS-Win
The sshfs-win open-source project (work in progress) can be found here: https://bitbucket.org/billziss/sshfs-win
== Step 3: Mapping Windows to POSIX
It would seem that we are now ready to start implementing the `fuse_operations`. However there is another matter that we need to attend to first and that is mapping the Windows file system view of the world to the POSIX one and vice-versa.
=== Mapping Paths
The Windows and POSIX file systems both use paths to address files. The path conventions are different, so we need a technique to convert between the two. This goes beyond a simple translation of the backslash character (`\`) to slash (`/`), because several characters are reserved and cannot be used in a Windows file path, but are legal when used in a POSIX path.
The reserved Windows characters are:
----
< > : " / \ | ? *
any character between 0 and 31
----
POSIX only has two reserved characters: slash (`/`) and `NUL`.
So how do we map between the two? Luckily this problem has been solved before by "Services for Macintosh" (SFM), "Services for UNIX" (SFU) and Gygwin. The solution involves the use of the Unicode "private use area". When mapping a POSIX path to Windows, if we encounter any of the Windows reserved characters we simply map it to the Unicode range U+F000 - U+F0FF. The reverse mapping from Windows to POSIX is obvious.
=== Mapping Security
Mapping Windows security to POSIX (and vice-versa) is a much more interesting (and difficult) problem. We have the following requirements:
- We need a method to map a Windows SID (Security Identifier) to a POSIX uid/gid.
- We need a method to map a Windows ACL (Access Control List) to a POSIX permission set.
- We want any mapping method we come up with to be bijective (to the extent that it is possible).
Luckily "Services for UNIX" (and Cygwin) come to the rescue again. The following Cygwin document describes in great detail a method to map a Windows SID to a POSIX uid/gid that is compatible with SFU: https://cygwin.com/cygwin-ug-net/ntsec.html. A different document from SFU describes how to map a Windows ACL to POSIX permissions: https://technet.microsoft.com/en-us/library/bb463216.aspx.
The mappings provided are not perfect, but they come pretty close. They are also proven as they have been used in SFU and Cygwin for years.
=== WinFsp Implementation
A WinFsp implementation of the above mappings can be found in the file `src/dll/posix.c`.
== Step 4: Implementing FUSE Core
We are now finally ready to implement the `fuse_operations`. This actually proves to be a straightforward mapping of the WinFSP `FSP_FILE_SYSTEM_INTERACE` to `fuse_operations`:
GetVolumeInfo:: Mapped to `statfs`. Volume labels are not supported by FUSE (see below).
SetVolumeLabel:: No equivalent on FUSE, so simply return `STATUS_INVALID_PARAMETER`. One thought is to map this call into a `setxattr("sys.VolumeLabel")` (or similar) call on the root directory (`/`).
GetSecurityByName:: Mapped to `fgetattr`/`getattr`. The returned `stat` information is translated into a Windows security descriptor using `FspPosixMapPermissionsToSecurityDescriptor`.
Create:: This is used to create a new file or directory. If a file is created this is mapped to `create` or `mknod`;`open`. If a directory is created this is mapped to `mkdir`;`opendir` calls (the reason is that on Windows a directory remains open after being created). In some circumstances a `chown` may be issued as well. After the file or directory has been created a `fgetattr`/`getattr` is issued to get `stat` information to return to the FSD.
Open:: This is used to open a new file or directory. First a `fgetattr`/`getattr` is issued. If the file is not a directory it is followed by `open`. If the file is a directory it is followed by `opendir`.
Overwrite:: This is used to overwrite a file when one of the `FILE_OVERWRITE`, `FILE_SUPERSEDE` or `FILE_OVERWRITE_IF` flags has been set. Mapped to `ftruncate`/`truncate`.
Cleanup:: Mapped to `unlink` when deleting a file and `rmdir` when deleting a directory.
Close:: Mapped to `flush`;`release` when closing a file and `releasedir` when closing a directory.
Read:: Mapped to `read`.
Write:: Mapped to `fgetattr`/`getattr` and `write`.
Flush:: Mapped to `fsync` or `fsyncdir`.
GetFileInfo:: Mapped to `fgetattr`/`getattr`.
SetBasicInfo:: Mapped to `utimens`/`utime`.
SetAllocationSize:: Mapped to `fgetattr`/`getattr` followed by `ftruncate`/`truncate`. Note that this call and `SetFileSize` may be consolidated soon in the WinFsp API.
SetFileSize:: Mapped to `fgetattr`/`getattr` followed by `ftruncate`/`truncate`. Note that this call and `SetAllocationSize` may be consolidated soon in the WinFsp API.
CanDelete:: For directories only: mapped to a `getdir`/`readdir` call to determine if they are empty and can therefore be deleted.
Rename:: Mapped to `fgetattr`/`getattr` on the destination file name and `rename`.
GetSecurity:: Mapped to `fgetattr`/`getattr`. The returned `stat` information is translated into a Windows security descriptor using `FspPosixMapPermissionsToSecurityDescriptor`.
SetSecurity:: Mapped to `fgetattr`/`getattr` followed by `chmod` and/or `chown`.
ReadDirectory:: Mapped to `getdir`/`readdir`. Note that because of how the Windows directory enumeration API's work there is a further `fgetattr`/`getattr` per file returned!
=== Some Additional Challenges
Let us now discuss a couple of final challenges in getting a proper FUSE port working under Cygwin: the implementation of `fuse_set_signal_handlers`/`fuse_remove_signal_handlers` and `fuse_daemonize`.
Let us start with `fuse_set_signal_handlers`/`fuse_remove_signal_handlers`. Cygwin supports POSIX signals and we can simply set up signal handlers similar to what libfuse does. However this simple approach does not work within WinFsp, because it uses native API's that Cygwin cannot interrupt with its signal mechanism. For example, the `fuse_loop` FUSE call eventually results in a `WaitForSingleObject` API call that Cygwin cannot interrupt. Even trying with an alertable `WaitForSingleObjectEx` did not work as unfortunately Cygwin does not issue a `QueueUserAPC` when issuing a signal. So we need an alternative mechanism to support signals.
The alternative is to use `sigwait` in a separate thread. `Fsp_fuse_signal_handler` is a WinFsp API that knows how to interrupt that `WaitForSingleObject` (actually it just signals the waited event).
----
static inline void *fsp_fuse_signal_thread(void *psigmask)
{
int sig;
if (0 == sigwait(psigmask, &sig))
fsp_fuse_signal_handler(sig);
return 0;
}
----
Let us now move to `fuse_daemonize`. This FUSE call allows a FUSE file system to become a (UNIX) daemon. This is achieved by using the POSIX fork call, which unfortunately has many limitations in Cygwin. One such limitation (and the one that bit us in WinFsp) is that it does not know how to clone Windows heaps (`HeapAlloc`/`HeapFree`).
Recall that WinFsp uses its own memory allocator (just a thin wrapper around `HeapAlloc`/`HeapFree`). This means that any allocations made prior to the fork() call are doomed after a fork(); with good luck the pointers will point to invalid memory and one will get an Access Violation; with bad luck the pointers will point to valid memory that contains bad data and the program may stumble for a while, just enough to hide the actual cause of the problem.
Luckily there is a rather straightforward work-around: "do not allocate any non-Cygwin resources prior to fork". This is actually possible within WinFsp, because we are already capturing the Cygwin environment and its `malloc`/`free` (see `fsp_fuse_env` in "Step 2"). It is also possible, because the typical FUSE program structure looks like this:
----
fuse_new
fuse_daemonize // do not allocate any non-Cygwin resources prior to this
fuse_loop/fuse_loop_mt // safe to allocate non-Cygwin resources
fuse_destroy
----
With this change `fuse_daemonize` works and allows me to declare the Cygwin portion of the SSHFS port complete!
== Step 5: POSIX special files
Although WinFsp now has a working FUSE implementation there remains an important problem: how to handle POSIX special files such as named pipes (FIFO), devices (CHR, BLK), sockets (SOCK) or symbolic links (LNK).
While Windows has support for symbolic links (LNK) there is no direct support for other POSIX special files. The question then is how to represent such files when they are accessed by Windows. This is especially important to systems like Cygwin that understand POSIX special files and can even create them.
Cygwin normally emulates symbolic links and special files using special shortcut (.lnk) files. However many FUSE file systems support POSIX special files; it is desirable then that applications, like Cygwin, that understand them should be able to create and access them without resorting to hacks like using .lnk files.
The problem was originally mentioned by Herbert Stocker on the Cygwin mailing list:
[quote]
____
The mkfifo system call will have Cygwin create a .lnk file and
WinFsp will forward it as such to the file system process. The
system calls readdir or open will then have the file system
process tell WinFsp that there is a .lnk file and Cygwin will
translate this back to a fifo, so in this sense it does work.
But the file system will see a file (with name *.lnk) where it
should see a pipe (mknod call with \'mode' set to S_IFIFO).
IMHO one could say this is a break of the FUSE API.
Practically it will break:
- File systems that special-treat pipe files (or .lnk files).
- If one uses sshfs to connect to a Linux based server and
issues the command mkfifo foo from Cygwin, the server will
end up with a .lnk file instead of a pipe special file.
- Imagine something like mysqlfs, which stores the stuff in a
database. When you run SQL statements to analyze the data
in the file system, you won't see the pipes as such. Or if
you open the file system from Linux you'll see the .lnk
files.
____
Herbert is of course right. A .lnk file is not a FIFO to any application other than Cygwin. We need a better mechanism for representing special files. One such mechanism is reparse points.
Reparse points can be viewed as a form of special metadata that can be attached to a file or directory. The interesting thing about reparse points is that they can have special meaning to a file system driver (NTFS/WinFsp), a filter driver (e.g. a hierarchical storage system) or even an application (Cygwin).
Symbolic links are already implemented as reparse points on Windows. We could perhaps define a new reparse point type for representing POSIX special files. Turns out that this is unnecessary, because Microsoft has already defined a reparse point type for special files on NFS: https://msdn.microsoft.com/en-us/library/dn617178.aspx
It is a relatively straightforward task then to map reparse point operations into their FUSE equivalents:
GetReparsePoint:: Mapped to `getattr`/`fgetattr` and possibly `readlink` (in the case of a symbolic link). The returned `stat.st_mode` information is transformed to the appropriate reparse point information.
SetReparsePoint:: Mapped to `symlink` or `mknod` depending on whether a symbolic link or other special file is created.

1
ext/test Submodule

Submodule ext/test added at feb554380e

220
inc/fuse/fuse.h Normal file
View File

@ -0,0 +1,220 @@
/**
* @file fuse/fuse.h
* WinFsp FUSE compatible API.
*
* This file is derived from libfuse/include/fuse.h:
* FUSE: Filesystem in Userspace
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#ifndef FUSE_H_
#define FUSE_H_
#include "fuse_common.h"
#ifdef __cplusplus
extern "C" {
#endif
struct fuse;
typedef int (*fuse_fill_dir_t)(void *buf, const char *name,
const struct fuse_stat *stbuf, fuse_off_t off);
typedef struct fuse_dirhandle *fuse_dirh_t;
typedef int (*fuse_dirfil_t)(fuse_dirh_t h, const char *name,
int type, fuse_ino_t ino);
struct fuse_operations
{
int (*getattr)(const char *path, struct fuse_stat *stbuf);
int (*getdir)(const char *path, fuse_dirh_t h, fuse_dirfil_t filler);
int (*readlink)(const char *path, char *buf, size_t size);
int (*mknod)(const char *path, fuse_mode_t mode, fuse_dev_t dev);
int (*mkdir)(const char *path, fuse_mode_t mode);
int (*unlink)(const char *path);
int (*rmdir)(const char *path);
int (*symlink)(const char *dstpath, const char *srcpath);
int (*rename)(const char *oldpath, const char *newpath);
int (*link)(const char *srcpath, const char *dstpath);
int (*chmod)(const char *path, fuse_mode_t mode);
int (*chown)(const char *path, fuse_uid_t uid, fuse_gid_t gid);
int (*truncate)(const char *path, fuse_off_t size);
int (*utime)(const char *path, struct fuse_utimbuf *timbuf);
int (*open)(const char *path, struct fuse_file_info *fi);
int (*read)(const char *path, char *buf, size_t size, fuse_off_t off,
struct fuse_file_info *fi);
int (*write)(const char *path, const char *buf, size_t size, fuse_off_t off,
struct fuse_file_info *fi);
int (*statfs)(const char *path, struct fuse_statvfs *stbuf);
int (*flush)(const char *path, struct fuse_file_info *fi);
int (*release)(const char *path, struct fuse_file_info *fi);
int (*fsync)(const char *path, int datasync, struct fuse_file_info *fi);
int (*setxattr)(const char *path, const char *name, const char *value, size_t size,
int flags);
int (*getxattr)(const char *path, const char *name, char *value, size_t size);
int (*listxattr)(const char *path, char *namebuf, size_t size);
int (*removexattr)(const char *path, const char *name);
int (*opendir)(const char *path, struct fuse_file_info *fi);
int (*readdir)(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
struct fuse_file_info *fi);
int (*releasedir)(const char *path, struct fuse_file_info *fi);
int (*fsyncdir)(const char *path, int datasync, struct fuse_file_info *fi);
void *(*init)(struct fuse_conn_info *conn);
void (*destroy)(void *data);
int (*access)(const char *path, int mask);
int (*create)(const char *path, fuse_mode_t mode, struct fuse_file_info *fi);
int (*ftruncate)(const char *path, fuse_off_t off, struct fuse_file_info *fi);
int (*fgetattr)(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi);
int (*lock)(const char *path, struct fuse_file_info *fi, int cmd, struct fuse_flock *lock);
int (*utimens)(const char *path, const struct fuse_timespec tv[2]);
int (*bmap)(const char *path, size_t blocksize, uint64_t *idx);
unsigned int flag_nullpath_ok:1;
unsigned int flag_reserved:31;
int (*ioctl)(const char *path, int cmd, void *arg, struct fuse_file_info *fi,
unsigned int flags, void *data);
int (*poll)(const char *path, struct fuse_file_info *fi,
struct fuse_pollhandle *ph, unsigned *reventsp);
};
struct fuse_context
{
struct fuse *fuse;
fuse_uid_t uid;
fuse_gid_t gid;
fuse_pid_t pid;
void *private_data;
fuse_mode_t umask;
};
#define fuse_main(argc, argv, ops, data)\
fuse_main_real(argc, argv, ops, sizeof *(ops), data)
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_main_real)(struct fsp_fuse_env *env,
int argc, char *argv[],
const struct fuse_operations *ops, size_t opsize, void *data);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_is_lib_option)(struct fsp_fuse_env *env,
const char *opt);
FSP_FUSE_API struct fuse *FSP_FUSE_API_NAME(fsp_fuse_new)(struct fsp_fuse_env *env,
struct fuse_chan *ch, struct fuse_args *args,
const struct fuse_operations *ops, size_t opsize, void *data);
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_destroy)(struct fsp_fuse_env *env,
struct fuse *f);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_loop)(struct fsp_fuse_env *env,
struct fuse *f);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_loop_mt)(struct fsp_fuse_env *env,
struct fuse *f);
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_exit)(struct fsp_fuse_env *env,
struct fuse *f);
FSP_FUSE_API struct fuse_context *FSP_FUSE_API_NAME(fsp_fuse_get_context)(struct fsp_fuse_env *env);
FSP_FUSE_SYM(
int fuse_main_real(int argc, char *argv[],
const struct fuse_operations *ops, size_t opsize, void *data),
{
return FSP_FUSE_API_CALL(fsp_fuse_main_real)
(fsp_fuse_env(), argc, argv, ops, opsize, data);
})
FSP_FUSE_SYM(
int fuse_is_lib_option(const char *opt),
{
return FSP_FUSE_API_CALL(fsp_fuse_is_lib_option)
(fsp_fuse_env(), opt);
})
FSP_FUSE_SYM(
struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
const struct fuse_operations *ops, size_t opsize, void *data),
{
return FSP_FUSE_API_CALL(fsp_fuse_new)
(fsp_fuse_env(), ch, args, ops, opsize, data);
})
FSP_FUSE_SYM(
void fuse_destroy(struct fuse *f),
{
FSP_FUSE_API_CALL(fsp_fuse_destroy)
(fsp_fuse_env(), f);
})
FSP_FUSE_SYM(
int fuse_loop(struct fuse *f),
{
return FSP_FUSE_API_CALL(fsp_fuse_loop)
(fsp_fuse_env(), f);
})
FSP_FUSE_SYM(
int fuse_loop_mt(struct fuse *f),
{
return FSP_FUSE_API_CALL(fsp_fuse_loop_mt)
(fsp_fuse_env(), f);
})
FSP_FUSE_SYM(
void fuse_exit(struct fuse *f),
{
FSP_FUSE_API_CALL(fsp_fuse_exit)
(fsp_fuse_env(), f);
})
FSP_FUSE_SYM(
struct fuse_context *fuse_get_context(void),
{
return FSP_FUSE_API_CALL(fsp_fuse_get_context)
(fsp_fuse_env());
})
FSP_FUSE_SYM(
int fuse_getgroups(int size, fuse_gid_t list[]),
{
(void)size;
(void)list;
return -ENOSYS;
})
FSP_FUSE_SYM(
int fuse_interrupted(void),
{
return 0;
})
FSP_FUSE_SYM(
int fuse_invalidate(struct fuse *f, const char *path),
{
(void)f;
(void)path;
return -EINVAL;
})
FSP_FUSE_SYM(
int fuse_notify_poll(struct fuse_pollhandle *ph),
{
(void)ph;
return 0;
})
FSP_FUSE_SYM(
struct fuse_session *fuse_get_session(struct fuse *f),
{
return (struct fuse_session *)f;
})
#ifdef __cplusplus
}
#endif
#endif

149
inc/fuse/fuse_common.h Normal file
View File

@ -0,0 +1,149 @@
/**
* @file fuse/fuse_common.h
* WinFsp FUSE compatible API.
*
* This file is derived from libfuse/include/fuse_common.h:
* FUSE: Filesystem in Userspace
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#ifndef FUSE_COMMON_H_
#define FUSE_COMMON_H_
#include "winfsp_fuse.h"
#include "fuse_opt.h"
#ifdef __cplusplus
extern "C" {
#endif
#define FUSE_MAJOR_VERSION 2
#define FUSE_MINOR_VERSION 8
#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min))
#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
#define FUSE_CAP_ASYNC_READ (1 << 0)
#define FUSE_CAP_POSIX_LOCKS (1 << 1)
#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3)
#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
#define FUSE_CAP_BIG_WRITES (1 << 5)
#define FUSE_CAP_DONT_MASK (1 << 6)
#define FUSE_IOCTL_COMPAT (1 << 0)
#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
#define FUSE_IOCTL_RETRY (1 << 2)
#define FUSE_IOCTL_MAX_IOV 256
struct fuse_file_info
{
int flags;
unsigned int fh_old;
int writepage;
unsigned int direct_io:1;
unsigned int keep_cache:1;
unsigned int flush:1;
unsigned int nonseekable:1;
unsigned int padding:28;
uint64_t fh;
uint64_t lock_owner;
};
struct fuse_conn_info
{
unsigned proto_major;
unsigned proto_minor;
unsigned async_read;
unsigned max_write;
unsigned max_readahead;
unsigned capable;
unsigned want;
unsigned reserved[25];
};
struct fuse_session;
struct fuse_chan;
struct fuse_pollhandle;
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_version)(struct fsp_fuse_env *env);
FSP_FUSE_API struct fuse_chan *FSP_FUSE_API_NAME(fsp_fuse_mount)(struct fsp_fuse_env *env,
const char *mountpoint, struct fuse_args *args);
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_unmount)(struct fsp_fuse_env *env,
const char *mountpoint, struct fuse_chan *ch);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_parse_cmdline)(struct fsp_fuse_env *env,
struct fuse_args *args,
char **mountpoint, int *multithreaded, int *foreground);
FSP_FUSE_API int32_t FSP_FUSE_API_NAME(fsp_fuse_ntstatus_from_errno)(struct fsp_fuse_env *env,
int err);
FSP_FUSE_SYM(
int fuse_version(void),
{
return FSP_FUSE_API_CALL(fsp_fuse_version)
(fsp_fuse_env());
})
FSP_FUSE_SYM(
struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args),
{
return FSP_FUSE_API_CALL(fsp_fuse_mount)
(fsp_fuse_env(), mountpoint, args);
})
FSP_FUSE_SYM(
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch),
{
FSP_FUSE_API_CALL(fsp_fuse_unmount)
(fsp_fuse_env(), mountpoint, ch);
})
FSP_FUSE_SYM(
int fuse_parse_cmdline(struct fuse_args *args,
char **mountpoint, int *multithreaded, int *foreground),
{
return FSP_FUSE_API_CALL(fsp_fuse_parse_cmdline)
(fsp_fuse_env(), args, mountpoint, multithreaded, foreground);
})
FSP_FUSE_SYM(
void fuse_pollhandle_destroy(struct fuse_pollhandle *ph),
{
(void)ph;
})
FSP_FUSE_SYM(
int fuse_daemonize(int foreground),
{
return fsp_fuse_daemonize(foreground);
})
FSP_FUSE_SYM(
int fuse_set_signal_handlers(struct fuse_session *se),
{
return fsp_fuse_set_signal_handlers(se);
})
FSP_FUSE_SYM(
void fuse_remove_signal_handlers(struct fuse_session *se),
{
(void)se;
fsp_fuse_set_signal_handlers(0);
})
#ifdef __cplusplus
}
#endif
#endif

129
inc/fuse/fuse_opt.h Normal file
View File

@ -0,0 +1,129 @@
/**
* @file fuse/fuse_opt.h
* WinFsp FUSE compatible API.
*
* This file is derived from libfuse/include/fuse_opt.h:
* FUSE: Filesystem in Userspace
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#ifndef FUSE_OPT_H_
#define FUSE_OPT_H_
#include "winfsp_fuse.h"
#ifdef __cplusplus
extern "C" {
#endif
#define FUSE_OPT_KEY(templ, key) { templ, -1, key }
#define FUSE_OPT_END { NULL, 0, 0 }
#define FUSE_OPT_KEY_OPT -1
#define FUSE_OPT_KEY_NONOPT -2
#define FUSE_OPT_KEY_KEEP -3
#define FUSE_OPT_KEY_DISCARD -4
#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 }
struct fuse_opt
{
const char *templ;
unsigned int offset;
int value;
};
struct fuse_args
{
int argc;
char **argv;
int allocated;
};
typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
struct fuse_args *outargs);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_parse)(struct fsp_fuse_env *env,
struct fuse_args *args, void *data,
const struct fuse_opt opts[], fuse_opt_proc_t proc);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_add_arg)(struct fsp_fuse_env *env,
struct fuse_args *args, const char *arg);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_insert_arg)(struct fsp_fuse_env *env,
struct fuse_args *args, int pos, const char *arg);
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_opt_free_args)(struct fsp_fuse_env *env,
struct fuse_args *args);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_add_opt)(struct fsp_fuse_env *env,
char **opts, const char *opt);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_add_opt_escaped)(struct fsp_fuse_env *env,
char **opts, const char *opt);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_match)(struct fsp_fuse_env *env,
const struct fuse_opt opts[], const char *opt);
FSP_FUSE_SYM(
int fuse_opt_parse(struct fuse_args *args, void *data,
const struct fuse_opt opts[], fuse_opt_proc_t proc),
{
return FSP_FUSE_API_CALL(fsp_fuse_opt_parse)
(fsp_fuse_env(), args, data, opts, proc);
})
FSP_FUSE_SYM(
int fuse_opt_add_arg(struct fuse_args *args, const char *arg),
{
return FSP_FUSE_API_CALL(fsp_fuse_opt_add_arg)
(fsp_fuse_env(), args, arg);
})
FSP_FUSE_SYM(
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg),
{
return FSP_FUSE_API_CALL(fsp_fuse_opt_insert_arg)
(fsp_fuse_env(), args, pos, arg);
})
FSP_FUSE_SYM(
void fuse_opt_free_args(struct fuse_args *args),
{
FSP_FUSE_API_CALL(fsp_fuse_opt_free_args)
(fsp_fuse_env(), args);
})
FSP_FUSE_SYM(
int fuse_opt_add_opt(char **opts, const char *opt),
{
return FSP_FUSE_API_CALL(fsp_fuse_opt_add_opt)
(fsp_fuse_env(), opts, opt);
})
FSP_FUSE_SYM(
int fuse_opt_add_opt_escaped(char **opts, const char *opt),
{
return FSP_FUSE_API_CALL(fsp_fuse_opt_add_opt_escaped)
(fsp_fuse_env(), opts, opt);
})
FSP_FUSE_SYM(
int fuse_opt_match(const struct fuse_opt opts[], const char *opt),
{
return FSP_FUSE_API_CALL(fsp_fuse_opt_match)
(fsp_fuse_env(), opts, opt);
})
#ifdef __cplusplus
}
#endif
#endif

364
inc/fuse/winfsp_fuse.h Normal file
View File

@ -0,0 +1,364 @@
/**
* @file fuse/winfsp_fuse.h
* WinFsp FUSE compatible API.
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#ifndef FUSE_WINFSP_FUSE_H_INCLUDED
#define FUSE_WINFSP_FUSE_H_INCLUDED
#include <errno.h>
#include <stdint.h>
#if !defined(WINFSP_DLL_INTERNAL)
#include <stdlib.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(FSP_FUSE_API)
#if defined(WINFSP_DLL_INTERNAL)
#define FSP_FUSE_API __declspec(dllexport)
#else
#define FSP_FUSE_API __declspec(dllimport)
#endif
#endif
#if !defined(FSP_FUSE_API_NAME)
#define FSP_FUSE_API_NAME(n) (n)
#endif
#if !defined(FSP_FUSE_API_CALL)
#define FSP_FUSE_API_CALL(n) (n)
#endif
#if !defined(FSP_FUSE_SYM)
#if !defined(CYGFUSE)
#define FSP_FUSE_SYM(proto, ...) static inline proto { __VA_ARGS__ }
#else
#define FSP_FUSE_SYM(proto, ...) proto;
#endif
#endif
/*
* FUSE uses a number of types (notably: struct stat) that are OS specific.
* Furthermore there are sometimes multiple definitions of the same type even
* within the same OS. This is certainly true on Windows, where these types
* are not even native.
*
* For this reason we will define our own fuse_* types which represent the
* types as the WinFsp DLL expects to see them. We will define these types
* to be compatible with the equivalent Cygwin types as we want WinFsp-FUSE
* to be usable from Cygwin.
*/
#if defined(_WIN64) || defined(_WIN32)
typedef uint32_t fuse_uid_t;
typedef uint32_t fuse_gid_t;
typedef int32_t fuse_pid_t;
typedef uint32_t fuse_dev_t;
typedef uint64_t fuse_ino_t;
typedef uint32_t fuse_mode_t;
typedef uint16_t fuse_nlink_t;
typedef int64_t fuse_off_t;
#if defined(_WIN64)
typedef uint64_t fuse_fsblkcnt_t;
typedef uint64_t fuse_fsfilcnt_t;
#else
typedef uint32_t fuse_fsblkcnt_t;
typedef uint32_t fuse_fsfilcnt_t;
#endif
typedef int32_t fuse_blksize_t;
typedef int64_t fuse_blkcnt_t;
#if defined(_WIN64)
struct fuse_utimbuf
{
int64_t actime;
int64_t modtime;
};
struct fuse_timespec
{
int64_t tv_sec;
int64_t tv_nsec;
};
#else
struct fuse_utimbuf
{
int32_t actime;
int32_t modtime;
};
struct fuse_timespec
{
int32_t tv_sec;
int32_t tv_nsec;
};
#endif
struct fuse_stat
{
fuse_dev_t st_dev;
fuse_ino_t st_ino;
fuse_mode_t st_mode;
fuse_nlink_t st_nlink;
fuse_uid_t st_uid;
fuse_gid_t st_gid;
fuse_dev_t st_rdev;
fuse_off_t st_size;
struct fuse_timespec st_atim;
struct fuse_timespec st_mtim;
struct fuse_timespec st_ctim;
fuse_blksize_t st_blksize;
fuse_blkcnt_t st_blocks;
struct fuse_timespec st_birthtim;
};
#if defined(_WIN64)
struct fuse_statvfs
{
uint64_t f_bsize;
uint64_t f_frsize;
fuse_fsblkcnt_t f_blocks;
fuse_fsblkcnt_t f_bfree;
fuse_fsblkcnt_t f_bavail;
fuse_fsfilcnt_t f_files;
fuse_fsfilcnt_t f_ffree;
fuse_fsfilcnt_t f_favail;
uint64_t f_fsid;
uint64_t f_flag;
uint64_t f_namemax;
};
#else
struct fuse_statvfs
{
uint32_t f_bsize;
uint32_t f_frsize;
fuse_fsblkcnt_t f_blocks;
fuse_fsblkcnt_t f_bfree;
fuse_fsblkcnt_t f_bavail;
fuse_fsfilcnt_t f_files;
fuse_fsfilcnt_t f_ffree;
fuse_fsfilcnt_t f_favail;
uint32_t f_fsid;
uint32_t f_flag;
uint32_t f_namemax;
};
#endif
struct fuse_flock
{
int16_t l_type;
int16_t l_whence;
fuse_off_t l_start;
fuse_off_t l_len;
fuse_pid_t l_pid;
};
#if defined(WINFSP_DLL_INTERNAL)
#define FSP_FUSE_ENV_INIT \
{ \
'W', \
MemAlloc, MemFree, \
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
}
#else
#define FSP_FUSE_ENV_INIT \
{ \
'W', \
malloc, free, \
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
}
#endif
#elif defined(__CYGWIN__)
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <utime.h>
#define fuse_uid_t uid_t
#define fuse_gid_t gid_t
#define fuse_pid_t pid_t
#define fuse_dev_t dev_t
#define fuse_ino_t ino_t
#define fuse_mode_t mode_t
#define fuse_nlink_t nlink_t
#define fuse_off_t off_t
#define fuse_fsblkcnt_t fsblkcnt_t
#define fuse_fsfilcnt_t fsfilcnt_t
#define fuse_blksize_t blksize_t
#define fuse_blkcnt_t blkcnt_t
#define fuse_utimbuf utimbuf
#define fuse_timespec timespec
#define fuse_stat stat
#define fuse_statvfs statvfs
#define fuse_flock flock
#define FSP_FUSE_ENV_INIT \
{ \
'C', \
malloc, free, \
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
}
/*
* Note that long is 8 bytes long in Cygwin64 and 4 bytes long in Win64.
* For this reason we avoid using long anywhere in these headers.
*/
#else
#error unsupported environment
#endif
struct fsp_fuse_env
{
unsigned environment;
void *(*memalloc)(size_t);
void (*memfree)(void *);
int (*daemonize)(int);
int (*set_signal_handlers)(void *);
void (*reserved[4])();
};
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_signal_handler)(int sig);
#if defined(_WIN64) || defined(_WIN32)
static inline int fsp_fuse_daemonize(int foreground)
{
(void)foreground;
return 0;
}
static inline int fsp_fuse_set_signal_handlers(void *se)
{
(void)se;
return 0;
}
#elif defined(__CYGWIN__)
static inline int fsp_fuse_daemonize(int foreground)
{
int daemon(int nochdir, int noclose);
int chdir(const char *path);
if (!foreground)
{
if (-1 == daemon(0, 0))
return -1;
}
else
chdir("/");
return 0;
}
static inline void *fsp_fuse_signal_thread(void *psigmask)
{
int sig;
if (0 == sigwait((sigset_t *)psigmask, &sig))
FSP_FUSE_API_CALL(fsp_fuse_signal_handler)(sig);
return 0;
}
static inline int fsp_fuse_set_signal_handlers(void *se)
{
#define FSP_FUSE_SET_SIGNAL_HANDLER(sig, newha)\
if (-1 != sigaction((sig), 0, &oldsa) &&\
oldsa.sa_handler == (se ? SIG_DFL : (newha)))\
{\
newsa.sa_handler = se ? (newha) : SIG_DFL;\
sigaction((sig), &newsa, 0);\
}
#define FSP_FUSE_SIGADDSET(sig)\
if (-1 != sigaction((sig), 0, &oldsa) &&\
oldsa.sa_handler == SIG_DFL)\
sigaddset(&sigmask, (sig));
static sigset_t sigmask;
static pthread_t sigthr;
struct sigaction oldsa, newsa = { 0 };
if (0 != se)
{
if (0 == sigthr)
{
FSP_FUSE_SET_SIGNAL_HANDLER(SIGPIPE, SIG_IGN);
sigemptyset(&sigmask);
FSP_FUSE_SIGADDSET(SIGHUP);
FSP_FUSE_SIGADDSET(SIGINT);
FSP_FUSE_SIGADDSET(SIGTERM);
if (0 != pthread_sigmask(SIG_BLOCK, &sigmask, 0))
return -1;
if (0 != pthread_create(&sigthr, 0, fsp_fuse_signal_thread, &sigmask))
return -1;
}
}
else
{
if (0 != sigthr)
{
pthread_cancel(sigthr);
pthread_join(sigthr, 0);
sigthr = 0;
if (0 != pthread_sigmask(SIG_UNBLOCK, &sigmask, 0))
return -1;
sigemptyset(&sigmask);
FSP_FUSE_SET_SIGNAL_HANDLER(SIGPIPE, SIG_IGN);
}
}
return 0;
#undef FSP_FUSE_SIGADDSET
#undef FSP_FUSE_SET_SIGNAL_HANDLER
}
#endif
static inline struct fsp_fuse_env *fsp_fuse_env(void)
{
static struct fsp_fuse_env env = FSP_FUSE_ENV_INIT;
return &env;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -24,11 +24,17 @@
extern "C" {
#endif
/* static_assert is a C++11 feature, but seems to work with C on MSVC 2015 */
#if defined(WINFSP_SYS_INTERNAL) || defined(WINFSP_DLL_INTERNAL)
#define FSP_FSCTL_STATIC_ASSERT(e,m) static_assert(e,m)
#else
#define FSP_FSCTL_STATIC_ASSERT(e,m)
#endif
#define FSP_FSCTL_DRIVER_NAME "WinFsp"
#define FSP_FSCTL_DISK_DEVICE_NAME "WinFsp.Disk"
#define FSP_FSCTL_NET_DEVICE_NAME "WinFsp.Net"
#define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams="
// {6F9D25FA-6DEE-4A9D-80F5-E98E14F35E54}
extern const __declspec(selectany) GUID FspFsctlDeviceClassGuid =
{ 0x6f9d25fa, 0x6dee, 0x4a9d, { 0x80, 0xf5, 0xe9, 0x8e, 0x14, 0xf3, 0x5e, 0x54 } };
@ -54,15 +60,26 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
#define FSP_FSCTL_STOP \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'S', METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSP_FSCTL_VOLUME_NAME_SIZE (64 * sizeof(WCHAR))
#define FSP_FSCTL_VOLUME_PREFIX_SIZE (64 * sizeof(WCHAR))
#define FSP_FSCTL_VOLUME_NAME_SIZEMAX (FSP_FSCTL_VOLUME_NAME_SIZE + FSP_FSCTL_VOLUME_PREFIX_SIZE)
#define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams="
#define FSP_FSCTL_TRANSACT_REQ_SIZEMAX (4096 - 64) /* 64: size for internal request header */
#define FSP_FSCTL_TRANSACT_RSP_SIZEMAX (4096 - 64) /* symmetry! */
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN 16384
#define FSP_FSCTL_VOLUME_NAME_SIZE (64 * sizeof(WCHAR))
#define FSP_FSCTL_VOLUME_PREFIX_SIZE (192 * sizeof(WCHAR))
#define FSP_FSCTL_VOLUME_FSNAME_SIZE (16 * sizeof(WCHAR))
#define FSP_FSCTL_VOLUME_NAME_SIZEMAX (FSP_FSCTL_VOLUME_NAME_SIZE + FSP_FSCTL_VOLUME_PREFIX_SIZE)
FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
"Max volume name size is greater than MAX_PATH.");
#define FSP_FSCTL_TRANSACT_PATH_SIZEMAX (1024 * sizeof(WCHAR))
#define FSP_FSCTL_TRANSACT_REQ_SIZEMAX (16 * 1024 - 64) /* 64: size for internal request header */
#define FSP_FSCTL_TRANSACT_RSP_SIZEMAX (16 * 1024)
#define FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMAX (FSP_FSCTL_TRANSACT_REQ_SIZEMAX - sizeof(FSP_FSCTL_TRANSACT_REQ))
#define FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX (FSP_FSCTL_TRANSACT_RSP_SIZEMAX - sizeof(FSP_FSCTL_TRANSACT_RSP))
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (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 */
@ -89,6 +106,7 @@ enum
FspFsctlTransactLockControlKind,
FspFsctlTransactQuerySecurityKind,
FspFsctlTransactSetSecurityKind,
FspFsctlTransactQueryStreamInformationKind,
FspFsctlTransactKindCount,
};
enum
@ -123,12 +141,20 @@ typedef struct
UINT32 CasePreservedNames:1; /* file system preserves the case of file names */
UINT32 UnicodeOnDisk:1; /* file system supports Unicode in file names */
UINT32 PersistentAcls:1; /* file system preserves and enforces access control lists */
UINT32 ReparsePoints:1; /* file system supports reparse points (!!!: unimplemented) */
UINT32 NamedStreams:1; /* file system supports named streams (!!!: unimplemented) */
UINT32 ReparsePoints:1; /* file system supports reparse points */
UINT32 ReparsePointsAccessCheck:1; /* file system performs reparse point access checks */
UINT32 NamedStreams:1; /* file system supports named streams */
UINT32 HardLinks:1; /* unimplemented; set to 0 */
UINT32 ExtendedAttributes:1; /* unimplemented; set to 0 */
UINT32 ReadOnlyVolume:1;
/* kernel-mode flags */
UINT32 PostCleanupOnDeleteOnly:1; /* post Cleanup when deleting a file only */
UINT32 KmReservedFlags:5;
/* user-mode flags */
UINT32 UmFileNodeIsUserContext2:1; /* user mode: FileNode parameter is UserContext2 */
UINT32 UmReservedFlags:15;
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
} FSP_FSCTL_VOLUME_PARAMS;
typedef struct
{
@ -159,6 +185,13 @@ typedef struct
WCHAR FileNameBuf[];
} FSP_FSCTL_DIR_INFO;
typedef struct
{
UINT16 Size;
UINT64 StreamSize;
UINT64 StreamAllocationSize;
WCHAR StreamNameBuf[];
} FSP_FSCTL_STREAM_INFO;
typedef struct
{
UINT16 Offset;
UINT16 Size;
@ -185,6 +218,8 @@ typedef struct
UINT32 HasTraversePrivilege:1; /* requestor has TOKEN_HAS_TRAVERSE_PRIVILEGE */
UINT32 OpenTargetDirectory:1; /* open target dir and report FILE_{EXISTS,DOES_NOT_EXIST} */
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
UINT32 ReservedFlags:28;
UINT16 NamedStream; /* request targets named stream; colon offset in FileName */
} Create;
struct
{
@ -257,7 +292,7 @@ typedef struct
struct
{
FSP_FSCTL_TRANSACT_BUF NewFileName;
UINT32 ReplaceIfExists:1;
UINT64 AccessToken; /* request access token (HANDLE) */
} Rename;
} Info;
} SetInformation;
@ -287,6 +322,14 @@ typedef struct
FSP_FSCTL_TRANSACT_BUF Pattern;
} QueryDirectory;
struct
{
UINT64 UserContext;
UINT64 UserContext2;
UINT32 FsControlCode;
FSP_FSCTL_TRANSACT_BUF Buffer;
UINT16 TargetOnFileSystem; /* the target of the symbolic link is on this file system */
} FileSystemControl;
struct
{
UINT64 UserContext;
UINT64 UserContext2;
@ -299,6 +342,11 @@ typedef struct
UINT64 AccessToken; /* request access token (HANDLE) */
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
} SetSecurity;
struct
{
UINT64 UserContext;
UINT64 UserContext2;
} QueryStreamInformation;
} Req;
FSP_FSCTL_TRANSACT_BUF FileName; /* {Create,Cleanup,SetInformation/{...},QueryDirectory} */
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
@ -311,7 +359,7 @@ typedef struct
UINT64 Hint;
struct
{
UINT64 Information;
UINT32 Information;
UINT32 Status;
} IoStatus;
union
@ -329,7 +377,7 @@ typedef struct
/* IoStatus.Status == STATUS_REPARSE */
struct
{
FSP_FSCTL_TRANSACT_BUF FileName; /* file name to use for STATUS_REPARSE */
FSP_FSCTL_TRANSACT_BUF Buffer;
} Reparse;
} Create;
struct
@ -357,6 +405,10 @@ typedef struct
FSP_FSCTL_VOLUME_INFO VolumeInfo;
} SetVolumeInformation;
struct
{
FSP_FSCTL_TRANSACT_BUF Buffer;
} FileSystemControl;
struct
{
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
} QuerySecurity;
@ -364,6 +416,10 @@ typedef struct
{
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* Size==0 means no security descriptor returned */
} SetSecurity;
struct
{
FSP_FSCTL_TRANSACT_BUF Buffer;
} QueryStreamInformation;
} Rsp;
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
} FSP_FSCTL_TRANSACT_RSP;
@ -421,6 +477,7 @@ FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle,
FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle);
FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath,
PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize);
FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath);
#endif
#ifdef __cplusplus

File diff suppressed because it is too large Load Diff

20
opt/cygfuse/Makefile Normal file
View File

@ -0,0 +1,20 @@
Version = $(shell sed -n '/^VERSION=/s/VERSION=\(.*\)/\1/p' fuse.cygport)
#Debug = -g
cygfuse-$(Version).dll libfuse-$(Version).dll.a fuse.pc: cygfuse.c fuse.pc.in
gcc $(Debug) -shared -o cygfuse-$(Version).dll -Wl,--out-implib=libfuse-$(Version).dll.a -I../../inc/fuse cygfuse.c
[ -n "$(Debug)" ] || strip cygfuse-$(Version).dll
sed "s/@Version@/$(Version)/g" fuse.pc.in > fuse.pc
cygfuse-test.exe: cygfuse-test.c cygfuse-$(Version).dll libfuse-$(Version).dll.a
gcc $(Debug) -o cygfuse-test.exe -I../../inc/fuse -DCYGFUSE cygfuse-test.c -L$(PWD) -lfuse-$(Version)
cygport:
git clean -dfx
(\
cd `git rev-parse --show-toplevel` &&\
Stash=`git stash create` &&\
git archive --prefix=winfsp-work/ --format=tar.gz $${Stash:-HEAD}\
> opt/cygfuse/winfsp-work.tar.gz\
)
CYGPORT_SRC_URI=winfsp-work.tar.gz CYGPORT_SRC_DIR=winfsp-work cygport fuse.cygport download prep compile install package

View File

@ -0,0 +1,6 @@
#include <fuse.h>
int main()
{
return !(FUSE_VERSION == fuse_version());
}

146
opt/cygfuse/cygfuse.c Normal file
View File

@ -0,0 +1,146 @@
/**
* @file cygfuse/cygfuse.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dlfcn.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/cygwin.h>
static void *cygfuse_init_winfsp();
static void *cygfuse_init_fail();
static pthread_mutex_t cygfuse_mutex = PTHREAD_MUTEX_INITIALIZER;
static void *cygfuse_handle = 0;
static inline void cygfuse_init(int force)
{
pthread_mutex_lock(&cygfuse_mutex);
if (force || 0 == cygfuse_handle)
cygfuse_handle = cygfuse_init_winfsp();
pthread_mutex_unlock(&cygfuse_mutex);
}
/*
* Unfortunately Cygwin fork is very fragile and cannot even correctly
* handle dlopen'ed DLL's if they are native (rather than Cygwin ones).
*
* So we have this very nasty hack where we reset the dlopen'ed handle
* immediately after daemonization. This will force cygfuse_init() to
* reload the WinFsp DLL and reset all API pointers in the daemonized
* process.
*/
static inline int cygfuse_daemon(int nochdir, int noclose)
{
if (-1 == daemon(nochdir, noclose))
return -1;
/* force reload of WinFsp DLL to workaround fork() problems */
cygfuse_init(1);
return 0;
}
#define daemon cygfuse_daemon
#define FSP_FUSE_API static
#define FSP_FUSE_API_NAME(api) (* pfn_ ## api)
#define FSP_FUSE_API_CALL(api) (cygfuse_init(0), pfn_ ## api)
#define FSP_FUSE_SYM(proto, ...) __attribute__ ((visibility("default"))) proto { __VA_ARGS__ }
#include <fuse_common.h>
#include <fuse.h>
#include <fuse_opt.h>
#if defined(__LP64__)
#define CYGFUSE_WINFSP_NAME "winfsp-x64.dll"
#else
#define CYGFUSE_WINFSP_NAME "winfsp-x86.dll"
#endif
#define CYGFUSE_WINFSP_PATH "bin\\" CYGFUSE_WINFSP_NAME
#define CYGFUSE_GET_API(h, n) \
if (0 == (*(void **)&(pfn_ ## n) = dlsym(h, #n)))\
return cygfuse_init_fail();
static void *cygfuse_init_winfsp()
{
void *h;
h = dlopen(CYGFUSE_WINFSP_NAME, RTLD_NOW);
if (0 == h)
{
char winpath[260], *psxpath;
int regfd, bytes;
regfd = open("/proc/registry32/HKEY_LOCAL_MACHINE/Software/WinFsp/InstallDir", O_RDONLY);
if (-1 == regfd)
return cygfuse_init_fail();
bytes = read(regfd, winpath, sizeof winpath - sizeof CYGFUSE_WINFSP_PATH);
close(regfd);
if (-1 == bytes || 0 == bytes)
return cygfuse_init_fail();
if ('\0' == winpath[bytes - 1])
bytes--;
memcpy(winpath + bytes, CYGFUSE_WINFSP_PATH, sizeof CYGFUSE_WINFSP_PATH);
psxpath = (char *)cygwin_create_path(CCP_WIN_A_TO_POSIX | CCP_PROC_CYGDRIVE, winpath);
if (0 == psxpath)
return cygfuse_init_fail();
h = dlopen(psxpath, RTLD_NOW);
free(psxpath);
if (0 == h)
return cygfuse_init_fail();
}
/* winfsp_fuse.h */
CYGFUSE_GET_API(h, fsp_fuse_signal_handler);
/* fuse_common.h */
CYGFUSE_GET_API(h, fsp_fuse_version);
CYGFUSE_GET_API(h, fsp_fuse_mount);
CYGFUSE_GET_API(h, fsp_fuse_unmount);
CYGFUSE_GET_API(h, fsp_fuse_parse_cmdline);
CYGFUSE_GET_API(h, fsp_fuse_ntstatus_from_errno);
/* fuse.h */
CYGFUSE_GET_API(h, fsp_fuse_main_real);
CYGFUSE_GET_API(h, fsp_fuse_is_lib_option);
CYGFUSE_GET_API(h, fsp_fuse_new);
CYGFUSE_GET_API(h, fsp_fuse_destroy);
CYGFUSE_GET_API(h, fsp_fuse_loop);
CYGFUSE_GET_API(h, fsp_fuse_loop_mt);
CYGFUSE_GET_API(h, fsp_fuse_exit);
CYGFUSE_GET_API(h, fsp_fuse_get_context);
/* fuse_opt.h */
CYGFUSE_GET_API(h, fsp_fuse_opt_parse);
CYGFUSE_GET_API(h, fsp_fuse_opt_add_arg);
CYGFUSE_GET_API(h, fsp_fuse_opt_insert_arg);
CYGFUSE_GET_API(h, fsp_fuse_opt_free_args);
CYGFUSE_GET_API(h, fsp_fuse_opt_add_opt);
CYGFUSE_GET_API(h, fsp_fuse_opt_add_opt_escaped);
CYGFUSE_GET_API(h, fsp_fuse_opt_match);
return h;
}
static void *cygfuse_init_fail()
{
abort();
return 0;
}

35
opt/cygfuse/fuse.cygport Normal file
View File

@ -0,0 +1,35 @@
NAME="fuse"
VERSION=2.8
RELEASE=3
CATEGORY="Utils"
SUMMARY="WinFsp-FUSE compatibility layer"
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."
HOMEPAGE="http://www.secfs.net/winfsp/"
SRC_URI=${CYGPORT_SRC_URI:-"https://github.com/billziss-gh/winfsp/archive/master.tar.gz"}
SRC_DIR=${CYGPORT_SRC_DIR:-winfsp-master}
src_compile()
{
lndirs
cd ${B}/opt/cygfuse
make
}
src_install()
{
cd ${B}/inc/fuse
includeinto fuse
doinclude fuse.h
doinclude fuse_common.h
doinclude fuse_opt.h
doinclude winfsp_fuse.h
cd ${B}/opt/cygfuse
dobin cygfuse-${VERSION}.dll
dolib libfuse-${VERSION}.dll.a
dosym libfuse-${VERSION}.dll.a /usr/lib/libfuse.dll.a
dopkgconfig fuse.pc
}
RESTRICT="strip postinst-doc"

9
opt/cygfuse/fuse.pc.in Normal file
View File

@ -0,0 +1,9 @@
prefix=/usr
incdir=${prefix}/include/fuse
Name: fuse
Description: WinFsp FUSE compatible API
Version: @Version@
URL: http://www.secfs.net/winfsp/
Libs: -lfuse-@Version@
Cflags: -I"${incdir}" -DCYGFUSE

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -19,6 +19,13 @@
#include <sddl.h>
#include <stdarg.h>
static HANDLE FspDebugLogHandle = INVALID_HANDLE_VALUE;
FSP_API VOID FspDebugLogSetHandle(HANDLE Handle)
{
FspDebugLogHandle = Handle;
}
FSP_API VOID FspDebugLog(const char *format, ...)
{
char buf[1024];
@ -28,6 +35,12 @@ FSP_API VOID FspDebugLog(const char *format, ...)
wvsprintfA(buf, format, ap);
va_end(ap);
buf[sizeof buf - 1] = '\0';
if (INVALID_HANDLE_VALUE != FspDebugLogHandle)
{
DWORD bytes;
WriteFile(FspDebugLogHandle, buf, lstrlenA(buf), &bytes, 0);
}
else
OutputDebugStringA(buf);
}
@ -37,7 +50,8 @@ FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDesc
if (0 == SecurityDescriptor)
FspDebugLog(format, "null security descriptor");
else if (ConvertSecurityDescriptorToStringSecurityDescriptorA(SecurityDescriptor, SDDL_REVISION_1,
else if (ConvertSecurityDescriptorToStringSecurityDescriptorA(SecurityDescriptor,
SDDL_REVISION_1,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
&Sddl, 0))
@ -65,3 +79,744 @@ FSP_API VOID FspDebugLogFT(const char *format, PFILETIME FileTime)
else
FspDebugLog(format, "invalid file time");
}
#define MAKE_UINT32_PAIR(v) \
((PLARGE_INTEGER)&(v))->HighPart, ((PLARGE_INTEGER)&(v))->LowPart
static const char *FspDebugLogDispositionString(UINT32 CreateOptions)
{
switch ((CreateOptions >> 24) & 0xff)
{
case FILE_CREATE:
return "FILE_CREATE";
case FILE_OPEN:
return "FILE_OPEN";
case FILE_OPEN_IF:
return "FILE_OPEN_IF";
case FILE_OVERWRITE:
return "FILE_OVERWRITE";
case FILE_SUPERSEDE:
return "FILE_SUPERSEDE";
case FILE_OVERWRITE_IF:
return "FILE_OVERWRITE_IF";
default:
return "INVALID";
}
}
static const char *FspDebugLogUserContextString(UINT64 UserContext, UINT64 UserContext2, char *Buf)
{
wsprintfA(Buf, 0 == UserContext2 ? "%p" : "%p:%p", UserContext, UserContext2);
return Buf;
}
static const char *FspDebugLogFileTimeString(UINT64 FileTime, char *Buf)
{
SYSTEMTIME SystemTime;
if (0 == FileTime)
lstrcpyA(Buf, "0");
else if (FileTimeToSystemTime((PFILETIME)&FileTime, &SystemTime))
{
wsprintfA(Buf, "%04hu-%02hu-%02huT%02hu:%02hu:%02hu.%03huZ",
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay,
SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond,
SystemTime.wMilliseconds);
}
else
lstrcpyA(Buf, "INVALID");
return Buf;
}
static const char *FspDebugLogFileInfoString(FSP_FSCTL_FILE_INFO *FileInfo, char *Buf)
{
char CreationTimeBuf[32], LastAccessTimeBuf[32], LastWriteTimeBuf[32], ChangeTimeBuf[32];
wsprintfA(Buf,
"{"
"FileAttributes=%lx, "
"ReparseTag=%lx, "
"AllocationSize=%lx:%lx, "
"FileSize=%lx:%lx, "
"CreationTime=%s, "
"LastAccessTime=%s, "
"LastWriteTime=%s, "
"ChangeTime=%s, "
"IndexNumber=%lx:%lx"
"}",
FileInfo->FileAttributes,
FileInfo->ReparseTag,
MAKE_UINT32_PAIR(FileInfo->AllocationSize),
MAKE_UINT32_PAIR(FileInfo->FileSize),
FspDebugLogFileTimeString(FileInfo->CreationTime, CreationTimeBuf),
FspDebugLogFileTimeString(FileInfo->LastAccessTime, LastAccessTimeBuf),
FspDebugLogFileTimeString(FileInfo->LastWriteTime, LastWriteTimeBuf),
FspDebugLogFileTimeString(FileInfo->ChangeTime, ChangeTimeBuf),
MAKE_UINT32_PAIR(FileInfo->IndexNumber));
return Buf;
}
static const char *FspDebugLogVolumeInfoString(FSP_FSCTL_VOLUME_INFO *VolumeInfo, char *Buf)
{
wsprintfA(Buf,
"{"
"TotalSize=%lx:%lx, "
"FreeSize=%lx:%lx, "
"VolumeLabel=\"%.32S\""
"}",
MAKE_UINT32_PAIR(VolumeInfo->TotalSize),
MAKE_UINT32_PAIR(VolumeInfo->FreeSize),
&VolumeInfo->VolumeLabel);
return Buf;
}
static const char *FspDebugLogWideCharBufferString(PVOID WideCharBuf, ULONG Length, char *Buf)
{
WCHAR TempWideCharBuf[64 + 1];
if (Length > sizeof TempWideCharBuf - sizeof(WCHAR))
Length = sizeof TempWideCharBuf - sizeof(WCHAR);
memcpy(TempWideCharBuf, WideCharBuf, Length);
TempWideCharBuf[Length / sizeof(WCHAR)] = L'\0';
wsprintfA(Buf, "%.64S", TempWideCharBuf);
return Buf;
}
static const char *FspDebugLogReparseDataString(PVOID ReparseData0, char *Buf)
{
union
{
PREPARSE_DATA_BUFFER D;
PREPARSE_GUID_DATA_BUFFER G;
} ReparseData;
char SubstituteName[64 + 1], PrintName[64 + 1];
ReparseData.D = ReparseData0;
if (0 == ReparseData.D->ReparseDataLength)
wsprintfA(Buf,
"{"
"ReparseTag=%#lx, "
"ReparseDataLength=%hu"
"}",
ReparseData.D->ReparseTag, ReparseData.D->ReparseDataLength);
else if (IO_REPARSE_TAG_MOUNT_POINT == ReparseData.D->ReparseTag)
wsprintfA(Buf,
"{"
"ReparseTag=IO_REPARSE_TAG_MOUNT_POINT, "
"SubstituteName=\"%s\", "
"PrintName=\"%s\""
"}",
FspDebugLogWideCharBufferString(
ReparseData.D->MountPointReparseBuffer.PathBuffer +
ReparseData.D->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
ReparseData.D->MountPointReparseBuffer.SubstituteNameLength,
SubstituteName),
FspDebugLogWideCharBufferString(
ReparseData.D->MountPointReparseBuffer.PathBuffer +
ReparseData.D->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR),
ReparseData.D->MountPointReparseBuffer.PrintNameLength,
PrintName));
else if (IO_REPARSE_TAG_SYMLINK == ReparseData.D->ReparseTag)
wsprintfA(Buf,
"{"
"ReparseTag=IO_REPARSE_TAG_SYMLINK, "
"SubstituteName=\"%s\", "
"PrintName=\"%s\", "
"Flags=%u"
"}",
FspDebugLogWideCharBufferString(
ReparseData.D->SymbolicLinkReparseBuffer.PathBuffer +
ReparseData.D->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
ReparseData.D->SymbolicLinkReparseBuffer.SubstituteNameLength,
SubstituteName),
FspDebugLogWideCharBufferString(
ReparseData.D->SymbolicLinkReparseBuffer.PathBuffer +
ReparseData.D->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR),
ReparseData.D->SymbolicLinkReparseBuffer.PrintNameLength,
PrintName),
ReparseData.D->SymbolicLinkReparseBuffer.Flags);
else if (IsReparseTagMicrosoft(ReparseData.D->ReparseTag))
wsprintfA(Buf,
"{"
"ReparseTag=%#lx, "
"ReparseDataLength=%hu"
"}",
ReparseData.D->ReparseTag, ReparseData.D->ReparseDataLength);
else
#define Guid ReparseData.G->ReparseGuid
wsprintfA(Buf,
"{"
"ReparseTag=%#lx, "
"ReparseDataLength=%hu, "
"ReparseGuid={%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"
"}",
ReparseData.G->ReparseTag, ReparseData.G->ReparseDataLength,
Guid.Data1, Guid.Data2, Guid.Data3,
Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
#undef Guid
return Buf;
}
static VOID FspDebugLogRequestVoid(FSP_FSCTL_TRANSACT_REQ *Request, const char *Name)
{
FspDebugLog("%S[TID=%04lx]: %p: >>%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint, Name);
}
static VOID FspDebugLogResponseStatus(FSP_FSCTL_TRANSACT_RSP *Response, const char *Name)
{
FspDebugLog("%S[TID=%04lx]: %p: <<%s IoStatus=%lx[%ld]\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint, Name,
Response->IoStatus.Status, Response->IoStatus.Information);
}
FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
{
char UserContextBuf[40];
char CreationTimeBuf[32], LastAccessTimeBuf[32], LastWriteTimeBuf[32];
char InfoBuf[256];
char *Sddl = 0;
switch (Request->Kind)
{
case FspFsctlTransactReservedKind:
FspDebugLogRequestVoid(Request, "RESERVED");
break;
case FspFsctlTransactCreateKind:
if (0 != Request->Req.Create.SecurityDescriptor.Offset)
ConvertSecurityDescriptorToStringSecurityDescriptorA(
Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset,
SDDL_REVISION_1,
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\", "
"%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, "
"AllocationSize=%lx:%lx, AccessToken=%p, DesiredAccess=%lx, ShareAccess=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->Req.Create.UserMode ? 'U' : 'K',
Request->Req.Create.HasTraversePrivilege ? 'T' : '-',
Request->Req.Create.OpenTargetDirectory ? 'D' : '-',
Request->Req.Create.CaseSensitive ? 'C' : '-',
(PWSTR)Request->Buffer,
FspDebugLogDispositionString(Request->Req.Create.CreateOptions),
Request->Req.Create.CreateOptions & 0xffffff,
Request->Req.Create.FileAttributes,
Sddl ? "\"" : "",
Sddl ? Sddl : "NULL",
Sddl ? "\"" : "",
MAKE_UINT32_PAIR(Request->Req.Create.AllocationSize),
(PVOID)Request->Req.Create.AccessToken,
Request->Req.Create.DesiredAccess,
Request->Req.Create.ShareAccess);
LocalFree(Sddl);
break;
case FspFsctlTransactOverwriteKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Overwrite%s %s%S%s%s, "
"FileAttributes=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->Req.Overwrite.Supersede ? " [Supersede]" : "",
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.Overwrite.UserContext, Request->Req.Overwrite.UserContext2,
UserContextBuf),
Request->Req.Overwrite.FileAttributes);
break;
case FspFsctlTransactCleanupKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Cleanup%s %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->Req.Cleanup.Delete ? " [Delete]" : "",
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.Cleanup.UserContext, Request->Req.Cleanup.UserContext2,
UserContextBuf));
break;
case FspFsctlTransactCloseKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Close %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.Close.UserContext, Request->Req.Close.UserContext2,
UserContextBuf));
break;
case FspFsctlTransactReadKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Read %s%S%s%s, "
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.Read.UserContext, Request->Req.Read.UserContext2,
UserContextBuf),
Request->Req.Read.Address,
MAKE_UINT32_PAIR(Request->Req.Read.Offset),
Request->Req.Read.Length,
Request->Req.Read.Key);
break;
case FspFsctlTransactWriteKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Write%s %s%S%s%s, "
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->Req.Write.ConstrainedIo ? " [C]" : "",
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.Write.UserContext, Request->Req.Write.UserContext2,
UserContextBuf),
Request->Req.Write.Address,
MAKE_UINT32_PAIR(Request->Req.Write.Offset),
Request->Req.Write.Length,
Request->Req.Write.Key);
break;
case FspFsctlTransactQueryInformationKind:
FspDebugLog("%S[TID=%04lx]: %p: >>QueryInformation %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.QueryInformation.UserContext, Request->Req.QueryInformation.UserContext2,
UserContextBuf));
break;
case FspFsctlTransactSetInformationKind:
switch (Request->Req.SetInformation.FileInformationClass)
{
case 4/*FileBasicInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Basic] %s%S%s%s, "
"FileAttributes=%lx, CreationTime=%s, LastAccessTime=%s, LastWriteTime=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
UserContextBuf),
Request->Req.SetInformation.Info.Basic.FileAttributes,
FspDebugLogFileTimeString(Request->Req.SetInformation.Info.Basic.CreationTime,
CreationTimeBuf),
FspDebugLogFileTimeString(Request->Req.SetInformation.Info.Basic.LastAccessTime,
LastAccessTimeBuf),
FspDebugLogFileTimeString(Request->Req.SetInformation.Info.Basic.LastWriteTime,
LastWriteTimeBuf));
break;
case 19/*FileAllocationInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Allocation] %s%S%s%s, "
"AllocationSize=%lx:%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
UserContextBuf),
MAKE_UINT32_PAIR(Request->Req.SetInformation.Info.Allocation.AllocationSize));
break;
case 20/*FileEndOfFileInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [EndOfFile] %s%S%s%s, "
"FileSize = %lx:%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
UserContextBuf),
MAKE_UINT32_PAIR(Request->Req.SetInformation.Info.EndOfFile.FileSize));
break;
case 13/*FileDispositionInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Disposition] %s%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.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
UserContextBuf),
Request->Req.SetInformation.Info.Disposition.Delete ? "Delete" : "Undelete");
break;
case 10/*FileRenameInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Rename] %s%S%s%s, "
"NewFileName=\"%S\", AccessToken=%p\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
UserContextBuf),
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
(PVOID)Request->Req.SetInformation.Info.Rename.AccessToken);
break;
default:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [INVALID] %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.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
UserContextBuf));
break;
}
break;
case FspFsctlTransactQueryEaKind:
FspDebugLogRequestVoid(Request, "QUERYEA");
break;
case FspFsctlTransactSetEaKind:
FspDebugLogRequestVoid(Request, "SETEA");
break;
case FspFsctlTransactFlushBuffersKind:
FspDebugLog("%S[TID=%04lx]: %p: >>FlushBuffers %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.FlushBuffers.UserContext, Request->Req.FlushBuffers.UserContext2,
UserContextBuf));
break;
case FspFsctlTransactQueryVolumeInformationKind:
FspDebugLogRequestVoid(Request, "QueryVolumeInformation");
break;
case FspFsctlTransactSetVolumeInformationKind:
switch (Request->Req.SetVolumeInformation.FsInformationClass)
{
case 2/*FileFsLabelInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [FsLabel] "
"Label=\"%S\"\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
(PWSTR)Request->Buffer);
break;
default:
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [INVALID]\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint);
break;
}
break;
case FspFsctlTransactQueryDirectoryKind:
FspDebugLog("%S[TID=%04lx]: %p: >>QueryDirectory %s%S%s%s, "
"Address=%p, Offset=%lx:%lx, Length=%ld, Pattern=%s%S%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.QueryDirectory.UserContext, Request->Req.QueryDirectory.UserContext2,
UserContextBuf),
Request->Req.QueryDirectory.Address,
MAKE_UINT32_PAIR(Request->Req.QueryDirectory.Offset),
Request->Req.QueryDirectory.Length,
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "",
Request->Req.QueryDirectory.Pattern.Size ?
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : L"NULL",
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "");
break;
case FspFsctlTransactFileSystemControlKind:
switch (Request->Req.FileSystemControl.FsControlCode)
{
case FSCTL_GET_REPARSE_POINT:
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [FSCTL_GET_REPARSE_POINT] %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.FileSystemControl.UserContext, Request->Req.FileSystemControl.UserContext2,
UserContextBuf));
break;
case FSCTL_SET_REPARSE_POINT:
case FSCTL_DELETE_REPARSE_POINT:
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [%s] %s%S%s%s "
"ReparseData=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FSCTL_SET_REPARSE_POINT == Request->Req.FileSystemControl.FsControlCode ?
"FSCTL_SET_REPARSE_POINT" : "FSCTL_DELETE_REPARSE_POINT",
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.FileSystemControl.UserContext, Request->Req.FileSystemControl.UserContext2,
UserContextBuf),
FspDebugLogReparseDataString(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset,
InfoBuf));
break;
default:
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [INVALID] %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.FileSystemControl.UserContext, Request->Req.FileSystemControl.UserContext2,
UserContextBuf));
break;
}
break;
case FspFsctlTransactDeviceControlKind:
FspDebugLogRequestVoid(Request, "DEVICECONTROL");
break;
case FspFsctlTransactShutdownKind:
FspDebugLogRequestVoid(Request, "SHUTDOWN");
break;
case FspFsctlTransactLockControlKind:
FspDebugLogRequestVoid(Request, "LOCKCONTROL");
break;
case FspFsctlTransactQuerySecurityKind:
FspDebugLog("%S[TID=%04lx]: %p: >>QuerySecurity %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.QuerySecurity.UserContext, Request->Req.QuerySecurity.UserContext2,
UserContextBuf));
break;
case FspFsctlTransactSetSecurityKind:
if (0 != Request->Req.SetSecurity.SecurityDescriptor.Size)
ConvertSecurityDescriptorToStringSecurityDescriptorA(
Request->Buffer + Request->Req.SetSecurity.SecurityDescriptor.Offset,
SDDL_REVISION_1,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
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",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
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;
default:
FspDebugLogRequestVoid(Request, "INVALID");
break;
}
}
FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
{
if (STATUS_PENDING == Response->IoStatus.Status)
return;
char UserContextBuf[40];
char InfoBuf[256];
char *Sddl = 0;
switch (Response->Kind)
{
case FspFsctlTransactReservedKind:
FspDebugLogResponseStatus(Response, "RESERVED");
break;
case FspFsctlTransactCreateKind:
if (!NT_SUCCESS(Response->IoStatus.Status))
FspDebugLogResponseStatus(Response, "Create");
else if (STATUS_REPARSE == Response->IoStatus.Status)
{
if (0/*IO_REPARSE*/ == Response->IoStatus.Information)
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
"Reparse.FileName=\"%s\"\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogWideCharBufferString(
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
Response->Rsp.Create.Reparse.Buffer.Size,
InfoBuf));
else if (1/*IO_REMOUNT*/ == Response->IoStatus.Information)
FspDebugLogResponseStatus(Response, "Create");
else
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
"Reparse.Data=\"%s\"\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogReparseDataString(
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
InfoBuf));
}
else
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
"UserContext=%s, GrantedAccess=%lx, FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogUserContextString(
Response->Rsp.Create.Opened.UserContext, Response->Rsp.Create.Opened.UserContext2,
UserContextBuf),
Response->Rsp.Create.Opened.GrantedAccess,
FspDebugLogFileInfoString(&Response->Rsp.Create.Opened.FileInfo, InfoBuf));
break;
case FspFsctlTransactOverwriteKind:
if (!NT_SUCCESS(Response->IoStatus.Status))
FspDebugLogResponseStatus(Response, "Overwrite");
else
FspDebugLog("%S[TID=%04lx]: %p: <<Overwrite IoStatus=%lx[%ld] "
"FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogFileInfoString(&Response->Rsp.Overwrite.FileInfo, InfoBuf));
break;
case FspFsctlTransactCleanupKind:
FspDebugLogResponseStatus(Response, "Cleanup");
break;
case FspFsctlTransactCloseKind:
FspDebugLogResponseStatus(Response, "Close");
break;
case FspFsctlTransactReadKind:
FspDebugLogResponseStatus(Response, "Read");
break;
case FspFsctlTransactWriteKind:
if (!NT_SUCCESS(Response->IoStatus.Status))
FspDebugLogResponseStatus(Response, "Write");
else
FspDebugLog("%S[TID=%04lx]: %p: <<Write IoStatus=%lx[%ld] "
"FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogFileInfoString(&Response->Rsp.Write.FileInfo, InfoBuf));
break;
case FspFsctlTransactQueryInformationKind:
if (!NT_SUCCESS(Response->IoStatus.Status))
FspDebugLogResponseStatus(Response, "QueryInformation");
else
FspDebugLog("%S[TID=%04lx]: %p: <<QueryInformation IoStatus=%lx[%ld] "
"FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogFileInfoString(&Response->Rsp.QueryInformation.FileInfo, InfoBuf));
break;
case FspFsctlTransactSetInformationKind:
if (!NT_SUCCESS(Response->IoStatus.Status))
FspDebugLogResponseStatus(Response, "SetInformation");
else
FspDebugLog("%S[TID=%04lx]: %p: <<SetInformation IoStatus=%lx[%ld] "
"FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogFileInfoString(&Response->Rsp.SetInformation.FileInfo, InfoBuf));
break;
case FspFsctlTransactQueryEaKind:
FspDebugLogResponseStatus(Response, "QUERYEA");
break;
case FspFsctlTransactSetEaKind:
FspDebugLogResponseStatus(Response, "SETEA");
break;
case FspFsctlTransactFlushBuffersKind:
FspDebugLogResponseStatus(Response, "FlushBuffers");
break;
case FspFsctlTransactQueryVolumeInformationKind:
if (!NT_SUCCESS(Response->IoStatus.Status))
FspDebugLogResponseStatus(Response, "QueryVolumeInformation");
else
FspDebugLog("%S[TID=%04lx]: %p: <<QueryVolumeInformation IoStatus=%lx[%ld] "
"VolumeInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogVolumeInfoString(&Response->Rsp.QueryVolumeInformation.VolumeInfo, InfoBuf));
break;
case FspFsctlTransactSetVolumeInformationKind:
if (!NT_SUCCESS(Response->IoStatus.Status))
FspDebugLogResponseStatus(Response, "SetVolumeInformation");
else
FspDebugLog("%S[TID=%04lx]: %p: <<SetVolumeInformation IoStatus=%lx[%ld] "
"VolumeInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogVolumeInfoString(&Response->Rsp.SetVolumeInformation.VolumeInfo, InfoBuf));
break;
case FspFsctlTransactQueryDirectoryKind:
FspDebugLogResponseStatus(Response, "QueryDirectory");
break;
case FspFsctlTransactFileSystemControlKind:
if (!NT_SUCCESS(Response->IoStatus.Status) ||
0 == Response->Rsp.FileSystemControl.Buffer.Size)
FspDebugLogResponseStatus(Response, "FileSystemControl");
else
FspDebugLog("%S[TID=%04lx]: %p: <<FileSystemControl IoStatus=%lx[%ld] "
"ReparseData=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogReparseDataString(Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset,
InfoBuf));
break;
case FspFsctlTransactDeviceControlKind:
FspDebugLogResponseStatus(Response, "DEVICECONTROL");
break;
case FspFsctlTransactShutdownKind:
FspDebugLogResponseStatus(Response, "SHUTDOWN");
break;
case FspFsctlTransactLockControlKind:
FspDebugLogResponseStatus(Response, "LOCKCONTROL");
break;
case FspFsctlTransactQuerySecurityKind:
if (!NT_SUCCESS(Response->IoStatus.Status))
FspDebugLogResponseStatus(Response, "QuerySecurity");
else
{
if (0 != Response->Rsp.QuerySecurity.SecurityDescriptor.Size)
ConvertSecurityDescriptorToStringSecurityDescriptorA(
Response->Buffer + Response->Rsp.QuerySecurity.SecurityDescriptor.Offset,
SDDL_REVISION_1,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
&Sddl, 0);
FspDebugLog("%S[TID=%04lx]: %p: <<QuerySecurity IoStatus=%lx[%ld] "
"Security=%s%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
Sddl ? "\"" : "",
Sddl ? Sddl : "NULL",
Sddl ? "\"" : "");
LocalFree(Sddl);
}
break;
case FspFsctlTransactSetSecurityKind:
if (!NT_SUCCESS(Response->IoStatus.Status))
FspDebugLogResponseStatus(Response, "SetSecurity");
else
{
if (0 != Response->Rsp.SetSecurity.SecurityDescriptor.Size)
ConvertSecurityDescriptorToStringSecurityDescriptorA(
Response->Buffer + Response->Rsp.SetSecurity.SecurityDescriptor.Offset,
SDDL_REVISION_1,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
&Sddl, 0);
FspDebugLog("%S[TID=%04lx]: %p: <<SetSecurity IoStatus=%lx[%ld] "
"Security=%s%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
Sddl ? "\"" : "",
Sddl ? Sddl : "NULL",
Sddl ? "\"" : "");
LocalFree(Sddl);
}
break;
default:
FspDebugLogResponseStatus(Response, "INVALID");
break;
}
}

139
src/dll/eventlog.c Normal file
View File

@ -0,0 +1,139 @@
/**
* @file dll/eventlog.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dll/library.h>
#include <stdarg.h>
#include "eventlog/eventlog.h"
#define FSP_EVENTLOG_NAME LIBRARY_NAME
static INIT_ONCE FspEventLogInitOnce = INIT_ONCE_STATIC_INIT;
static HANDLE FspEventLogHandle;
static BOOL WINAPI FspEventLogInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
FspEventLogHandle = RegisterEventSourceW(0, L"" FSP_EVENTLOG_NAME);
if (0 == FspEventLogHandle)
FspEventLogHandle = RegisterEventSourceW(0, FspDiagIdent());
return TRUE;
}
VOID FspEventLogFinalize(BOOLEAN Dynamic)
{
/*
* This function is called during DLL_PROCESS_DETACH. We must therefore keep
* finalization tasks to a minimum.
*
* We must deregister our event source (if any). We only do so if the library
* is being explicitly unloaded (rather than the process exiting).
*/
if (Dynamic && 0 != FspEventLogHandle)
DeregisterEventSource(FspEventLogHandle);
}
FSP_API VOID FspEventLog(ULONG Type, PWSTR Format, ...)
{
va_list ap;
va_start(ap, Format);
FspEventLogV(Type, Format, ap);
va_end(ap);
}
FSP_API VOID FspEventLogV(ULONG Type, PWSTR Format, va_list ap)
{
InitOnceExecuteOnce(&FspEventLogInitOnce, FspEventLogInitialize, 0, 0);
if (0 == FspEventLogHandle)
return;
WCHAR Buf[1024], *Strings[2];
/* wvsprintfW is only safe with a 1024 WCHAR buffer */
DWORD EventId;
Strings[0] = FspDiagIdent();
wvsprintfW(Buf, Format, ap);
Buf[(sizeof Buf / sizeof Buf[0]) - 1] = L'\0';
Strings[1] = Buf;
switch (Type)
{
default:
case EVENTLOG_INFORMATION_TYPE:
case EVENTLOG_SUCCESS:
EventId = FSP_EVENTLOG_INFORMATION;
break;
case EVENTLOG_WARNING_TYPE:
EventId = FSP_EVENTLOG_WARNING;
break;
case EVENTLOG_ERROR_TYPE:
EventId = FSP_EVENTLOG_ERROR;
break;
}
ReportEventW(FspEventLogHandle, (WORD)Type, 0, EventId, 0, 2, 0, Strings, 0);
}
NTSTATUS FspEventLogRegister(VOID)
{
extern HINSTANCE DllInstance;
WCHAR Path[MAX_PATH];
DWORD RegResult, DwordValue;
HKEY RegKey;
if (0 == GetModuleFileNameW(DllInstance, Path, MAX_PATH))
return FspNtStatusFromWin32(GetLastError());
RegResult = RegCreateKeyExW(
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\" FSP_EVENTLOG_NAME,
0, 0, 0, KEY_ALL_ACCESS, 0, &RegKey, 0);
if (ERROR_SUCCESS != RegResult)
return FspNtStatusFromWin32(RegResult);
RegResult = RegSetValueExW(RegKey,
L"EventMessageFile", 0, REG_SZ, (PVOID)Path, (lstrlenW(Path) + 1) * sizeof(WCHAR));
if (ERROR_SUCCESS != RegResult)
goto close_and_exit;
DwordValue = EVENTLOG_INFORMATION_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_ERROR_TYPE;
RegResult = RegSetValueExW(RegKey,
L"TypesSupported", 0, REG_DWORD, (PVOID)&DwordValue, sizeof DwordValue);
if (ERROR_SUCCESS != RegResult)
goto close_and_exit;
RegCloseKey(RegKey);
return STATUS_SUCCESS;
close_and_exit:
RegCloseKey(RegKey);
return FspNtStatusFromWin32(RegResult);
}
NTSTATUS FspEventLogUnregister(VOID)
{
DWORD RegResult;
RegResult = RegDeleteTreeW(
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\" FSP_EVENTLOG_NAME);
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
return FspNtStatusFromWin32(RegResult);
return STATUS_SUCCESS;
}

View File

@ -0,0 +1,63 @@
//
// Values are 32 bit values laid out as follows:
//
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +---+-+-+-----------------------+-------------------------------+
// |Sev|C|R| Facility | Code |
// +---+-+-+-----------------------+-------------------------------+
//
// where
//
// Sev - is the severity code
//
// 00 - Success
// 01 - Informational
// 10 - Warning
// 11 - Error
//
// C - is the Customer code flag
//
// R - is a reserved bit
//
// Facility - is the facility code
//
// Code - is the facility's status code
//
//
// Define the facility codes
//
//
// Define the severity codes
//
//
// MessageId: FSP_EVENTLOG_INFORMATION
//
// MessageText:
//
// %1: %2
//
#define FSP_EVENTLOG_INFORMATION 0x60000001L
//
// MessageId: FSP_EVENTLOG_WARNING
//
// MessageText:
//
// %1: %2
//
#define FSP_EVENTLOG_WARNING 0xA0000001L
//
// MessageId: FSP_EVENTLOG_ERROR
//
// MessageText:
//
// %1: %2
//
#define FSP_EVENTLOG_ERROR 0xE0000001L

View File

@ -0,0 +1,20 @@
MessageId=1
Severity=Informational
SymbolicName=FSP_EVENTLOG_INFORMATION
Language=English
%1: %2
.
MessageId=1
Severity=Warning
SymbolicName=FSP_EVENTLOG_WARNING
Language=English
%1: %2
.
MessageId=1
Severity=Error
SymbolicName=FSP_EVENTLOG_ERROR
Language=English
%1: %2
.

View File

@ -0,0 +1,2 @@
LANGUAGE 0x9,0x1
1 11 "eventlog_MSG00001.bin"

Binary file not shown.

View File

@ -0,0 +1,5 @@
@echo off
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat"
mc -b -c eventlog.mc

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -24,61 +24,35 @@ enum
static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface;
static CRITICAL_SECTION FspFileSystemMountListGuard;
static LIST_ENTRY FspFileSystemMountList = { &FspFileSystemMountList, &FspFileSystemMountList };
static INIT_ONCE FspFileSystemInitOnce = INIT_ONCE_STATIC_INIT;
static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
static NTSTATUS (NTAPI *FspNtMakeTemporaryObject)(
HANDLE Handle);
static NTSTATUS (NTAPI *FspNtClose)(
HANDLE Handle);
VOID FspFileSystemInitialize(VOID)
static BOOL WINAPI FspFileSystemInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
/*
* This function is called during DLL_PROCESS_ATTACH. We must therefore keep initialization
* tasks to a minimum.
*
* Initialization of synchronization objects is allowed! See:
* https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx
*/
HANDLE Handle;
InitializeCriticalSection(&FspFileSystemMountListGuard);
}
VOID FspFileSystemFinalize(VOID)
{
/*
* This function is called during DLL_PROCESS_DETACH. We must therefore keep finalization
* tasks to a minimum.
*
* Very few things can be safely done during DLL_PROCESS_DETACH. See:
* https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx
* https://blogs.msdn.microsoft.com/oldnewthing/20070503-00/?p=27003/
* https://blogs.msdn.microsoft.com/oldnewthing/20100122-00/?p=15193/
*
* We enter our FspFileSystemMountListGuard critical section here and then attempt to cleanup
* our mount points using DefineDosDeviceW. On Vista and later orphaned critical sections
* become "electrified", so our process will be forcefully terminated if one of its threads
* was already modifying the list when the ExitProcess happened. This is a good thing!
*
* The use of DefineDosDeviceW is rather suspect and probably unsafe. DefineDosDeviceW reaches
* out to CSRSS, which is probably not the safest thing to do when in DllMain! There is also
* some evidence that it may attempt to load DLL's under some circumstances, which is a
* definite no-no as we are under the loader lock!
*/
FSP_FILE_SYSTEM *FileSystem;
PLIST_ENTRY MountEntry;
EnterCriticalSection(&FspFileSystemMountListGuard);
for (MountEntry = FspFileSystemMountList.Flink;
&FspFileSystemMountList != MountEntry;
MountEntry = MountEntry->Flink)
Handle = GetModuleHandleW(L"ntdll.dll");
if (0 != Handle)
{
FileSystem = CONTAINING_RECORD(MountEntry, FSP_FILE_SYSTEM, MountEntry);
FspNtOpenSymbolicLinkObject = (PVOID)GetProcAddress(Handle, "NtOpenSymbolicLinkObject");
FspNtMakeTemporaryObject = (PVOID)GetProcAddress(Handle, "NtMakeTemporaryObject");
FspNtClose = (PVOID)GetProcAddress(Handle, "NtClose");
DefineDosDeviceW(
DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
FileSystem->MountPoint, FileSystem->VolumeName);
if (0 == FspNtOpenSymbolicLinkObject || 0 == FspNtMakeTemporaryObject || 0 == FspNtClose)
{
FspNtOpenSymbolicLinkObject = 0;
FspNtMakeTemporaryObject = 0;
FspNtClose = 0;
}
}
LeaveCriticalSection(&FspFileSystemMountListGuard);
return TRUE;
}
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
@ -94,6 +68,8 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
if (0 == Interface)
Interface = &FspFileSystemNullInterface;
InitOnceExecuteOnce(&FspFileSystemInitOnce, FspFileSystemInitialize, 0, 0);
FileSystem = MemAlloc(sizeof *FileSystem);
if (0 == FileSystem)
return STATUS_INSUFFICIENT_RESOURCES;
@ -120,11 +96,19 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
FileSystem->Operations[FspFsctlTransactQueryVolumeInformationKind] = FspFileSystemOpQueryVolumeInformation;
FileSystem->Operations[FspFsctlTransactSetVolumeInformationKind] = FspFileSystemOpSetVolumeInformation;
FileSystem->Operations[FspFsctlTransactQueryDirectoryKind] = FspFileSystemOpQueryDirectory;
FileSystem->Operations[FspFsctlTransactFileSystemControlKind] = FspFileSystemOpFileSystemControl;
FileSystem->Operations[FspFsctlTransactQuerySecurityKind] = FspFileSystemOpQuerySecurity;
FileSystem->Operations[FspFsctlTransactSetSecurityKind] = FspFileSystemOpSetSecurity;
// !!!: ...
FileSystem->Operations[FspFsctlTransactQueryStreamInformationKind] = FspFileSystemOpQueryStreamInformation;
FileSystem->Interface = Interface;
FileSystem->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE;
InitializeSRWLock(&FileSystem->OpGuardLock);
FileSystem->EnterOperation = FspFileSystemOpEnter;
FileSystem->LeaveOperation = FspFileSystemOpLeave;
FileSystem->UmFileNodeIsUserContext2 = !!VolumeParams->UmFileNodeIsUserContext2;
*PFileSystem = FileSystem;
return STATUS_SUCCESS;
@ -143,6 +127,7 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
return STATUS_INVALID_PARAMETER;
NTSTATUS Result;
HANDLE MountHandle = 0;
if (0 == MountPoint)
{
@ -195,13 +180,41 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
}
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))
{
FileSystem->MountPoint = MountPoint;
EnterCriticalSection(&FspFileSystemMountListGuard);
InsertTailList(&FspFileSystemMountList, &FileSystem->MountEntry);
LeaveCriticalSection(&FspFileSystemMountListGuard);
FileSystem->MountHandle = MountHandle;
}
else
MemFree(MountPoint);
@ -214,15 +227,16 @@ FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
if (0 == FileSystem->MountPoint)
return;
EnterCriticalSection(&FspFileSystemMountListGuard);
RemoveEntryList(&FileSystem->MountEntry);
LeaveCriticalSection(&FspFileSystemMountListGuard);
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
FileSystem->MountPoint, FileSystem->VolumeName);
MemFree(FileSystem->MountPoint);
FileSystem->MountPoint = 0;
if (0 != FileSystem->MountHandle)
{
FspNtClose(FileSystem->MountHandle);
FileSystem->MountHandle = 0;
}
}
static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
@ -266,24 +280,37 @@ static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
if (0 == RequestSize)
continue;
#if 0
FspDebugLog("FspFileSystemDispatcherThread: TID=%ld, Request={Kind=%d, Hint=%p}\n",
GetCurrentThreadId(), Request->Kind, (PVOID)Request->Hint);
#endif
if (FileSystem->DebugLog)
{
if (FspFsctlTransactKindCount <= Request->Kind ||
(FileSystem->DebugLog & (1 << Request->Kind)))
FspDebugLogRequest(Request);
}
Response->Size = sizeof *Response;
Response->Kind = Request->Kind;
Response->Hint = Request->Hint;
if (FspFsctlTransactKindCount > Request->Kind && 0 != FileSystem->Operations[Request->Kind])
{
Response->IoStatus.Status =
FspFileSystemEnterOperation(FileSystem, Request, Response);
if (NT_SUCCESS(Response->IoStatus.Status))
{
Response->IoStatus.Status =
FileSystem->Operations[Request->Kind](FileSystem, Request, Response);
FspFileSystemLeaveOperation(FileSystem, Request, Response);
}
}
else
Response->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
if (FileSystem->DebugLog)
{
if (FspFsctlTransactKindCount <= Response->Kind ||
(FileSystem->DebugLog & (1 << Response->Kind)))
FspDebugLogResponse(Response);
}
ResponseSize = FSP_FSCTL_DEFAULT_ALIGN_UP(Response->Size);
if (FSP_FSCTL_TRANSACT_RSP_SIZEMAX < ResponseSize/* should NOT happen */)
{
@ -356,6 +383,7 @@ FSP_API VOID FspFileSystemStopDispatcher(FSP_FILE_SYSTEM *FileSystem)
WaitForSingleObject(FileSystem->DispatcherThread, INFINITE);
CloseHandle(FileSystem->DispatcherThread);
FileSystem->DispatcherThread = 0;
}
FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
@ -363,6 +391,13 @@ FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
{
NTSTATUS Result;
if (FileSystem->DebugLog)
{
if (FspFsctlTransactKindCount <= Response->Kind ||
(FileSystem->DebugLog & (1 << Response->Kind)))
FspDebugLogResponse(Response);
}
Result = FspFsctlTransact(FileSystem->VolumeHandle,
Response, Response->Size, 0, 0, FALSE);
if (!NT_SUCCESS(Result))

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -16,11 +16,14 @@
*/
#include <dll/library.h>
#include <aclapi.h>
#define GLOBALROOT L"\\\\?\\GLOBALROOT"
#define PREFIXW L"" FSP_FSCTL_VOLUME_PARAMS_PREFIX
#define PREFIXW_SIZE (sizeof PREFIXW - sizeof(WCHAR))
static NTSTATUS FspFsctlStartService(VOID);
FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
PWCHAR VolumeNameBuf, SIZE_T VolumeNameSize,
@ -29,7 +32,7 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
NTSTATUS Result;
PWSTR DeviceRoot;
SIZE_T DeviceRootSize, DevicePathSize;
WCHAR DevicePathBuf[MAX_PATH], *DevicePathPtr, *DevicePathEnd;
WCHAR DevicePathBuf[MAX_PATH + sizeof *VolumeParams], *DevicePathPtr, *DevicePathEnd;
HANDLE VolumeHandle = INVALID_HANDLE_VALUE;
DWORD Bytes;
@ -37,7 +40,7 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
VolumeNameBuf[0] = L'\0';
*PVolumeHandle = INVALID_HANDLE_VALUE;
/* check lengths; everything (including encoded volume params) must fit within MAX_PATH */
/* check lengths; everything (including encoded volume params) must fit within DevicePathBuf */
DeviceRoot = L'\\' == DevicePath[0] ? GLOBALROOT : GLOBALROOT "\\Device\\";
DeviceRootSize = lstrlenW(DeviceRoot) * sizeof(WCHAR);
DevicePathSize = lstrlenW(DevicePath) * sizeof(WCHAR);
@ -62,6 +65,10 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
}
*DevicePathPtr = L'\0';
Result = FspFsctlStartService();
if (!NT_SUCCESS(Result))
return Result;
VolumeHandle = CreateFileW(DevicePathBuf,
0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (INVALID_HANDLE_VALUE == VolumeHandle)
@ -125,7 +132,9 @@ exit:
FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle)
{
if (!DeviceIoControl(VolumeHandle, FSP_FSCTL_STOP, 0, 0, 0, 0, 0, 0))
DWORD Bytes;
if (!DeviceIoControl(VolumeHandle, FSP_FSCTL_STOP, 0, 0, 0, 0, &Bytes, 0))
return FspNtStatusFromWin32(GetLastError());
return STATUS_SUCCESS;
@ -185,3 +194,341 @@ exit:
return Result;
}
FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath)
{
NTSTATUS Result;
SIZE_T VolumeListSize;
Result = FspFsctlStartService();
if (!NT_SUCCESS(Result))
return Result;
VolumeListSize = 0;
Result = FspFsctlGetVolumeList(DevicePath, 0, &VolumeListSize);
if (!NT_SUCCESS(Result) && STATUS_BUFFER_TOO_SMALL != Result)
return Result;
return STATUS_SUCCESS;
}
static NTSTATUS FspFsctlStartService(VOID)
{
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME;
SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0;
SERVICE_STATUS ServiceStatus;
DWORD LastError;
NTSTATUS Result;
ScmHandle = OpenSCManagerW(0, 0, 0);
if (0 == ScmHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
SvcHandle = OpenServiceW(ScmHandle, DriverName, SERVICE_QUERY_STATUS | SERVICE_START);
if (0 == SvcHandle)
{
LastError = GetLastError();
if (ERROR_SERVICE_DOES_NOT_EXIST != LastError)
Result = FspNtStatusFromWin32(LastError);
else
Result = STATUS_NO_SUCH_DEVICE;
goto exit;
}
if (!StartServiceW(SvcHandle, 0, 0))
{
LastError = GetLastError();
if (ERROR_SERVICE_ALREADY_RUNNING != LastError)
Result = FspNtStatusFromWin32(LastError);
else
Result = STATUS_SUCCESS;
goto exit;
}
/* Poll until the service is running! Yes, that's the best we can do! */
Result = STATUS_DRIVER_UNABLE_TO_LOAD;
for (DWORD Timeout = 500, N = 20, I = 0; N > I; I++)
/* wait up to 500ms * 20 = 10000ms = 10s */
{
if (!QueryServiceStatus(SvcHandle, &ServiceStatus))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (SERVICE_RUNNING == ServiceStatus.dwCurrentState)
{
Result = STATUS_SUCCESS;
break;
}
Sleep(Timeout);
}
exit:
if (0 != SvcHandle)
CloseServiceHandle(SvcHandle);
if (0 != ScmHandle)
CloseServiceHandle(ScmHandle);
return Result;
}
static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
{
/*
* This function adds an ACE that allows Everyone to start a service.
*/
PSID WorldSid = 0;
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PSECURITY_DESCRIPTOR NewSecurityDescriptor = 0;
EXPLICIT_ACCESSW AccessEntry;
ACCESS_MASK AccessRights;
PACL Dacl;
BOOL DaclPresent, DaclDefaulted;
DWORD Size;
DWORD LastError;
NTSTATUS Result;
/* get the Everyone (World) SID */
Size = SECURITY_MAX_SID_SIZE;
WorldSid = MemAlloc(Size);
if (0 == WorldSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!CreateWellKnownSid(WinWorldSid, 0, WorldSid, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
/* get the service security descriptor DACL */
Size = 0;
if (!QueryServiceObjectSecurity(SvcHandle, DACL_SECURITY_INFORMATION, SecurityDescriptor, Size, &Size))
{
LastError = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
}
SecurityDescriptor = MemAlloc(Size);
if (0 == SecurityDescriptor)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!QueryServiceObjectSecurity(SvcHandle, DACL_SECURITY_INFORMATION, SecurityDescriptor, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
/* extract the DACL */
if (!GetSecurityDescriptorDacl(SecurityDescriptor, &DaclPresent, &Dacl, &DaclDefaulted))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
/* prepare an EXPLICIT_ACCESS for the SERVICE_QUERY_STATUS | SERVICE_START right for Everyone */
AccessEntry.grfAccessPermissions = SERVICE_QUERY_STATUS | SERVICE_START;
AccessEntry.grfAccessMode = GRANT_ACCESS;
AccessEntry.grfInheritance = NO_INHERITANCE;
AccessEntry.Trustee.pMultipleTrustee = 0;
AccessEntry.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
AccessEntry.Trustee.TrusteeForm = TRUSTEE_IS_SID;
AccessEntry.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
AccessEntry.Trustee.ptstrName = WorldSid;
/* get the effective rights for Everyone */
AccessRights = 0;
if (DaclPresent && 0 != Dacl)
{
LastError = GetEffectiveRightsFromAclW(Dacl, &AccessEntry.Trustee, &AccessRights);
if (0 != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
}
/* do we have the required access rights? */
if (AccessEntry.grfAccessPermissions != (AccessRights & AccessEntry.grfAccessPermissions))
{
/* create a new security descriptor with the new access */
LastError = BuildSecurityDescriptorW(0, 0, 1, &AccessEntry, 0, 0, SecurityDescriptor,
&Size, &NewSecurityDescriptor);
if (0 != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
/* set the new service security descriptor DACL */
if (!SetServiceObjectSecurity(SvcHandle, DACL_SECURITY_INFORMATION, NewSecurityDescriptor))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Result = STATUS_SUCCESS;
exit:
LocalFree(NewSecurityDescriptor);
MemFree(SecurityDescriptor);
MemFree(WorldSid);
return Result;
}
NTSTATUS FspFsctlRegister(VOID)
{
extern HINSTANCE DllInstance;
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME;
WCHAR DriverPath[MAX_PATH];
DWORD Size;
SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0;
PVOID VersionInfo = 0;
SERVICE_DESCRIPTION ServiceDescription;
NTSTATUS Result;
if (0 == GetModuleFileNameW(DllInstance, DriverPath, MAX_PATH))
return FspNtStatusFromWin32(GetLastError());
Size = lstrlenW(DriverPath);
if (4 < Size &&
(L'.' == DriverPath[Size - 4]) &&
(L'D' == DriverPath[Size - 3] || L'd' == DriverPath[Size - 3]) &&
(L'L' == DriverPath[Size - 2] || L'l' == DriverPath[Size - 2]) &&
(L'L' == DriverPath[Size - 1] || L'l' == DriverPath[Size - 1]) &&
(L'\0' == DriverPath[Size]))
{
DriverPath[Size - 3] = L's';
DriverPath[Size - 2] = L'y';
DriverPath[Size - 1] = L's';
}
else
/* should not happen! */
return STATUS_NO_SUCH_DEVICE;
ScmHandle = OpenSCManagerW(0, 0, SC_MANAGER_CREATE_SERVICE);
if (0 == ScmHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
SvcHandle = OpenServiceW(ScmHandle, DriverName, SERVICE_CHANGE_CONFIG | READ_CONTROL | WRITE_DAC);
if (0 != SvcHandle)
{
if (!ChangeServiceConfigW(SvcHandle,
SERVICE_FILE_SYSTEM_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, DriverPath,
0, 0, 0, 0, 0, DriverName))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
else
{
SvcHandle = CreateServiceW(ScmHandle, DriverName, DriverName,
SERVICE_CHANGE_CONFIG | READ_CONTROL | WRITE_DAC,
SERVICE_FILE_SYSTEM_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, DriverPath,
0, 0, 0, 0, 0);
if (0 == SvcHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Size = GetFileVersionInfoSizeW(DriverPath, &Size/*dummy*/);
if (0 < Size)
{
VersionInfo = MemAlloc(Size);
if (0 != VersionInfo &&
GetFileVersionInfoW(DriverPath, 0, Size, VersionInfo) &&
VerQueryValueW(VersionInfo, L"\\StringFileInfo\\040904b0\\FileDescription",
&ServiceDescription.lpDescription, &Size))
{
ChangeServiceConfig2W(SvcHandle, SERVICE_CONFIG_DESCRIPTION, &ServiceDescription);
}
}
Result = FspFsctlFixServiceSecurity(SvcHandle);
if (!NT_SUCCESS(Result))
goto exit;
Result = STATUS_SUCCESS;
exit:
MemFree(VersionInfo);
if (0 != SvcHandle)
CloseServiceHandle(SvcHandle);
if (0 != ScmHandle)
CloseServiceHandle(ScmHandle);
return Result;
}
NTSTATUS FspFsctlUnregister(VOID)
{
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME;
SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0;
DWORD LastError;
NTSTATUS Result;
ScmHandle = OpenSCManagerW(0, 0, SC_MANAGER_CREATE_SERVICE);
/*
* The SC_MANAGER_CREATE_SERVICE access right is not strictly needed here,
* but we use it to enforce admin rights.
*/
if (0 == ScmHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
SvcHandle = OpenServiceW(ScmHandle, DriverName, DELETE);
if (0 == SvcHandle)
{
LastError = GetLastError();
if (ERROR_SERVICE_DOES_NOT_EXIST != LastError)
Result = FspNtStatusFromWin32(LastError);
else
Result = STATUS_SUCCESS;
goto exit;
}
if (!DeleteService(SvcHandle))
{
LastError = GetLastError();
if (ERROR_SERVICE_MARKED_FOR_DELETE != LastError)
Result = FspNtStatusFromWin32(LastError);
else
Result = STATUS_SUCCESS;
goto exit;
}
Result = STATUS_SUCCESS;
exit:
if (0 != SvcHandle)
CloseServiceHandle(SvcHandle);
if (0 != ScmHandle)
CloseServiceHandle(ScmHandle);
return Result;
}

File diff suppressed because it is too large Load Diff

115
src/dll/fuse/errno.i Normal file
View File

@ -0,0 +1,115 @@
#if FSP_FUSE_ERRNO == 87 /* Windows */
case 0: return STATUS_SUCCESS;
case 1: return STATUS_ACCESS_DENIED;
case 2: return STATUS_OBJECT_NAME_NOT_FOUND;
case 3: return STATUS_PROCEDURE_NOT_FOUND;
case 4: return STATUS_CANCELLED;
case 5: return STATUS_IO_DEVICE_ERROR;
case 6: return STATUS_FILE_INVALID;
case 7: return STATUS_INSUFFICIENT_RESOURCES;
case 8: return STATUS_INVALID_IMAGE_FORMAT;
case 9: return STATUS_INVALID_HANDLE;
case 12: return STATUS_INSUFFICIENT_RESOURCES;
case 13: return STATUS_ACCESS_DENIED;
case 14: return STATUS_ACCESS_VIOLATION;
case 16: return STATUS_DEVICE_BUSY;
case 17: return STATUS_OBJECT_NAME_COLLISION;
case 18: return STATUS_NOT_SAME_DEVICE;
case 19: return STATUS_NO_SUCH_DEVICE;
case 20: return STATUS_NOT_A_DIRECTORY;
case 21: return STATUS_FILE_IS_A_DIRECTORY;
case 22: return STATUS_INVALID_PARAMETER;
case 23: return STATUS_TOO_MANY_OPENED_FILES;
case 24: return STATUS_TOO_MANY_OPENED_FILES;
case 27: return STATUS_DISK_FULL;
case 28: return STATUS_DISK_FULL;
case 29: return STATUS_INVALID_PARAMETER;
case 30: return STATUS_MEDIA_WRITE_PROTECTED;
case 31: return STATUS_TOO_MANY_LINKS;
case 32: return STATUS_PIPE_BROKEN;
case 33: return STATUS_INVALID_PARAMETER;
case 34: return STATUS_INVALID_PARAMETER;
case 36: return STATUS_POSSIBLE_DEADLOCK;
case 38: return STATUS_NAME_TOO_LONG;
case 39: return STATUS_LOCK_NOT_GRANTED;
case 40: return STATUS_INVALID_DEVICE_REQUEST;
case 41: return STATUS_DIRECTORY_NOT_EMPTY;
case 42: return STATUS_INVALID_PARAMETER;
case 100: return STATUS_ADDRESS_ALREADY_ASSOCIATED;
case 103: return STATUS_CONNECTION_ACTIVE;
case 105: return STATUS_CANCELLED;
case 106: return STATUS_CONNECTION_ABORTED;
case 107: return STATUS_CONNECTION_REFUSED;
case 108: return STATUS_CONNECTION_RESET;
case 110: return STATUS_HOST_UNREACHABLE;
case 113: return STATUS_CONNECTION_ACTIVE;
case 114: return STATUS_REPARSE_POINT_NOT_RESOLVED;
case 116: return STATUS_HOST_DOWN;
case 117: return STATUS_CONNECTION_RESET;
case 118: return STATUS_NETWORK_UNREACHABLE;
case 119: return STATUS_INSUFFICIENT_RESOURCES;
case 120: return STATUS_END_OF_FILE;
case 121: return STATUS_CONNECTION_INVALID;
case 126: return STATUS_CONNECTION_INVALID;
case 128: return STATUS_INVALID_HANDLE;
case 138: return STATUS_TRANSACTION_TIMED_OUT;
#elif FSP_FUSE_ERRNO == 67 /* Cygwin */
case 0: return STATUS_SUCCESS;
case 1: return STATUS_ACCESS_DENIED;
case 2: return STATUS_OBJECT_NAME_NOT_FOUND;
case 3: return STATUS_PROCEDURE_NOT_FOUND;
case 4: return STATUS_CANCELLED;
case 5: return STATUS_IO_DEVICE_ERROR;
case 6: return STATUS_FILE_INVALID;
case 7: return STATUS_INSUFFICIENT_RESOURCES;
case 8: return STATUS_INVALID_IMAGE_FORMAT;
case 9: return STATUS_INVALID_HANDLE;
case 12: return STATUS_INSUFFICIENT_RESOURCES;
case 13: return STATUS_ACCESS_DENIED;
case 14: return STATUS_ACCESS_VIOLATION;
case 16: return STATUS_DEVICE_BUSY;
case 17: return STATUS_OBJECT_NAME_COLLISION;
case 18: return STATUS_NOT_SAME_DEVICE;
case 19: return STATUS_NO_SUCH_DEVICE;
case 20: return STATUS_NOT_A_DIRECTORY;
case 21: return STATUS_FILE_IS_A_DIRECTORY;
case 22: return STATUS_INVALID_PARAMETER;
case 23: return STATUS_TOO_MANY_OPENED_FILES;
case 24: return STATUS_TOO_MANY_OPENED_FILES;
case 27: return STATUS_DISK_FULL;
case 28: return STATUS_DISK_FULL;
case 29: return STATUS_INVALID_PARAMETER;
case 30: return STATUS_MEDIA_WRITE_PROTECTED;
case 31: return STATUS_TOO_MANY_LINKS;
case 32: return STATUS_PIPE_BROKEN;
case 33: return STATUS_INVALID_PARAMETER;
case 34: return STATUS_INVALID_PARAMETER;
case 45: return STATUS_POSSIBLE_DEADLOCK;
case 91: return STATUS_NAME_TOO_LONG;
case 46: return STATUS_LOCK_NOT_GRANTED;
case 88: return STATUS_INVALID_DEVICE_REQUEST;
case 90: return STATUS_DIRECTORY_NOT_EMPTY;
case 138: return STATUS_INVALID_PARAMETER;
case 112: return STATUS_ADDRESS_ALREADY_ASSOCIATED;
case 120: return STATUS_CONNECTION_ACTIVE;
case 140: return STATUS_CANCELLED;
case 113: return STATUS_CONNECTION_ABORTED;
case 111: return STATUS_CONNECTION_REFUSED;
case 104: return STATUS_CONNECTION_RESET;
case 118: return STATUS_HOST_UNREACHABLE;
case 127: return STATUS_CONNECTION_ACTIVE;
case 92: return STATUS_REPARSE_POINT_NOT_RESOLVED;
case 115: return STATUS_HOST_DOWN;
case 126: return STATUS_CONNECTION_RESET;
case 114: return STATUS_NETWORK_UNREACHABLE;
case 105: return STATUS_INSUFFICIENT_RESOURCES;
case 61: return STATUS_END_OF_FILE;
case 67: return STATUS_CONNECTION_INVALID;
case 128: return STATUS_CONNECTION_INVALID;
case 108: return STATUS_INVALID_HANDLE;
case 116: return STATUS_TRANSACTION_TIMED_OUT;
#endif

684
src/dll/fuse/fuse.c Normal file
View File

@ -0,0 +1,684 @@
/**
* @file dll/fuse/fuse.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dll/fuse/library.h>
#define FSP_FUSE_SECTORSIZE_MIN 512
#define FSP_FUSE_SECTORSIZE_MAX 4096
struct fuse_chan
{
PWSTR MountPoint;
UINT8 Buffer[];
};
#define FSP_FUSE_CORE_OPT(n, f, v) { n, offsetof(struct fsp_fuse_core_opt_data, f), v }
struct fsp_fuse_core_opt_data
{
struct fsp_fuse_env *env;
int help, debug;
int hard_remove,
use_ino, readdir_ino,
set_umask, umask,
set_uid, uid,
set_gid, gid,
set_attr_timeout, attr_timeout,
rellinks;
int set_FileInfoTimeout;
int CaseInsensitiveSearch,
ReadOnlyVolume;
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
};
static struct fuse_opt fsp_fuse_core_opts[] =
{
FUSE_OPT_KEY("-h", 'h'),
FUSE_OPT_KEY("--help", 'h'),
FUSE_OPT_KEY("-V", 'V'),
FUSE_OPT_KEY("--version", 'V'),
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
FSP_FUSE_CORE_OPT("-d", debug, 1),
FSP_FUSE_CORE_OPT("debug", debug, 1),
FSP_FUSE_CORE_OPT("hard_remove", hard_remove, 1),
FSP_FUSE_CORE_OPT("use_ino", use_ino, 1),
FSP_FUSE_CORE_OPT("readdir_ino", readdir_ino, 1),
FUSE_OPT_KEY("direct_io", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("kernel_cache", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("auto_cache", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("noauto_cache", FUSE_OPT_KEY_DISCARD),
FSP_FUSE_CORE_OPT("umask=", set_umask, 1),
FSP_FUSE_CORE_OPT("umask=%o", umask, 0),
FSP_FUSE_CORE_OPT("uid=", set_uid, 1),
FSP_FUSE_CORE_OPT("uid=%d", uid, 0),
FSP_FUSE_CORE_OPT("gid=", set_gid, 1),
FSP_FUSE_CORE_OPT("gid=%d", gid, 0),
FUSE_OPT_KEY("entry_timeout", FUSE_OPT_KEY_DISCARD),
FSP_FUSE_CORE_OPT("attr_timeout=", set_attr_timeout, 1),
FSP_FUSE_CORE_OPT("attr_timeout=%d", attr_timeout, 0),
FUSE_OPT_KEY("ac_attr_timeout", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("negative_timeout", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("noforget", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("intr", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("intr_signal=", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("modules=", FUSE_OPT_KEY_DISCARD),
FSP_FUSE_CORE_OPT("rellinks", rellinks, 1),
FSP_FUSE_CORE_OPT("norellinks", rellinks, 0),
FUSE_OPT_KEY("fstypename=", 'F'),
FSP_FUSE_CORE_OPT("SectorSize=%hu", VolumeParams.SectorSize, 4096),
FSP_FUSE_CORE_OPT("SectorsPerAllocationUnit=%hu", VolumeParams.SectorsPerAllocationUnit, 1),
FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
FSP_FUSE_CORE_OPT("VolumeCreationTime=%lli", VolumeParams.VolumeCreationTime, 0),
FSP_FUSE_CORE_OPT("VolumeSerialNumber=%lx", VolumeParams.VolumeSerialNumber, 0),
FSP_FUSE_CORE_OPT("TransactTimeout=%u", VolumeParams.TransactTimeout, 0),
FSP_FUSE_CORE_OPT("IrpTimeout=%u", VolumeParams.IrpTimeout, 0),
FSP_FUSE_CORE_OPT("IrpCapacity=%u", VolumeParams.IrpCapacity, 0),
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
FSP_FUSE_CORE_OPT("CaseInsensitiveSearch", CaseInsensitiveSearch, 1),
FSP_FUSE_CORE_OPT("ReadOnlyVolume", ReadOnlyVolume, 1),
FUSE_OPT_KEY("ReparsePoints", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("NamedStreams", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("HardLinks", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("ExtendedAttributes", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("--UNC=", 'U'),
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
FUSE_OPT_KEY("--FileSystemName=", 'F'),
FUSE_OPT_END,
};
static INIT_ONCE fsp_fuse_initonce = INIT_ONCE_STATIC_INIT;
static DWORD fsp_fuse_tlskey = TLS_OUT_OF_INDEXES;
struct fsp_fuse_obj_hdr
{
void (*dtor)(void *);
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ObjectBuf[];
};
static inline void *fsp_fuse_obj_alloc(struct fsp_fuse_env *env, size_t size)
{
struct fsp_fuse_obj_hdr *hdr;
hdr = env->memalloc(sizeof(struct fsp_fuse_obj_hdr) + size);
if (0 == hdr)
return 0;
hdr->dtor = env->memfree;
memset(hdr->ObjectBuf, 0, size);
return hdr->ObjectBuf;
}
static inline void fsp_fuse_obj_free(void *obj)
{
struct fsp_fuse_obj_hdr *hdr = (PVOID)((PUINT8)obj - sizeof(struct fsp_fuse_obj_hdr));
hdr->dtor(hdr);
}
static BOOL WINAPI fsp_fuse_initialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
fsp_fuse_tlskey = TlsAlloc();
return TRUE;
}
VOID fsp_fuse_finalize(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 != fsp_fuse_tlskey)
{
/* !!!:
* We should also free all thread local contexts, which means putting them in a list,
* protected with a critical section, etc. Arghhh!
*
* I am too lazy and I am not going to do that, unless people start using this
* DLL dynamically (LoadLibrary/FreeLibrary).
*/
TlsFree(fsp_fuse_tlskey);
}
}
VOID fsp_fuse_finalize_thread(VOID)
{
struct fuse_context *context;
if (TLS_OUT_OF_INDEXES != fsp_fuse_tlskey)
{
context = TlsGetValue(fsp_fuse_tlskey);
if (0 != context)
{
fsp_fuse_obj_free(FSP_FUSE_HDR_FROM_CONTEXT(context));
TlsSetValue(fsp_fuse_tlskey, 0);
}
}
}
FSP_FUSE_API int fsp_fuse_version(struct fsp_fuse_env *env)
{
return FUSE_VERSION;
}
FSP_FUSE_API struct fuse_chan *fsp_fuse_mount(struct fsp_fuse_env *env,
const char *mountpoint, struct fuse_args *args)
{
struct fuse_chan *ch = 0;
int Size;
if (0 == mountpoint)
mountpoint = "";
Size = MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, 0, 0);
if (0 == Size)
goto fail;
ch = fsp_fuse_obj_alloc(env, sizeof *ch + Size * sizeof(WCHAR));
if (0 == ch)
goto fail;
ch->MountPoint = (PVOID)ch->Buffer;
Size = MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, ch->MountPoint, Size);
if (0 == Size)
goto fail;
return ch;
fail:
fsp_fuse_obj_free(ch);
return 0;
}
FSP_FUSE_API void fsp_fuse_unmount(struct fsp_fuse_env *env,
const char *mountpoint, struct fuse_chan *ch)
{
fsp_fuse_obj_free(ch);
}
FSP_FUSE_API int fsp_fuse_is_lib_option(struct fsp_fuse_env *env,
const char *opt)
{
return fsp_fuse_opt_match(env, fsp_fuse_core_opts, opt);
}
static void fsp_fuse_cleanup(struct fuse *f);
static NTSTATUS fsp_fuse_preflight(struct fuse *f)
{
NTSTATUS Result;
Result = FspFsctlPreflight(f->VolumeParams.Prefix[0] ?
L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME);
if (!NT_SUCCESS(Result))
return Result;
if (L'\0' != f->MountPoint)
{
if ((
(L'A' <= f->MountPoint[0] && f->MountPoint[0] <= L'Z') ||
(L'a' <= f->MountPoint[0] && f->MountPoint[0] <= L'z')
) &&
L':' == f->MountPoint[1] || L'\0' == f->MountPoint[2])
{
if (GetLogicalDrives() & (1 << ((f->MountPoint[0] & ~0x20) - 'a')))
return STATUS_OBJECT_NAME_COLLISION;
}
else
if (L'*' == f->MountPoint[0] && L'\0' == f->MountPoint[1])
;
else
return STATUS_OBJECT_NAME_INVALID;
}
return STATUS_SUCCESS;
}
static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
{
struct fuse *f = Service->UserContext;
struct fuse_context *context;
struct fuse_conn_info conn;
NTSTATUS Result;
f->Service = Service;
context = fsp_fuse_get_context(f->env);
if (0 == context)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto fail;
}
context->fuse = f;
context->private_data = f->data;
context->uid = -1;
context->gid = -1;
memset(&conn, 0, sizeof conn);
conn.proto_major = 7; /* pretend that we are FUSE kernel protocol 7.12 */
conn.proto_minor = 12; /* which was current at the time of FUSE 2.8 */
conn.async_read = 1;
conn.max_write = UINT_MAX;
conn.capable =
FUSE_CAP_ASYNC_READ |
//FUSE_CAP_POSIX_LOCKS | /* WinFsp handles locking in the FSD currently */
//FUSE_CAP_ATOMIC_O_TRUNC | /* due to Windows/WinFsp design, no support */
//FUSE_CAP_EXPORT_SUPPORT | /* not needed in Windows/WinFsp */
FUSE_CAP_BIG_WRITES |
FUSE_CAP_DONT_MASK;
if (0 != f->ops.init)
context->private_data = f->data = f->ops.init(&conn);
f->fsinit = TRUE;
if (0 != f->ops.statfs)
{
struct fuse_statvfs stbuf;
int err;
memset(&stbuf, 0, sizeof stbuf);
err = f->ops.statfs("/", &stbuf);
if (0 != err)
{
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
goto fail;
}
if (stbuf.f_frsize > FSP_FUSE_SECTORSIZE_MAX)
stbuf.f_frsize = FSP_FUSE_SECTORSIZE_MAX;
if (0 == f->VolumeParams.SectorSize)
f->VolumeParams.SectorSize = (UINT16)stbuf.f_frsize;
if (0 == f->VolumeParams.MaxComponentLength)
f->VolumeParams.MaxComponentLength = (UINT16)stbuf.f_namemax;
}
if (0 != f->ops.getattr)
{
struct fuse_stat stbuf;
int err;
memset(&stbuf, 0, sizeof stbuf);
err = f->ops.getattr("/", (void *)&stbuf);
if (0 != err)
{
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
goto fail;
}
if (0 == f->VolumeParams.VolumeCreationTime)
{
if (0 != stbuf.st_birthtim.tv_sec)
f->VolumeParams.VolumeCreationTime =
Int32x32To64(stbuf.st_birthtim.tv_sec, 10000000) + 116444736000000000 +
stbuf.st_birthtim.tv_nsec / 100;
else
if (0 != stbuf.st_ctim.tv_sec)
f->VolumeParams.VolumeCreationTime =
Int32x32To64(stbuf.st_ctim.tv_sec, 10000000) + 116444736000000000 +
stbuf.st_ctim.tv_nsec / 100;
}
}
/* the FSD does not currently limit these VolumeParams fields; do so here! */
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN)
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MIN;
if (f->VolumeParams.SectorSize > FSP_FUSE_SECTORSIZE_MAX)
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MAX;
if (f->VolumeParams.SectorsPerAllocationUnit == 0)
f->VolumeParams.SectorsPerAllocationUnit = 1;
if (f->VolumeParams.MaxComponentLength > 255)
f->VolumeParams.MaxComponentLength = 255;
if (0 == f->VolumeParams.VolumeCreationTime)
{
FILETIME FileTime;
GetSystemTimeAsFileTime(&FileTime);
f->VolumeParams.VolumeCreationTime = *(PUINT64)&FileTime;
}
if (0 == f->VolumeParams.VolumeSerialNumber)
f->VolumeParams.VolumeSerialNumber =
((PLARGE_INTEGER)&f->VolumeParams.VolumeCreationTime)->HighPart ^
((PLARGE_INTEGER)&f->VolumeParams.VolumeCreationTime)->LowPart;
Result = FspFileSystemCreate(
f->VolumeParams.Prefix[0] ?
L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME,
&f->VolumeParams, &fsp_fuse_intf,
&f->FileSystem);
if (!NT_SUCCESS(Result))
{
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"Cannot create " FSP_FUSE_LIBRARY_NAME " file system.");
goto fail;
}
f->FileSystem->UserContext = f;
FspFileSystemSetOperationGuard(f->FileSystem, fsp_fuse_op_enter, fsp_fuse_op_leave);
FspFileSystemSetOperationGuardStrategy(f->FileSystem, f->OpGuardStrategy);
FspFileSystemSetDebugLog(f->FileSystem, f->DebugLog);
if (L'\0' != f->MountPoint)
{
Result = FspFileSystemSetMountPoint(f->FileSystem,
L'*' == f->MountPoint[0] && L'\0' == f->MountPoint[1] ? 0 : f->MountPoint);
if (!NT_SUCCESS(Result))
{
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"Cannot set " FSP_FUSE_LIBRARY_NAME " file system mount point.");
goto fail;
}
}
Result = FspFileSystemStartDispatcher(f->FileSystem, 0);
if (!NT_SUCCESS(Result))
{
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"Cannot start " FSP_FUSE_LIBRARY_NAME " file system dispatcher.");
goto fail;
}
return STATUS_SUCCESS;
fail:
fsp_fuse_cleanup(f);
return Result;
}
static NTSTATUS fsp_fuse_svcstop(FSP_SERVICE *Service)
{
struct fuse *f = Service->UserContext;
FspFileSystemStopDispatcher(f->FileSystem);
fsp_fuse_cleanup(f);
return STATUS_SUCCESS;
}
static void fsp_fuse_cleanup(struct fuse *f)
{
if (0 != f->FileSystem)
{
FspFileSystemDelete(f->FileSystem);
f->FileSystem = 0;
}
if (f->fsinit)
{
if (f->ops.destroy)
f->ops.destroy(f->data);
f->fsinit = FALSE;
}
f->Service = 0;
}
static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
struct fuse_args *outargs)
{
struct fsp_fuse_core_opt_data *opt_data = opt_data0;
switch (key)
{
default:
return 1;
case 'h':
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
FSP_FUSE_LIBRARY_NAME " options:\n"
" -o SectorSize=N sector size for Windows (512-4096, deflt: 512)\n"
" -o SectorsPerAllocationUnit=N allocation unit size (deflt: 1*SectorSize)\n"
" -o MaxComponentLength=N max file name component length (deflt: 255)\n"
" -o VolumeCreationTime=T volume creation time (FILETIME hex format)\n"
" -o VolumeSerialNumber=N 32-bit wide\n"
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n"
" -o CaseInsensitiveSearch file system supports case-insensitive file names\n"
//" -o ReadOnlyVolume file system is read only\n"
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n"
" --FileSystemName=FSN Name of user mode file system\n");
opt_data->help = 1;
return 1;
case 'V':
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
FSP_FUSE_LIBRARY_NAME " version %d.%d",
FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION);
opt_data->help = 1;
return 1;
case 'U':
if ('U' == arg[2])
arg += sizeof "--UNC=" - 1;
else if ('V' == arg[2])
arg += sizeof "--VolumePrefix=" - 1;
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
opt_data->VolumeParams.Prefix, sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR)))
return -1;
opt_data->VolumeParams.Prefix
[sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR) - 1] = L'\0';
return 0;
case 'F':
if ('f' == arg[0])
arg += sizeof "fstypename=" - 1;
else if ('F' == arg[2])
arg += sizeof "--FileSystemName=" - 1;
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
opt_data->VolumeParams.FileSystemName + 5,
sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR)) - 5)
return -1;
opt_data->VolumeParams.FileSystemName
[sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0';
memcpy(opt_data->VolumeParams.FileSystemName, L"FUSE-", 5 * sizeof(WCHAR));
return 0;
}
}
FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
struct fuse_chan *ch, struct fuse_args *args,
const struct fuse_operations *ops, size_t opsize, void *data)
{
struct fuse *f = 0;
struct fsp_fuse_core_opt_data opt_data;
ULONG Size;
PWSTR ErrorMessage = L".";
NTSTATUS Result;
if (opsize > sizeof(struct fuse_operations))
opsize = sizeof(struct fuse_operations);
memset(&opt_data, 0, sizeof opt_data);
opt_data.env = env;
if (-1 == fsp_fuse_opt_parse(env, args, &opt_data, fsp_fuse_core_opts, fsp_fuse_core_opt_proc))
return 0;
if (opt_data.help)
return 0;
if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout)
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
opt_data.VolumeParams.CaseSensitiveSearch = !opt_data.CaseInsensitiveSearch;
opt_data.VolumeParams.PersistentAcls = TRUE;
opt_data.VolumeParams.ReparsePoints = TRUE;
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
opt_data.VolumeParams.NamedStreams = FALSE;
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
opt_data.VolumeParams.PostCleanupOnDeleteOnly = TRUE;
opt_data.VolumeParams.UmFileNodeIsUserContext2 = TRUE;
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
f = fsp_fuse_obj_alloc(env, sizeof *f);
if (0 == f)
goto fail;
f->env = env;
f->set_umask = opt_data.set_umask; f->umask = opt_data.umask;
f->set_uid = opt_data.set_uid; f->uid = opt_data.uid;
f->set_gid = opt_data.set_gid; f->gid = opt_data.gid;
f->rellinks = opt_data.rellinks;
memcpy(&f->ops, ops, opsize);
f->data = data;
f->DebugLog = opt_data.debug ? -1 : 0;
memcpy(&f->VolumeParams, &opt_data.VolumeParams, sizeof opt_data.VolumeParams);
Size = (lstrlenW(ch->MountPoint) + 1) * sizeof(WCHAR);
f->MountPoint = fsp_fuse_obj_alloc(env, Size);
if (0 == f->MountPoint)
goto fail;
memcpy(f->MountPoint, ch->MountPoint, Size);
Result = fsp_fuse_preflight(f);
if (!NT_SUCCESS(Result))
{
switch (Result)
{
case STATUS_ACCESS_DENIED:
ErrorMessage = L": access denied.";
break;
case STATUS_NO_SUCH_DEVICE:
ErrorMessage = L": FSD not found.";
break;
case STATUS_OBJECT_NAME_INVALID:
ErrorMessage = L": invalid mount point.";
break;
case STATUS_OBJECT_NAME_COLLISION:
ErrorMessage = L": mount point in use.";
break;
default:
ErrorMessage = L": unspecified error.";
break;
}
goto fail;
}
return f;
fail:
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"Cannot create " FSP_FUSE_LIBRARY_NAME " file system%s",
ErrorMessage);
if (0 != f)
fsp_fuse_destroy(env, f);
return 0;
}
FSP_FUSE_API void fsp_fuse_destroy(struct fsp_fuse_env *env,
struct fuse *f)
{
fsp_fuse_cleanup(f);
fsp_fuse_obj_free(f->MountPoint);
fsp_fuse_obj_free(f);
}
FSP_FUSE_API int fsp_fuse_loop(struct fsp_fuse_env *env,
struct fuse *f)
{
f->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE;
return 0 == FspServiceRunEx(FspDiagIdent(), fsp_fuse_svcstart, fsp_fuse_svcstop, 0, f) ?
0 : -1;
}
FSP_FUSE_API int fsp_fuse_loop_mt(struct fsp_fuse_env *env,
struct fuse *f)
{
f->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE;
return 0 == FspServiceRunEx(FspDiagIdent(), fsp_fuse_svcstart, fsp_fuse_svcstop, 0, f) ?
0 : -1;
}
FSP_FUSE_API void fsp_fuse_exit(struct fsp_fuse_env *env,
struct fuse *f)
{
if (0 != f->Service)
FspServiceStop(f->Service);
}
FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env)
{
struct fuse_context *context;
InitOnceExecuteOnce(&fsp_fuse_initonce, fsp_fuse_initialize, 0, 0);
if (TLS_OUT_OF_INDEXES == fsp_fuse_tlskey)
return 0;
context = TlsGetValue(fsp_fuse_tlskey);
if (0 == context)
{
struct fsp_fuse_context_header *contexthdr;
contexthdr = fsp_fuse_obj_alloc(env,
sizeof(struct fsp_fuse_context_header) + sizeof(struct fuse_context));
if (0 == contexthdr)
return 0;
context = FSP_FUSE_CONTEXT_FROM_HDR(contexthdr);
context->pid = -1;
TlsSetValue(fsp_fuse_tlskey, context);
}
return context;
}
FSP_FUSE_API int32_t fsp_fuse_ntstatus_from_errno(struct fsp_fuse_env *env,
int err)
{
if (0 > err)
err = -err;
if ('C' == env->environment)
switch (err)
{
#undef FSP_FUSE_ERRNO
#define FSP_FUSE_ERRNO 67
#include "errno.i"
default:
return STATUS_ACCESS_DENIED;
}
else
switch (err)
{
#undef FSP_FUSE_ERRNO
#define FSP_FUSE_ERRNO 87
#include "errno.i"
default:
return STATUS_ACCESS_DENIED;
}
}
/* Cygwin signal support */
FSP_FUSE_API void fsp_fuse_signal_handler(int sig)
{
FspServiceConsoleCtrlHandler(CTRL_BREAK_EVENT);
}

10
src/dll/fuse/fuse.pc Normal file
View File

@ -0,0 +1,10 @@
prefix=${pcfiledir}/..
incdir=${prefix}/inc/fuse
implib=${prefix}/bin/winfsp-${arch}.dll
Name: fuse
Description: WinFsp FUSE compatible API
Version: 2.8
URL: http://www.secfs.net/winfsp/
Libs: "${implib}"
Cflags: -I"${incdir}"

2117
src/dll/fuse/fuse_intf.c Normal file

File diff suppressed because it is too large Load Diff

179
src/dll/fuse/fuse_main.c Normal file
View File

@ -0,0 +1,179 @@
/**
* @file dll/fuse/fuse_main.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dll/fuse/library.h>
#define FSP_FUSE_MAIN_OPT(n, f, v) { n, offsetof(struct fsp_fuse_main_opt_data, f), v }
struct fsp_fuse_main_opt_data
{
struct fsp_fuse_env *env;
char *mountpoint;
int singlethread;
int foreground;
};
static struct fuse_opt fsp_fuse_main_opts[] =
{
FUSE_OPT_KEY("-h", 'h'),
FUSE_OPT_KEY("--help", 'h'),
FUSE_OPT_KEY("-ho", 'H'),
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
FSP_FUSE_MAIN_OPT("-d", foreground, 1),
FSP_FUSE_MAIN_OPT("debug", foreground, 1),
FSP_FUSE_MAIN_OPT("-f", foreground, 1),
FSP_FUSE_MAIN_OPT("-s", singlethread, 1),
FUSE_OPT_END,
};
static int fsp_fuse_main_opt_proc(void *opt_data0, const char *arg, int key,
struct fuse_args *outargs)
{
static PWSTR HeaderHelp = L""
"\n"
" -o opt,[opt...] mount options\n"
" -h --help print help\n"
" -V --version print version\n";
static PWSTR MainHelp = L""
"FUSE options:\n"
" -d -o debug enable debug output (implies -f)\n"
" -f foreground operation\n"
" -s disable multi-threaded operation\n";
struct fsp_fuse_main_opt_data *opt_data = opt_data0;
switch (key)
{
default:
return 1;
case 'h':
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
"usage: %s mountpoint [options]\n"
"%s"
"\n"
"%s",
FspDiagIdent(), HeaderHelp, MainHelp);
return 1;
case 'H':
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
"%s",
MainHelp);
fsp_fuse_opt_add_arg(opt_data->env, outargs, "-h");
return 0;
case FUSE_OPT_KEY_NONOPT:
if (0 == opt_data->mountpoint)
{
size_t size = lstrlenA(arg) + 1;
opt_data->mountpoint = opt_data->env->memalloc(size);
if (0 == opt_data->mountpoint)
return -1;
memcpy(opt_data->mountpoint, arg, size);
}
else
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"Invalid argument \"%S\"", arg);
return 1;
}
}
FSP_FUSE_API int fsp_fuse_parse_cmdline(struct fsp_fuse_env *env,
struct fuse_args *args,
char **mountpoint, int *multithreaded, int *foreground)
{
struct fsp_fuse_main_opt_data opt_data;
memset(&opt_data, 0, sizeof opt_data);
opt_data.env = env;
if (-1 == fsp_fuse_opt_parse(env, args, &opt_data, fsp_fuse_main_opts, fsp_fuse_main_opt_proc))
return -1;
if (0 != mountpoint)
*mountpoint = opt_data.mountpoint;
else
env->memfree(mountpoint);
if (0 != multithreaded)
*multithreaded = !opt_data.singlethread;
if (0 != foreground)
*foreground = opt_data.foreground;
return 0;
}
FSP_FUSE_API int fsp_fuse_main_real(struct fsp_fuse_env *env,
int argc, char *argv[],
const struct fuse_operations *ops, size_t opsize, void *data)
{
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
char *mountpoint = 0;
int multithreaded = 0;
int foreground = 0;
struct fuse_chan *ch = 0;
struct fuse *f = 0;
int signal_handlers = 0;
int result;
result = fsp_fuse_parse_cmdline(env, &args, &mountpoint, &multithreaded, &foreground);
if (-1 == result)
goto exit;
ch = fsp_fuse_mount(env, mountpoint, &args);
if (0 == ch)
{
result = -1;
goto exit;
}
f = fsp_fuse_new(env, ch, &args, ops, opsize, data);
if (0 == f)
{
result = -1;
goto exit;
}
result = env->daemonize(foreground);
if (-1 == result)
goto exit;
result = env->set_signal_handlers(f);
if (-1 == result)
goto exit;
signal_handlers = 1;
result = multithreaded ? fsp_fuse_loop_mt(env, f) : fsp_fuse_loop(env, f);
exit:
if (signal_handlers)
env->set_signal_handlers(0);
if (0 != f)
fsp_fuse_destroy(env, f);
if (0 != ch)
fsp_fuse_unmount(env, mountpoint, ch);
env->memfree(mountpoint);
fsp_fuse_opt_free_args(env, &args);
/* main() style return: 0 success, 1 error */
return !!result;
}

622
src/dll/fuse/fuse_opt.c Normal file
View File

@ -0,0 +1,622 @@
/**
* @file dll/fuse/fuse_opt.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dll/fuse/library.h>
/*
* Define the following symbol to support escaped commas (',') during fuse_opt_parse.
*/
#define FSP_FUSE_OPT_PARSE_ESCAPED_COMMAS
#define fsp_fuse_opt_match_none ((const char *)0) /* no option match */
#define fsp_fuse_opt_match_exact ((const char *)1) /* exact option match */
#define fsp_fuse_opt_match_next ((const char *)2) /* option match, value is next arg */
static long long strtoint(const char *p, int base, int is_signed)
{
long long v;
int maxdig, maxalp, sign = +1;
if (is_signed)
{
if ('+' == *p)
p++;
else if ('-' == *p)
p++, sign = -1;
}
if (0 == base)
{
if ('0' == *p)
{
p++;
if ('x' == *p || 'X' == *p)
{
p++;
base = 16;
}
else
base = 8;
}
else
{
base = 10;
}
}
maxdig = 10 < base ? '9' : (base - 1) + '0';
maxalp = 10 < base ? (base - 1 - 10) + 'a' : 0;
for (v = 0; *p; p++)
{
int c = *p;
if ('0' <= c && c <= maxdig)
v = base * v + (c - '0');
else
{
c |= 0x20;
if ('a' <= c && c <= maxalp)
v = base * v + (c - 'a') + 10;
else
break;
}
}
return sign * v;
}
static void fsp_fuse_opt_match_templ(
const char *templ, const char **pspec,
const char **parg)
{
const char *p, *q;
*pspec = 0;
for (p = templ, q = *parg;; p++, q++)
if ('\0' == *q)
{
if ('\0' == *p)
*parg = fsp_fuse_opt_match_exact;
else if (' ' == *p)
*pspec = p + 1, *parg = fsp_fuse_opt_match_next;
else
*parg = fsp_fuse_opt_match_none;
break;
}
else if ('=' == *p)
{
if (*q == *p)
{
p++, q++;
if ('%' == *p || '\0' == *p)
*pspec = p, *parg = q;
else
*parg = 0 == lstrcmpA(q, p) ?
fsp_fuse_opt_match_exact : fsp_fuse_opt_match_none;
}
else
*parg = fsp_fuse_opt_match_none;
break;
}
else if (' ' == *p)
{
*pspec = p + 1, *parg = q;
break;
}
else if (*q != *p)
{
*parg = fsp_fuse_opt_match_none;
break;
}
}
static const struct fuse_opt *fsp_fuse_opt_find(
const struct fuse_opt opts[], const char **pspec,
const char **parg)
{
const struct fuse_opt *opt;
const char *arg;
for (opt = opts; 0 != opt->templ; opt++)
{
arg = *parg;
fsp_fuse_opt_match_templ(opt->templ, pspec, &arg);
if (fsp_fuse_opt_match_none != arg)
{
*parg = arg;
return opt;
}
}
return 0;
}
static int fsp_fuse_opt_call_proc(struct fsp_fuse_env *env,
void *data, fuse_opt_proc_t proc,
const char *arg, const char *argl,
int key, int is_opt,
struct fuse_args *outargs)
{
int result, len0, len1;
char *fullarg = 0;
if (FUSE_OPT_KEY_DISCARD == key)
return 0;
len0 = lstrlenA(arg);
if (0 != argl && !(arg <= argl && argl < arg + len0))
{
len1 = lstrlenA(argl);
fullarg = env->memalloc(len0 + len1 + 1);
if (0 == fullarg)
return -1;
memcpy(fullarg, arg, len0);
memcpy(fullarg + len0, argl, len1);
fullarg[len0 + len1] = '\0';
arg = fullarg;
}
if (FUSE_OPT_KEY_KEEP != key && 0 != proc)
{
result = proc(data, arg, key, outargs);
if (-1 == result || 0 == result)
goto exit;
}
if (is_opt)
{
if (!(3 <= outargs->argc &&
'-' == outargs->argv[1][0] && 'o' == outargs->argv[1][1] &&
'\0' == outargs->argv[1][2]))
{
result = fsp_fuse_opt_insert_arg(env, outargs, 1, "-o");
if (-1 == result)
goto exit;
result = fsp_fuse_opt_insert_arg(env, outargs, 2, "");
if (-1 == result)
goto exit;
}
#if defined(FSP_FUSE_OPT_PARSE_ESCAPED_COMMAS)
result = fsp_fuse_opt_add_opt_escaped(env, &outargs->argv[2], arg);
#else
result = fsp_fuse_opt_add_opt(env, &outargs->argv[2], arg);
#endif
if (-1 == result)
goto exit;
}
else
{
result = fsp_fuse_opt_add_arg(env, outargs, arg);
if (-1 == result)
goto exit;
}
exit:
if (0 != fullarg)
env->memfree(fullarg);
return 0;
}
static int fsp_fuse_opt_process_arg(struct fsp_fuse_env *env,
void *data, const struct fuse_opt *opt, fuse_opt_proc_t proc,
const char *spec,
const char *arg, const char *argl,
int is_opt,
struct fuse_args *outargs)
{
#define VAR(data, opt, type) *(type *)((char *)(data) + (opt)->offset)
if (-1L == opt->offset)
return fsp_fuse_opt_call_proc(env,
data, proc, arg, argl, opt->value, is_opt, outargs);
else
{
int h, j, l, t, z;
long long llv;
char *s;
int len;
if (0 == spec || '\0' == spec[0])
{
VAR(data, opt, int) = opt->value;
return 0;
}
if ('%' != spec[0])
return -1; /* bad option template */
h = j = l = t = z = 0;
for (spec++; *spec; spec++)
switch (*spec)
{
default:
case 0: case 1: case 2: case 3: case 4:
case 5: case 6: case 7: case 8: case 9:
case 'm':
break;
case 'h':
h++;
break;
case 'j':
j++;
break;
case 'l':
l++;
break;
case 'L': case 'q':
l += 2;
break;
case 't':
t++;
break;
case 'z':
z++;
break;
case 'd':
llv = strtoint(argl, 10, 1);
goto ivar;
case 'i':
llv = strtoint(argl, 0, 1);
goto ivar;
case 'o':
llv = strtoint(argl, 8, 0);
goto ivar;
case 'u':
llv = strtoint(argl, 10, 0);
goto ivar;
case 'x': case 'X':
llv = strtoint(argl, 16, 0);
ivar:
if (z)
VAR(data, opt, size_t) = (size_t)llv;
else if (t)
VAR(data, opt, ptrdiff_t) = (ptrdiff_t)llv;
else if (j)
VAR(data, opt, intmax_t) = (intmax_t)llv;
else if (1 == h)
VAR(data, opt, short) = (short)llv;
else if (2 <= h)
VAR(data, opt, char) = (char)llv;
else if (1 == l)
{
#if defined(_WIN64)
/* long is 8 bytes long in Cygwin64 and 4 bytes long in Win64 */
if ('C' == env->environment)
VAR(data, opt, long long) = (long long)llv;
else
VAR(data, opt, long) = (long)llv;
#else
VAR(data, opt, long) = (long)llv;
#endif
}
else if (2 <= l)
VAR(data, opt, long long) = (long long)llv;
else
VAR(data, opt, int) = (int)llv;
return 0;
case 's': case 'c':
len = lstrlenA(argl);
s = env->memalloc(len + 1);
if (0 == s)
return -1;
memcpy(s, argl, len);
s[len] = '\0';
VAR(data, opt, const char *) = (const char *)s;
return 0;
case 'a': case 'e': case 'E': case 'f': case 'g':
return -1; /* no float support */
}
return -1; /* bad option template */
}
#undef VAR
}
static int fsp_fuse_opt_parse_arg(struct fsp_fuse_env *env,
void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc,
const char *arg, const char *nextarg, int *pconsumed_nextarg,
int is_opt,
struct fuse_args *outargs)
{
const struct fuse_opt *opt;
const char *spec, *argl;
int processed = 0;
argl = arg;
opt = opts;
while (0 != (opt = fsp_fuse_opt_find(opt, &spec, &argl)))
{
if (fsp_fuse_opt_match_exact == argl)
argl = arg;
else if (fsp_fuse_opt_match_next == argl)
{
if (0 == nextarg)
return -1; /* missing argument for option */
argl = nextarg;
*pconsumed_nextarg = 1;
}
if (-1 == fsp_fuse_opt_process_arg(env,
data, opt, proc, spec, arg, argl, is_opt, outargs))
return -1;
processed++;
argl = arg;
opt++;
}
if (0 != processed)
return 0;
return fsp_fuse_opt_call_proc(env,
data, proc, arg, arg, FUSE_OPT_KEY_OPT, is_opt, outargs);
}
static int fsp_fuse_opt_proc0(void *data, const char *arg, int key,
struct fuse_args *outargs)
{
return 1;
}
FSP_FUSE_API int fsp_fuse_opt_parse(struct fsp_fuse_env *env,
struct fuse_args *args,
void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
{
static struct fuse_args args0 = FUSE_ARGS_INIT(0, 0);
static struct fuse_opt opts0[1] = { FUSE_OPT_END };
struct fuse_args outargs = FUSE_ARGS_INIT(0, 0);
const char *arg;
char *argcopy, *argend;
int dashdash = 0, consumed_nextarg;
if (0 == args)
args = &args0;
if (0 == opts)
opts = opts0;
if (0 == proc)
proc = fsp_fuse_opt_proc0;
if (-1 == fsp_fuse_opt_add_arg(env, &outargs, args->argv[0]))
return -1;
for (int argi = 1; args->argc > argi; argi++)
{
arg = args->argv[argi];
if ('-' == arg[0] && !dashdash)
{
switch (arg[1])
{
case 'o':
if ('\0' == arg[2])
{
if (args->argc <= argi + 1)
goto fail; /* missing argument for option "-o" */
arg = args->argv[++argi];
}
else
arg += 2;
argcopy = env->memalloc(lstrlenA(arg) + 1);
if (0 == argcopy)
goto fail;
argend = argcopy;
for (;;)
{
#if defined(FSP_FUSE_OPT_PARSE_ESCAPED_COMMAS)
if ('\\' == *arg)
{
arg++;
*argend++ = *arg++;
continue;
}
#endif
if ('\0' == *arg || ',' == *arg)
{
*argend = '\0';
if (-1 == fsp_fuse_opt_parse_arg(env,
data, opts, proc, argcopy, 0, 0, 1, &outargs))
{
env->memfree(argcopy);
goto fail;
}
if ('\0' == *arg)
break;
arg++;
argend = argcopy;
}
else
*argend++ = *arg++;
}
env->memfree(argcopy);
break;
case '-':
if ('\0' == arg[2])
{
if (-1 == fsp_fuse_opt_add_arg(env, &outargs, arg))
return -1;
dashdash = 1;
break;
}
/* fall through */
default:
consumed_nextarg = 0;
if (-1 == fsp_fuse_opt_parse_arg(env,
data, opts, proc, arg, args->argv[argi + 1], &consumed_nextarg, 0, &outargs))
goto fail;
if (consumed_nextarg)
argi++;
break;
}
}
else
if (-1 == fsp_fuse_opt_call_proc(env,
data, proc, arg, arg, FUSE_OPT_KEY_NONOPT, 0, &outargs))
goto fail;
}
/* if "--" is the last argument, remove it (fuse_opt compatibility) */
if (0 < outargs.argc &&
'-' == outargs.argv[outargs.argc - 1][0] &&
'-' == outargs.argv[outargs.argc - 1][1] &&
'\0' == outargs.argv[outargs.argc - 1][2])
{
env->memfree(outargs.argv[--outargs.argc]);
outargs.argv[outargs.argc] = 0;
}
fsp_fuse_opt_free_args(env, args);
memcpy(args, &outargs, sizeof outargs);
return 0;
fail:
fsp_fuse_opt_free_args(env, &outargs);
return -1;
}
FSP_FUSE_API int fsp_fuse_opt_add_arg(struct fsp_fuse_env *env,
struct fuse_args *args, const char *arg)
{
return fsp_fuse_opt_insert_arg(env, args, args->argc, arg);
}
FSP_FUSE_API int fsp_fuse_opt_insert_arg(struct fsp_fuse_env *env,
struct fuse_args *args, int pos, const char *arg)
{
char **argv;
int argsize;
if (0 == args)
return -1;
if (0 != args->argv && !args->allocated)
return -1;
if (0 > pos || pos > args->argc)
return -1;
argv = env->memalloc((args->argc + 2) * sizeof(char *));
if (0 == argv)
return -1;
argsize = lstrlenA(arg) + 1;
argv[pos] = env->memalloc(argsize);
if (0 == argv[pos])
{
env->memfree(argv);
return -1;
}
memcpy(argv[pos], arg, argsize);
memcpy(argv, args->argv, sizeof(char *) * pos);
memcpy(argv + pos + 1, args->argv + pos, sizeof(char *) * (args->argc - pos));
env->memfree(args->argv);
args->argc++;
args->argv = argv;
argv[args->argc] = 0;
args->allocated = 1;
return 0;
}
FSP_FUSE_API void fsp_fuse_opt_free_args(struct fsp_fuse_env *env,
struct fuse_args *args)
{
if (0 == args)
return;
if (args->allocated && 0 != args->argv)
{
for (int argi = 0; args->argc > argi; argi++)
env->memfree(args->argv[argi]);
env->memfree(args->argv);
}
args->argc = 0;
args->argv = 0;
args->allocated = 0;
}
static int fsp_fuse_opt_add_opt_internal(struct fsp_fuse_env *env,
char **opts, const char *opt, int escaped)
{
size_t optsize, optlen;
char *newopts;
const char *p;
optsize = 0 != *opts && '\0' != (*opts)[0] ? lstrlenA(*opts) + 1 : 0;
for (p = opt, optlen = 0; *p; p++, optlen++)
if (escaped && (',' == *p || '\\' == *p))
optlen++;
newopts = env->memalloc(optsize + optlen + 1);
if (0 == newopts)
return -1;
if (0 != optsize)
{
memcpy(newopts, *opts, optsize - 1);
newopts[optsize - 1] = ',';
}
env->memfree(*opts);
*opts = newopts;
newopts += optsize;
for (p = opt; *p; p++, newopts++)
{
if (escaped && (',' == *p || '\\' == *p))
*newopts++ = '\\';
*newopts = *p;
}
*newopts = '\0';
return 0;
}
FSP_FUSE_API int fsp_fuse_opt_add_opt(struct fsp_fuse_env *env,
char **opts, const char *opt)
{
return fsp_fuse_opt_add_opt_internal(env, opts, opt, 0);
}
FSP_FUSE_API int fsp_fuse_opt_add_opt_escaped(struct fsp_fuse_env *env,
char **opts, const char *opt)
{
return fsp_fuse_opt_add_opt_internal(env, opts, opt, 1);
}
FSP_FUSE_API int fsp_fuse_opt_match(struct fsp_fuse_env *env,
const struct fuse_opt opts[], const char *arg)
{
if (0 == opts)
return 0;
const char *spec;
return !!fsp_fuse_opt_find(opts, &spec, &arg);
}

101
src/dll/fuse/library.h Normal file
View File

@ -0,0 +1,101 @@
/**
* @file dll/fuse/library.h
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#ifndef WINFSP_DLL_FUSE_LIBRARY_H_INCLUDED
#define WINFSP_DLL_FUSE_LIBRARY_H_INCLUDED
#include <dll/library.h>
#include <fuse/fuse.h>
#include <fuse/fuse_opt.h>
#define FSP_FUSE_LIBRARY_NAME LIBRARY_NAME "-FUSE"
#define FSP_FUSE_HDR_FROM_CONTEXT(c) \
(struct fsp_fuse_context_header *)((PUINT8)(c) - sizeof(struct fsp_fuse_context_header))
#define FSP_FUSE_CONTEXT_FROM_HDR(h) \
(struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header))
#define FSP_FUSE_HAS_SYMLINKS(f) (0 != (f)->ops.readlink)
struct fuse
{
struct fsp_fuse_env *env;
int set_umask, umask;
int set_uid, uid;
int set_gid, gid;
int rellinks;
struct fuse_operations ops;
void *data;
UINT32 DebugLog;
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
PWSTR MountPoint;
FSP_FILE_SYSTEM *FileSystem;
BOOLEAN fsinit;
FSP_SERVICE *Service; /* weak */
};
struct fsp_fuse_context_header
{
char *PosixPath;
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ContextBuf[];
};
struct fsp_fuse_file_desc
{
char *PosixPath;
BOOLEAN IsDirectory, IsReparsePoint;
int OpenFlags;
UINT64 FileHandle;
PVOID DirBuffer;
ULONG DirBufferSize;
};
struct fuse_dirhandle
{
PVOID Buffer;
ULONG Length;
ULONG BytesTransferred;
BOOLEAN NonZeroOffset;
BOOLEAN DotFiles, HasChild;
};
struct fsp_fuse_dirinfo
{
UINT16 Size;
FSP_FSCTL_FILE_INFO FileInfo;
BOOLEAN FileInfoValid;
UINT64 NextOffset;
char PosixNameBuf[]; /* includes term-0 (unlike FSP_FSCTL_DIR_INFO) */
};
NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
extern FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf;
/* NFS reparse points */
#define NFS_SPECFILE_FIFO 0x000000004F464946
#define NFS_SPECFILE_CHR 0x0000000000524843
#define NFS_SPECFILE_BLK 0x00000000004b4c42
#define NFS_SPECFILE_LNK 0x00000000014b4e4c
#define NFS_SPECFILE_SOCK 0x000000004B434F53
#endif

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -18,41 +18,68 @@
#include <dll/library.h>
HINSTANCE DllInstance;
HANDLE ProcessHeap;
BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
{
BOOLEAN Dynamic;
switch (Reason)
{
case DLL_PROCESS_ATTACH:
DllInstance = Instance;
ProcessHeap = GetProcessHeap();
if (0 == ProcessHeap)
return FALSE;
FspFileSystemInitialize();
break;
case DLL_PROCESS_DETACH:
FspFileSystemFinalize();
/*
* These functions are called during DLL_PROCESS_DETACH. We must therefore keep
* finalization tasks to a minimum.
*
* See the following documents:
* https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx
* https://blogs.msdn.microsoft.com/oldnewthing/20070503-00/?p=27003/
* https://blogs.msdn.microsoft.com/oldnewthing/20100122-00/?p=15193/
*/
Dynamic = 0 == Reserved;
fsp_fuse_finalize(Dynamic);
FspServiceFinalize(Dynamic);
FspEventLogFinalize(Dynamic);
FspPosixFinalize(Dynamic);
break;
case DLL_THREAD_DETACH:
fsp_fuse_finalize_thread();
break;
}
return TRUE;
}
/* see comments in library.h */
#if defined(WINFSP_DLL_NODEFAULTLIB)
/* see comments in shared/minimal.h */
BOOL WINAPI _DllMainCRTStartup(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
{
return DllMain(Instance, Reason, Reserved);
}
#endif
HRESULT WINAPI DllRegisterServer(VOID)
{
NTSTATUS Result;
Result = FspNpRegister();
Result = FspFsctlRegister();
FspDebugLog("FspFsctlRegister = %lx\n", Result);
if (!NT_SUCCESS(Result))
goto exit;
/* ignore errors below; these are non-critical */
Result = FspNpRegister();
FspDebugLog("FspNpRegister = %lx\n", Result);
Result = FspEventLogRegister();
FspDebugLog("FspEventLogRegister = %lx\n", Result);
Result = STATUS_SUCCESS;
exit:
return NT_SUCCESS(Result) ? S_OK : 0x80040201/*SELFREG_E_CLASS*/;
}
@ -60,7 +87,21 @@ HRESULT WINAPI DllUnregisterServer(VOID)
{
NTSTATUS Result;
Result = FspNpUnregister();
Result = FspFsctlUnregister();
FspDebugLog("FspFsctlUnregister = %lx\n", Result);
if (!NT_SUCCESS(Result))
goto exit;
/* ignore errors below; these are non-critical */
Result = FspNpUnregister();
FspDebugLog("FspNpUnregister = %lx\n", Result);
Result = FspEventLogUnregister();
FspDebugLog("FspEventLogUnregister = %lx\n", Result);
Result = STATUS_SUCCESS;
exit:
return NT_SUCCESS(Result) ? S_OK : 0x80040201/*SELFREG_E_CLASS*/;
}

View File

@ -3,3 +3,9 @@ EXPORTS
DllUnregisterServer PRIVATE
NPGetCaps PRIVATE
NPGetConnection PRIVATE
NPAddConnection PRIVATE
NPAddConnection3 PRIVATE
NPCancelConnection PRIVATE
NPOpenEnum PRIVATE
NPEnumResource PRIVATE
NPCloseEnum PRIVATE

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -19,8 +19,8 @@
#define WINFSP_DLL_LIBRARY_H_INCLUDED
#define WINFSP_DLL_INTERNAL
#define WINFSP_DLL_NODEFAULTLIB
#include <winfsp/winfsp.h>
#include <shared/minimal.h>
#include <strsafe.h>
#define LIBRARY_NAME "WinFsp"
@ -36,77 +36,34 @@
#define DEBUGLOGSD(fmt, SD) ((void)0)
#endif
static inline PVOID MemAlloc(SIZE_T Size)
{
extern HANDLE ProcessHeap;
return HeapAlloc(ProcessHeap, 0, Size);
}
static inline VOID MemFree(PVOID Pointer)
{
extern HANDLE ProcessHeap;
if (0 != Pointer)
HeapFree(ProcessHeap, 0, Pointer);
}
/*
* Define WINFSP_DLL_NODEFAULTLIB to eliminate dependency on the MSVCRT libraries.
*
* For this to work the following project settings must be set:
* - "C/C++ > General > SDL checks" must be empty (not "Yes" or "No").
* - "C/C++ > Code Generation > Basic Runtime Checks" must be set to "Default"
* - "C/C++ > Code Generation > Security Check" must be disabled (/GS-).
* - "Linker > Input > Ignore All Default Libraries" must be "Yes".
*/
#if defined(WINFSP_DLL_NODEFAULTLIB)
#undef RtlFillMemory
#undef RtlMoveMemory
NTSYSAPI VOID NTAPI RtlFillMemory(VOID *Destination, DWORD Length, BYTE Fill);
NTSYSAPI VOID NTAPI RtlMoveMemory(VOID *Destination, CONST VOID *Source, DWORD Length);
#pragma function(memcpy)
#pragma function(memset)
static inline
void *memcpy(void *dst, const void *src, size_t siz)
{
RtlMoveMemory(dst, src, (DWORD)siz);
return dst;
}
static inline
void *memset(void *dst, int val, size_t siz)
{
RtlFillMemory(dst, (DWORD)siz, val);
return dst;
}
#endif
static FORCEINLINE
VOID InsertTailList(PLIST_ENTRY ListHead, PLIST_ENTRY Entry)
{
PLIST_ENTRY Blink;
Blink = ListHead->Blink;
Entry->Flink = ListHead;
Entry->Blink = Blink;
Blink->Flink = Entry;
ListHead->Blink = Entry;
}
static FORCEINLINE
BOOLEAN RemoveEntryList(PLIST_ENTRY Entry)
{
PLIST_ENTRY Blink;
PLIST_ENTRY Flink;
Flink = Entry->Flink;
Blink = Entry->Blink;
Blink->Flink = Flink;
Flink->Blink = Blink;
return Flink == Blink;
}
VOID FspFileSystemInitialize(VOID);
VOID FspFileSystemFinalize(VOID);
VOID FspPosixFinalize(BOOLEAN Dynamic);
VOID FspEventLogFinalize(BOOLEAN Dynamic);
VOID FspServiceFinalize(BOOLEAN Dynamic);
VOID fsp_fuse_finalize(BOOLEAN Dynamic);
VOID fsp_fuse_finalize_thread(VOID);
NTSTATUS FspFsctlRegister(VOID);
NTSTATUS FspFsctlUnregister(VOID);
NTSTATUS FspNpRegister(VOID);
NTSTATUS FspNpUnregister(VOID);
NTSTATUS FspEventLogRegister(VOID);
NTSTATUS FspEventLogUnregister(VOID);
PWSTR FspDiagIdent(VOID);
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
static inline ULONG FspPathSuffixIndex(PWSTR FileName)
{
WCHAR Root[2] = L"\\";
PWSTR Remain, Suffix;
ULONG Result;
FspPathSuffix(FileName, &Remain, &Suffix, Root);
Result = Remain == Root ? 0 : (ULONG)(Suffix - Remain);
FspPathCombine(FileName, Suffix);
return Result;
}
#endif

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -16,12 +16,31 @@
*/
#include <dll/library.h>
#include <launcher/launcher.h>
#include <npapi.h>
#include <wincred.h>
#define FSP_NP_NAME "WinFsp.Np"
#define FSP_NP_DESC "File System Proxy"
#define FSP_NP_NAME LIBRARY_NAME ".Np"
#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */
/*
* Define the following macro to use CredUIPromptForWindowsCredentials.
* Otherwise CredUIPromptForCredentials will be used.
*/
#define FSP_NP_CREDUI_PROMPT_NEW
/*
* Define the following macro to include support for the credential manager.
*/
#define FSP_NP_CREDENTIAL_MANAGER
enum
{
FSP_NP_CREDENTIALS_NONE = 0,
FSP_NP_CREDENTIALS_PASSWORD = 1,
FSP_NP_CREDENTIALS_USERPASS = 3,
};
DWORD APIENTRY NPGetCaps(DWORD Index)
{
switch (Index)
@ -34,14 +53,17 @@ DWORD APIENTRY NPGetCaps(DWORD Index)
return 0;
case WNNC_CONNECTION:
/*
* WNNC_CON_ADDCONECTION
* WNNC_CON_ADDCONNECTION
* WNNC_CON_CANCELCONNECTION
* WNNC_CON_GETCONNECTIONS
* WNNC_CON_ADDCONECTION3
* WNNC_CON_ADDCONNECTION3
* WNNC_CON_GETPERFORMANCE
* WNNC_CON_DEFER
*/
return WNNC_CON_GETCONNECTIONS;
return
WNNC_CON_GETCONNECTIONS |
WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3 |
WNNC_CON_CANCELCONNECTION;
case WNNC_DIALOG:
/*
* WNNC_DLG_DEVICEMODE
@ -59,7 +81,7 @@ DWORD APIENTRY NPGetCaps(DWORD Index)
* WNNC_ENUM_LOCAL
* WNNC_ENUM_CONTEXT
*/
return 0;
return WNNC_ENUM_LOCAL | WNNC_ENUM_CONTEXT;
case WNNC_NET_TYPE:
return FSP_NP_TYPE;
case WNNC_SPEC_VERSION:
@ -76,6 +98,115 @@ 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];
}
static inline BOOLEAN FspNpCheckRemoteName(PWSTR RemoteName)
{
return 0 != RemoteName && L'\\' == RemoteName[0] && L'\\' == RemoteName[1] &&
sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR) >= lstrlenW(RemoteName);
}
static inline BOOLEAN FspNpParseRemoteName(PWSTR RemoteName,
PWSTR *PClassName, PULONG PClassNameLen,
PWSTR *PInstanceName, PULONG PInstanceNameLen)
{
PWSTR ClassName, InstanceName, P;
ULONG ClassNameLen, InstanceNameLen;
if (!FspNpCheckRemoteName(RemoteName))
return FALSE;
ClassName = RemoteName + 2; /* skip \\ */
for (P = ClassName; *P; P++)
if (L'\\' == *P)
break;
if (ClassName == P || L'\\' != *P)
return FALSE;
ClassNameLen = (ULONG)(P - ClassName);
InstanceName = P + 1;
for (P = InstanceName; *P; P++)
;
for (;;)
{
if (InstanceName == P)
return FALSE;
if (L'\\' != P[-1])
break;
P--;
}
InstanceNameLen = (ULONG)(P - InstanceName);
*PClassName = ClassName; *PClassNameLen = ClassNameLen;
*PInstanceName = InstanceName; *PInstanceNameLen = InstanceNameLen;
return TRUE;
}
static inline BOOLEAN FspNpParseUserName(PWSTR RemoteName,
PWSTR UserName, ULONG UserNameSize/* in chars */)
{
PWSTR ClassName, InstanceName, P;
ULONG ClassNameLen, InstanceNameLen;
if (FspNpParseRemoteName(RemoteName,
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
{
for (P = InstanceName; *P; P++)
if ('@' == *P && (ULONG)(P - InstanceName) < UserNameSize)
{
memcpy(UserName, InstanceName, (P - InstanceName) * sizeof(WCHAR));
UserName[P - InstanceName] = L'\0';
return TRUE;
}
}
return FALSE;
}
static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
{
DWORD NpResult;
NTSTATUS Result;
DWORD BytesTransferred;
Result = FspCallNamedPipeSecurely(L"" LAUNCHER_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize,
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, LAUNCHER_PIPE_OWNER);
if (!NT_SUCCESS(Result))
NpResult = WN_NO_NETWORK;
else if (sizeof(WCHAR) > BytesTransferred)
NpResult = WN_NO_NETWORK;
else if (LauncherSuccess == PipeBuf[0])
NpResult = WN_SUCCESS;
else if (LauncherFailure == PipeBuf[0])
{
NpResult = 0;
for (PWSTR P = PipeBuf + 1, EndP = PipeBuf + BytesTransferred / sizeof(WCHAR); EndP > P; P++)
{
if (L'0' > *P || *P > L'9')
break;
NpResult = 10 * NpResult + (*P - L'0');
}
if (0 == NpResult)
NpResult = WN_NO_NETWORK;
}
else
NpResult = WN_NO_NETWORK;
return NpResult;
}
static NTSTATUS FspNpGetVolumeList(
PWCHAR *PVolumeListBuf, PSIZE_T PVolumeListSize)
{
@ -108,7 +239,175 @@ static NTSTATUS FspNpGetVolumeList(
}
}
DWORD APIENTRY NPGetConnection(LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpnBufferLen)
static WCHAR FspNpGetDriveLetter(PDWORD PLogicalDrives, PWSTR VolumeName)
{
WCHAR VolumeNameBuf[MAX_PATH];
WCHAR LocalNameBuf[3];
WCHAR Drive;
if (0 == *PLogicalDrives)
return 0;
LocalNameBuf[1] = L':';
LocalNameBuf[2] = L'\0';
for (Drive = 'Z'; 'A' <= Drive; Drive--)
if (0 != (*PLogicalDrives & (1 << (Drive - 'A'))))
{
LocalNameBuf[0] = Drive;
if (QueryDosDeviceW(LocalNameBuf, VolumeNameBuf, sizeof VolumeNameBuf / sizeof(WCHAR)))
{
if (0 == lstrcmpW(VolumeNameBuf, VolumeName))
{
*PLogicalDrives &= ~(1 << (Drive - 'A'));
return Drive;
}
}
}
return 0;
}
static DWORD FspNpGetCredentialsKind(PWSTR RemoteName, PDWORD PCredentialsKind)
{
HKEY RegKey = 0;
DWORD NpResult, RegSize;
DWORD Credentials;
PWSTR ClassName, InstanceName;
ULONG ClassNameLen, InstanceNameLen;
WCHAR ClassNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
*PCredentialsKind = FSP_NP_CREDENTIALS_NONE;
if (!FspNpParseRemoteName(RemoteName,
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
return WN_BAD_NETNAME;
if (ClassNameLen > sizeof ClassNameBuf / sizeof ClassNameBuf[0] - 1)
ClassNameLen = sizeof ClassNameBuf / sizeof ClassNameBuf[0] - 1;
memcpy(ClassNameBuf, ClassName, ClassNameLen * sizeof(WCHAR));
ClassNameBuf[ClassNameLen] = '\0';
NpResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY, 0, KEY_READ, &RegKey);
if (ERROR_SUCCESS != NpResult)
goto exit;
RegSize = sizeof Credentials;
Credentials = 0; /* default is NO credentials */
NpResult = RegGetValueW(RegKey, ClassNameBuf, L"Credentials", RRF_RT_REG_DWORD, 0,
&Credentials, &RegSize);
if (ERROR_SUCCESS != NpResult && ERROR_FILE_NOT_FOUND != NpResult)
goto exit;
switch (Credentials)
{
case FSP_NP_CREDENTIALS_NONE:
case FSP_NP_CREDENTIALS_PASSWORD:
case FSP_NP_CREDENTIALS_USERPASS:
*PCredentialsKind = Credentials;
break;
}
NpResult = ERROR_SUCCESS;
exit:
if (0 != RegKey)
RegCloseKey(RegKey);
return NpResult;
}
static DWORD FspNpGetCredentials(
HWND hwndOwner, PWSTR Caption, DWORD PrevNpResult,
DWORD CredentialsKind,
PBOOL PSave,
PWSTR UserName, ULONG UserNameSize/* in chars */,
PWSTR Password, ULONG PasswordSize/* in chars */)
{
DWORD NpResult;
CREDUI_INFOW UiInfo;
memset(&UiInfo, 0, sizeof UiInfo);
UiInfo.cbSize = sizeof UiInfo;
UiInfo.hwndParent = hwndOwner;
UiInfo.pszCaptionText = Caption;
UiInfo.pszMessageText = L"Enter credentials to unlock this file system.";
#if !defined(FSP_NP_CREDUI_PROMPT_NEW)
NpResult = CredUIPromptForCredentialsW(&UiInfo, L"NONE", 0, 0,
UserName, UserNameSize,
Password, PasswordSize,
PSave,
CREDUI_FLAGS_GENERIC_CREDENTIALS |
CREDUI_FLAGS_DO_NOT_PERSIST |
CREDUI_FLAGS_ALWAYS_SHOW_UI |
(0 != PrevNpResult ? CREDUI_FLAGS_INCORRECT_PASSWORD : 0) |
(0 != PSave ? CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX : 0) |
(FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind ? 0/*CREDUI_FLAGS_KEEP_USERNAME*/ : 0));
#else
WCHAR Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1];
ULONG AuthPackage = 0;
PVOID InAuthBuf = 0, OutAuthBuf = 0;
ULONG InAuthSize, OutAuthSize, DomainSize;
InAuthSize = 0;
if (!CredPackAuthenticationBufferW(
CRED_PACK_GENERIC_CREDENTIALS, UserName, Password, 0, &InAuthSize) &&
ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
NpResult = GetLastError();
goto exit;
}
InAuthBuf = MemAlloc(InAuthSize);
if (0 == InAuthBuf)
{
NpResult = ERROR_NO_SYSTEM_RESOURCES;
goto exit;
}
if (!CredPackAuthenticationBufferW(
CRED_PACK_GENERIC_CREDENTIALS, UserName, Password, InAuthBuf, &InAuthSize))
{
NpResult = GetLastError();
goto exit;
}
NpResult = CredUIPromptForWindowsCredentialsW(&UiInfo, PrevNpResult,
&AuthPackage, InAuthBuf, InAuthSize, &OutAuthBuf, &OutAuthSize, PSave,
CREDUIWIN_GENERIC | (0 != PSave ? CREDUIWIN_CHECKBOX : 0));
if (ERROR_SUCCESS != NpResult)
goto exit;
DomainSize = sizeof Domain / sizeof Domain[0];
if (!CredUnPackAuthenticationBufferW(0, OutAuthBuf, OutAuthSize,
UserName, &UserNameSize, Domain, &DomainSize, Password, &PasswordSize))
{
NpResult = GetLastError();
goto exit;
}
NpResult = ERROR_SUCCESS;
exit:
if (0 != OutAuthBuf)
{
SecureZeroMemory(OutAuthBuf, OutAuthSize);
CoTaskMemFree(OutAuthBuf);
}
if (0 != InAuthBuf)
{
SecureZeroMemory(InAuthBuf, InAuthSize);
MemFree(InAuthBuf);
}
#endif
return NpResult;
}
DWORD APIENTRY NPGetConnection(
LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpnBufferLen)
{
DWORD NpResult;
NTSTATUS Result;
@ -118,15 +417,10 @@ DWORD APIENTRY NPGetConnection(LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD
SIZE_T VolumeListSize, VolumeNameSize;
ULONG Backslashes;
if (0 == lpLocalName ||
!(
(L'A' <= lpLocalName[0] && lpLocalName[0] <= L'Z') ||
(L'a' <= lpLocalName[0] && lpLocalName[0] <= L'z')
) ||
L':' != lpLocalName[1])
if (!FspNpCheckLocalName(lpLocalName))
return WN_BAD_LOCALNAME;
LocalNameBuf[0] = lpLocalName[0];
LocalNameBuf[0] = lpLocalName[0] & ~0x20; /* convert to uppercase */
LocalNameBuf[1] = L':';
LocalNameBuf[2] = L'\0';
@ -189,6 +483,479 @@ DWORD APIENTRY NPGetConnection(LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD
return NpResult;
}
DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName)
{
DWORD NpResult;
DWORD dwType = lpNetResource->dwType;
LPWSTR lpRemoteName = lpNetResource->lpRemoteName;
LPWSTR lpLocalName = lpNetResource->lpLocalName;
WCHAR LocalNameBuf[3];
PWSTR ClassName, InstanceName, RemoteName, P;
ULONG ClassNameLen, InstanceNameLen;
DWORD CredentialsKind;
PWSTR PipeBuf = 0;
#if defined(FSP_NP_CREDENTIAL_MANAGER)
PCREDENTIALW Credential = 0;
#endif
if (dwType & RESOURCETYPE_PRINT)
return WN_BAD_VALUE;
if (!FspNpParseRemoteName(lpRemoteName,
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
return WN_BAD_NETNAME;
RemoteName = lpRemoteName + 1;
LocalNameBuf[0] = L'\0';
if (0 != lpLocalName && L'\0' != lpLocalName[0])
{
if (!FspNpCheckLocalName(lpLocalName))
return WN_BAD_LOCALNAME;
LocalNameBuf[0] = lpLocalName[0] & ~0x20; /* convert to uppercase */
LocalNameBuf[1] = L':';
LocalNameBuf[2] = L'\0';
if (GetLogicalDrives() & (1 << (LocalNameBuf[0] - 'A')))
return WN_ALREADY_CONNECTED;
}
FspNpGetCredentialsKind(lpRemoteName, &CredentialsKind);
#if defined(FSP_NP_CREDENTIAL_MANAGER)
/* if we need credentials and none were passed check with the credential manager */
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind && 0 == lpPassword &&
CredReadW(lpRemoteName, CRED_TYPE_GENERIC, 0, &Credential))
{
if (sizeof(WCHAR) <= Credential->CredentialBlobSize &&
L'\0' == ((PWSTR)(Credential->CredentialBlob))
[(Credential->CredentialBlobSize / sizeof(WCHAR)) - 1])
{
lpUserName = Credential->UserName;
lpPassword = (PVOID)Credential->CredentialBlob;
}
}
#endif
/* if we need credentials and we don't have any return ACCESS DENIED */
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind)
{
int Length;
if (0 == lpPassword ||
(0 == (Length = lstrlenW(lpPassword))) || CREDUI_MAX_PASSWORD_LENGTH < Length)
{
NpResult = WN_ACCESS_DENIED;
goto exit;
}
}
if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
{
int Length;
if (0 == lpUserName ||
(0 == (Length = lstrlenW(lpUserName))) || CREDUI_MAX_USERNAME_LENGTH < Length)
{
NpResult = WN_ACCESS_DENIED;
goto exit;
}
}
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
if (0 == PipeBuf)
{
NpResult = WN_OUT_OF_MEMORY;
goto exit;
}
/* we do not explicitly check, but assumption is it all fits in LAUNCHER_PIPE_BUFFER_SIZE */
P = PipeBuf;
*P++ = FSP_NP_CREDENTIALS_NONE != CredentialsKind ?
LauncherSvcInstanceStartWithSecret : LauncherSvcInstanceStart;
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
lstrcpyW(P, RemoteName); P += lstrlenW(RemoteName) + 1;
lstrcpyW(P, LocalNameBuf); P += lstrlenW(LocalNameBuf) + 1;
if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
{
lstrcpyW(P, lpUserName); P += lstrlenW(lpUserName) + 1;
}
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind)
{
lstrcpyW(P, lpPassword); P += lstrlenW(lpPassword) + 1;
}
NpResult = FspNpCallLauncherPipe(
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE);
switch (NpResult)
{
case WN_SUCCESS:
case WN_ACCESS_DENIED:
break;
case ERROR_ALREADY_EXISTS:
/*
* The file system is already running! If we are being asked for a drive mapping,
* see if it is the one we already have to decide on the error code to return.
*/
if (L'\0' != LocalNameBuf[0])
{
WCHAR ExpectRemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
WCHAR RemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
DWORD RemoteNameSize;
P = ExpectRemoteNameBuf;
*P++ = L'\\'; *P++ = L'\\';
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\\';
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
RemoteNameSize = sizeof RemoteNameBuf / sizeof(WCHAR);
NpResult = NPGetConnection(LocalNameBuf, RemoteNameBuf, &RemoteNameSize);
if (WN_SUCCESS == NpResult)
NpResult = 0 == lstrcmpW(ExpectRemoteNameBuf, RemoteNameBuf) ? WN_SUCCESS : WN_NO_NETWORK;
else
NpResult = WN_NO_NETWORK;
}
else
/* we are not being asked for a drive mapping, so whatever we have is good! */
NpResult = WN_SUCCESS;
break;
default:
NpResult = WN_NO_NETWORK;
break;
}
exit:
MemFree(PipeBuf);
#if defined(FSP_NP_CREDENTIAL_MANAGER)
if (0 != Credential)
CredFree(Credential);
#endif
return NpResult;
}
DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName, DWORD dwFlags)
{
DWORD NpResult;
PWSTR RemoteName = lpNetResource->lpRemoteName;
DWORD CredentialsKind;
WCHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1], Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
#if defined(FSP_NP_CREDENTIAL_MANAGER)
BOOL Save = TRUE;
#endif
//dwFlags |= CONNECT_INTERACTIVE | CONNECT_PROMPT; /* TESTING ONLY! */
/* CONNECT_PROMPT is only valid if CONNECT_INTERACTIVE is also set */
if (CONNECT_PROMPT == (dwFlags & (CONNECT_INTERACTIVE | CONNECT_PROMPT)))
return WN_BAD_VALUE;
/* if not CONNECT_PROMPT go ahead and attempt to NPAddConnection once */
if (0 == (dwFlags & CONNECT_PROMPT))
{
NpResult = NPAddConnection(lpNetResource, lpPassword, lpUserName);
if (WN_ACCESS_DENIED != NpResult || 0 == (dwFlags & CONNECT_INTERACTIVE))
return NpResult;
}
FspNpGetCredentialsKind(RemoteName, &CredentialsKind);
if (FSP_NP_CREDENTIALS_NONE == CredentialsKind)
return WN_CANCEL;
/* if CONNECT_INTERACTIVE keep asking the user for valid credentials or cancel */
NpResult = WN_SUCCESS;
lstrcpyW(UserName, L"UNSPECIFIED");
Password[0] = L'\0';
if (FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind)
FspNpParseUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]);
do
{
NpResult = FspNpGetCredentials(
hwndOwner, RemoteName, NpResult,
CredentialsKind,
#if defined(FSP_NP_CREDENTIAL_MANAGER)
&Save,
#else
0,
#endif
UserName, sizeof UserName / sizeof UserName[0],
Password, sizeof Password / sizeof Password[0]);
if (WN_SUCCESS != NpResult)
break;
NpResult = NPAddConnection(lpNetResource, Password, UserName);
} while (WN_ACCESS_DENIED == NpResult);
#if defined(FSP_NP_CREDENTIAL_MANAGER)
if (WN_SUCCESS == NpResult && Save)
{
CREDENTIALW Credential;
memset(&Credential, 0, sizeof Credential);
Credential.Type = CRED_TYPE_GENERIC;
Credential.Persist = CRED_PERSIST_LOCAL_MACHINE;
Credential.TargetName = RemoteName;
Credential.UserName = UserName;
Credential.CredentialBlobSize = (lstrlenW(Password) + 1) * sizeof(WCHAR);
Credential.CredentialBlob = (PVOID)Password;
CredWriteW(&Credential, 0);
}
#endif
SecureZeroMemory(Password, sizeof Password);
return NpResult;
}
DWORD APIENTRY NPCancelConnection(LPWSTR lpName, BOOL fForce)
{
DWORD NpResult;
WCHAR RemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
DWORD RemoteNameSize;
PWSTR ClassName, InstanceName, RemoteName, P;
ULONG ClassNameLen, InstanceNameLen;
PWSTR PipeBuf = 0;
if (FspNpCheckLocalName(lpName))
{
RemoteNameSize = sizeof RemoteNameBuf / sizeof(WCHAR);
NpResult = NPGetConnection(lpName, RemoteNameBuf, &RemoteNameSize);
if (WN_SUCCESS != NpResult)
return NpResult;
RemoteName = RemoteNameBuf;
}
else if (FspNpCheckRemoteName(lpName))
RemoteName = lpName;
else
return WN_BAD_NETNAME;
if (!FspNpParseRemoteName(RemoteName,
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
return WN_BAD_NETNAME;
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
if (0 == PipeBuf)
return WN_OUT_OF_MEMORY;
P = PipeBuf;
*P++ = LauncherSvcInstanceStop;
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
NpResult = FspNpCallLauncherPipe(
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE);
switch (NpResult)
{
case WN_SUCCESS:
break;
case ERROR_FILE_NOT_FOUND:
NpResult = WN_NOT_CONNECTED;
break;
default:
NpResult = WN_NO_NETWORK;
break;
}
MemFree(PipeBuf);
return NpResult;
}
typedef struct
{
DWORD Signature; /* cheap and cheerful! */
DWORD dwScope;
PWCHAR VolumeListBuf, VolumeListBufEnd, VolumeName;
DWORD LogicalDrives;
} FSP_NP_ENUM;
static inline BOOLEAN FspNpValidateEnum(FSP_NP_ENUM *Enum)
{
#if 0
return
0 != Enum &&
HeapValidate(GetProcessHeap(), 0, Enum) &&
'munE' == Enum->Signature;
#else
return
0 != Enum &&
'munE' == Enum->Signature;
#endif
}
DWORD APIENTRY NPOpenEnum(
DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCEW lpNetResource, LPHANDLE lphEnum)
{
NTSTATUS Result;
FSP_NP_ENUM *Enum = 0;
SIZE_T VolumeListSize;
switch (dwScope)
{
case RESOURCE_CONNECTED:
case RESOURCE_CONTEXT:
/* ignore lpNetResource; according to documentation it should be NULL */
break;
default:
return WN_NOT_SUPPORTED;
}
if (dwType & RESOURCETYPE_PRINT)
return WN_BAD_VALUE;
Enum = MemAlloc(sizeof *Enum);
if (0 == Enum)
return WN_OUT_OF_MEMORY;
Result = FspNpGetVolumeList(&Enum->VolumeListBuf, &VolumeListSize);
if (!NT_SUCCESS(Result))
{
MemFree(Enum);
return WN_OUT_OF_MEMORY;
}
Enum->Signature = 'munE';
Enum->dwScope = dwScope;
Enum->VolumeListBufEnd = (PVOID)((PUINT8)Enum->VolumeListBuf + VolumeListSize);
Enum->VolumeName = Enum->VolumeListBuf;
Enum->LogicalDrives = GetLogicalDrives();
*lphEnum = Enum;
return WN_SUCCESS;
}
DWORD APIENTRY NPEnumResource(
HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
{
FSP_NP_ENUM *Enum = hEnum;
DWORD NpResult;
LPNETRESOURCEW Resource; /* grows upwards */
PWCHAR Strings; /* grows downwards */
PWCHAR ProviderName = 0;
DWORD Count;
PWCHAR P, VolumePrefix;
ULONG Backslashes;
WCHAR Drive;
if (!FspNpValidateEnum(Enum))
return WN_BAD_HANDLE;
if (0 == lpcCount || 0 == lpBuffer || 0 == lpBufferSize)
return WN_BAD_VALUE;
Resource = lpBuffer;
Strings = (PVOID)((PUINT8)lpBuffer + (*lpBufferSize & ~1/* WCHAR alignment */));
Count = 0;
for (P = Enum->VolumeName; *lpcCount > Count && Enum->VolumeListBufEnd > P; P++)
{
if (L'\0' == *P)
{
/*
* Extract the VolumePrefix from the VolumeName.
*
* The VolumeName will have the following syntax:
* \Device\Volume{GUID}\Server\Share
*
* We want to extract the \Server\Share part. We will simply count backslashes and
* stop at the third one.
*/
for (Backslashes = 0, VolumePrefix = Enum->VolumeName; VolumePrefix < P; VolumePrefix++)
if (L'\\' == *VolumePrefix)
if (3 == ++Backslashes)
break;
if (3 == Backslashes)
{
Drive = FspNpGetDriveLetter(&Enum->LogicalDrives, Enum->VolumeName);
Strings -= (Drive ? 3 : 0) + 2/* backslash + term-0 */ + lstrlenW(VolumePrefix) +
(0 == ProviderName ? lstrlenW(L"" FSP_NP_NAME) + 1 : 0);
if ((PVOID)(Resource + 1) > (PVOID)Strings)
{
if (0 == Count)
{
*lpBufferSize =
(DWORD)((PUINT8)(Resource + 1) - (PUINT8)lpBuffer) +
(DWORD)((PUINT8)lpBuffer + *lpBufferSize - (PUINT8)Strings);
NpResult = WN_MORE_DATA;
}
else
{
*lpcCount = Count;
NpResult = WN_SUCCESS;
}
goto exit;
}
if (0 == ProviderName)
{
ProviderName = Strings + (Drive ? 3 : 0) + 2/* backslash + term-0 */ + lstrlenW(VolumePrefix);
lstrcpyW(ProviderName, L"" FSP_NP_NAME);
}
if (Drive)
{
Strings[0] = Drive;
Strings[1] = L':';
Strings[2] = L'\0';
Strings[3] = L'\\';
lstrcpyW(Strings + 4, VolumePrefix);
}
else
{
Strings[0] = L'\\';
lstrcpyW(Strings + 1, VolumePrefix);
}
Resource->dwScope = Enum->dwScope;
Resource->dwType = RESOURCETYPE_DISK;
Resource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
Resource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
Resource->lpLocalName = Drive ? Strings : 0;
Resource->lpRemoteName = Drive ? Strings + 3 : Strings;
Resource->lpComment = 0;
Resource->lpProvider = ProviderName;
Resource++;
Count++;
}
Enum->VolumeName = P + 1;
}
}
if (0 == Count)
NpResult = WN_NO_MORE_ENTRIES;
else
{
*lpcCount = Count;
NpResult = WN_SUCCESS;
}
exit:
return NpResult;
}
DWORD APIENTRY NPCloseEnum(HANDLE hEnum)
{
FSP_NP_ENUM *Enum = hEnum;
if (!FspNpValidateEnum(Enum))
return WN_BAD_HANDLE;
MemFree(Enum->VolumeListBuf);
MemFree(Enum);
return WN_SUCCESS;
}
NTSTATUS FspNpRegister(VOID)
{
extern HINSTANCE DllInstance;
@ -221,8 +988,29 @@ NTSTATUS FspNpRegister(VOID)
if (ERROR_SUCCESS != RegResult)
return FspNtStatusFromWin32(RegResult);
RegResult = ERROR_RESOURCE_NAME_NOT_FOUND; /* not a real resource error! */
{
PVOID VersionInfo = 0;
DWORD Size;
PWSTR Description;
Size = GetFileVersionInfoSizeW(ProviderPath, &Size/*dummy*/);
if (0 < Size)
{
VersionInfo = MemAlloc(Size);
if (0 != VersionInfo &&
GetFileVersionInfoW(ProviderPath, 0, Size, VersionInfo) &&
VerQueryValueW(VersionInfo, L"\\StringFileInfo\\040904b0\\FileDescription",
&Description, &Size))
{
Size = Size * 2 + sizeof(WCHAR);
RegResult = RegSetValueExW(RegKey,
L"Name", 0, REG_SZ, (PVOID) L"" FSP_NP_DESC, sizeof L"" FSP_NP_DESC);
L"Name", 0, REG_SZ, (PVOID)Description, Size);
}
MemFree(VersionInfo);
}
}
if (ERROR_SUCCESS != RegResult)
goto close_and_exit;
@ -253,7 +1041,7 @@ NTSTATUS FspNpRegister(VOID)
{
if (L',' == *P || '\0' == *P)
{
if (CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
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)))
{
@ -316,7 +1104,7 @@ NTSTATUS FspNpUnregister(VOID)
{
if (L',' == *P || '\0' == *P)
{
if (CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
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)))
{

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -17,12 +17,37 @@
#include <dll/library.h>
static INIT_ONCE FspNtStatusInitOnce = INIT_ONCE_STATIC_INIT;
static ULONG (WINAPI *FspRtlNtStatusToDosError)(NTSTATUS Status);
static BOOL WINAPI FspNtStatusInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
HANDLE Handle;
Handle = GetModuleHandleW(L"ntdll.dll");
if (0 != Handle)
FspRtlNtStatusToDosError = (PVOID)GetProcAddress(Handle, "RtlNtStatusToDosError");
return TRUE;
}
FSP_API NTSTATUS FspNtStatusFromWin32(DWORD Error)
{
switch (Error)
{
#include "ntstatus.i"
default:
return STATUS_ACCESS_DENIED;
/* use FACILITY_NTWIN32 if able, else STATUS_ACCESS_DENIED */
return 0xffff >= Error ? (0x80070000 | Error) : STATUS_ACCESS_DENIED;
}
}
FSP_API DWORD FspWin32FromNtStatus(NTSTATUS Status)
{
InitOnceExecuteOnce(&FspNtStatusInitOnce, FspNtStatusInitialize, 0, 0);
if (0 == FspRtlNtStatusToDosError)
return ERROR_MR_MID_NOT_FOUND;
return FspRtlNtStatusToDosError(Status);
}

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the

925
src/dll/posix.c Normal file
View File

@ -0,0 +1,925 @@
/**
* @file dll/posix.c
* POSIX Interop.
*
* This file provides routines for Windows/POSIX interoperability. It is based
* on "Services for UNIX" and Cygwin. See the following documents:
*
* [PERMS]
* https://technet.microsoft.com/en-us/library/bb463216.aspx
* [WKSID]
* https://support.microsoft.com/en-us/kb/243330
* [IDMAP]
* https://cygwin.com/cygwin-ug-net/ntsec.html
* [SNAME]
* https://www.cygwin.com/cygwin-ug-net/using-specialnames.html
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dll/library.h>
#include <aclapi.h>
#define _NTDEF_
#include <ntsecapi.h>
static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...);
static INIT_ONCE FspPosixInitOnce = INIT_ONCE_STATIC_INIT;
union
{
SID V;
UINT8 B[sizeof(SID) - sizeof(DWORD) + (1 * sizeof(DWORD))];
} FspUnmappedSidBuf =
{
/* S-1-0-65534 */
.V.Revision = SID_REVISION,
.V.SubAuthorityCount = 1,
.V.IdentifierAuthority.Value[5] = 0,
.V.SubAuthority[0] = 65534,
};
static PISID FspAccountDomainSid, FspPrimaryDomainSid;
#define FspUnmappedSid (&FspUnmappedSidBuf.V)
#define FspUnmappedUid (65534)
static BOOL WINAPI FspPosixInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
static LSA_OBJECT_ATTRIBUTES Obja;
LSA_HANDLE PolicyHandle = 0;
PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = 0;
PPOLICY_DNS_DOMAIN_INFO PrimaryDomainInfo = 0;
BYTE Count;
ULONG Size;
NTSTATUS Result;
Result = LsaOpenPolicy(0, &Obja, POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle);
if (!NT_SUCCESS(Result))
goto exit;
Result = LsaQueryInformationPolicy(PolicyHandle, PolicyAccountDomainInformation,
&AccountDomainInfo);
if (NT_SUCCESS(Result) && 0 != AccountDomainInfo && 0 != AccountDomainInfo->DomainSid)
{
Count = *GetSidSubAuthorityCount(AccountDomainInfo->DomainSid);
Size = sizeof(SID) - sizeof(DWORD) + (Count * sizeof(DWORD));
FspAccountDomainSid = MemAlloc(Size);
if (0 != FspAccountDomainSid)
memcpy(FspAccountDomainSid, AccountDomainInfo->DomainSid, Size);
}
Result = LsaQueryInformationPolicy(PolicyHandle, PolicyDnsDomainInformation,
&PrimaryDomainInfo);
if (NT_SUCCESS(Result) && 0 != PrimaryDomainInfo && 0 != PrimaryDomainInfo->Sid)
{
Count = *GetSidSubAuthorityCount(PrimaryDomainInfo->Sid);
Size = sizeof(SID) - sizeof(DWORD) + (Count * sizeof(DWORD));
FspPrimaryDomainSid = MemAlloc(Size);
if (0 != FspPrimaryDomainSid)
memcpy(FspPrimaryDomainSid, PrimaryDomainInfo->Sid, Size);
}
exit:
if (0 != PrimaryDomainInfo)
LsaFreeMemory(PrimaryDomainInfo);
if (0 != AccountDomainInfo)
LsaFreeMemory(AccountDomainInfo);
if (0 != PolicyHandle)
LsaClose(PolicyHandle);
return TRUE;
}
VOID FspPosixFinalize(BOOLEAN Dynamic)
{
/*
* This function is called during DLL_PROCESS_DETACH. We must therefore keep
* finalization tasks to a minimum.
*/
if (Dynamic)
{
MemFree(FspAccountDomainSid);
MemFree(FspPrimaryDomainSid);
}
}
FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
{
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
*PSid = 0;
/*
* UID namespace partitioning (from [IDMAP] rules):
*
* 0x000000 + RID S-1-5-RID,S-1-5-32-RID
* 0x000ffe OtherSession
* 0x000fff CurrentSession
* 0x001000 * X + RID S-1-5-X-RID ([WKSID]: X=1-15,17-21,32,64,80,83)
* 0x010000 + 0x100 * X + Y S-1-X-Y ([WKSID]: X=1,2,3,4,5,9,16)
* 0x030000 + RID S-1-5-21-X-Y-Z-RID
* 0x060000 + RID S-1-16-RID
* 0x100000 + RID S-1-5-21-X-Y-Z-RID
*/
/* [IDMAP]
* Well-known SIDs in the NT_AUTHORITY domain of the S-1-5-RID type,
* or aliases of the S-1-5-32-RID type are mapped to the uid/gid value RID.
* Examples:
* "SYSTEM" S-1-5-18 <=> uid/gid: 18
* "Users" S-1-5-32-545 <=> uid/gid: 545
*/
if (0x200 > Uid || 1000 == Uid)
*PSid = FspPosixCreateSid(5, 1, Uid);
else if (1000 > Uid)
*PSid = FspPosixCreateSid(5, 2, 32, Uid);
/* [IDMAP]
* Logon SIDs: The LogonSid of the current user's session is converted
* to the fixed uid 0xfff == 4095 and named "CurrentSession". Any other
* LogonSid is converted to the fixed uid 0xffe == 4094 and named
* "OtherSession".
*/
else if (0xfff == Uid || 0xffe == Uid)
{
/*
* Actually we do not support Logon SID's for translation.
* We need an access token to find its Logon SID and we do not have one.
*/
}
/* [IDMAP]
* Accounts from the local machine's user DB (SAM):
* S-1-5-21-X-Y-Z-RID <=> uid/gid: 0x30000 + RID
*
* Accounts from the machine's primary domain:
* S-1-5-21-X-Y-Z-RID <=> uid/gid: 0x100000 + RID
*
* Accounts from a trusted domain of the machine's primary domain:
* S-1-5-21-X-Y-Z-RID <=> uid/gid: trustPosixOffset(domain) + RID
*/
else if (0x30000 <= Uid && Uid < 0x40000)
{
if (0 != FspAccountDomainSid &&
5 == FspAccountDomainSid->IdentifierAuthority.Value[5] &&
4 == FspAccountDomainSid->SubAuthorityCount)
{
*PSid = FspPosixCreateSid(5, 5,
21,
FspAccountDomainSid->SubAuthority[1],
FspAccountDomainSid->SubAuthority[2],
FspAccountDomainSid->SubAuthority[3],
Uid - 0x30000);
}
}
else if (0x100000 <= Uid && Uid < 0x200000)
{
if (0 != FspPrimaryDomainSid &&
5 == FspPrimaryDomainSid->IdentifierAuthority.Value[5] &&
4 == FspPrimaryDomainSid->SubAuthorityCount)
{
*PSid = FspPosixCreateSid(5, 5,
21,
FspPrimaryDomainSid->SubAuthority[1],
FspPrimaryDomainSid->SubAuthority[2],
FspPrimaryDomainSid->SubAuthority[3],
Uid - 0x100000);
}
}
/*
* I am sorry, I am not going to bother with all that trustPosixOffset stuff.
* But if you need it, I accept patches :)
*/
/* [IDMAP]
* Mandatory Labels:
* S-1-16-RID <=> uid/gid: 0x60000 + RID
*/
else if (0x60000 <= Uid && Uid < 0x70000)
*PSid = FspPosixCreateSid(16, 1, Uid - 0x60000);
/* [IDMAP]
* Other well-known SIDs:
* S-1-X-Y <=> uid/gid: 0x10000 + 0x100 * X + Y
*/
else if (0x10000 <= Uid && Uid < 0x11000)
*PSid = FspPosixCreateSid((Uid - 0x10000) >> 8, 1, (Uid - 0x10000) & 0xff);
/* [IDMAP]
* Other well-known SIDs in the NT_AUTHORITY domain (S-1-5-X-RID):
* S-1-5-X-RID <=> uid/gid: 0x1000 * X + RID
*/
else if (FspUnmappedUid != Uid && 0x1000 <= Uid && Uid < 0x100000)
*PSid = FspPosixCreateSid(5, 2, Uid >> 12, Uid & 0xfff);
if (0 == *PSid)
*PSid = FspUnmappedSid;
return STATUS_SUCCESS;
}
FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
{
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
BYTE Authority;
BYTE Count;
UINT32 SubAuthority0, Rid;
*PUid = -1;
if (!IsValidSid(Sid) || 0 == (Count = *GetSidSubAuthorityCount(Sid)))
return STATUS_INVALID_SID;
Authority = GetSidIdentifierAuthority(Sid)->Value[5];
SubAuthority0 = 2 <= Count ? *GetSidSubAuthority(Sid, 0) : 0;
Rid = *GetSidSubAuthority(Sid, Count - 1);
if (5 == Authority)
{
/* [IDMAP]
* Well-known SIDs in the NT_AUTHORITY domain of the S-1-5-RID type,
* or aliases of the S-1-5-32-RID type are mapped to the uid/gid value RID.
* Examples:
* "SYSTEM" S-1-5-18 <=> uid/gid: 18
* "Users" S-1-5-32-545 <=> uid/gid: 545
*/
if (1 == Count)
*PUid = Rid;
else if (2 == Count && 32 == SubAuthority0)
*PUid = Rid;
/* [IDMAP]
* Logon SIDs: The LogonSid of the current user's session is converted
* to the fixed uid 0xfff == 4095 and named "CurrentSession". Any other
* LogonSid is converted to the fixed uid 0xffe == 4094 and named
* "OtherSession".
*/
else if (2 <= Count && 5 == SubAuthority0)
{
/*
* Actually we do not support Logon SID's for translation.
* We need an access token to find its Logon SID and we do not have one.
*/
}
/* [IDMAP]
* Accounts from the local machine's user DB (SAM):
* S-1-5-21-X-Y-Z-RID <=> uid/gid: 0x30000 + RID
*
* Accounts from the machine's primary domain:
* S-1-5-21-X-Y-Z-RID <=> uid/gid: 0x100000 + RID
*
* Accounts from a trusted domain of the machine's primary domain:
* S-1-5-21-X-Y-Z-RID <=> uid/gid: trustPosixOffset(domain) + RID
*/
else if (5 <= Count && 21 == SubAuthority0)
{
/*
* The order is important! A server that is also a domain controller
* has PrimaryDomainSid == AccountDomainSid.
*/
BOOL EqualDomains = FALSE;
if (0 != FspPrimaryDomainSid &&
EqualDomainSid(FspPrimaryDomainSid, Sid, &EqualDomains) && EqualDomains)
*PUid = 0x100000 + Rid;
else if (0 != FspAccountDomainSid &&
EqualDomainSid(FspAccountDomainSid, Sid, &EqualDomains) && EqualDomains)
*PUid = 0x30000 + Rid;
/*
* I am sorry, I am not going to bother with all that trustPosixOffset stuff.
* But if you need it, I accept patches :)
*/
}
/* [IDMAP]
* Other well-known SIDs in the NT_AUTHORITY domain (S-1-5-X-RID):
* S-1-5-X-RID <=> uid/gid: 0x1000 * X + RID
*/
else if (2 == Count)
{
*PUid = 0x1000 * SubAuthority0 + Rid;
}
}
else if (16 == Authority)
{
/* [IDMAP]
* Mandatory Labels:
* S-1-16-RID <=> uid/gid: 0x60000 + RID
*/
*PUid = 0x60000 + Rid;
}
else if (
FspUnmappedSid->IdentifierAuthority.Value[5] != Authority ||
FspUnmappedSid->SubAuthority[0] != Rid)
{
/* [IDMAP]
* Other well-known SIDs:
* S-1-X-Y <=> uid/gid: 0x10000 + 0x100 * X + Y
*/
*PUid = 0x10000 + 0x100 * Authority + Rid;
}
if (-1 == *PUid)
*PUid = FspUnmappedUid;
return STATUS_SUCCESS;
}
static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...)
{
PISID Sid;
SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
va_list ap;
Sid = MemAlloc(sizeof(SID) - sizeof(DWORD) + (Count * sizeof(DWORD)));
if (0 == Sid)
return 0;
memset(&IdentifierAuthority, 0, sizeof IdentifierAuthority);
IdentifierAuthority.Value[5] = Authority;
InitializeSid(Sid, &IdentifierAuthority, (BYTE)Count);
va_start(ap, Count);
for (ULONG Index = 0; Count > Index; Index++)
Sid->SubAuthority[Index] = va_arg(ap, DWORD);
va_end(ap);
return Sid;
}
FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)())
{
if (FspUnmappedSid == Sid)
;
else if ((NTSTATUS (*)())FspPosixMapUidToSid == CreateFunc)
MemFree(Sid);
}
/* [PERMS]
* By default, all access-allowed ACEs will contain the following Windows access rights.
*/
#define FspPosixDefaultPerm \
(SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA)
/* [PERMS]
* There are some additional Windows access rights that are always set in the
* access-allowed ACE for the file's owner.
*/
#define FspPosixOwnerDefaultPerm \
(FspPosixDefaultPerm | DELETE | WRITE_DAC | WRITE_OWNER | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
static inline ACCESS_MASK FspPosixMapPermissionToAccessMask(UINT32 Mode, UINT32 Perm)
{
/*
* We use only the 0040000 (directory) and 0001000 (sticky) bits from Mode.
* If this is a directory and it does not have the sticky bit set (and the
* write permission is enabled) we add FILE_DELETE_CHILD access.
*
* When calling this function for computing the Owner access mask, we always
* pass Mode & ~0001000 to remove the sticky bit and thus add FILE_DELETE_CHILD
* access if it is a directory. For Group and World permissions we do not
* remove the sticky bit as we do not want FILE_DELETE_CHILD access in these
* cases.
*/
ACCESS_MASK DeleteChild = 0040000 == (Mode & 0041000) ? FILE_DELETE_CHILD : 0;
/* [PERMS]
* Additionally, if the UNIX read permission bit is set, then the Windows
* File_Read access right is added to the ACE. When enabled on directories,
* this allows them to be searched. When enabled on files, it allows the data
* to be viewed. If the UNIX execute permission bit is set, then the Windows
* File_Execute access right is added to the ACE. On directories this enables
* the directory to be traversed. On files it allows the file to be executed.
*
* If the UNIX write permission bit is set then the following Windows access
* rights are added: Write_Data, Write_Attributes, Append_Data, Delete_Child.
*
* Notice how Windows has four separate access rights to UNIX's single "write"
* permission. In UNIX, the write permission bit on a directory permits both
* the creation and removal of new files or sub-directories in the directory.
* On Windows, the Write_Data access right controls the creation of new
* sub-files and the Delete_Child access right controls the deletion. The
* Delete_Child access right is not always present in all ACEs. In the case
* where the UNIX sticky-bit is enabled, the Delete_Child bit will be set only
* in the file owner ACE and no other ACEs. This will permit only the directory
* owner to remove any files or sub-directories from this directory regardless
* of the ownership on these sub-files. Other users will be allowed to delete
* files or sub-directories only if they are granted the Delete access right
* in an ACE of the file or sub-directory itself.
*/
return
((Perm & 4) ? FILE_READ_DATA : 0) |
((Perm & 2) ? FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | FILE_APPEND_DATA | DeleteChild : 0) |
((Perm & 1) ? FILE_EXECUTE : 0);
}
FSP_API NTSTATUS FspPosixMapPermissionsToSecurityDescriptor(
UINT32 Uid, UINT32 Gid, UINT32 Mode,
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
{
PSID OwnerSid = 0, GroupSid = 0, WorldSid = 0;
UINT32 OwnerPerm, OwnerDeny, GroupPerm, GroupDeny, WorldPerm;
PACL Acl = 0;
SECURITY_DESCRIPTOR SecurityDescriptor;
PSECURITY_DESCRIPTOR RelativeSecurityDescriptor = 0;
ULONG Size;
NTSTATUS Result;
*PSecurityDescriptor = 0;
Result = FspPosixMapUidToSid(Uid, &OwnerSid);
if (!NT_SUCCESS(Result))
goto exit;
Result = FspPosixMapUidToSid(Gid, &GroupSid);
if (!NT_SUCCESS(Result))
goto exit;
Result = FspPosixMapUidToSid(0x10100, &WorldSid);
if (!NT_SUCCESS(Result))
goto exit;
OwnerPerm = (Mode & 0700) >> 6;
GroupPerm = (Mode & 0070) >> 3;
WorldPerm = (Mode & 0007);
/* [PERMS]
* What about the case where both owner and group are the same SID and
* a chmod(1) request is made where the owner and the group permission
* bits are different?. In this case, the most restrictive permissions
* are chosen and assigned to both ACEs.
*/
if (EqualSid(OwnerSid, GroupSid))
OwnerPerm = GroupPerm = OwnerPerm & GroupPerm;
/* [PERMS]
* There are situations where one or two access-denied ACEs must be added
* to the DACL. If you recall, the UNIX file access algorithm makes a
* distinction between owner, group and other such that each is unique
* and the ID used in an access request can only match one of them.
* However, the Windows file access algorithm makes no such distinction
* while scanning the DACL. If the ID in the request is granted permission
* in any of the access-allowed ACEs then the request is permitted. This
* is a problem when the owner permissions are specified to be more
* restrictive than say the group or the other permissions (eg. when a
* "chmod 577 foobar" is executed) So, to support UNIX semantics we must
* examine the permissions granted to Everyone and if they are more
* permissive than those in the group permissions then a special
* access-denied ACE must be created for the group. And similarly, if
* either the group or other permissions are more permissive than the
* owner permissions, then an access-denied ACE must be created for the owner.
*/
OwnerDeny = (OwnerPerm ^ GroupPerm) & GroupPerm;
OwnerDeny |= (OwnerPerm ^ WorldPerm) & WorldPerm;
GroupDeny = (GroupPerm ^ WorldPerm) & WorldPerm;
Size = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) * 3 +
sizeof(ACCESS_DENIED_ACE) * (!!OwnerDeny + !!GroupDeny);
Size += GetLengthSid(OwnerSid) - sizeof(DWORD);
Size += GetLengthSid(GroupSid) - sizeof(DWORD);
Size += GetLengthSid(WorldSid) - sizeof(DWORD);
if (OwnerDeny)
Size += GetLengthSid(OwnerSid) - sizeof(DWORD);
if (GroupDeny)
Size += GetLengthSid(GroupSid) - sizeof(DWORD);
Size += sizeof(DWORD) - 1;
Size &= ~(sizeof(DWORD) - 1);
Acl = MemAlloc(Size);
if (0 == Acl)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!InitializeAcl(Acl, Size, ACL_REVISION))
goto lasterror;
if (!AddAccessAllowedAce(Acl, ACL_REVISION,
FspPosixOwnerDefaultPerm | FspPosixMapPermissionToAccessMask(Mode & ~001000, OwnerPerm),
OwnerSid))
goto lasterror;
if (OwnerDeny)
{
if (!AddAccessDeniedAce(Acl, ACL_REVISION,
~FILE_WRITE_ATTRIBUTES & FspPosixMapPermissionToAccessMask(Mode & ~001000, OwnerDeny),
OwnerSid))
goto lasterror;
}
if (!AddAccessAllowedAce(Acl, ACL_REVISION,
FspPosixDefaultPerm | FspPosixMapPermissionToAccessMask(Mode, GroupPerm),
GroupSid))
goto lasterror;
if (GroupDeny)
{
if (!AddAccessDeniedAce(Acl, ACL_REVISION,
FspPosixMapPermissionToAccessMask(Mode, GroupDeny),
GroupSid))
goto lasterror;
}
if (!AddAccessAllowedAce(Acl, ACL_REVISION,
FspPosixDefaultPerm | FspPosixMapPermissionToAccessMask(Mode, WorldPerm),
WorldSid))
goto lasterror;
if (!InitializeSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
goto lasterror;
if (!SetSecurityDescriptorControl(&SecurityDescriptor, SE_DACL_PROTECTED, SE_DACL_PROTECTED))
goto lasterror;
if (!SetSecurityDescriptorOwner(&SecurityDescriptor, OwnerSid, FALSE))
goto lasterror;
if (!SetSecurityDescriptorGroup(&SecurityDescriptor, GroupSid, FALSE))
goto lasterror;
if (!SetSecurityDescriptorDacl(&SecurityDescriptor, TRUE, Acl, FALSE))
goto lasterror;
Size = 0;
if (!MakeSelfRelativeSD(&SecurityDescriptor, 0, &Size) &&
ERROR_INSUFFICIENT_BUFFER != GetLastError())
goto lasterror;
RelativeSecurityDescriptor = MemAlloc(Size);
if (0 == RelativeSecurityDescriptor)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!MakeSelfRelativeSD(&SecurityDescriptor, RelativeSecurityDescriptor, &Size))
goto lasterror;
*PSecurityDescriptor = RelativeSecurityDescriptor;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
MemFree(RelativeSecurityDescriptor);
MemFree(Acl);
if (0 != WorldSid)
FspDeleteSid(WorldSid, FspPosixMapUidToSid);
if (0 != GroupSid)
FspDeleteSid(GroupSid, FspPosixMapUidToSid);
if (0 != OwnerSid)
FspDeleteSid(OwnerSid, FspPosixMapUidToSid);
return Result;
lasterror:
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
static inline UINT32 FspPosixMapAccessMaskToPermission(ACCESS_MASK AccessMask)
{
/* [PERMS]
* Once all the granted Windows access right bits have been collected,
* then the UNIX permission bits are assembled. For each class, if the
* Read_Data bit is granted, then the corresponding "r" permission bit
* is set. If both the Write_Data and Append_Data access rights are
* granted then the "w" permission bit is set. And finally, if the
* Execute access right is granted, then the "x" permission bit is set.
*/
return
((AccessMask & FILE_READ_DATA) ? 4 : 0) |
((FILE_WRITE_DATA | FILE_APPEND_DATA) ==
(AccessMask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? 2 : 0) |
((AccessMask & FILE_EXECUTE) ? 1 : 0);
}
FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
PSECURITY_DESCRIPTOR SecurityDescriptor,
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode)
{
PSID OwnerSid = 0, GroupSid = 0, WorldSid = 0, AuthUsersSid = 0;
BOOL Defaulted, DaclPresent;
PACL Acl = 0;
ACL_SIZE_INFORMATION AclSizeInfo;
PACE_HEADER Ace;
PSID AceSid;
DWORD AceAccessMask;
DWORD OwnerAllow, OwnerDeny, GroupAllow, GroupDeny, WorldAllow, WorldDeny;
UINT32 Uid, Gid, Mode;
NTSTATUS Result;
*PUid = 0;
*PGid = 0;
*PMode = 0;
if (!GetSecurityDescriptorOwner(SecurityDescriptor, &OwnerSid, &Defaulted))
goto lasterror;
if (!GetSecurityDescriptorGroup(SecurityDescriptor, &GroupSid, &Defaulted))
goto lasterror;
if (!GetSecurityDescriptorDacl(SecurityDescriptor, &DaclPresent, &Acl, &Defaulted))
goto lasterror;
Result = FspPosixMapSidToUid(OwnerSid, &Uid);
if (!NT_SUCCESS(Result))
goto exit;
Result = FspPosixMapSidToUid(GroupSid, &Gid);
if (!NT_SUCCESS(Result))
goto exit;
if (0 != Acl)
{
Result = FspPosixMapUidToSid(0x10100, &WorldSid);
if (!NT_SUCCESS(Result))
goto exit;
Result = FspPosixMapUidToSid(11, &AuthUsersSid);
if (!NT_SUCCESS(Result))
goto exit;
OwnerAllow = OwnerDeny = GroupAllow = GroupDeny = WorldAllow = WorldDeny = 0;
if (!GetAclInformation(Acl, &AclSizeInfo, sizeof AclSizeInfo, AclSizeInformation))
goto lasterror;
/* [PERMS]
* For each of the ACEs in the file's DACL
*/
for (ULONG Index = 0; AclSizeInfo.AceCount > Index; Index++)
{
if (!GetAce(Acl, Index, &Ace))
goto lasterror;
/* [PERMS]
* Ignore the ACE if it is not an access-denied or access-allowed type.
*/
if (ACCESS_ALLOWED_ACE_TYPE == Ace->AceType)
{
AceSid = &((PACCESS_ALLOWED_ACE)Ace)->SidStart;
AceAccessMask = ((PACCESS_ALLOWED_ACE)Ace)->Mask;
}
else if (ACCESS_DENIED_ACE_TYPE == Ace->AceType)
{
AceSid = &((PACCESS_DENIED_ACE)Ace)->SidStart;
AceAccessMask = ((PACCESS_DENIED_ACE)Ace)->Mask;
}
else
continue;
/* [PERMS]
* If the ACE contains the Authenticated Users SID or the World SID then
* add the allowed or denied access right bits into the "owner", "group"
* and "other" collections.
*/
if (EqualSid(WorldSid, AceSid) || EqualSid(AuthUsersSid, AceSid))
{
/* [PERMS]
* If this is an access-denied ACE, then add each access right to the set
* of denied rights in each collection but only if the access right is not
* already present in the set of granted rights in that collection. Similarly
* If this is an access-allowed ACE, then add each access right to the set
* of granted rights in each collection but only if the access right is not
* already present in the set of denied rights in that collection.
*/
if (ACCESS_ALLOWED_ACE_TYPE == Ace->AceType)
{
WorldAllow |= AceAccessMask & ~WorldDeny;
GroupAllow |= AceAccessMask & ~GroupDeny;
OwnerAllow |= AceAccessMask & ~OwnerDeny;
}
else //if (ACCESS_DENIED_ACE_TYPE == Ace->AceType)
{
WorldDeny |= AceAccessMask & ~WorldAllow;
GroupDeny |= AceAccessMask & ~GroupAllow;
OwnerDeny |= AceAccessMask & ~OwnerAllow;
}
}
else
{
/* [PERMS]
* Note that if the file owner and file group SIDs are the same,
* then the access rights are saved in both the "owner" and "group"
* collections.
*/
/* [PERMS]
* If the ACE contains the file's group SID, then save the access rights
* in the "group" collection as appropriate in the corresponding set of
* granted or denied rights (as described above).
*/
if (EqualSid(GroupSid, AceSid))
{
if (ACCESS_ALLOWED_ACE_TYPE == Ace->AceType)
GroupAllow |= AceAccessMask & ~GroupDeny;
else //if (ACCESS_DENIED_ACE_TYPE == Ace->AceType)
GroupDeny |= AceAccessMask & ~GroupAllow;
}
/* [PERMS]
* If the ACE contains the file's owner SID, then save the access rights
* in the "owner" collection as appropriate in the corresponding set of
* granted or denied rights (as described above).
*/
if (EqualSid(OwnerSid, AceSid))
{
if (ACCESS_ALLOWED_ACE_TYPE == Ace->AceType)
OwnerAllow |= AceAccessMask & ~OwnerDeny;
else //if (ACCESS_DENIED_ACE_TYPE == Ace->AceType)
OwnerDeny |= AceAccessMask & ~OwnerAllow;
}
}
}
Mode =
(FspPosixMapAccessMaskToPermission(OwnerAllow) << 6) |
(FspPosixMapAccessMaskToPermission(GroupAllow) << 3) |
(FspPosixMapAccessMaskToPermission(WorldAllow));
if (0 != (OwnerAllow & FILE_DELETE_CHILD) &&
(
(0 == (GroupAllow & FILE_DELETE_CHILD) && 0 != (Mode & 0000020)) ||
(0 == (WorldAllow & FILE_DELETE_CHILD) && 0 != (Mode & 0000002))
))
Mode |= 0001000; /* sticky bit */
}
else
Mode = 0777;
*PUid = Uid;
*PGid = Gid;
*PMode = Mode;
Result = STATUS_SUCCESS;
exit:
if (0 != AuthUsersSid)
FspDeleteSid(AuthUsersSid, FspPosixMapUidToSid);
if (0 != WorldSid)
FspDeleteSid(WorldSid, FspPosixMapUidToSid);
return Result;
lasterror:
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
/*
* Services for Macintosh and Cygwin compatible filename transformation:
* Transform characters invalid for Windows filenames to the Unicode
* private use area in the U+F0XX range.
*
* The invalid maps are produced by the following Python script:
* reserved = ['<', '>', ':', '"', '\\', '|', '?', '*']
* l = [str(int(0 < i < 32 or chr(i) in reserved)) for i in xrange(0, 128)]
* print "0x%08x" % int("".join(l[0:32]), 2)
* print "0x%08x" % int("".join(l[32:64]), 2)
* print "0x%08x" % int("".join(l[64:96]), 2)
* print "0x%08x" % int("".join(l[96:128]), 2)
*/
static UINT32 FspPosixInvalidPathChars[4] =
{
0x7fffffff,
0x2020002b,
0x00000008,
0x00000008,
};
FSP_API NTSTATUS FspPosixMapWindowsToPosixPathEx(PWSTR WindowsPath, char **PPosixPath,
BOOLEAN Translate)
{
NTSTATUS Result;
ULONG Size;
char *PosixPath = 0, *p, *q;
*PPosixPath = 0;
Size = WideCharToMultiByte(CP_UTF8, 0, WindowsPath, -1, 0, 0, 0, 0);
if (0 == Size)
goto lasterror;
PosixPath = MemAlloc(Size);
if (0 == PosixPath)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
Size = WideCharToMultiByte(CP_UTF8, 0, WindowsPath, -1, PosixPath, Size, 0, 0);
if (0 == Size)
goto lasterror;
if (Translate)
{
for (p = PosixPath, q = p; *p; p++)
{
unsigned char c = *p;
if ('\\' == c)
*q++ = '/';
/* encode characters in the Unicode private use area: U+F0XX -> XX */
else if (0xef == c && 0x80 == (0xfc & p[1]) && 0x80 == (0xc0 & p[2]))
{
c = ((p[1] & 0x3) << 6) | (p[2] & 0x3f);
if (128 > c && (FspPosixInvalidPathChars[c >> 5] & (0x80000000 >> (c & 0x1f))))
*q++ = c, p += 2;
else
*q++ = *p++, *q++ = *p++, *q++ = *p;
}
else
*q++ = c;
}
*q = '\0';
}
*PPosixPath = PosixPath;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
MemFree(PosixPath);
return Result;
lasterror:
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
FSP_API NTSTATUS FspPosixMapPosixToWindowsPathEx(const char *PosixPath, PWSTR *PWindowsPath,
BOOLEAN Translate)
{
NTSTATUS Result;
ULONG Size;
PWSTR WindowsPath = 0, p;
*PWindowsPath = 0;
Size = MultiByteToWideChar(CP_UTF8, 0, PosixPath, -1, 0, 0);
if (0 == Size)
goto lasterror;
WindowsPath = MemAlloc(Size * sizeof(WCHAR));
if (0 == PosixPath)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
Size = MultiByteToWideChar(CP_UTF8, 0, PosixPath, -1, WindowsPath, Size);
if (0 == Size)
goto lasterror;
if (Translate)
{
for (p = WindowsPath; *p; p++)
{
WCHAR c = *p;
if (L'/' == c)
*p = L'\\';
else if (128 > c && (FspPosixInvalidPathChars[c >> 5] & (0x80000000 >> (c & 0x1f))))
*p |= 0xf000;
}
}
*PWindowsPath = WindowsPath;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
MemFree(WindowsPath);
return Result;
lasterror:
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
FSP_API VOID FspPosixDeletePath(void *Path)
{
MemFree(Path);
}

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -50,10 +50,21 @@ static NTSTATUS FspGetSecurityByName(FSP_FILE_SYSTEM *FileSystem,
FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
BOOLEAN CheckParentDirectory, BOOLEAN AllowTraverseCheck,
BOOLEAN CheckParentOrMain, BOOLEAN AllowTraverseCheck,
UINT32 DesiredAccess, PUINT32 PGrantedAccess,
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
{
BOOLEAN CheckParentDirectory, CheckMainFile;
CheckParentDirectory = CheckMainFile = FALSE;
if (CheckParentOrMain)
{
if (!Request->Req.Create.NamedStream)
CheckParentDirectory = TRUE;
else
CheckMainFile = TRUE;
}
*PGrantedAccess = 0;
if (0 != PSecurityDescriptor)
*PSecurityDescriptor = 0;
@ -61,6 +72,10 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
if (FspFsctlTransactCreateKind != Request->Kind)
return STATUS_INVALID_PARAMETER;
if (CheckParentDirectory &&
L'\\' == ((PWSTR)Request->Buffer)[0] && L'\0' == ((PWSTR)Request->Buffer)[1])
return STATUS_INVALID_PARAMETER;
if (0 == FileSystem->Interface->GetSecurityByName ||
(!Request->Req.Create.UserMode && 0 == PSecurityDescriptor))
{
@ -72,17 +87,23 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS Result;
WCHAR Root[2] = L"\\", TraverseCheckRoot[2] = L"\\";
PWSTR FileName, Suffix, Prefix, Remain;
UINT32 FileAttributes;
UINT32 FileAttributes = 0;
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
SIZE_T SecurityDescriptorSize;
UINT8 PrivilegeSetBuf[sizeof(PRIVILEGE_SET) + 15 * sizeof(LUID_AND_ATTRIBUTES)];
PPRIVILEGE_SET PrivilegeSet = (PVOID)PrivilegeSetBuf;
DWORD PrivilegeSetLength = sizeof PrivilegeSetBuf;
UINT32 TraverseAccess;
UINT32 TraverseAccess, ParentAccess, DesiredAccess2;
UINT16 NamedStreamSave;
BOOL AccessStatus;
if (CheckParentDirectory)
FspPathSuffix((PWSTR)Request->Buffer, &FileName, &Suffix, Root);
else if (CheckMainFile)
{
((PWSTR)Request->Buffer)[Request->Req.Create.NamedStream / sizeof(WCHAR)] = L'\0';
FileName = (PWSTR)Request->Buffer;
}
else
FileName = (PWSTR)Request->Buffer;
@ -107,18 +128,54 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
break;
}
Result = FspGetSecurityByName(FileSystem, Prefix, 0,
FileAttributes = 0;
Result = FspGetSecurityByName(FileSystem, Prefix, &FileAttributes,
&SecurityDescriptor, &SecurityDescriptorSize);
/* compute the ReparsePointIndex and place it in FileAttributes now */
if (NT_SUCCESS(Result) && STATUS_REPARSE != Result &&
(FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
FileAttributes = FspPathSuffixIndex(Prefix);
FspPathCombine(FileName, Remain);
if (!NT_SUCCESS(Result))
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
{
if (STATUS_OBJECT_NAME_NOT_FOUND == Result)
Result = STATUS_OBJECT_PATH_NOT_FOUND;
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.
*/
if (0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
Result = STATUS_OBJECT_PATH_NOT_FOUND; /* use STATUS_OBJECT_PATH_INVALID? */
goto exit;
}
if (0 < SecurityDescriptorSize)
{
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, FILE_TRAVERSE,
@ -132,14 +189,13 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
}
}
FileAttributes = 0;
Result = FspGetSecurityByName(FileSystem, FileName, &FileAttributes,
&SecurityDescriptor, &SecurityDescriptorSize);
if (!NT_SUCCESS(Result))
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
goto exit;
if (Request->Req.Create.UserMode)
{
if (0 < SecurityDescriptorSize)
if (Request->Req.Create.UserMode && 0 < SecurityDescriptorSize)
{
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess,
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
@ -147,19 +203,107 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
else
Result = FspNtStatusFromWin32(GetLastError());
if (!NT_SUCCESS(Result))
{
/*
* If the desired access includes the DELETE or FILE_READ_ATTRIBUTES
* (or MAXIMUM_ALLOWED) rights we must still check with our parent to
* see if it gives us access (through the FILE_DELETE_CHILD and
* FILE_LIST_DIRECTORY rights).
*
* Does the Windows security model suck? Ermmmm...
*/
if (STATUS_ACCESS_DENIED != Result ||
0 == ((MAXIMUM_ALLOWED | DELETE | FILE_READ_ATTRIBUTES) & DesiredAccess))
goto exit;
NamedStreamSave = Request->Req.Create.NamedStream;
Request->Req.Create.NamedStream = 0;
Result = FspAccessCheck(FileSystem, Request, TRUE, FALSE,
(MAXIMUM_ALLOWED & DesiredAccess) ? (FILE_DELETE_CHILD | FILE_LIST_DIRECTORY) :
(
((DELETE & DesiredAccess) ? FILE_DELETE_CHILD : 0) |
((FILE_READ_ATTRIBUTES & DesiredAccess) ? FILE_LIST_DIRECTORY : 0)
),
&ParentAccess);
Request->Req.Create.NamedStream = NamedStreamSave;
if (!NT_SUCCESS(Result))
{
/* any failure just becomes ACCESS DENIED at this point */
Result = STATUS_ACCESS_DENIED;
goto exit;
}
/* redo the access check but remove the DELETE and/or FILE_READ_ATTRIBUTES rights */
DesiredAccess2 = DesiredAccess & ~(
((FILE_DELETE_CHILD & ParentAccess) ? DELETE : 0) |
((FILE_LIST_DIRECTORY & ParentAccess) ? FILE_READ_ATTRIBUTES : 0));
if (0 != DesiredAccess2)
{
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess2,
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
else
/* any failure just becomes ACCESS DENIED at this point */
Result = STATUS_ACCESS_DENIED;
if (!NT_SUCCESS(Result))
goto exit;
}
if (FILE_DELETE_CHILD & ParentAccess)
*PGrantedAccess |= DELETE;
if (FILE_LIST_DIRECTORY & ParentAccess)
*PGrantedAccess |= FILE_READ_ATTRIBUTES;
}
}
if (CheckParentDirectory)
{
/*
* 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.
*/
if (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
{
FileAttributes = FspPathSuffixIndex(FileName);
Result = STATUS_REPARSE;
goto exit;
}
if (0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
Result = STATUS_NOT_A_DIRECTORY;
goto exit;
}
}
else if (CheckMainFile)
{
/*
* We check to see if this is a reparse point and FILE_OPEN_REPARSE_POINT
* was not specified, in which case we return STATUS_REPARSE.
*/
if (0 != (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
0 == (Request->Req.Create.CreateOptions & FILE_OPEN_REPARSE_POINT))
{
FileAttributes = FspPathSuffixIndex(FileName);
Result = STATUS_REPARSE;
goto exit;
}
}
else
{
/*
* We check to see if this is a reparse point and FILE_OPEN_REPARSE_POINT
* was not specified, in which case we return STATUS_REPARSE.
*/
if (0 != (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
0 == (Request->Req.Create.CreateOptions & FILE_OPEN_REPARSE_POINT))
{
FileAttributes = FspPathSuffixIndex(FileName);
Result = STATUS_REPARSE;
goto exit;
}
if ((Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) &&
0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
@ -174,6 +318,8 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
}
}
if (Request->Req.Create.UserMode)
{
if (0 != (FileAttributes & FILE_ATTRIBUTE_READONLY))
{
if (DesiredAccess &
@ -192,6 +338,11 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
if (0 == SecurityDescriptorSize)
*PGrantedAccess = (MAXIMUM_ALLOWED & DesiredAccess) ?
FspFileGenericMapping.GenericAll : DesiredAccess;
if (0 != (FileAttributes & FILE_ATTRIBUTE_READONLY) &&
0 != (MAXIMUM_ALLOWED & DesiredAccess))
*PGrantedAccess &= ~(FILE_WRITE_DATA | FILE_APPEND_DATA |
FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD);
}
else
*PGrantedAccess = (MAXIMUM_ALLOWED & DesiredAccess) ?
@ -200,7 +351,9 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
Result = STATUS_SUCCESS;
exit:
if (0 != PSecurityDescriptor && 0 < SecurityDescriptorSize && NT_SUCCESS(Result))
if (STATUS_REPARSE == Result)
*PGrantedAccess = FileAttributes; /* FileAttributes contains ReparsePointIndex */
else if (0 != PSecurityDescriptor && 0 < SecurityDescriptorSize && NT_SUCCESS(Result))
*PSecurityDescriptor = SecurityDescriptor;
else
MemFree(SecurityDescriptor);
@ -212,6 +365,8 @@ exit:
if (STATUS_OBJECT_NAME_NOT_FOUND == Result)
Result = STATUS_OBJECT_PATH_NOT_FOUND;
}
else if (CheckMainFile)
((PWSTR)Request->Buffer)[Request->Req.Create.NamedStream / sizeof(WCHAR)] = L':';
return Result;
}
@ -226,6 +381,10 @@ FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
if (FspFsctlTransactCreateKind != Request->Kind)
return STATUS_INVALID_PARAMETER;
/* stream support: return NULL security descriptor when creating named stream */
if (Request->Req.Create.NamedStream)
return STATUS_SUCCESS;
if (!CreatePrivateObjectSecurity(
ParentDescriptor,
0 != Request->Req.Create.SecurityDescriptor.Offset ?
@ -306,7 +465,12 @@ FSP_API NTSTATUS FspSetSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
FSP_API VOID FspDeleteSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
NTSTATUS (*CreateFunc)())
{
if ((NTSTATUS (*)())FspAccessCheckEx == CreateFunc)
/* stream support: allow NULL security descriptors */
if (0 == SecurityDescriptor)
return;
if ((NTSTATUS (*)())FspAccessCheckEx == CreateFunc ||
(NTSTATUS (*)())FspPosixMapPermissionsToSecurityDescriptor == CreateFunc)
MemFree(SecurityDescriptor);
else
if ((NTSTATUS (*)())FspCreateSecurityDescriptor == CreateFunc ||

606
src/dll/service.c Normal file
View File

@ -0,0 +1,606 @@
/**
* @file dll/service.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dll/library.h>
enum
{
SetStatus_ServiceType = 0x0001,
SetStatus_CurrentState = 0x0002,
SetStatus_ControlsAccepted = 0x0004,
SetStatus_Win32ExitCode = 0x0008,
SetStatus_ServiceSpecificExitCode = 0x0010,
SetStatus_CheckPoint = 0x0020,
SetStatus_WaitHint = 0x0040,
AddStatus_CheckPoint = 0x0080,
GetStatus_ServiceType = 0x0100,
GetStatus_CurrentState = 0x0200,
GetStatus_ControlsAccepted = 0x0400,
GetStatus_Win32ExitCode = 0x0800,
GetStatus_ServiceSpecificExitCode = 0x1000,
GetStatus_CheckPoint = 0x2000,
GetStatus_WaitHint = 0x4000,
};
static SERVICE_TABLE_ENTRYW *FspServiceTable;
static HANDLE FspServiceConsoleModeEvent;
static UINT32 FspServiceConsoleCtrlHandlerDisabled;
static VOID FspServiceSetStatus(FSP_SERVICE *Service, ULONG Flags, SERVICE_STATUS *ServiceStatus);
static VOID WINAPI FspServiceEntry(DWORD Argc, PWSTR *Argv);
static VOID FspServiceMain(FSP_SERVICE *Service, DWORD Argc, PWSTR *Argv);
static DWORD WINAPI FspServiceCtrlHandler(
DWORD Control, DWORD EventType, PVOID EventData, PVOID Context);
static DWORD WINAPI FspServiceConsoleModeThread(PVOID Context);
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
#define FspServiceFromTable() (0 != FspServiceTable ?\
(FSP_SERVICE *)((PUINT8)FspServiceTable[0].lpServiceName - FIELD_OFFSET(FSP_SERVICE, ServiceName)) :\
0)
VOID FspServiceFinalize(BOOLEAN Dynamic)
{
/*
* This function is called during DLL_PROCESS_DETACH. We must therefore keep
* finalization tasks to a minimum.
*
* We must close our console mode event handle. We only do so when we are
* explicitly unloaded. If the process is exiting the OS will clean up for us.
*/
if (Dynamic && 0 != FspServiceConsoleModeEvent)
CloseHandle(FspServiceConsoleModeEvent);
}
FSP_API ULONG FspServiceRunEx(PWSTR ServiceName,
FSP_SERVICE_START *OnStart,
FSP_SERVICE_STOP *OnStop,
FSP_SERVICE_CONTROL *OnControl,
PVOID UserContext)
{
FSP_SERVICE *Service;
NTSTATUS Result;
ULONG ExitCode;
Result = FspServiceCreate(ServiceName, OnStart, OnStop, OnControl, &Service);
if (!NT_SUCCESS(Result))
{
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"The service %s cannot be created (Status=%lx).", Service->ServiceName, Result);
return FspWin32FromNtStatus(Result);
}
Service->UserContext = UserContext;
FspServiceAllowConsoleMode(Service);
Result = FspServiceLoop(Service);
ExitCode = FspServiceGetExitCode(Service);
FspServiceDelete(Service);
if (!NT_SUCCESS(Result))
{
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"The service %s has failed to run (Status=%lx).", Service->ServiceName, Result);
return FspWin32FromNtStatus(Result);
}
return ExitCode;
}
FSP_API NTSTATUS FspServiceCreate(PWSTR ServiceName,
FSP_SERVICE_START *OnStart,
FSP_SERVICE_STOP *OnStop,
FSP_SERVICE_CONTROL *OnControl,
FSP_SERVICE **PService)
{
FSP_SERVICE *Service;
DWORD Size;
*PService = 0;
Size = (lstrlenW(ServiceName) + 1) * sizeof(WCHAR);
Service = MemAlloc(sizeof *Service + Size);
if (0 == Service)
return STATUS_INSUFFICIENT_RESOURCES;
memset(Service, 0, sizeof *Service);
memcpy(Service->ServiceName, ServiceName, Size);
Service->OnStart = OnStart;
Service->OnStop = OnStop;
Service->OnControl = OnControl;
Service->AcceptControl = OnStop ? SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN : 0;
InitializeCriticalSection(&Service->ServiceStatusGuard);
InitializeCriticalSection(&Service->ServiceStopGuard);
*PService = Service;
return STATUS_SUCCESS;
}
FSP_API VOID FspServiceDelete(FSP_SERVICE *Service)
{
DeleteCriticalSection(&Service->ServiceStopGuard);
DeleteCriticalSection(&Service->ServiceStatusGuard);
MemFree(Service);
}
static VOID FspServiceSetStatus(FSP_SERVICE *Service, ULONG Flags, SERVICE_STATUS *ServiceStatus)
{
#define XCHG(FIELD)\
if (Flags & SetStatus_##FIELD)\
{\
DWORD Temp = ServiceStatus->dw##FIELD;\
if (Flags & GetStatus_##FIELD)\
ServiceStatus->dw##FIELD = Service->ServiceStatus.dw##FIELD;\
Service->ServiceStatus.dw##FIELD = Temp;\
}
EnterCriticalSection(&Service->ServiceStatusGuard);
//XCHG(ServiceType);
XCHG(CurrentState);
XCHG(ControlsAccepted);
XCHG(Win32ExitCode);
//XCHG(ServiceSpecificExitCode);
if (Flags & AddStatus_CheckPoint)
{
DWORD Temp = ServiceStatus->dwCheckPoint;
if (Flags & GetStatus_CheckPoint)
ServiceStatus->dwCheckPoint = Service->ServiceStatus.dwCheckPoint;
Service->ServiceStatus.dwCheckPoint += Temp;
}
else
XCHG(CheckPoint);
XCHG(WaitHint);
if (0 != Service->StatusHandle)
{
if (!SetServiceStatus(Service->StatusHandle, &Service->ServiceStatus))
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"" __FUNCTION__ ": SetServiceStatus = %ld", GetLastError());
}
else if (0 != FspServiceConsoleModeEvent &&
SERVICE_STOPPED == Service->ServiceStatus.dwCurrentState)
{
SetEvent(FspServiceConsoleModeEvent);
}
LeaveCriticalSection(&Service->ServiceStatusGuard);
#undef XCHG
}
FSP_API VOID FspServiceAllowConsoleMode(FSP_SERVICE *Service)
{
Service->AllowConsoleMode = TRUE;
}
FSP_API VOID FspServiceAcceptControl(FSP_SERVICE *Service, ULONG Control)
{
Service->AcceptControl = Control & ~SERVICE_ACCEPT_PAUSE_CONTINUE;
}
FSP_API VOID FspServiceRequestTime(FSP_SERVICE *Service, ULONG Time)
{
SERVICE_STATUS ServiceStatus;
ServiceStatus.dwCheckPoint = +1;
ServiceStatus.dwWaitHint = Time;
FspServiceSetStatus(Service,
AddStatus_CheckPoint | SetStatus_WaitHint, &ServiceStatus);
}
FSP_API VOID FspServiceSetExitCode(FSP_SERVICE *Service, ULONG ExitCode)
{
Service->ExitCode = ExitCode;
}
FSP_API ULONG FspServiceGetExitCode(FSP_SERVICE *Service)
{
return Service->ServiceStatus.dwWin32ExitCode;
}
FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service)
{
NTSTATUS Result;
SERVICE_TABLE_ENTRYW ServiceTable[2];
Service->ExitCode = NO_ERROR;
Service->ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
Service->ServiceStatus.dwCurrentState = SERVICE_STOPPED;
Service->ServiceStatus.dwControlsAccepted = 0;
Service->ServiceStatus.dwWin32ExitCode = NO_ERROR;
Service->ServiceStatus.dwServiceSpecificExitCode = 0;
Service->ServiceStatus.dwCheckPoint = 0;
Service->ServiceStatus.dwWaitHint = 0;
ServiceTable[0].lpServiceName = Service->ServiceName;
ServiceTable[0].lpServiceProc = FspServiceEntry;
ServiceTable[1].lpServiceName = 0;
ServiceTable[1].lpServiceProc = 0;
FspServiceTable = ServiceTable;
if (!StartServiceCtrlDispatcherW(ServiceTable))
{
HANDLE Thread;
PWSTR *Argv;
DWORD Argc;
DWORD WaitResult;
DWORD LastError;
LastError = GetLastError();
if (!Service->AllowConsoleMode || ERROR_FAILED_SERVICE_CONTROLLER_CONNECT != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
/* ENTER CONSOLE MODE! */
/* create/reset the console mode event and console control handler */
if (0 == FspServiceConsoleModeEvent)
{
FspServiceConsoleModeEvent = CreateEventW(0, TRUE, FALSE, 0);
if (0 == FspServiceConsoleModeEvent)
{
Result = FspNtStatusFromWin32(GetLastError());
goto console_mode_exit;
}
if (!SetConsoleCtrlHandler(FspServiceConsoleCtrlHandler, TRUE))
{
Result = FspNtStatusFromWin32(GetLastError());
goto console_mode_exit;
}
}
else
{
ResetEvent(FspServiceConsoleModeEvent);
FspServiceConsoleCtrlHandlerDisabled = 0;
MemoryBarrier();
}
/* prepare the command line arguments */
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
if (0 == Argv)
{
Result = FspNtStatusFromWin32(GetLastError());
goto console_mode_exit;
}
Argv[0] = Service->ServiceName;
/* create the console mode startup thread (mimic StartServiceCtrlDispatcherW) */
Thread = CreateThread(0, 0, FspServiceConsoleModeThread, Argv/* give ownership */, 0, 0);
if (0 == Thread)
{
LocalFree(Argv);
Result = FspNtStatusFromWin32(GetLastError());
goto console_mode_exit;
}
/* wait for the console mode startup thread to terminate */
WaitResult = WaitForSingleObject(Thread, INFINITE);
CloseHandle(Thread);
if (WAIT_OBJECT_0 != WaitResult)
{
Result = FspNtStatusFromWin32(GetLastError());
goto console_mode_exit;
}
/* wait until signaled by the console control handler */
WaitResult = WaitForSingleObject(FspServiceConsoleModeEvent, INFINITE);
if (WAIT_OBJECT_0 != WaitResult)
{
Result = FspNtStatusFromWin32(GetLastError());
goto console_mode_exit;
}
if (Service->AcceptControl & SERVICE_ACCEPT_STOP)
FspServiceCtrlHandler(SERVICE_CONTROL_STOP, 0, 0, Service);
console_mode_exit:
/*
* Turns out that if we are sleeping/waiting in the FspServiceConsoleCtrlHandler
* we cannot call SetConsoleCtrlHandler, because we will deadlock. So we cannot
* really cleanup our console control handler upon return from this function.
*
* What we do instead is disable our handler by setting a variable.
*/
FspServiceConsoleCtrlHandlerDisabled = 1;
MemoryBarrier();
}
Result = STATUS_SUCCESS;
exit:
FspServiceTable = 0;
return Result;
}
FSP_API VOID FspServiceStop(FSP_SERVICE *Service)
{
SERVICE_STATUS ServiceStatus;
BOOLEAN Stopped;
NTSTATUS Result;
if (!TryEnterCriticalSection(&Service->ServiceStopGuard))
return; /* the service is already being stopped! */
EnterCriticalSection(&Service->ServiceStatusGuard);
Stopped = SERVICE_STOPPED == Service->ServiceStatus.dwCurrentState;
LeaveCriticalSection(&Service->ServiceStatusGuard);
if (Stopped)
goto exit;
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
FspServiceSetStatus(Service,
SetStatus_CurrentState | SetStatus_CheckPoint | SetStatus_WaitHint |
GetStatus_CurrentState | GetStatus_CheckPoint | GetStatus_WaitHint,
&ServiceStatus);
Result = STATUS_SUCCESS;
if (0 != Service->OnStop)
Result = Service->OnStop(Service);
if (NT_SUCCESS(Result))
{
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = Service->ExitCode;
FspServiceSetStatus(Service,
SetStatus_CurrentState | SetStatus_Win32ExitCode, &ServiceStatus);
FspServiceLog(EVENTLOG_INFORMATION_TYPE,
L"The service %s has been stopped.", Service->ServiceName);
}
else
{
/* revert the service status */
FspServiceSetStatus(Service,
SetStatus_CurrentState | SetStatus_CheckPoint | SetStatus_WaitHint,
&ServiceStatus);
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"The service %s has failed to stop (Status=%lx).", Service->ServiceName, Result);
}
exit:
LeaveCriticalSection(&Service->ServiceStopGuard);
}
static VOID WINAPI FspServiceEntry(DWORD Argc, PWSTR *Argv)
{
FSP_SERVICE *Service;
Service = FspServiceFromTable();
if (0 == Service)
{
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"" __FUNCTION__ ": internal error: FspServiceFromTable = 0");
return;
}
Service->StatusHandle = RegisterServiceCtrlHandlerExW(Service->ServiceName,
FspServiceCtrlHandler, Service);
if (0 == Service->StatusHandle)
{
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"" __FUNCTION__ ": RegisterServiceCtrlHandlerW = %ld", GetLastError());
return;
}
FspServiceMain(Service, Argc, Argv);
}
static VOID FspServiceMain(FSP_SERVICE *Service, DWORD Argc, PWSTR *Argv)
{
SERVICE_STATUS ServiceStatus;
NTSTATUS Result;
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwControlsAccepted = 0;
FspServiceSetStatus(Service,
SetStatus_CurrentState | SetStatus_ControlsAccepted, &ServiceStatus);
Result = STATUS_SUCCESS;
if (0 != Service->OnStart)
Result = Service->OnStart(Service, Argc, Argv);
if (NT_SUCCESS(Result))
{
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwControlsAccepted = Service->AcceptControl;
FspServiceSetStatus(Service,
SetStatus_CurrentState | SetStatus_ControlsAccepted, &ServiceStatus);
FspServiceLog(EVENTLOG_INFORMATION_TYPE,
L"The service %s has been started.", Service->ServiceName);
}
else
{
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = FspWin32FromNtStatus(Result);
FspServiceSetStatus(Service,
SetStatus_CurrentState | SetStatus_Win32ExitCode, &ServiceStatus);
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"The service %s has failed to start (Status=%lx).", Service->ServiceName, Result);
}
}
static DWORD WINAPI FspServiceCtrlHandler(
DWORD Control, DWORD EventType, PVOID EventData, PVOID Context)
{
FSP_SERVICE *Service = Context;
NTSTATUS Result;
switch (Control)
{
case SERVICE_CONTROL_SHUTDOWN:
/*
* Shutdown simply falls through to Stop. If specific Shutdown handling is needed
* we need to enable this. We also need to arrange for console mode to have two
* events: one to signal Stop and another to signal Shutdown. We currently use a
* single event for both console mode controls.
*/
#if 0
Result = STATUS_NOT_IMPLEMENTED;
if (0 != Service->OnControl)
Result = Service->OnControl(Service, Control, EventType, EventData);
if (STATUS_NOT_IMPLEMENTED != Result)
return FspWin32FromNtStatus(Result);
/* fall through */
#endif
case SERVICE_CONTROL_STOP:
FspServiceStop(Service);
return NO_ERROR;
case SERVICE_CONTROL_PAUSE:
case SERVICE_CONTROL_CONTINUE:
return ERROR_CALL_NOT_IMPLEMENTED;
case SERVICE_CONTROL_INTERROGATE:
return NO_ERROR;
default:
Result = STATUS_SUCCESS;
if (0 != Service->OnControl)
Result = Service->OnControl(Service, Control, EventType, EventData);
return FspWin32FromNtStatus(Result);
}
}
static DWORD WINAPI FspServiceConsoleModeThread(PVOID Context)
{
FSP_SERVICE *Service;
PWSTR *Argv = Context;
DWORD Argc;
for (Argc = 0; 0 != Argv[Argc]; Argc++)
;
Service = FspServiceFromTable();
if (0 == Service)
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"" __FUNCTION__ ": internal error: FspServiceFromTable = 0");
else
FspServiceMain(Service, Argc, Argv);
LocalFree(Argv);
return 0;
}
/* expose FspServiceConsoleCtrlHandler so it can be used from fsp_fuse_signal_handler */
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType)
{
UINT32 Disabled = FspServiceConsoleCtrlHandlerDisabled;
MemoryBarrier();
if (Disabled)
return FALSE;
switch (CtrlType)
{
default:
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
if (0 != FspServiceConsoleModeEvent)
SetEvent(FspServiceConsoleModeEvent);
return TRUE;
case CTRL_CLOSE_EVENT:
case CTRL_SHUTDOWN_EVENT:
/*
* Returning from these events will kill the process. OTOH if we do not return timely
* the OS will kill us within 5-20 seconds. Our strategy is to wait some time (30 sec)
* to give the process some time to cleanup itself.
*
* We only do so if we have a Close event or we are interactive. If we are running as
* a service the OS will not kill us after delivering a Shutdown (or Logoff) event.
*/
if (0 != FspServiceConsoleModeEvent)
SetEvent(FspServiceConsoleModeEvent);
if (CTRL_CLOSE_EVENT == CtrlType || FspServiceIsInteractive())
Sleep(30000);
return TRUE;
case CTRL_LOGOFF_EVENT:
/* services should ignore this! */
return TRUE;
}
}
FSP_API BOOLEAN FspServiceIsInteractive(VOID)
{
/*
* Modeled after System.Environment.UserInteractive.
* See http://referencesource.microsoft.com/#mscorlib/system/environment.cs,947ad026e7cb830c
*/
static HWINSTA ProcessWindowStation;
static BOOLEAN IsInteractive;
HWINSTA CurrentWindowStation;
USEROBJECTFLAGS Flags;
CurrentWindowStation = GetProcessWindowStation();
if (0 != CurrentWindowStation && ProcessWindowStation != CurrentWindowStation)
{
if (GetUserObjectInformationW(CurrentWindowStation, UOI_FLAGS, &Flags, sizeof Flags, 0))
IsInteractive = 0 != (Flags.dwFlags & WSF_VISIBLE);
ProcessWindowStation = CurrentWindowStation;
}
return IsInteractive;
}
FSP_API VOID FspServiceLog(ULONG Type, PWSTR Format, ...)
{
va_list ap;
va_start(ap, Format);
FspServiceLogV(Type, Format, ap);
va_end(ap);
}
FSP_API VOID FspServiceLogV(ULONG Type, PWSTR Format, va_list ap)
{
if (FspServiceIsInteractive())
{
WCHAR BufW[1024];
/* wvsprintfW is only safe with a 1024 WCHAR buffer */
PSTR BufA;
DWORD Length;
wvsprintfW(BufW, Format, ap);
BufW[(sizeof BufW / sizeof BufW[0]) - 1] = L'\0';
Length = lstrlenW(BufW);
BufA = MemAlloc(Length * 3 + 1/* '\n' */);
if (0 != BufA)
{
Length = WideCharToMultiByte(CP_UTF8, 0, BufW, Length, BufA, Length * 3 + 1/* '\n' */,
0, 0);
if (0 < Length)
{
BufA[Length++] = '\n';
WriteFile(GetStdHandle(STD_ERROR_HANDLE), BufA, Length, &Length, 0);
}
MemFree(BufA);
}
}
else
FspEventLogV(Type, Format, ap);
}

165
src/dll/util.c Normal file
View File

@ -0,0 +1,165 @@
/**
* @file dll/util.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dll/library.h>
#include <aclapi.h>
static INIT_ONCE FspDiagIdentInitOnce = INIT_ONCE_STATIC_INIT;
static WCHAR FspDiagIdentBuf[20] = L"UNKNOWN";
static BOOL WINAPI FspDiagIdentInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
WCHAR ModuleFileName[MAX_PATH];
WCHAR Root[2] = L"\\";
PWSTR Parent, ModuleBaseName;
if (0 != GetModuleFileNameW(0, ModuleFileName, sizeof ModuleFileName / sizeof(WCHAR)))
FspPathSuffix(ModuleFileName, &Parent, &ModuleBaseName, Root);
else
lstrcpyW(ModuleBaseName = ModuleFileName, L"UNKNOWN");
for (PWSTR P = ModuleBaseName, Dot = 0;; P++)
{
if (L'\0' == *P)
{
if (0 != Dot)
*Dot = L'\0';
break;
}
if (L'.' == *P)
Dot = P;
}
memcpy(FspDiagIdentBuf, ModuleBaseName, sizeof FspDiagIdentBuf);
FspDiagIdentBuf[(sizeof FspDiagIdentBuf / sizeof(WCHAR)) - 1] = L'\0';
return TRUE;
}
PWSTR FspDiagIdent(VOID)
{
/* internal only: get a diagnostic identifier (eventlog, debug) */
InitOnceExecuteOnce(&FspDiagIdentInitOnce, FspDiagIdentInitialize, 0, 0);
return FspDiagIdentBuf;
}
FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout,
PSID Sid)
{
NTSTATUS Result;
HANDLE Pipe = INVALID_HANDLE_VALUE;
DWORD PipeMode;
Pipe = CreateFileW(PipeName,
GENERIC_READ | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, 0);
if (INVALID_HANDLE_VALUE == Pipe)
{
if (ERROR_PIPE_BUSY != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
WaitNamedPipeW(PipeName, Timeout);
Pipe = CreateFileW(PipeName,
GENERIC_READ | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, 0);
if (INVALID_HANDLE_VALUE == Pipe)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
if (0 != Sid)
{
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PSID OwnerSid, WellKnownSid = 0;
DWORD SidSize, LastError;
/* if it is a small number treat it like a well known SID */
if (1024 > (INT_PTR)Sid)
{
SidSize = SECURITY_MAX_SID_SIZE;
WellKnownSid = MemAlloc(SidSize);
if (0 == WellKnownSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto sid_exit;
}
if (!CreateWellKnownSid((INT_PTR)Sid, 0, WellKnownSid, &SidSize))
{
Result = FspNtStatusFromWin32(GetLastError());
goto sid_exit;
}
}
LastError = GetSecurityInfo(Pipe, SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION, &OwnerSid, 0, 0, 0, &SecurityDescriptor);
if (0 != LastError)
{
Result = FspNtStatusFromWin32(GetLastError());
goto sid_exit;
}
if (!EqualSid(OwnerSid, WellKnownSid ? WellKnownSid : Sid))
{
Result = STATUS_ACCESS_DENIED;
goto sid_exit;
}
Result = STATUS_SUCCESS;
sid_exit:
MemFree(WellKnownSid);
LocalFree(SecurityDescriptor);
if (!NT_SUCCESS(Result))
goto exit;
}
PipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
if (!SetNamedPipeHandleState(Pipe, &PipeMode, 0, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (!TransactNamedPipe(Pipe, InBuffer, InBufferSize, OutBuffer, OutBufferSize,
PBytesTransferred, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Result = STATUS_SUCCESS;
exit:
if (INVALID_HANDLE_VALUE != Pipe)
CloseHandle(Pipe);
return Result;
}

37
src/dll/version.rc Normal file
View File

@ -0,0 +1,37 @@
#include <winver.h>
#define STR(x) STR_(x)
#define STR_(x) #x
VS_VERSION_INFO VERSIONINFO
FILEVERSION MyVersionWithCommas
PRODUCTVERSION MyVersionWithCommas
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0
#endif
FILEOS VOS_NT
FILETYPE VFT_DLL
FILESUBTYPE 0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", STR(MyCompanyName)
VALUE "FileDescription", STR(MyDescription)
VALUE "FileVersion", STR(MyVersion)
VALUE "InternalName", "winfsp.dll"
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "winfsp.dll"
VALUE "ProductName", STR(MyProductName)
VALUE "ProductVersion", STR(MyVersion)
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

View File

@ -0,0 +1,37 @@
#include <winver.h>
#define STR(x) STR_(x)
#define STR_(x) #x
VS_VERSION_INFO VERSIONINFO
FILEVERSION MyVersionWithCommas
PRODUCTVERSION MyVersionWithCommas
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0
#endif
FILEOS VOS_NT
FILETYPE VFT_APP
FILESUBTYPE 0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", STR(MyCompanyName)
VALUE "FileDescription", STR(MyDescription)
VALUE "FileVersion", STR(MyVersion)
VALUE "InternalName", "launchctl.exe"
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "launchctl.exe"
VALUE "ProductName", STR(MyProductName)
VALUE "ProductVersion", STR(MyVersion)
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

296
src/launcher/launchctl.c Normal file
View File

@ -0,0 +1,296 @@
/**
* @file launcher/launchctl.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <launcher/launcher.h>
#define PROGNAME "launchctl"
#define info(format, ...) printlog(GetStdHandle(STD_OUTPUT_HANDLE), format, __VA_ARGS__)
#define warn(format, ...) printlog(GetStdHandle(STD_ERROR_HANDLE), format, __VA_ARGS__)
#define fatal(ExitCode, format, ...) (warn(format, __VA_ARGS__), ExitProcess(ExitCode))
static void vprintlog(HANDLE h, const char *format, va_list ap)
{
char buf[1024];
/* wvsprintf is only safe with a 1024 byte buffer */
size_t len;
DWORD BytesTransferred;
wvsprintfA(buf, format, ap);
buf[sizeof buf - 1] = '\0';
len = lstrlenA(buf);
buf[len++] = '\n';
WriteFile(h, buf, (DWORD)len, &BytesTransferred, 0);
}
static void printlog(HANDLE h, const char *format, ...)
{
va_list ap;
va_start(ap, format);
vprintlog(h, format, ap);
va_end(ap);
}
static void usage(void)
{
fatal(ERROR_INVALID_PARAMETER,
"usage: %s COMMAND ARGS\n"
"\n"
"commands:\n"
" start ClassName InstanceName Args...\n"
" startWithSecret ClassName InstanceName Args... Secret\n"
" stop ClassName InstanceName\n"
" info ClassName InstanceName\n"
" list\n",
PROGNAME);
}
static int call_pipe_and_report(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
{
NTSTATUS Result;
DWORD LastError, BytesTransferred;
Result = FspCallNamedPipeSecurely(L"" LAUNCHER_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize,
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, LAUNCHER_PIPE_OWNER);
LastError = FspWin32FromNtStatus(Result);
if (0 != LastError)
warn("KO CallNamedPipe = %ld", LastError);
else if (sizeof(WCHAR) > BytesTransferred)
warn("KO launcher: empty buffer");
else if (LauncherSuccess == PipeBuf[0])
{
if (sizeof(WCHAR) == BytesTransferred)
info("OK");
else
{
ULONG Count = 0;
for (PWSTR P = PipeBuf, PipeBufEnd = P + BytesTransferred / sizeof(WCHAR);
PipeBufEnd > P; P++)
if (L'\0' == *P)
{
/* print a newline every 2 nulls; this works for both list and info */
*P = 1 == Count % 2 ? L'\n' : L' ';
Count++;
}
if (BytesTransferred < RecvSize)
PipeBuf[BytesTransferred / sizeof(WCHAR)] = L'\0';
else
PipeBuf[RecvSize / sizeof(WCHAR) - 1] = L'\0';
info("OK\n%S", PipeBuf + 1);
}
}
else if (LauncherFailure == PipeBuf[0])
{
if (BytesTransferred < RecvSize)
PipeBuf[BytesTransferred / sizeof(WCHAR)] = L'\0';
else
PipeBuf[RecvSize / sizeof(WCHAR) - 1] = L'\0';
info("KO launcher: error %S", PipeBuf + 1);
}
else
warn("KO launcher: corrupted buffer", 0);
return LastError;
}
int start(PWSTR PipeBuf, ULONG PipeBufSize,
PWSTR ClassName, PWSTR InstanceName, DWORD Argc, PWSTR *Argv,
BOOLEAN HasSecret)
{
PWSTR P;
DWORD ClassNameSize, InstanceNameSize, ArgvSize;
ClassNameSize = lstrlenW(ClassName) + 1;
InstanceNameSize = lstrlenW(InstanceName) + 1;
ArgvSize = 0;
for (DWORD Argi = 0; Argc > Argi; Argi++)
ArgvSize += lstrlenW(Argv[Argi]) + 1;
if (PipeBufSize < (1 + ClassNameSize + InstanceNameSize + ArgvSize) * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER;
P = PipeBuf;
*P++ = HasSecret ? LauncherSvcInstanceStartWithSecret : LauncherSvcInstanceStart;
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
for (DWORD Argi = 0; Argc > Argi; Argi++)
{
ArgvSize = lstrlenW(Argv[Argi]) + 1;
memcpy(P, Argv[Argi], ArgvSize * sizeof(WCHAR)); P += ArgvSize;
}
return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize);
}
int stop(PWSTR PipeBuf, ULONG PipeBufSize,
PWSTR ClassName, PWSTR InstanceName)
{
PWSTR P;
DWORD ClassNameSize, InstanceNameSize;
ClassNameSize = lstrlenW(ClassName) + 1;
InstanceNameSize = lstrlenW(InstanceName) + 1;
if (PipeBufSize < (1 + ClassNameSize + InstanceNameSize) * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER;
P = PipeBuf;
*P++ = LauncherSvcInstanceStop;
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize);
}
int getinfo(PWSTR PipeBuf, ULONG PipeBufSize,
PWSTR ClassName, PWSTR InstanceName)
{
PWSTR P;
DWORD ClassNameSize, InstanceNameSize;
ClassNameSize = lstrlenW(ClassName) + 1;
InstanceNameSize = lstrlenW(InstanceName) + 1;
if (PipeBufSize < (1 + ClassNameSize + InstanceNameSize) * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER;
P = PipeBuf;
*P++ = LauncherSvcInstanceInfo;
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize);
}
int list(PWSTR PipeBuf, ULONG PipeBufSize)
{
PWSTR P;
if (PipeBufSize < 1 * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER;
P = PipeBuf;
*P++ = LauncherSvcInstanceList;
return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize);
}
int quit(PWSTR PipeBuf, ULONG PipeBufSize)
{
/* works only against DEBUG version of launcher */
PWSTR P;
if (PipeBufSize < 1 * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER;
P = PipeBuf;
*P++ = LauncherQuit;
return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize);
}
int wmain(int argc, wchar_t **argv)
{
PWSTR PipeBuf = 0;
/* allocate our PipeBuf early on; freed on process exit by the system */
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
if (0 == PipeBuf)
return ERROR_NO_SYSTEM_RESOURCES;
argc--;
argv++;
if (0 == argc)
usage();
if (0 == lstrcmpW(L"start", argv[0]))
{
if (3 > argc || argc > 12)
usage();
return start(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3,
FALSE);
}
else
if (0 == lstrcmpW(L"startWithSecret", argv[0]))
{
if (4 > argc || argc > 13)
usage();
return start(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3,
TRUE);
}
else
if (0 == lstrcmpW(L"stop", argv[0]))
{
if (3 != argc)
usage();
return stop(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2]);
}
else
if (0 == lstrcmpW(L"info", argv[0]))
{
if (3 != argc)
usage();
return getinfo(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2]);
}
else
if (0 == lstrcmpW(L"list", argv[0]))
{
if (1 != argc)
usage();
return list(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE);
}
else
if (0 == lstrcmpW(L"quit", argv[0]))
{
if (1 != argc)
usage();
/* works only against DEBUG version of launcher */
return quit(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE);
}
else
usage();
return 0;
}
void wmainCRTStartup(void)
{
DWORD Argc;
PWSTR *Argv;
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
if (0 == Argv)
ExitProcess(GetLastError());
ExitProcess(wmain(Argc, Argv));
}

View File

@ -0,0 +1,37 @@
#include <winver.h>
#define STR(x) STR_(x)
#define STR_(x) #x
VS_VERSION_INFO VERSIONINFO
FILEVERSION MyVersionWithCommas
PRODUCTVERSION MyVersionWithCommas
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0
#endif
FILEOS VOS_NT
FILETYPE VFT_APP
FILESUBTYPE 0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", STR(MyCompanyName)
VALUE "FileDescription", STR(MyDescription)
VALUE "FileVersion", STR(MyVersion)
VALUE "InternalName", "launcher.exe"
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "launcher.exe"
VALUE "ProductName", STR(MyProductName)
VALUE "ProductVersion", STR(MyVersion)
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

1277
src/launcher/launcher.c Normal file

File diff suppressed because it is too large Load Diff

70
src/launcher/launcher.h Normal file
View File

@ -0,0 +1,70 @@
/**
* @file launcher/launcher.h
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#ifndef WINFSP_LAUNCHER_LAUNCHER_H_INCLUDED
#define WINFSP_LAUNCHER_LAUNCHER_H_INCLUDED
#include <winfsp/winfsp.h>
#include <shared/minimal.h>
#define LAUNCHER_REGKEY "SYSTEM\\CurrentControlSet\\Services\\WinFsp.Launcher\\Services"
#define LAUNCHER_STOP_TIMEOUT 5500
#define LAUNCHER_KILL_TIMEOUT 5000
#define LAUNCHER_PIPE_NAME "\\\\.\\pipe\\WinFsp.{14E7137D-22B4-437A-B0C1-D21D1BDF3767}"
#define LAUNCHER_PIPE_BUFFER_SIZE 4096
#define LAUNCHER_PIPE_DEFAULT_TIMEOUT 3000
#define LAUNCHER_START_WITH_SECRET_TIMEOUT 15000
/*
* The launcher named pipe SDDL gives full access to LocalSystem and Administrators and
* GENERIC_READ and FILE_WRITE_DATA access to Everyone. We are careful not to give the
* FILE_CREATE_PIPE_INSTANCE right to Everyone to disallow the creation of additional
* pipe instances.
*/
#define LAUNCHER_PIPE_SDDL "O:SYG:SYD:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRDCCR;;;WD)"
#define LAUNCHER_PIPE_OWNER ((PSID)WinLocalSystemSid)
/*
* The default service instance SDDL gives full access to LocalSystem and Administrators.
* The only possible service instance rights are as follows:
* RP SERVICE_START
* WP SERVICE_STOP
* LC SERVICE_QUERY_STATUS
*
* To create a service that can be started, stopped or queried by Everyone, you can set
* the following SDDL:
* D:P(A;;RPWPLC;;;WD)
*/
#define SVC_INSTANCE_DEFAULT_SDDL "D:P(A;;RPWPLC;;;SY)(A;;RPWPLC;;;BA)"
enum
{
LauncherSvcInstanceStart = 'S', /* requires: SERVICE_START */
LauncherSvcInstanceStartWithSecret = 'X', /* requires: SERVICE_START */
LauncherSvcInstanceStop = 'T', /* requires: SERVICE_STOP */
LauncherSvcInstanceInfo = 'I', /* requires: SERVICE_QUERY_STATUS */
LauncherSvcInstanceList = 'L', /* requires: none*/
LauncherQuit = 'Q', /* DEBUG version only */
LauncherSuccess = '$',
LauncherFailure = '!',
};
#endif

124
src/shared/minimal.h Normal file
View File

@ -0,0 +1,124 @@
/**
* @file shared/minimal.h
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#ifndef WINFSP_SHARED_MINIMAL_H_INCLUDED
#define WINFSP_SHARED_MINIMAL_H_INCLUDED
/*
* Eliminate dependency on the MSVCRT libraries.
*
* For this to work the following project settings must be set:
* - "C/C++ > General > SDL checks" must be empty (not "Yes" or "No").
* - "C/C++ > Code Generation > Basic Runtime Checks" must be set to "Default"
* - "C/C++ > Code Generation > Runtime Library" must be set to "Multi-threaded (/MT)".
* - "C/C++ > Code Generation > Security Check" must be disabled (/GS-).
* - "Linker > Input > Ignore All Default Libraries" must be "Yes".
*
*
* Update 1:
*
* It is possible to have the "Linker > Input > Ignore All Default Libraries"
* setting to "No" and still eliminate most dependencies on the MSVCRT libraries.
* For example, the WinFsp DLL does this on 32-bit builds (only) to include the
* __allmul symbol that is used when doing int64_t multiplications.
*
* The following project setting must be changed:
* - "Linker > Input > Ignore All Default Libraries" must be "No".
*
* Extreme care must be taken to ensure that the linker does not pull in symbols
* that are not required (or worse create a half-baked CRT). For example, the WinFsp
* DLL ensures this by setting the "Linker > Input > Ignore All Default Libraries"
* to "Yes" on 64-bit builds and "No" on 32-bit builds.
*
*
* Update 2:
*
* Using the /Gs[size] compiler option with a large size is a very bad idea.
* Turns out that the compiler uses the _chkstk call to ensure that enough
* stack space has been committed even when a function accesses locations in
* the stack below the guard page.
*
* The following links explain the problem very well:
* - http://stackoverflow.com/questions/8400118/what-is-the-purpose-of-the-chkstk-function#8400171
* - https://support.microsoft.com/en-us/kb/100775
*
* A library/program that does not wish to use the MSVCRT libraries (and hence
* does not have _chkstk available) must take care to not use more than a page
* (4096 bytes) of stack within a single function.
*/
#undef RtlFillMemory
#undef RtlMoveMemory
NTSYSAPI VOID NTAPI RtlFillMemory(VOID *Destination, DWORD Length, BYTE Fill);
NTSYSAPI VOID NTAPI RtlMoveMemory(VOID *Destination, CONST VOID *Source, DWORD Length);
#pragma function(memset)
#pragma function(memcpy)
static inline
void *memset(void *dst, int val, size_t siz)
{
RtlFillMemory(dst, (DWORD)siz, val);
return dst;
}
static inline
void *memcpy(void *dst, const void *src, size_t siz)
{
RtlMoveMemory(dst, src, (DWORD)siz);
return dst;
}
static inline
void *memmove(void *dst, const void *src, size_t siz)
{
RtlMoveMemory(dst, src, (DWORD)siz);
return dst;
}
static inline void *MemAlloc(size_t Size)
{
return HeapAlloc(GetProcessHeap(), 0, Size);
}
static inline void MemFree(void *Pointer)
{
if (0 != Pointer)
HeapFree(GetProcessHeap(), 0, Pointer);
}
static FORCEINLINE
VOID InsertTailList(PLIST_ENTRY ListHead, PLIST_ENTRY Entry)
{
PLIST_ENTRY Blink;
Blink = ListHead->Blink;
Entry->Flink = ListHead;
Entry->Blink = Blink;
Blink->Flink = Entry;
ListHead->Blink = Entry;
}
static FORCEINLINE
BOOLEAN RemoveEntryList(PLIST_ENTRY Entry)
{
PLIST_ENTRY Blink;
PLIST_ENTRY Flink;
Flink = Entry->Flink;
Blink = Entry->Blink;
Blink->Flink = Flink;
Flink->Blink = Blink;
return Flink == Blink;
}
#endif

View File

@ -7,9 +7,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -116,7 +116,9 @@ NTSTATUS FspAcquireForModWrite(
Success = FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, FALSE);
if (Success)
{
*ResourceToRelease = FileNode->Header.PagingIoResource;
*ResourceToRelease = 0 == FileNode->MainFileNode ?
FileNode->Header.PagingIoResource :
FileNode->MainFileNode->Header.PagingIoResource;
Result = STATUS_SUCCESS;
}
else

View File

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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -77,7 +77,7 @@ static NTSTATUS FspFsvolClose(
FspFileNodeClose(FileNode, FileObject);
/* delete the FileDesc and deref the FileNode; order is important (FileDesc has FileNode ref) */
FspFileDescDelete(FileDesc);
FspFileDescDelete(FileDesc); /* this will also close the MainFileObject if any */
FspFileNodeDereference(FileNode);
/*

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -24,7 +24,8 @@ static NTSTATUS FspFsvrtCreate(
static NTSTATUS FspFsvolCreate(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolCreateNoLock(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN MainFileOpen);
FSP_IOPREP_DISPATCH FspFsvolCreatePrepare;
FSP_IOCMPL_DISPATCH FspFsvolCreateComplete;
static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
@ -109,23 +110,30 @@ static NTSTATUS FspFsvolCreate(
PAGED_CODE();
NTSTATUS Result = STATUS_SUCCESS;
BOOLEAN MainFileOpen = FspMainFileOpenCheck(Irp);
if (!MainFileOpen)
{
FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject);
try
{
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp);
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp, FALSE);
}
finally
{
if (FSP_STATUS_IOQ_POST != Result)
FspFsvolDeviceFileRenameRelease(FsvolDeviceObject);
}
}
else
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp, TRUE);
return Result;
}
static NTSTATUS FspFsvolCreateNoLock(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN MainFileOpen)
{
PAGED_CODE();
@ -162,10 +170,16 @@ static NTSTATUS FspFsvolCreateNoLock(
ULONG Flags = IrpSp->Flags;
KPROCESSOR_MODE RequestorMode =
FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode;
BOOLEAN CaseSensitiveRequested =
BooleanFlagOn(Flags, SL_CASE_SENSITIVE);
BOOLEAN CaseSensitive =
CaseSensitiveRequested || FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch;
BOOLEAN HasTraversePrivilege =
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE);
FSP_FILE_NODE *FileNode, *RelatedFileNode;
FSP_FILE_DESC *FileDesc;
UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 };
ULONG StreamType = FspUnicodePathStreamTypeNone;
FSP_FSCTL_TRANSACT_REQ *Request;
/* cannot open files by fileid */
@ -210,10 +224,6 @@ static NTSTATUS FspFsvolCreateNoLock(
FileName.Buffer++;
}
/* check filename validity */
if (!FspUnicodePathIsValid(&FileName, 0 != FsvolDeviceExtension->VolumeParams.NamedStreams))
return STATUS_OBJECT_NAME_INVALID;
/* is this a relative or absolute open? */
if (0 != RelatedFileObject)
{
@ -265,22 +275,48 @@ static NTSTATUS FspFsvolCreateNoLock(
Result = RtlAppendUnicodeStringToString(&FileNode->FileName, &FileName);
ASSERT(NT_SUCCESS(Result));
/* check filename validity */
if (!FspUnicodePathIsValid(&FileNode->FileName,
FsvolDeviceExtension->VolumeParams.NamedStreams ? &StreamPart : 0,
&StreamType))
{
FspFileNodeDereference(FileNode);
return STATUS_OBJECT_NAME_INVALID;
}
/* if we have a stream part (even non-empty), ensure that FileNode->FileName has single colon */
if (0 != StreamPart.Buffer)
{
ASSERT(
(PUINT8)FileNode->FileName.Buffer + sizeof(WCHAR) <= (PUINT8)StreamPart.Buffer &&
(PUINT8)StreamPart.Buffer + StreamPart.Length <=
(PUINT8)FileNode->FileName.Buffer + FileNode->FileName.Length);
FileNode->FileName.Length = (USHORT)
((PUINT8)StreamPart.Buffer - (PUINT8)FileNode->FileName.Buffer + StreamPart.Length -
(0 == StreamPart.Length) * sizeof(WCHAR));
}
/* check and remove any volume prefix */
if (0 == RelatedFileObject && 0 < FsvolDeviceExtension->VolumePrefix.Length)
{
if (FileNode->FileName.Length <= FsvolDeviceExtension->VolumePrefix.Length ||
!RtlEqualMemory(FileNode->FileName.Buffer, FsvolDeviceExtension->VolumePrefix.Buffer,
FsvolDeviceExtension->VolumePrefix.Length) ||
'\\' != FileNode->FileName.Buffer[FsvolDeviceExtension->VolumePrefix.Length / sizeof(WCHAR)])
if (!FspFsvolDeviceVolumePrefixInString(FsvolDeviceObject, &FileNode->FileName) ||
(FileNode->FileName.Length > FsvolDeviceExtension->VolumePrefix.Length &&
'\\' != FileNode->FileName.Buffer[FsvolDeviceExtension->VolumePrefix.Length / sizeof(WCHAR)]))
{
FspFileNodeDereference(FileNode);
return STATUS_OBJECT_PATH_NOT_FOUND;
}
if (FileNode->FileName.Length > FsvolDeviceExtension->VolumePrefix.Length)
{
FileNode->FileName.Length -= FsvolDeviceExtension->VolumePrefix.Length;
FileNode->FileName.MaximumLength -= FsvolDeviceExtension->VolumePrefix.Length;
FileNode->FileName.Buffer += FsvolDeviceExtension->VolumePrefix.Length / sizeof(WCHAR);
}
else
FileNode->FileName.Length = sizeof(WCHAR);
}
ASSERT(sizeof(WCHAR) <= FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0]);
@ -297,6 +333,16 @@ static NTSTATUS FspFsvolCreateNoLock(
FileNode->FileName.Length -= sizeof(WCHAR);
}
/* if a $DATA stream type, this cannot be a directory */
if (FspUnicodePathStreamTypeData == StreamType)
{
if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
{
FspFileNodeDereference(FileNode);
return STATUS_NOT_A_DIRECTORY;
}
}
/* not all operations allowed on the root directory */
if (sizeof(WCHAR) == FileNode->FileName.Length &&
(FILE_CREATE == CreateDisposition ||
@ -324,6 +370,71 @@ static NTSTATUS FspFsvolCreateNoLock(
return Result;
}
/* fix FileAttributes */
ClearFlag(FileAttributes,
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
if (CreateOptions & FILE_DIRECTORY_FILE)
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
/* if we have a non-empty stream part, open the main file */
if (0 != StreamPart.Length)
{
/* named streams can never be directories (even when attached to directories) */
if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
{
Result = STATUS_NOT_A_DIRECTORY;
goto main_stream_exit;
}
/* cannot open target directory of a named stream */
if (FlagOn(Flags, SL_OPEN_TARGET_DIRECTORY))
{
Result = STATUS_OBJECT_NAME_INVALID;
goto main_stream_exit;
}
MainFileName.Length = MainFileName.MaximumLength = (USHORT)
((PUINT8)StreamPart.Buffer - (PUINT8)FileNode->FileName.Buffer - sizeof(WCHAR));
MainFileName.Buffer = FileNode->FileName.Buffer;
Result = FspMainFileOpen(
FsvolDeviceObject,
FileObject->DeviceObject, /* use as device hint when using MUP */
&MainFileName, CaseSensitive,
SecurityDescriptor,
FileAttributes,
CreateDisposition,
&FileDesc->MainFileHandle,
&FileDesc->MainFileObject);
if (!NT_SUCCESS(Result))
goto main_stream_exit;
/* check that the main file is one we recognize */
if (!FspFileNodeIsValid(FileDesc->MainFileObject->FsContext))
{
Result = STATUS_OBJECT_NAME_NOT_FOUND;
goto main_stream_exit;
}
/* cannot set security descriptor or file attributes on named stream */
SecurityDescriptor = 0;
SecurityDescriptorSize = 0;
FileAttributes = 0;
/* remember the main file node */
FileNode->MainFileNode = FileDesc->MainFileObject->FsContext;
Result = STATUS_SUCCESS;
main_stream_exit:
if (!NT_SUCCESS(Result))
{
FspFileDescDelete(FileDesc);
FspFileNodeDereference(FileNode);
return Result;
}
}
/* create the user-mode file system request */
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, SecurityDescriptorSize,
FspFsvolCreateRequestFini, &Request);
@ -334,23 +445,19 @@ static NTSTATUS FspFsvolCreateNoLock(
return Result;
}
/* fix FileAttributes */
ClearFlag(FileAttributes, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
if (CreateOptions & FILE_DIRECTORY_FILE)
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
/*
* The new request is associated with our IRP. Go ahead and associate our FileNode/FileDesc
* with the Request as well. After this is done completing our IRP will automatically
* delete the Request and any associated resources.
*/
FileDesc->FileNode = FileNode;
FileDesc->CaseSensitive =
0 != FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch ||
BooleanFlagOn(Flags, SL_CASE_SENSITIVE);
FileDesc->CaseSensitive = CaseSensitive;
FileDesc->HasTraversePrivilege = HasTraversePrivilege;
if (!MainFileOpen)
{
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
}
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
/* populate the Create request */
@ -369,7 +476,12 @@ static NTSTATUS FspFsvolCreateNoLock(
Request->Req.Create.UserMode = UserMode == RequestorMode;
Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege;
Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY);
Request->Req.Create.CaseSensitive = BooleanFlagOn(Flags, SL_CASE_SENSITIVE);
Request->Req.Create.CaseSensitive = CaseSensitiveRequested;
Request->Req.Create.NamedStream = MainFileName.Length;
ASSERT(
0 == StreamPart.Length && 0 == MainFileName.Length ||
0 != StreamPart.Length && 0 != MainFileName.Length);
/* copy the security descriptor (if any) into the request */
if (0 != SecurityDescriptorSize)
@ -485,7 +597,8 @@ NTSTATUS FspFsvolCreateComplete(
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
FSP_FILE_NODE *OpenedFileNode;
UNICODE_STRING ReparseFileName;
PREPARSE_DATA_BUFFER ReparseData;
UNICODE_STRING ReparseTargetPrefix0, ReparseTargetPrefix1, ReparseTargetPath;
if (FspFsctlTransactCreateKind == Request->Kind)
{
@ -498,32 +611,100 @@ NTSTATUS FspFsvolCreateComplete(
}
/* special case STATUS_REPARSE */
if (STATUS_REPARSE == Result)
if (STATUS_REPARSE == Response->IoStatus.Status)
{
ReparseFileName.Buffer =
(PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.FileName.Offset);
ReparseFileName.Length = ReparseFileName.MaximumLength =
Response->Rsp.Create.Reparse.FileName.Size;
if (IO_REMOUNT == Response->IoStatus.Information)
{
Irp->IoStatus.Information = IO_REMOUNT;
FSP_RETURN(Result = STATUS_REPARSE);
}
else
if (IO_REPARSE == Response->IoStatus.Information ||
IO_REPARSE_TAG_SYMLINK == Response->IoStatus.Information)
{
/*
* IO_REPARSE means that the user-mode file system has returned an absolute (in
* the device namespace) path. Send it as is to the IO Manager.
*
* IO_REPARSE_TAG_SYMLINK means that the user-mode file system has returned a full
* symbolic link reparse buffer. If the symbolic link is absolute send it to the
* IO Manager as is. If the symbolic link is device-relative (absolute in the
* device namespace) prefix it with our volume name/prefix and then send it to the
* IO Manager.
*
* We do our own handling of IO_REPARSE_TAG_SYMLINK reparse points because
* experimentation with handing them directly to the IO Manager revealed problems
* with UNC paths (\??\UNC\{VolumePrefix}\{FilePath}).
*/
Result = STATUS_ACCESS_DENIED;
if (IO_REPARSE == Response->IoStatus.Information)
{
if (0 == ReparseFileName.Length ||
(PUINT8)ReparseFileName.Buffer + ReparseFileName.Length >
(PUINT8)Response + Response->Size)
FSP_RETURN();
RtlZeroMemory(&ReparseTargetPrefix0, sizeof ReparseTargetPrefix0);
RtlZeroMemory(&ReparseTargetPrefix1, sizeof ReparseTargetPrefix1);
if (ReparseFileName.Length > FileObject->FileName.MaximumLength)
ReparseTargetPath.Length = ReparseTargetPath.MaximumLength =
Response->Rsp.Create.Reparse.Buffer.Size;
ReparseTargetPath.Buffer =
(PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset);
if ((PUINT8)ReparseTargetPath.Buffer + ReparseTargetPath.Length >
(PUINT8)Response + Response->Size ||
ReparseTargetPath.Length < sizeof(WCHAR) || L'\\' != ReparseTargetPath.Buffer[0])
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
}
else
{
PVOID Buffer = FspAllocExternal(ReparseFileName.Length);
ASSERT(IO_REPARSE_TAG_SYMLINK == Response->IoStatus.Information);
ReparseData = (PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset);
if ((PUINT8)ReparseData + Response->Rsp.Create.Reparse.Buffer.Size >
(PUINT8)Response + Response->Size)
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.Create.Reparse.Buffer.Size,
ReparseData);
if (!NT_SUCCESS(Result))
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
if (!FlagOn(ReparseData->SymbolicLinkReparseBuffer.Flags, SYMLINK_FLAG_RELATIVE))
{
RtlZeroMemory(&ReparseTargetPrefix0, sizeof ReparseTargetPrefix0);
RtlZeroMemory(&ReparseTargetPrefix1, sizeof ReparseTargetPrefix1);
}
else
{
RtlCopyMemory(&ReparseTargetPrefix0, &FsvolDeviceExtension->VolumeName,
sizeof ReparseTargetPrefix0);
RtlCopyMemory(&ReparseTargetPrefix1, &FsvolDeviceExtension->VolumePrefix,
sizeof ReparseTargetPrefix1);
}
ReparseTargetPath.Buffer = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
ReparseTargetPath.Length = ReparseTargetPath.MaximumLength =
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
if (ReparseTargetPath.Length < sizeof(WCHAR) || L'\\' != ReparseTargetPath.Buffer[0])
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
}
if (ReparseTargetPrefix0.Length + ReparseTargetPrefix1.Length + ReparseTargetPath.Length >
FileObject->FileName.MaximumLength)
{
PVOID Buffer = FspAllocExternal(
ReparseTargetPrefix0.Length + ReparseTargetPrefix1.Length + ReparseTargetPath.Length);
if (0 == Buffer)
FSP_RETURN(Result = STATUS_INSUFFICIENT_RESOURCES);
FspFreeExternal(FileObject->FileName.Buffer);
FileObject->FileName.MaximumLength = ReparseFileName.Length;
FileObject->FileName.MaximumLength =
ReparseTargetPrefix0.Length + ReparseTargetPrefix1.Length + ReparseTargetPath.Length;
FileObject->FileName.Buffer = Buffer;
}
FileObject->FileName.Length = 0;
RtlCopyUnicodeString(&FileObject->FileName, &ReparseFileName);
RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPrefix0);
RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPrefix1);
RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPath);
/*
* The RelatedFileObject does not need to be changed according to:
@ -539,19 +720,35 @@ NTSTATUS FspFsvolCreateComplete(
* STATUS_REPARSE status returned by the filter. Therefore, it is not
* the responsibility of the filter to free that file object.
*/
Irp->IoStatus.Information = IO_REPARSE;
FSP_RETURN(Result = STATUS_REPARSE);
}
else
if (IO_REMOUNT == Response->IoStatus.Information)
{
if (0 != ReparseFileName.Length)
FSP_RETURN();
}
else
ReparseData = (PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset);
if ((PUINT8)ReparseData + Response->Rsp.Create.Reparse.Buffer.Size >
(PUINT8)Response + Response->Size)
FSP_RETURN(Result = STATUS_IO_REPARSE_DATA_INVALID);
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.Create.Reparse.Buffer.Size,
ReparseData);
if (!NT_SUCCESS(Result))
FSP_RETURN();
Irp->IoStatus.Information = (ULONG_PTR)Response->IoStatus.Information;
Result = Response->IoStatus.Status;
FSP_RETURN();
ASSERT(0 == Irp->Tail.Overlay.AuxiliaryBuffer);
Irp->Tail.Overlay.AuxiliaryBuffer = FspAllocNonPagedExternal(
Response->Rsp.Create.Reparse.Buffer.Size);
if (0 == Irp->Tail.Overlay.AuxiliaryBuffer)
FSP_RETURN(Result = STATUS_INSUFFICIENT_RESOURCES);
RtlCopyMemory(Irp->Tail.Overlay.AuxiliaryBuffer, ReparseData,
Response->Rsp.Create.Reparse.Buffer.Size);
Irp->IoStatus.Information = ReparseData->ReparseTag;
FSP_RETURN(Result = STATUS_REPARSE);
}
}
/* fix FileNode->FileName if we were doing SL_OPEN_TARGET_DIRECTORY */
@ -634,6 +831,8 @@ NTSTATUS FspFsvolCreateComplete(
if (FileNode->IsDirectory)
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
PVOID RequestDeviceObjectValue = FspIopRequestContext(Request, RequestDeviceObject);
/* disassociate the FileDesc momentarily from the Request */
FspIopRequestContext(Request, RequestDeviceObject) = 0;
FspIopRequestContext(Request, RequestFileDesc) = 0;
@ -642,7 +841,7 @@ NTSTATUS FspFsvolCreateComplete(
Request->Kind = FspFsctlTransactOverwriteKind;
RtlZeroMemory(&Request->Req.Create, sizeof Request->Req.Create);
FspIopResetRequest(Request, FspFsvolCreateOverwriteRequestFini);
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
FspIopRequestContext(Request, RequestDeviceObject) = RequestDeviceObjectValue;
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
FspIopRequestContext(Request, RequestFileObject) = FileObject;
FspIopRequestContext(Request, RequestState) = (PVOID)RequestPending;
@ -725,7 +924,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
if (FspFsctlTransactCreateKind == Request->Kind)
{
PDEVICE_OBJECT FsvolDeviceObject = FspIopRequestContext(Request, RequestDeviceObject);
PVOID RequestDeviceObjectValue = FspIopRequestContext(Request, RequestDeviceObject);
/* disassociate the FileDesc momentarily from the Request */
Request = FspIrpRequest(Irp);
@ -735,7 +934,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
/* reset the Request and reassociate the FileDesc and FileObject with it */
Request->Kind = FspFsctlTransactReservedKind;
FspIopResetRequest(Request, FspFsvolCreateTryOpenRequestFini);
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
FspIopRequestContext(Request, RequestDeviceObject) = RequestDeviceObjectValue;
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
FspIopRequestContext(Request, RequestFileObject) = FileObject;
FspIopRequestContext(Request, RequestState) = (PVOID)(UINT_PTR)FlushImage;

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -47,7 +47,7 @@ NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount);
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
BOOLEAN SubpathOnly, PVOID *PRestartKey);
BOOLEAN NextFlag, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY *RestartKey);
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
PVOID FspFsvolDeviceInsertContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID Context,
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted);
@ -295,7 +295,7 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
NTSTATUS Result;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
LARGE_INTEGER IrpTimeout;
LARGE_INTEGER SecurityTimeout, DirInfoTimeout;
LARGE_INTEGER SecurityTimeout, DirInfoTimeout, StreamInfoTimeout;
/*
* Volume device initialization is a mess, because of the different ways of
@ -347,6 +347,16 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
return Result;
FsvolDeviceExtension->InitDoneDir = 1;
/* create our stream info meta cache */
StreamInfoTimeout.QuadPart = FspTimeoutFromMillis(FsvolDeviceExtension->VolumeParams.FileInfoTimeout);
/* convert millis to nanos */
Result = FspMetaCacheCreate(
FspFsvolDeviceStreamInfoCacheCapacity, FspFsvolDeviceStreamInfoCacheItemSizeMax, &StreamInfoTimeout,
&FsvolDeviceExtension->StreamInfoCache);
if (!NT_SUCCESS(Result))
return Result;
FsvolDeviceExtension->InitDoneStrm = 1;
/* initialize the FSRTL Notify mechanism */
Result = FspNotifyInitializeSync(&FsvolDeviceExtension->NotifySync);
if (!NT_SUCCESS(Result))
@ -406,6 +416,10 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
FspNotifyUninitializeSync(&FsvolDeviceExtension->NotifySync);
}
/* delete the stream info meta cache */
if (FsvolDeviceExtension->InitDoneStrm)
FspMetaCacheDelete(FsvolDeviceExtension->StreamInfoCache);
/* delete the directory meta cache */
if (FsvolDeviceExtension->InitDoneDir)
FspMetaCacheDelete(FsvolDeviceExtension->DirInfoCache);
@ -484,6 +498,7 @@ static VOID FspFsvolDeviceExpirationRoutine(PVOID Context)
InterruptTime = KeQueryInterruptTime();
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->SecurityCache, InterruptTime);
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, InterruptTime);
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->StreamInfoCache, InterruptTime);
FspIoqRemoveExpired(FsvolDeviceExtension->Ioq, InterruptTime);
KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql);
@ -601,20 +616,19 @@ VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount)
}
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
BOOLEAN SubpathOnly, PVOID *PRestartKey)
BOOLEAN NextFlag, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY *RestartKey)
{
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
BOOLEAN CaseInsensitive = 0 == FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT_DATA *Result;
ULONG DeleteCount = 0;
if (0 != *PRestartKey)
SubpathOnly = FALSE;
if (0 != RestartKey->RestartKey)
NextFlag = TRUE;
Result = RtlEnumerateGenericTableLikeADirectory(&FsvolDeviceExtension->ContextByNameTable,
0, 0, SubpathOnly, PRestartKey, &DeleteCount, &FileName);
0, 0, NextFlag, &RestartKey->RestartKey, &RestartKey->DeleteCount, &FileName);
if (0 != Result &&
RtlPrefixUnicodeString(FileName, Result->FileName, CaseInsensitive) &&

View File

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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -105,6 +105,7 @@ NTSTATUS DriverEntry(
FspIopPrepareFunction[IRP_MJ_WRITE] = FspFsvolWritePrepare;
FspIopCompleteFunction[IRP_MJ_WRITE] = FspFsvolWriteComplete;
FspIopCompleteFunction[IRP_MJ_QUERY_INFORMATION] = FspFsvolQueryInformationComplete;
FspIopPrepareFunction[IRP_MJ_SET_INFORMATION] = FspFsvolSetInformationPrepare;
FspIopCompleteFunction[IRP_MJ_SET_INFORMATION] = FspFsvolSetInformationComplete;
FspIopCompleteFunction[IRP_MJ_QUERY_EA] = FspFsvolQueryEaComplete;
FspIopCompleteFunction[IRP_MJ_SET_EA] = FspFsvolSetEaComplete;

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -28,7 +28,7 @@
#pragma warning(disable:4100) /* unreferenced formal parameter */
#pragma warning(disable:4200) /* zero-sized array in struct/union */
#define DRIVER_NAME "WinFsp"
#define DRIVER_NAME FSP_FSCTL_DRIVER_NAME
/* IoCreateDeviceSecure default SDDL's */
#define FSP_FSCTL_DEVICE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;WD)"
@ -45,6 +45,7 @@
#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
@ -316,6 +317,7 @@ FSP_IOCMPL_DISPATCH FspFsvolQueryVolumeInformationComplete;
FSP_IOPREP_DISPATCH FspFsvolReadPrepare;
FSP_IOCMPL_DISPATCH FspFsvolReadComplete;
FSP_IOCMPL_DISPATCH FspFsvolSetEaComplete;
FSP_IOPREP_DISPATCH FspFsvolSetInformationPrepare;
FSP_IOCMPL_DISPATCH FspFsvolSetInformationComplete;
FSP_IOPREP_DISPATCH FspFsvolSetSecurityPrepare;
FSP_IOCMPL_DISPATCH FspFsvolSetSecurityComplete;
@ -415,17 +417,31 @@ BOOLEAN FspExpirationTimeValid(UINT64 ExpirationTime)
return 1 >= ExpirationTime + 1 ? (0 != ExpirationTime) : (KeQueryInterruptTime() < ExpirationTime);
}
static inline
BOOLEAN FspExpirationTimeValidEx(UINT64 ExpirationTime, UINT64 CurrentTime)
{
/* if ExpirationTime is 0 or -1 then ExpirationTime else CurrentTime < ExpirationTime */
return 1 >= ExpirationTime + 1 ? (0 != ExpirationTime) : (CurrentTime < ExpirationTime);
}
static inline
BOOLEAN FspExpirationTimeValid2(UINT64 ExpirationTime, UINT64 CurrentTime)
{
return CurrentTime < ExpirationTime;
}
/* utility */
enum
{
FspUnicodePathStreamTypeNone = 0,
FspUnicodePathStreamTypeData = 1,
};
PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag);
PVOID FspAllocateIrpMustSucceed(CCHAR StackSize);
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams);
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType);
BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Pattern);
VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
NTSTATUS FspCreateGuid(GUID *Guid);
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject);
NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length);
NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
@ -654,13 +670,14 @@ enum
#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 struct
{
FSP_IOP_REQUEST_FINI *RequestFini;
PVOID Context[4];
FSP_FSCTL_TRANSACT_RSP *Response;
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 RequestBuf[];
__declspec(align(REQ_ALIGN_SIZE)) UINT8 RequestBuf[];
} FSP_FSCTL_TRANSACT_REQ_HEADER;
static inline
PVOID *FspIopRequestContextAddress(FSP_FSCTL_TRANSACT_REQ *Request, ULONG I)
@ -717,6 +734,8 @@ enum
FspFsvolDeviceSecurityCacheItemSizeMax = 4096,
FspFsvolDeviceDirInfoCacheCapacity = 100,
FspFsvolDeviceDirInfoCacheItemSizeMax = FSP_FSCTL_ALIGN_UP(16384, PAGE_SIZE),
FspFsvolDeviceStreamInfoCacheCapacity = 100,
FspFsvolDeviceStreamInfoCacheItemSizeMax = FSP_FSCTL_ALIGN_UP(16384, PAGE_SIZE),
};
typedef struct
{
@ -728,6 +747,11 @@ typedef struct
RTL_BALANCED_LINKS Header;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT_DATA Data;
} FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT;
typedef struct
{
PVOID RestartKey;
ULONG DeleteCount;
} FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY;
enum
{
FspFsctlDeviceExtensionKind = '\0ltC', /* file system control device (e.g. \Device\WinFsp.Disk) */
@ -743,7 +767,7 @@ typedef struct
typedef struct
{
FSP_DEVICE_EXTENSION Base;
UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1,
UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, InitDoneStrm:1,
InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1;
PDEVICE_OBJECT FsctlDeviceObject;
PDEVICE_OBJECT FsvrtDeviceObject;
@ -755,6 +779,7 @@ typedef struct
FSP_IOQ *Ioq;
FSP_META_CACHE *SecurityCache;
FSP_META_CACHE *DirInfoCache;
FSP_META_CACHE *StreamInfoCache;
KSPIN_LOCK ExpirationLock;
WORK_QUEUE_ITEM ExpirationWorkItem;
BOOLEAN ExpirationInProgress;
@ -803,7 +828,7 @@ NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount);
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
BOOLEAN SubpathOnly, PVOID *PRestartKey);
BOOLEAN NextFlag, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY *RestartKey);
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
PVOID FspFsvolDeviceInsertContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID Context,
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted);
@ -813,6 +838,12 @@ VOID FspFsvolDeviceGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_I
BOOLEAN FspFsvolDeviceTryGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo);
VOID FspFsvolDeviceSetVolumeInfo(PDEVICE_OBJECT DeviceObject, const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
VOID FspFsvolDeviceInvalidateVolumeInfo(PDEVICE_OBJECT DeviceObject);
static inline
BOOLEAN FspFsvolDeviceVolumePrefixInString(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING String)
{
return RtlPrefixUnicodeString(&FspFsvolDeviceExtension(DeviceObject)->VolumePrefix, String,
FSP_VOLUME_PREFIX_CASE_INS);
}
NTSTATUS FspDeviceCopyList(
PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount);
VOID FspDeviceDeleteList(
@ -877,10 +908,11 @@ typedef struct
ERESOURCE PagingIoResource;
FAST_MUTEX HeaderFastMutex;
SECTION_OBJECT_POINTERS SectionObjectPointers;
KSPIN_LOCK DirInfoSpinLock;
UINT64 DirInfo; /* allows to invalidate DirInfo w/o resources acquired */
KSPIN_LOCK NpInfoSpinLock; /* allows to invalidate non-page Info w/o resources acquired */
UINT64 DirInfo;
UINT64 StreamInfo;
} FSP_FILE_NODE_NONPAGED;
typedef struct
typedef struct FSP_FILE_NODE
{
FSRTL_ADVANCED_FCB_HEADER Header;
FSP_FILE_NODE_NONPAGED *NonPaged;
@ -891,22 +923,25 @@ typedef struct
LONG OpenCount; /* ContextTable ref count */
LONG HandleCount; /* HANDLE count (CREATE/CLEANUP) */
SHARE_ACCESS ShareAccess;
ULONG MainFileDenyDeleteCount; /* number of times main file is denying delete */
ULONG StreamDenyDeleteCount; /* number of times open streams are denying delete */
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT ContextByNameElementStorage;
/* locked under FSP_FSVOL_DEVICE_EXTENSION::FileRenameResource or Header.Resource */
UNICODE_STRING FileName;
PWSTR ExternalFileName;
/* locked under Header.Resource */
UINT64 InfoExpirationTime;
UINT64 FileInfoExpirationTime, BasicInfoExpirationTime;
UINT32 FileAttributes;
UINT32 ReparseTag;
UINT64 CreationTime;
UINT64 LastAccessTime;
UINT64 LastWriteTime;
UINT64 ChangeTime;
ULONG InfoChangeNumber;
ULONG FileInfoChangeNumber;
UINT64 Security;
ULONG SecurityChangeNumber;
ULONG DirInfoChangeNumber;
ULONG StreamInfoChangeNumber;
BOOLEAN TruncateOnClose;
FILE_LOCK FileLock;
struct
@ -924,6 +959,7 @@ typedef struct
UINT64 IndexNumber;
BOOLEAN IsDirectory;
BOOLEAN IsRootDirectory;
struct FSP_FILE_NODE *MainFileNode; /* this becomes invalid after our last desc close */
WCHAR FileNameBuf[];
} FSP_FILE_NODE;
typedef struct
@ -938,6 +974,9 @@ typedef struct
UINT64 DirectoryOffset;
UINT64 DirInfo;
ULONG DirInfoCacheHint;
/* stream support */
HANDLE MainFileHandle;
PFILE_OBJECT MainFileObject;
} FSP_FILE_DESC;
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
@ -982,20 +1021,86 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo);
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
static inline
ULONG FspFileNodeFileInfoChangeNumber(FSP_FILE_NODE *FileNode)
{
if (0 != FileNode->MainFileNode)
return (FileNode->MainFileNode->FileInfoChangeNumber & 0xfffff) |
((FileNode->FileInfoChangeNumber & 0xfff) << 20);
else
return FileNode->FileInfoChangeNumber & 0xfffff;
}
BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG SecurityChangeNumber);
static inline
ULONG FspFileNodeSecurityChangeNumber(FSP_FILE_NODE *FileNode)
{
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
return FileNode->SecurityChangeNumber;
}
BOOLEAN FspFileNodeReferenceDirInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG DirInfoChangeNumber);
static inline
ULONG FspFileNodeDirInfoChangeNumber(FSP_FILE_NODE *FileNode)
{
return FileNode->DirInfoChangeNumber;
}
BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
VOID FspFileNodeSetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG StreamInfoChangeNumber);
static inline
ULONG FspFileNodeStreamInfoChangeNumber(FSP_FILE_NODE *FileNode)
{
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
return FileNode->StreamInfoChangeNumber;
}
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action);
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN Reset);
NTSTATUS FspMainFileOpen(
PDEVICE_OBJECT FsvolDeviceObject,
PDEVICE_OBJECT DeviceObjectHint,
PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive,
PSECURITY_DESCRIPTOR SecurityDescriptor,
ULONG FileAttributes,
ULONG Disposition,
PHANDLE PMainFileHandle,
PFILE_OBJECT *PMainFileObject);
NTSTATUS FspMainFileClose(
HANDLE MainFileHandle,
PFILE_OBJECT MainFileObject);
static __forceinline
BOOLEAN FspMainFileOpenCheck(PIRP Irp)
{
extern const GUID FspMainFileOpenEcpGuid;
NTSTATUS Result;
PECP_LIST ExtraCreateParameters = 0;
PVOID ExtraCreateParameter = 0;
Result = FsRtlGetEcpListFromIrp(Irp, &ExtraCreateParameters);
if (!NT_SUCCESS(Result) || 0 == ExtraCreateParameters)
return FALSE;
Result = FsRtlFindExtraCreateParameter(ExtraCreateParameters,
&FspMainFileOpenEcpGuid, &ExtraCreateParameter, 0);
if (!NT_SUCCESS(Result) || 0 == ExtraCreateParameter)
return FALSE;
if (FsRtlIsEcpFromUserMode(ExtraCreateParameter))
return FALSE;
return TRUE;
}
#define FspFileNodeAcquireShared(N,F) FspFileNodeAcquireSharedF(N, FspFileNodeAcquire ## F)
#define FspFileNodeTryAcquireShared(N,F) FspFileNodeTryAcquireSharedF(N, FspFileNodeAcquire ## F, FALSE)
#define FspFileNodeAcquireExclusive(N,F) FspFileNodeAcquireExclusiveF(N, FspFileNodeAcquire ## F)
@ -1006,6 +1111,7 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
#define FspFileNodeReleaseOwner(N,F,P) FspFileNodeReleaseOwnerF(N, FspFileNodeAcquire ## F, P)
#define FspFileNodeDereferenceSecurity(P) FspMetaCacheDereferenceItemBuffer(P)
#define FspFileNodeDereferenceDirInfo(P) FspMetaCacheDereferenceItemBuffer(P)
#define FspFileNodeDereferenceStreamInfo(P) FspMetaCacheDereferenceItemBuffer(P)
#define FspFileNodeUnlockAll(N,F,P) FsRtlFastUnlockAll(&(N)->FileLock, F, P, N)
/* multiversion support */
@ -1030,7 +1136,30 @@ extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[];
extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[];
extern ERESOURCE FspDeviceGlobalResource;
extern WCHAR FspFileDescDirectoryPatternMatchAll[];
extern const GUID FspMainFileOpenEcpGuid;
extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;
extern ULONG FspMvMdlMappingNoWrite;
/*
* 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
LOGICAL RtlEqualMemory(const VOID *Source1, const VOID *Source2, SIZE_T Length)
{
return Length == RtlCompareMemory(Source1, Source2, Length);
}
#endif

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the

View File

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

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -38,6 +38,13 @@ static NTSTATUS FspFsvolQueryPositionInformation(PFILE_OBJECT FileObject,
static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd,
const FSP_FSCTL_FILE_INFO *FileInfo);
static NTSTATUS FspFsvolQueryStreamInformationCopy(
FSP_FSCTL_STREAM_INFO *StreamInfoBuffer, ULONG StreamInfoBufferSize,
PVOID DestBuf, PULONG PDestLen);
static NTSTATUS FspFsvolQueryStreamInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolQueryStreamInformationSuccess(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
static NTSTATUS FspFsvolQueryInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolQueryInformationComplete;
@ -63,6 +70,7 @@ static NTSTATUS FspFsvolSetRenameInformationSuccess(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
static NTSTATUS FspFsvolSetInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOPREP_DISPATCH FspFsvolSetInformationPrepare;
FSP_IOCMPL_DISPATCH FspFsvolSetInformationComplete;
static FSP_IOP_REQUEST_FINI FspFsvolSetInformationRequestFini;
FSP_DRIVER_DISPATCH FspQueryInformation;
@ -77,6 +85,9 @@ FSP_DRIVER_DISPATCH FspSetInformation;
#pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation)
#pragma alloc_text(PAGE, FspFsvolQueryPositionInformation)
#pragma alloc_text(PAGE, FspFsvolQueryStandardInformation)
#pragma alloc_text(PAGE, FspFsvolQueryStreamInformationCopy)
#pragma alloc_text(PAGE, FspFsvolQueryStreamInformation)
#pragma alloc_text(PAGE, FspFsvolQueryStreamInformationSuccess)
#pragma alloc_text(PAGE, FspFsvolQueryInformation)
#pragma alloc_text(PAGE, FspFsvolQueryInformationComplete)
#pragma alloc_text(PAGE, FspFsvolQueryInformationRequestFini)
@ -89,6 +100,7 @@ FSP_DRIVER_DISPATCH FspSetInformation;
#pragma alloc_text(PAGE, FspFsvolSetRenameInformation)
#pragma alloc_text(PAGE, FspFsvolSetRenameInformationSuccess)
#pragma alloc_text(PAGE, FspFsvolSetInformation)
#pragma alloc_text(PAGE, FspFsvolSetInformationPrepare)
#pragma alloc_text(PAGE, FspFsvolSetInformationComplete)
#pragma alloc_text(PAGE, FspFsvolSetInformationRequestFini)
#pragma alloc_text(PAGE, FspQueryInformation)
@ -106,6 +118,9 @@ enum
/* SetInformation */
//RequestFileNode = 0,
RequestDeviceObject = 1,
/* Rename */
RequestAccessToken = 2,
RequestProcess = 3,
};
static NTSTATUS FspFsvolQueryAllInformation(PFILE_OBJECT FileObject,
@ -344,6 +359,235 @@ static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject,
return STATUS_SUCCESS;
}
static NTSTATUS FspFsvolQueryStreamInformationCopy(
FSP_FSCTL_STREAM_INFO *StreamInfo, ULONG StreamInfoSize,
PVOID DestBuf, PULONG PDestLen)
{
#define STREAM_TYPE ":$DATA"
#define STREAM_TYPE_LENGTH (sizeof L"" STREAM_TYPE - sizeof(WCHAR))
#define STREAM_EXTRA_LENGTH (sizeof L":" STREAM_TYPE - sizeof(WCHAR))
#define FILL_INFO()\
do\
{\
FILE_STREAM_INFORMATION InfoStruct = { 0 }, *Info = &InfoStruct;\
Info->NextEntryOffset = 0;\
Info->StreamNameLength = StreamNameLength;\
Info->StreamSize.QuadPart = StreamInfo->StreamSize;\
Info->StreamAllocationSize.QuadPart = StreamInfo->StreamAllocationSize;\
Info = DestBuf;\
RtlCopyMemory(Info, &InfoStruct, FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName));\
{\
PWSTR StreamName = Info->StreamName;\
ULONG Length[3];\
Length[0] = 0 < CopyLength ? sizeof(WCHAR) : 0;\
Length[1] = Info->StreamNameLength - STREAM_EXTRA_LENGTH < CopyLength - Length[0] ?\
Info->StreamNameLength - STREAM_EXTRA_LENGTH : CopyLength - Length[0];\
Length[2] = CopyLength - Length[0] - Length[1];\
ASSERT(\
sizeof(WCHAR) >= Length[0] &&\
Info->StreamNameLength - STREAM_EXTRA_LENGTH >= Length[1] &&\
STREAM_TYPE_LENGTH >= Length[2]);\
RtlCopyMemory(StreamName, L":", Length[0]);\
StreamName += Length[0] / sizeof(WCHAR);\
RtlCopyMemory(StreamName, StreamInfo->StreamNameBuf, Length[1]);\
StreamName += Length[1] / sizeof(WCHAR);\
RtlCopyMemory(StreamName, L"" STREAM_TYPE, Length[2]);\
}\
} while (0,0)
PAGED_CODE();
NTSTATUS Result = STATUS_SUCCESS;
PUINT8 StreamInfoEnd = (PUINT8)StreamInfo + StreamInfoSize;
PUINT8 DestBufBgn = (PUINT8)DestBuf;
PUINT8 DestBufEnd = (PUINT8)DestBuf + *PDestLen;
PVOID PrevDestBuf = 0;
ULONG StreamNameLength, CopyLength;
ULONG BaseInfoLen = FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName);
*PDestLen = 0;
for (;
NT_SUCCESS(Result) && (PUINT8)StreamInfo + sizeof(StreamInfo->Size) <= StreamInfoEnd;
StreamInfo = (PVOID)((PUINT8)StreamInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(StreamInfoSize)))
{
StreamInfoSize = StreamInfo->Size;
if (sizeof(FSP_FSCTL_STREAM_INFO) > StreamInfoSize)
break;
StreamNameLength = StreamInfoSize - sizeof(FSP_FSCTL_STREAM_INFO) + STREAM_EXTRA_LENGTH;
/* CopyLength is the same as StreamNameLength except on STATUS_BUFFER_OVERFLOW */
CopyLength = StreamNameLength;
/* do we have enough space for this stream info? */
if ((PUINT8)DestBuf + BaseInfoLen + CopyLength > DestBufEnd)
{
/* can we even copy the base info? */
if ((PUINT8)DestBuf + BaseInfoLen > DestBufEnd)
{
if (0 == *PDestLen)
/* if we haven't copied anything yet, buffer is too small */
return STATUS_BUFFER_TOO_SMALL;
else
/* *PDestLen contains bytes copied so far */
return STATUS_BUFFER_OVERFLOW;
}
/* copy as much of the stream name as we can and return STATUS_BUFFER_OVERFLOW */
CopyLength = (ULONG)(DestBufEnd - ((PUINT8)DestBuf + BaseInfoLen));
Result = STATUS_BUFFER_OVERFLOW;
}
/* fill in NextEntryOffset */
if (0 != PrevDestBuf)
*(PULONG)PrevDestBuf = (ULONG)((PUINT8)DestBuf - (PUINT8)PrevDestBuf);
PrevDestBuf = DestBuf;
/* update bytes copied */
*PDestLen = (ULONG)((PUINT8)DestBuf + BaseInfoLen + CopyLength - DestBufBgn);
FILL_INFO();
/* advance DestBuf; make sure to align properly! */
DestBuf = (PVOID)((PUINT8)DestBuf +
FSP_FSCTL_ALIGN_UP(BaseInfoLen + CopyLength, sizeof(LONGLONG)));
}
/* our code flow should allow only these two status codes here */
ASSERT(STATUS_SUCCESS == Result || STATUS_BUFFER_OVERFLOW == Result);
return Result;
#undef FILL_INFO
#undef STREAM_EXTRA_LENGTH
#undef STREAM_TYPE_LENGTH
#undef STREAM_TYPE
}
static NTSTATUS FspFsvolQueryStreamInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
if (!FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.NamedStreams)
return STATUS_INVALID_PARAMETER;
NTSTATUS Result;
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
ULONG Length = IrpSp->Parameters.QueryFile.Length;
PVOID StreamInfoBuffer;
ULONG StreamInfoBufferSize;
FSP_FSCTL_TRANSACT_REQ *Request;
ASSERT(FileNode == FileDesc->FileNode);
FspFileNodeAcquireShared(FileNode, Main);
if (FspFileNodeReferenceStreamInfo(FileNode, &StreamInfoBuffer, &StreamInfoBufferSize))
{
FspFileNodeRelease(FileNode, Main);
Result = FspFsvolQueryStreamInformationCopy(
StreamInfoBuffer, StreamInfoBufferSize, Buffer, &Length);
FspFileNodeDereferenceStreamInfo(StreamInfoBuffer);
Irp->IoStatus.Information = Length;
return Result;
}
FspFileNodeAcquireShared(FileNode, Pgio);
Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolQueryInformationRequestFini, &Request);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
return Result;
}
Request->Kind = FspFsctlTransactQueryStreamInformationKind;
Request->Req.QueryStreamInformation.UserContext = FileNode->UserContext;
Request->Req.QueryStreamInformation.UserContext2 = FileDesc->UserContext2;
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
return FSP_STATUS_IOQ_POST;
}
static NTSTATUS FspFsvolQueryStreamInformationSuccess(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
{
PAGED_CODE();
if (!FspFsvolDeviceExtension(IoGetCurrentIrpStackLocation(Irp)->DeviceObject)->
VolumeParams.NamedStreams)
return STATUS_INVALID_PARAMETER;
NTSTATUS Result;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
ULONG Length = IrpSp->Parameters.QueryFile.Length;
PVOID StreamInfoBuffer = 0;
ULONG StreamInfoBufferSize = 0;
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
BOOLEAN Success;
if (0 != FspIopRequestContext(Request, RequestFileNode))
{
/* check that the stream info we got back is valid */
if (Response->Buffer + Response->Rsp.QueryStreamInformation.Buffer.Size >
(PUINT8)Response + Response->Size)
{
Irp->IoStatus.Information = 0;
return STATUS_INFO_LENGTH_MISMATCH; /* ???: what is the best code to return here? */
}
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)
FspFileNodeStreamInfoChangeNumber(FileNode);
FspIopRequestContext(Request, RequestFileNode) = 0;
FspFileNodeReleaseOwner(FileNode, Full, Request);
}
Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusive(FileNode, Main);
if (!Success)
{
FspIopRetryCompleteIrp(Irp, Response, &Result);
return Result;
}
Success = !FspFileNodeTrySetStreamInfo(FileNode,
Response->Buffer, Response->Rsp.QueryStreamInformation.Buffer.Size,
(ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestInfoChangeNumber));
Success = Success &&
FspFileNodeReferenceStreamInfo(FileNode, &StreamInfoBuffer, &StreamInfoBufferSize);
FspFileNodeRelease(FileNode, Main);
if (Success)
{
Result = FspFsvolQueryStreamInformationCopy(
StreamInfoBuffer, StreamInfoBufferSize, Buffer, &Length);
FspFileNodeDereferenceStreamInfo(StreamInfoBuffer);
}
else
{
StreamInfoBuffer = (PVOID)Response->Buffer;
StreamInfoBufferSize = Response->Rsp.QueryStreamInformation.Buffer.Size;
Result = FspFsvolQueryStreamInformationCopy(
StreamInfoBuffer, StreamInfoBufferSize, Buffer, &Length);
}
Irp->IoStatus.Information = Length;
return Result;
}
static NTSTATUS FspFsvolQueryInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
@ -353,8 +597,13 @@ static NTSTATUS FspFsvolQueryInformation(
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
return STATUS_INVALID_DEVICE_REQUEST;
NTSTATUS Result;
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
/* special case FileStreamInformation */
if (FileStreamInformation == FileInformationClass)
return FspFsvolQueryStreamInformation(FsvolDeviceObject, Irp, IrpSp);
NTSTATUS Result;
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
@ -410,9 +659,6 @@ static NTSTATUS FspFsvolQueryInformation(
case FileStandardInformation:
Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, 0);
break;
case FileStreamInformation:
Result = STATUS_INVALID_PARAMETER; /* !!!: no stream support yet! */
return Result;
default:
Result = STATUS_INVALID_PARAMETER;
return Result;
@ -491,6 +737,11 @@ NTSTATUS FspFsvolQueryInformationComplete(
}
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
/* special case FileStreamInformation */
if (FileStreamInformation == FileInformationClass)
FSP_RETURN(Result = FspFsvolQueryStreamInformationSuccess(Irp, Response));
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
@ -502,7 +753,8 @@ NTSTATUS FspFsvolQueryInformationComplete(
if (0 != FspIopRequestContext(Request, RequestFileNode))
{
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)FileNode->InfoChangeNumber;
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)
FspFileNodeFileInfoChangeNumber(FileNode);
FspIopRequestContext(Request, RequestFileNode) = 0;
FspFileNodeReleaseOwner(FileNode, Full, Request);
@ -845,7 +1097,6 @@ static NTSTATUS FspFsvolSetRenameInformation(
PFILE_OBJECT TargetFileObject = IrpSp->Parameters.SetFile.FileObject;
PFILE_RENAME_INFORMATION Info = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
ULONG Length = IrpSp->Parameters.SetFile.Length;
BOOLEAN ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
FSP_FILE_NODE *TargetFileNode = 0 != TargetFileObject ?
@ -865,7 +1116,7 @@ static NTSTATUS FspFsvolSetRenameInformation(
if (FileNode->IsRootDirectory)
/* cannot rename root directory */
return STATUS_INVALID_PARAMETER;
if (!FspUnicodePathIsValid(&FileNode->FileName, FALSE))
if (!FspUnicodePathIsValid(&FileNode->FileName, 0, 0))
/* cannot rename streams (WinFsp limitation) */
return STATUS_INVALID_PARAMETER;
@ -890,7 +1141,7 @@ static NTSTATUS FspFsvolSetRenameInformation(
if (L'\\' == Suffix.Buffer[0])
FspUnicodePathSuffix(&Suffix, &NewFileName, &Suffix);
if (!FspUnicodePathIsValid(&Remain, FALSE) || !FspUnicodePathIsValid(&Suffix, FALSE))
if (!FspUnicodePathIsValid(&Remain, 0, 0) || !FspUnicodePathIsValid(&Suffix, 0, 0))
{
/* cannot rename streams (WinFsp limitation) */
Result = STATUS_INVALID_PARAMETER;
@ -922,7 +1173,6 @@ static NTSTATUS FspFsvolSetRenameInformation(
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);
Request->Req.SetInformation.Info.Rename.ReplaceIfExists = ReplaceIfExists;
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
FspFileNodeSetOwner(FileNode, Full, Request);
@ -979,9 +1229,8 @@ static NTSTATUS FspFsvolSetRenameInformationSuccess(
NewFileName.Length = NewFileName.MaximumLength =
Request->Req.SetInformation.Info.Rename.NewFileName.Size - sizeof(WCHAR);
NewFileName.Buffer = FspAllocMustSucceed(NewFileName.Length);
RtlCopyMemory(NewFileName.Buffer, Request->Buffer + Request->FileName.Size, NewFileName.Length);
NewFileName.Buffer = (PVOID)
(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset);
FspFileNodeRename(FileNode, &NewFileName);
/* fastfat has some really arcane rules on rename notifications; simplify! */
@ -1095,6 +1344,59 @@ static NTSTATUS FspFsvolSetInformation(
return FSP_STATUS_IOQ_POST;
}
NTSTATUS FspFsvolSetInformationPrepare(
PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request)
{
PAGED_CODE();
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
if (FileRenameInformation != IrpSp->Parameters.SetFile.FileInformationClass ||
!IrpSp->Parameters.SetFile.ReplaceIfExists)
return STATUS_SUCCESS;
NTSTATUS Result;
SECURITY_SUBJECT_CONTEXT SecuritySubjectContext;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
SECURITY_CLIENT_CONTEXT SecurityClientContext;
HANDLE UserModeAccessToken;
PEPROCESS Process;
/* 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,
&SecurityQualityOfService, FALSE, &SecurityClientContext);
SeUnlockSubjectContext(&SecuritySubjectContext);
SeReleaseSubjectContext(&SecuritySubjectContext);
if (!NT_SUCCESS(Result))
return Result;
ASSERT(TokenImpersonation == SeTokenType(SecurityClientContext.ClientToken));
/* get a user-mode handle to the impersonation token */
Result = ObOpenObjectByPointer(SecurityClientContext.ClientToken,
0, 0, TOKEN_QUERY, *SeTokenObjectType, UserMode, &UserModeAccessToken);
SeDeleteClientSecurity(&SecurityClientContext);
if (!NT_SUCCESS(Result))
return Result;
/* get a pointer to the current process so that we can close the impersonation token later */
Process = PsGetCurrentProcess();
ObReferenceObject(Process);
/* send the user-mode handle to the user-mode file system */
FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken;
FspIopRequestContext(Request, RequestProcess) = Process;
Request->Req.SetInformation.Info.Rename.AccessToken = (UINT_PTR)UserModeAccessToken;
return STATUS_SUCCESS;
}
NTSTATUS FspFsvolSetInformationComplete(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
{
@ -1154,12 +1456,38 @@ static VOID FspFsvolSetInformationRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
PDEVICE_OBJECT FsvolDeviceObject = Context[RequestDeviceObject];
HANDLE AccessToken = Context[RequestAccessToken];
PEPROCESS Process = Context[RequestProcess];
if (0 != FileNode)
FspFileNodeReleaseOwner(FileNode, Full, Request);
if (0 != FsvolDeviceObject)
FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, Request);
if (0 != AccessToken)
{
KAPC_STATE ApcState;
BOOLEAN Attach;
ASSERT(0 != Process);
Attach = Process != PsGetCurrentProcess();
if (Attach)
KeStackAttachProcess(Process, &ApcState);
#if DBG
NTSTATUS Result0;
Result0 = ObCloseHandle(AccessToken, UserMode);
if (!NT_SUCCESS(Result0))
DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result0));
#else
ObCloseHandle(AccessToken, UserMode);
#endif
if (Attach)
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
}
}
NTSTATUS FspQueryInformation(

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the

View File

@ -6,9 +6,9 @@
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
@ -18,21 +18,36 @@
#include <sys/driver.h>
static NTSTATUS FspFsctlFileSystemControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolFileSystemControlReparsePoint(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN IsWrite);
static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
BOOLEAN IsWrite);
static NTSTATUS FspFsvolFileSystemControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
static FSP_IOP_REQUEST_FINI FspFsvolFileSystemControlRequestFini;
FSP_DRIVER_DISPATCH FspFileSystemControl;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePoint)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePointComplete)
#pragma alloc_text(PAGE, FspFsvolFileSystemControl)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlComplete)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlRequestFini)
#pragma alloc_text(PAGE, FspFileSystemControl)
#endif
enum
{
RequestFileNode = 0,
};
static NTSTATUS FspFsctlFileSystemControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
@ -44,32 +59,247 @@ static NTSTATUS FspFsctlFileSystemControl(
{
case FSP_FSCTL_VOLUME_NAME:
if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeGetName(DeviceObject, Irp, IrpSp);
Result = FspVolumeGetName(FsctlDeviceObject, Irp, IrpSp);
break;
case FSP_FSCTL_VOLUME_LIST:
Result = FspVolumeGetNameList(DeviceObject, Irp, IrpSp);
Result = FspVolumeGetNameList(FsctlDeviceObject, Irp, IrpSp);
break;
case FSP_FSCTL_TRANSACT:
case FSP_FSCTL_TRANSACT_BATCH:
if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeTransact(DeviceObject, Irp, IrpSp);
Result = FspVolumeTransact(FsctlDeviceObject, Irp, IrpSp);
break;
case FSP_FSCTL_STOP:
if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeStop(DeviceObject, Irp, IrpSp);
Result = FspVolumeStop(FsctlDeviceObject, Irp, IrpSp);
break;
}
break;
case IRP_MN_MOUNT_VOLUME:
Result = FspVolumeMount(DeviceObject, Irp, IrpSp);
Result = FspVolumeMount(FsctlDeviceObject, Irp, IrpSp);
break;
}
return Result;
}
static NTSTATUS FspFsvolFileSystemControlReparsePoint(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN IsWrite)
{
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PFILE_OBJECT FileObject = IrpSp->FileObject;
/* do we support reparse points? */
if (!FsvolDeviceExtension->VolumeParams.ReparsePoints)
return STATUS_INVALID_DEVICE_REQUEST;
/* is this a valid FileObject? */
if (!FspFileNodeIsValid(FileObject->FsContext))
return STATUS_INVALID_DEVICE_REQUEST;
NTSTATUS Result;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
ULONG FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;
PVOID OutputBuffer = Irp->UserBuffer;
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
PREPARSE_DATA_BUFFER ReparseData;
PWSTR ReparseTargetPath;
USHORT ReparseTargetPathLength;
UINT16 TargetOnFileSystem = 0;
FSP_FSCTL_TRANSACT_REQ *Request;
ASSERT(FileNode == FileDesc->FileNode);
if (IsWrite)
{
if (0 == InputBuffer || 0 == InputBufferLength ||
FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMAX - (FileNode->FileName.Length + sizeof(WCHAR)) <
InputBufferLength)
return STATUS_INVALID_PARAMETER;
Result = FsRtlValidateReparsePointBuffer(InputBufferLength, InputBuffer);
if (!NT_SUCCESS(Result))
return Result;
ReparseData = (PREPARSE_DATA_BUFFER)InputBuffer;
if (IO_REPARSE_TAG_SYMLINK == ReparseData->ReparseTag)
{
/* NTFS severely limits symbolic links; we will not do that unless our file system asks */
if (FsvolDeviceExtension->VolumeParams.ReparsePointsAccessCheck)
{
if (KernelMode != Irp->RequestorMode &&
!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_CREATE_SYMBOLIC_LINK_PRIVILEGE),
UserMode))
return STATUS_PRIVILEGE_NOT_HELD;
}
ReparseTargetPath = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
ReparseTargetPathLength = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
/* is this an absolute path? determine if target resides on same device as link */
if (!FlagOn(ReparseData->SymbolicLinkReparseBuffer.Flags, SYMLINK_FLAG_RELATIVE) &&
ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0])
{
UNICODE_STRING TargetObjectName;
PDEVICE_OBJECT TargetDeviceObject;
PFILE_OBJECT TargetFileObject;
ULONG TargetFileNameIndex;
ULONG32 TargetProviderId;
FSRTL_MUP_PROVIDER_INFO_LEVEL_1 ProviderInfo;
ULONG ProviderInfoSize;
TargetObjectName.Length = TargetObjectName.MaximumLength = ReparseTargetPathLength;
TargetObjectName.Buffer = ReparseTargetPath;
/* get a pointer to the target device */
Result = FspGetDeviceObjectPointer(&TargetObjectName, FILE_READ_DATA,
&TargetFileNameIndex, &TargetFileObject, &TargetDeviceObject);
if (!NT_SUCCESS(Result))
goto target_check_exit;
/* is the target device the same as ours? */
if (TargetFileNameIndex < ReparseTargetPathLength &&
IoGetRelatedDeviceObject(FileObject) == TargetDeviceObject)
{
if (0 == FsvolDeviceExtension->VolumePrefix.Length)
/* not going thru MUP: DONE! */
TargetOnFileSystem = (UINT16)TargetFileNameIndex;
else
{
/* going thru MUP cases: \Device\Volume{GUID} and \??\UNC\{VolumePrefix} */
ProviderInfoSize = sizeof ProviderInfo;
Result = FsRtlMupGetProviderInfoFromFileObject(TargetFileObject, 1,
&ProviderInfo, &ProviderInfoSize);
if (NT_SUCCESS(Result))
{
/* case \Device\Volume{GUID}: is the targer provider id same as ours? */
TargetProviderId = ProviderInfo.ProviderId;
ProviderInfoSize = sizeof ProviderInfo;
Result = FsRtlMupGetProviderInfoFromFileObject(FileObject, 1,
&ProviderInfo, &ProviderInfoSize);
if (!NT_SUCCESS(Result))
goto target_check_exit;
if (ProviderInfo.ProviderId == TargetProviderId)
TargetOnFileSystem = (UINT16)TargetFileNameIndex;
}
else
{
/* case \??\UNC\{VolumePrefix}: is the target volume prefix same as ours? */
TargetObjectName.Length = TargetObjectName.MaximumLength =
FsvolDeviceExtension->VolumePrefix.Length;
TargetObjectName.Buffer = ReparseTargetPath +
TargetFileNameIndex / sizeof(WCHAR);
TargetFileNameIndex += FsvolDeviceExtension->VolumePrefix.Length;
if (TargetFileNameIndex < ReparseTargetPathLength &&
RtlEqualUnicodeString(&FsvolDeviceExtension->VolumePrefix,
&TargetObjectName,
FSP_VOLUME_PREFIX_CASE_INS))
TargetOnFileSystem = (UINT16)TargetFileNameIndex;
}
}
}
ObDereferenceObject(TargetFileObject);
target_check_exit:
;
}
}
FspFileNodeAcquireExclusive(FileNode, Full);
}
else
{
if (0 == OutputBuffer || 0 == OutputBufferLength)
return STATUS_INVALID_PARAMETER;
/*
* NtFsControlFile (IopXxxControlFile) will setup Irp->AssociatedIrp.SystemBuffer
* with enough space for either InputBufferLength or OutputBufferLength. There is
* no need to call FspBufferUserBuffer ourselves.
*/
FspFileNodeAcquireShared(FileNode, Full);
}
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, IsWrite ? InputBufferLength : 0,
FspFsvolFileSystemControlRequestFini, &Request);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
return Result;
}
Request->Kind = FspFsctlTransactFileSystemControlKind;
Request->Req.FileSystemControl.UserContext = FileNode->UserContext;
Request->Req.FileSystemControl.UserContext2 = FileDesc->UserContext2;
Request->Req.FileSystemControl.FsControlCode = FsControlCode;
if (IsWrite)
{
Request->Req.FileSystemControl.Buffer.Offset = Request->FileName.Size;
Request->Req.FileSystemControl.Buffer.Size = (UINT16)InputBufferLength;
RtlCopyMemory(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset,
InputBuffer, InputBufferLength);
Request->Req.FileSystemControl.TargetOnFileSystem = TargetOnFileSystem;
}
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
return FSP_STATUS_IOQ_POST;
}
static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
BOOLEAN IsWrite)
{
PAGED_CODE();
if (IsWrite)
return STATUS_SUCCESS;
NTSTATUS Result;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PVOID OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
if (Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset +
Response->Rsp.FileSystemControl.Buffer.Size > (PUINT8)Response + Response->Size)
return STATUS_IO_REPARSE_DATA_INVALID;
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.FileSystemControl.Buffer.Size,
(PVOID)(Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset));
if (!NT_SUCCESS(Result))
return Result;
if (Response->Rsp.FileSystemControl.Buffer.Size > OutputBufferLength)
return STATUS_BUFFER_TOO_SMALL;
RtlCopyMemory(OutputBuffer, Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset,
Response->Rsp.FileSystemControl.Buffer.Size);
Irp->IoStatus.Information = Response->Rsp.FileSystemControl.Buffer.Size;
return STATUS_SUCCESS;
}
static NTSTATUS FspFsvolFileSystemControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
@ -81,7 +311,14 @@ static NTSTATUS FspFsvolFileSystemControl(
{
case FSP_FSCTL_WORK:
case FSP_FSCTL_WORK_BEST_EFFORT:
Result = FspVolumeWork(DeviceObject, Irp, IrpSp);
Result = FspVolumeWork(FsvolDeviceObject, Irp, IrpSp);
break;
case FSCTL_GET_REPARSE_POINT:
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, FALSE);
break;
case FSCTL_SET_REPARSE_POINT:
case FSCTL_DELETE_REPARSE_POINT:
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, TRUE);
break;
}
break;
@ -95,6 +332,43 @@ NTSTATUS FspFsvolFileSystemControlComplete(
{
FSP_ENTER_IOC(PAGED_CODE());
/* exit now if we do not have a FileObject (FSP_FSCTL_WORK*) */
if (0 == IrpSp->FileObject)
FSP_RETURN();
if (!NT_SUCCESS(Response->IoStatus.Status))
{
Irp->IoStatus.Information = 0;
Result = Response->IoStatus.Status;
FSP_RETURN();
}
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
Result = STATUS_INVALID_DEVICE_REQUEST;
switch (IrpSp->MinorFunction)
{
case IRP_MN_USER_FS_REQUEST:
switch (IrpSp->Parameters.FileSystemControl.FsControlCode)
{
case FSCTL_GET_REPARSE_POINT:
Result = FspFsvolFileSystemControlReparsePointComplete(Irp, Response, FALSE);
break;
case FSCTL_SET_REPARSE_POINT:
case FSCTL_DELETE_REPARSE_POINT:
Result = FspFsvolFileSystemControlReparsePointComplete(Irp, Response, TRUE);
break;
}
break;
}
ASSERT(STATUS_INVALID_DEVICE_REQUEST != Result);
FspIopRequestContext(Request, RequestFileNode) = 0;
FspFileNodeReleaseOwner(FileNode, Full, Request);
FSP_LEAVE_IOC(
"%s%sFileObject=%p",
IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ?
@ -103,6 +377,16 @@ NTSTATUS FspFsvolFileSystemControlComplete(
IrpSp->FileObject);
}
static VOID FspFsvolFileSystemControlRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4])
{
PAGED_CODE();
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
if (0 != FileNode)
FspFileNodeReleaseOwner(FileNode, Full, Request);
}
NTSTATUS FspFileSystemControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp)
{

View File

@ -89,82 +89,82 @@ SYM(FSCTL_DFSR_SET_GHOST_HANDLE_STATE)
SYM(FSCTL_TXFS_LIST_TRANSACTIONS)
SYM(FSCTL_QUERY_PAGEFILE_ENCRYPTION)
SYM(FSCTL_RESET_VOLUME_ALLOCATION_HINTS)
SYM(FSCTL_QUERY_DEPENDENT_VOLUME)
SYM(FSCTL_SD_GLOBAL_CHANGE)
//SYM(FSCTL_QUERY_DEPENDENT_VOLUME)
//SYM(FSCTL_SD_GLOBAL_CHANGE)
SYM(FSCTL_TXFS_READ_BACKUP_INFORMATION2)
SYM(FSCTL_LOOKUP_STREAM_FROM_CLUSTER)
SYM(FSCTL_TXFS_WRITE_BACKUP_INFORMATION2)
SYM(FSCTL_FILE_TYPE_NOTIFICATION)
SYM(FSCTL_FILE_LEVEL_TRIM)
SYM(FSCTL_GET_BOOT_AREA_INFO)
SYM(FSCTL_GET_RETRIEVAL_POINTER_BASE)
SYM(FSCTL_SET_PERSISTENT_VOLUME_STATE)
SYM(FSCTL_QUERY_PERSISTENT_VOLUME_STATE)
SYM(FSCTL_REQUEST_OPLOCK)
SYM(FSCTL_CSV_TUNNEL_REQUEST)
SYM(FSCTL_IS_CSV_FILE)
SYM(FSCTL_QUERY_FILE_SYSTEM_RECOGNITION)
SYM(FSCTL_CSV_GET_VOLUME_PATH_NAME)
SYM(FSCTL_CSV_GET_VOLUME_NAME_FOR_VOLUME_MOUNT_POINT)
SYM(FSCTL_CSV_GET_VOLUME_PATH_NAMES_FOR_VOLUME_NAME)
SYM(FSCTL_IS_FILE_ON_CSV_VOLUME)
SYM(FSCTL_CORRUPTION_HANDLING)
SYM(FSCTL_OFFLOAD_READ)
SYM(FSCTL_OFFLOAD_WRITE)
SYM(FSCTL_CSV_INTERNAL)
SYM(FSCTL_SET_PURGE_FAILURE_MODE)
SYM(FSCTL_QUERY_FILE_LAYOUT)
SYM(FSCTL_IS_VOLUME_OWNED_BYCSVFS)
SYM(FSCTL_GET_INTEGRITY_INFORMATION)
SYM(FSCTL_SET_INTEGRITY_INFORMATION)
SYM(FSCTL_QUERY_FILE_REGIONS)
SYM(FSCTL_DEDUP_FILE)
SYM(FSCTL_DEDUP_QUERY_FILE_HASHES)
SYM(FSCTL_DEDUP_QUERY_RANGE_STATE)
SYM(FSCTL_DEDUP_QUERY_REPARSE_INFO)
SYM(FSCTL_RKF_INTERNAL)
SYM(FSCTL_SCRUB_DATA)
SYM(FSCTL_REPAIR_COPIES)
SYM(FSCTL_DISABLE_LOCAL_BUFFERING)
SYM(FSCTL_CSV_MGMT_LOCK)
SYM(FSCTL_CSV_QUERY_DOWN_LEVEL_FILE_SYSTEM_CHARACTERISTICS)
SYM(FSCTL_ADVANCE_FILE_ID)
SYM(FSCTL_CSV_SYNC_TUNNEL_REQUEST)
SYM(FSCTL_CSV_QUERY_VETO_FILE_DIRECT_IO)
SYM(FSCTL_WRITE_USN_REASON)
SYM(FSCTL_CSV_CONTROL)
SYM(FSCTL_GET_REFS_VOLUME_DATA)
SYM(FSCTL_CSV_H_BREAKING_SYNC_TUNNEL_REQUEST)
SYM(FSCTL_QUERY_STORAGE_CLASSES)
SYM(FSCTL_QUERY_REGION_INFO)
SYM(FSCTL_USN_TRACK_MODIFIED_RANGES)
SYM(FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT)
SYM(FSCTL_SVHDX_SYNC_TUNNEL_REQUEST)
SYM(FSCTL_SVHDX_SET_INITIATOR_INFORMATION)
SYM(FSCTL_SET_EXTERNAL_BACKING)
SYM(FSCTL_GET_EXTERNAL_BACKING)
SYM(FSCTL_DELETE_EXTERNAL_BACKING)
SYM(FSCTL_ENUM_EXTERNAL_BACKING)
SYM(FSCTL_ENUM_OVERLAY)
SYM(FSCTL_ADD_OVERLAY)
SYM(FSCTL_REMOVE_OVERLAY)
SYM(FSCTL_UPDATE_OVERLAY)
SYM(FSCTL_DUPLICATE_EXTENTS_TO_FILE)
SYM(FSCTL_SPARSE_OVERALLOCATE)
SYM(FSCTL_STORAGE_QOS_CONTROL)
SYM(FSCTL_INITIATE_FILE_METADATA_OPTIMIZATION)
SYM(FSCTL_QUERY_FILE_METADATA_OPTIMIZATION)
SYM(FSCTL_SVHDX_ASYNC_TUNNEL_REQUEST)
SYM(FSCTL_GET_WOF_VERSION)
SYM(FSCTL_HCS_SYNC_TUNNEL_REQUEST)
SYM(FSCTL_HCS_ASYNC_TUNNEL_REQUEST)
SYM(FSCTL_QUERY_EXTENT_READ_CACHE_INFO)
SYM(FSCTL_QUERY_REFS_VOLUME_COUNTER_INFO)
SYM(FSCTL_CLEAN_VOLUME_METADATA)
SYM(FSCTL_SET_INTEGRITY_INFORMATION_EX)
SYM(FSCTL_SUSPEND_OVERLAY)
SYM(FSCTL_VIRTUAL_STORAGE_QUERY_PROPERTY)
SYM(FSCTL_FILESYSTEM_GET_STATISTICS_EX)
//SYM(FSCTL_LOOKUP_STREAM_FROM_CLUSTER)
//SYM(FSCTL_TXFS_WRITE_BACKUP_INFORMATION2)
//SYM(FSCTL_FILE_TYPE_NOTIFICATION)
//SYM(FSCTL_FILE_LEVEL_TRIM)
//SYM(FSCTL_GET_BOOT_AREA_INFO)
//SYM(FSCTL_GET_RETRIEVAL_POINTER_BASE)
//SYM(FSCTL_SET_PERSISTENT_VOLUME_STATE)
//SYM(FSCTL_QUERY_PERSISTENT_VOLUME_STATE)
//SYM(FSCTL_REQUEST_OPLOCK)
//SYM(FSCTL_CSV_TUNNEL_REQUEST)
//SYM(FSCTL_IS_CSV_FILE)
//SYM(FSCTL_QUERY_FILE_SYSTEM_RECOGNITION)
//SYM(FSCTL_CSV_GET_VOLUME_PATH_NAME)
//SYM(FSCTL_CSV_GET_VOLUME_NAME_FOR_VOLUME_MOUNT_POINT)
//SYM(FSCTL_CSV_GET_VOLUME_PATH_NAMES_FOR_VOLUME_NAME)
//SYM(FSCTL_IS_FILE_ON_CSV_VOLUME)
//SYM(FSCTL_CORRUPTION_HANDLING)
//SYM(FSCTL_OFFLOAD_READ)
//SYM(FSCTL_OFFLOAD_WRITE)
//SYM(FSCTL_CSV_INTERNAL)
//SYM(FSCTL_SET_PURGE_FAILURE_MODE)
//SYM(FSCTL_QUERY_FILE_LAYOUT)
//SYM(FSCTL_IS_VOLUME_OWNED_BYCSVFS)
//SYM(FSCTL_GET_INTEGRITY_INFORMATION)
//SYM(FSCTL_SET_INTEGRITY_INFORMATION)
//SYM(FSCTL_QUERY_FILE_REGIONS)
//SYM(FSCTL_DEDUP_FILE)
//SYM(FSCTL_DEDUP_QUERY_FILE_HASHES)
//SYM(FSCTL_DEDUP_QUERY_RANGE_STATE)
//SYM(FSCTL_DEDUP_QUERY_REPARSE_INFO)
//SYM(FSCTL_RKF_INTERNAL)
//SYM(FSCTL_SCRUB_DATA)
//SYM(FSCTL_REPAIR_COPIES)
//SYM(FSCTL_DISABLE_LOCAL_BUFFERING)
//SYM(FSCTL_CSV_MGMT_LOCK)
//SYM(FSCTL_CSV_QUERY_DOWN_LEVEL_FILE_SYSTEM_CHARACTERISTICS)
//SYM(FSCTL_ADVANCE_FILE_ID)
//SYM(FSCTL_CSV_SYNC_TUNNEL_REQUEST)
//SYM(FSCTL_CSV_QUERY_VETO_FILE_DIRECT_IO)
//SYM(FSCTL_WRITE_USN_REASON)
//SYM(FSCTL_CSV_CONTROL)
//SYM(FSCTL_GET_REFS_VOLUME_DATA)
//SYM(FSCTL_CSV_H_BREAKING_SYNC_TUNNEL_REQUEST)
//SYM(FSCTL_QUERY_STORAGE_CLASSES)
//SYM(FSCTL_QUERY_REGION_INFO)
//SYM(FSCTL_USN_TRACK_MODIFIED_RANGES)
//SYM(FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT)
//SYM(FSCTL_SVHDX_SYNC_TUNNEL_REQUEST)
//SYM(FSCTL_SVHDX_SET_INITIATOR_INFORMATION)
//SYM(FSCTL_SET_EXTERNAL_BACKING)
//SYM(FSCTL_GET_EXTERNAL_BACKING)
//SYM(FSCTL_DELETE_EXTERNAL_BACKING)
//SYM(FSCTL_ENUM_EXTERNAL_BACKING)
//SYM(FSCTL_ENUM_OVERLAY)
//SYM(FSCTL_ADD_OVERLAY)
//SYM(FSCTL_REMOVE_OVERLAY)
//SYM(FSCTL_UPDATE_OVERLAY)
//SYM(FSCTL_DUPLICATE_EXTENTS_TO_FILE)
//SYM(FSCTL_SPARSE_OVERALLOCATE)
//SYM(FSCTL_STORAGE_QOS_CONTROL)
//SYM(FSCTL_INITIATE_FILE_METADATA_OPTIMIZATION)
//SYM(FSCTL_QUERY_FILE_METADATA_OPTIMIZATION)
//SYM(FSCTL_SVHDX_ASYNC_TUNNEL_REQUEST)
//SYM(FSCTL_GET_WOF_VERSION)
//SYM(FSCTL_HCS_SYNC_TUNNEL_REQUEST)
//SYM(FSCTL_HCS_ASYNC_TUNNEL_REQUEST)
//SYM(FSCTL_QUERY_EXTENT_READ_CACHE_INFO)
//SYM(FSCTL_QUERY_REFS_VOLUME_COUNTER_INFO)
//SYM(FSCTL_CLEAN_VOLUME_METADATA)
//SYM(FSCTL_SET_INTEGRITY_INFORMATION_EX)
//SYM(FSCTL_SUSPEND_OVERLAY)
//SYM(FSCTL_VIRTUAL_STORAGE_QUERY_PROPERTY)
//SYM(FSCTL_FILESYSTEM_GET_STATISTICS_EX)
SYM(FSCTL_LMR_GET_LINK_TRACKING_INFORMATION)
SYM(FSCTL_LMR_SET_LINK_TRACKING_INFORMATION)
SYM(IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER)

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