Compare commits

..

203 Commits

Author SHA1 Message Date
d54e9a3049 update changelog 2018-05-01 10:38:58 -07:00
7d56b9c23d dll: fuse: GetSecurityByName: correctly handle "not found" paths with symlinks 2018-04-30 14:18:03 -07:00
deb237f7b0 dll: fuse: fsp_fuse_intf_AddDirInfo: avoid deadlock with ReaddirPlus and symlinks 2018-04-30 13:31:06 -07:00
5ae0804bd2 doc: add EncFS to known file systems 2018-04-27 12:12:25 -07:00
382599e38f dll: fuse: add ThreadCount option 2018-04-23 15:35:30 -07:00
498ab91123 dll: fuse: replace -oFlushAndPurgeOnCleanup with -oKeepFileCache option 2018-04-23 15:12:30 -07:00
c2f87029d7 sys: FspFileNodeCleanupFlush:
- CcFlushCache now happens during initial Cleanup call
- avoids recursive call into file system during Cleanup completion
2018-04-23 14:30:38 -07:00
157c4bc09a sys: FspFileNodeCleanupComplete: FlushAndPurgeOnCleanup:
- comment about difference in behavior when DeletePending
2018-04-23 09:57:47 -07:00
4fcaa99d63 sys: FspFileNodeCleanupComplete: FlushAndPurgeOnCleanup:
- handle DeletePending and non-zero PTruncateSize better
2018-04-23 00:33:00 -07:00
d6c3849120 dll: fuse: fix wrong calc of FileInfoTimeout from attr_timeout 2018-04-22 23:42:20 -07:00
ec39d4b888 dll: fuse: DirInfoTimeout, VolumeInfoTimeout options 2018-04-22 23:36:47 -07:00
ebc8c268e5 appveyor: FSP_FSCTL_VOLUME_PARAMS size change compat testing 2018-04-22 11:16:25 -07:00
9501b5771d inc,sys,tst: FSP_FSCTL_VOLUME_PARAMS: fine-grained timeouts 2018-04-21 11:53:14 -07:00
5d34a3bd8c dll: fuse: FlushAndPurgeOnCleanup option 2018-04-19 13:04:34 -07:00
5b72b4ad4a tools: run-tests: FlushAndPurgeOnCleanup 2018-04-19 11:17:41 -07:00
740411d604 tst: FlushAndPurgeOnCleanup: testing 2018-04-19 10:23:15 -07:00
5c3549c6eb sys: file: FspFileNodeCleanupComplete: FlushAndPurgeOnCleanup 2018-04-18 20:58:19 -07:00
9f56a21c7f sys: cleanup: minor change 2018-04-18 20:13:08 -07:00
2e7e95df76 appveyor: troubleshoot create_pid_test, rename_pid_test 2018-04-17 16:34:59 -07:00
b2e6c16ba0 update changelog 2018-04-17 13:47:37 -07:00
bd32f54904 Revert "installer: launch MEMFS as LocalService"
This reverts commit a7febb8265.
2018-04-17 13:24:57 -07:00
7908ba09ac appveyor: troubleshoot rename_pid_test 2018-04-17 13:16:52 -07:00
5713605030 appveyor: troubleshoot create_pid_test 2018-04-17 13:14:34 -07:00
994e232fb3 fuse: add create_umask option 2018-04-17 12:46:13 -07:00
9553bd52c4 update changelog for v1.3B2 (overdue) 2018-04-17 12:26:48 -07:00
1cab0f3975 cygfuse: correctly use cygwin_create_path 2018-03-26 14:11:58 -07:00
499a3d1138 Merge pull request #154 from benrubson/cast
Correct a cast in winfsp_fuse
2018-03-26 13:07:30 -07:00
d29218ba69 Update Contributors.asciidoc 2018-03-26 21:50:37 +02:00
5564a9efae Correct a cast in winfsp_fuse 2018-03-26 10:36:26 +02:00
750e72e601 installer: add launch.h 2018-01-29 09:16:30 -08:00
9f13c6e915 build: update version to 2018.1 B3 2018-01-29 09:04:17 -08:00
5005dd6f5b dll: np: NPGetConnection fix and FspNpGetRemoteInfo 2018-01-19 04:58:38 -08:00
f9b6fb8817 build: update version to 2018.1 B2 2018-01-17 17:21:03 -08:00
6b0b4c8b8e sys: mup: claim \ClassName instead of \ClassName\InstanceName prefix 2018-01-17 15:44:01 -08:00
abb504053b sys: FspUnload 2018-01-16 18:26:23 -08:00
fb507fc0bc dll: np: DeviceName 2018-01-16 13:38:49 -08:00
d38afe8d16 sys: shutdown: fix Release build 2018-01-16 11:49:14 -08:00
a4629b8f8b sys: fsmup device
- This commit introduces the fsmup device, which is a major change in how
network file systems are handled. Previously every network file system's
fsvol device was directly registered with the MUP. Now there is a single
fsmup device that is registered with the MUP; network file systems' fsvol
devices register with fsmup instead. The fsmup device maintains a prefix
table which it uses to demultiplex and forward requests to the appropriate
fsvol device.
- This device change was necessatitated to fix issue #87.
2018-01-16 10:38:52 -08:00
670a38d549 Update ISSUE_TEMPLATE.md 2018-01-11 18:29:56 -08:00
b939f6bd2b doc: update FAQ doc 2018-01-11 18:27:22 -08:00
3df27f5b28 doc: rename API doc files 2018-01-11 17:25:17 -08:00
7581cece81 doc: rename API doc files 2018-01-11 17:18:33 -08:00
b4f5707e4e tools: apidoc
doc: launch.h
2018-01-11 17:09:20 -08:00
309827860f tools: run-tests: extra time for memfs to spin up (LocalService) 2018-01-11 16:39:45 -08:00
2b6b049f86 inc: launch.h: documentation 2018-01-11 16:35:56 -08:00
77f3e064a2 winfsp-tests: launch-test: disable as test is very fragile 2018-01-10 11:01:39 -08:00
f691a7a3c7 dll: FspLaunch*: testing 2018-01-09 23:12:05 -08:00
cc58668ce5 dll: FspLaunchReg*: testing 2018-01-09 22:17:07 -08:00
064d0b94f2 dll: FspLaunchRegSetRecord, FspLaunchRegGetRecord, FspLaunchRegFreeRecord 2018-01-09 17:45:49 -08:00
a48668149b inc: winfsp/launch.h 2018-01-09 11:38:27 -08:00
b9915dcaa7 update changelog 2018-01-04 19:19:54 -08:00
a7febb8265 installer: launch MEMFS as LocalService 2018-01-04 11:44:29 -08:00
d6aaf0088a Merge branch 'master' into pvt-launcher 2018-01-04 11:39:31 -08:00
f05af124e7 Merge branch 'felfert-providerorder' 2018-01-04 11:35:00 -08:00
886b7cf9f7 Merge branch 'providerorder' of https://github.com/felfert/winfsp into felfert-providerorder 2018-01-04 11:10:19 -08:00
e111451475 dll: FspLaunch API 2018-01-04 11:08:23 -08:00
0c38f92082 Use FSP_NP_ORDER_FIRST to specify provider order 2018-01-04 01:12:34 +01:00
9bd9cf4fbd update source copyright notices for 2018 2018-01-03 15:29:38 -08:00
2f026cbc6f launcher: code cleanup 2018-01-03 14:55:27 -08:00
68d8ade667 Speed up mount operation by putting winfsp network provider at the head of network providers 2017-12-29 18:56:11 +01:00
d9c450ecf4 update Changelog 2017-12-20 13:30:34 -08:00
e6d2ef9274 launcher: new WorkDirectory registry value controls file system work dir 2017-12-19 17:50:26 -08:00
299f371dee Merge branch 'pvt-launcher2' 2017-12-19 16:48:05 -08:00
bb8aee8673 Sort contributor names (alpha-sort by first name) 2017-12-19 16:26:23 -08:00
08bf8e14ce Merge branch 'felfert-winfsp#128' 2017-12-19 16:22:37 -08:00
ef1912bd8a installer: Product.wxs: whitespace fixes 2017-12-19 16:22:12 -08:00
ff155694ce launcher: can now perform DefineDosDevice in LocalSystem context
dll: uses launcher to DefineDosDevice for LocalService, etc.
2017-12-19 14:49:22 -08:00
e6ed6dbf4f Signed Contributors.asciidoc 2017-12-15 15:30:02 +01:00
f13b98c880 Add WixDependencyExtension and Provides WinFSPprovider 2017-12-15 14:53:06 +01:00
5d3b37122c launcher: LogonCreateProcess 2017-12-12 14:39:56 -08:00
9d1c892d68 Merge branch 'master' into pvt-launcher2 2017-12-12 14:30:13 -08:00
7008871ed7 Merge branch 'release/1.2' 2017-12-12 13:13:41 -08:00
2a3eabfab2 changelog: v1.2POST1 2017-12-12 10:07:54 -08:00
35255526d3 launcher: work around Win7 CreateProcess problem 2017-12-11 21:40:47 -08:00
b2e474658d launcher: work around Win7 CreateProcess problem 2017-12-11 21:23:38 -08:00
4fe85222b1 dll: wksid: well known SID's 2017-12-11 15:03:32 -08:00
fd3e5bad43 src: launcher: SvcInstanceAddUserRights:
- users who start a file system can always stop it and get info about it
2017-12-10 14:49:18 -08:00
ea873ece22 src: launcher: LogonCreateProcess: ImpersonateLoggedOnUser 2017-12-09 17:45:10 -08:00
42e01a9b27 src: launcher: RunAs, LogonCreateProcess 2017-12-09 17:00:09 -08:00
c1c9dca94b build: update version to 2018.1 B1 2017-12-09 11:43:43 -08:00
dcabdff422 .github: add issue and PR templates 2017-12-08 21:53:57 -08:00
a2ec40008f build: choco: update chocolatey package as per guidelines from chocolatey admin 2017-12-06 16:24:27 -08:00
f3819ba839 tst: passthrough-dotnet: fix ReadDirectoryEntry when running fs over drive root 2017-12-05 18:50:39 -08:00
ead599e337 tst: passthrough-dotnet: handle undoc wildcards in ReadDirectoryEntry
- reported by Pavel Franc over email
2017-12-05 10:32:58 -08:00
eb88f25f40 tst: passthrough-dotnet: Create,Overwrite: set archive bit 2017-12-04 16:24:48 -08:00
c2b066a054 dll: fuse: Create: do not add FILE_ATTRIBUTE_ARCHIVE for directories 2017-12-04 14:16:24 -08:00
266e0f4bab dll: fuse: call chflags from Create and Overwrite
tst: winfsp-tests: file attributes test
2017-12-04 14:08:44 -08:00
d02030897d dll: fuse: add O_EXCL during FUSE create op 2017-12-03 19:56:36 -08:00
c87ff75b8f sys: fix filename length check during query directory operations 2017-12-01 17:01:59 -08:00
2ca33665ef update changelog 2017-11-29 16:28:21 -08:00
391dcf8a21 build: update version to 1.2 (Gold) 2017-11-29 16:24:19 -08:00
69d68eb22f launcher: compute user name from client token
dll: np: do not pass user name as launcher argument
2017-11-29 16:20:15 -08:00
d58f4b84a5 opt: cygfuse: update tarballs 2017-11-28 16:53:21 -08:00
61935e4671 tst: passthrough-fuse: gix cygwin build 2017-11-28 16:52:36 -08:00
41838627c0 update README 2017-11-28 15:55:06 -08:00
0b67329fc2 doc: update known file systems 2017-11-28 15:46:07 -08:00
5c962c8fc5 doc: includes notes on backwards compat testing 2017-11-15 15:08:26 -08:00
a9080208d9 tools,tst: backwards compat testing for FUSE layer 2017-11-15 13:41:17 -08:00
3cc9697248 update changelog for v1.2B3 2017-11-15 11:57:53 -08:00
9f45d513ca build: update version to 2017.2 B3 2017-11-15 11:29:08 -08:00
77349c1330 tst: winfsp-tests: setfileinfo_test, stream_setfileinfo_test:
- perform time tests around UNIX epoch to accommodate 32-bit file systems
2017-11-15 10:48:15 -08:00
7c11a45e6e tst: passthrough-fuse: setcrtime 2017-11-14 21:55:41 -08:00
48ad297df1 dll: fuse: setcrtime, setchgtime 2017-11-14 21:55:09 -08:00
3d2de57e9d tst: passthrough-fuse: streamline time calculations 2017-11-14 21:38:20 -08:00
658d873efb dll: fuse: streamline time calculations 2017-11-14 21:37:50 -08:00
efc93cacd3 tst: passthrough-fuse: BSD flags support 2017-11-14 14:25:17 -08:00
41b54ef57a tools: run-tests: enable setfileinfo_test for passthrough-fuse 2017-11-14 12:02:19 -08:00
fd662ee848 tst: passthrough-fuse: BSD flags support 2017-11-14 12:01:00 -08:00
895bf67691 dll: fuse: implement BSD flags support 2017-11-14 09:11:51 -08:00
e06fe4153d dll: fuse: implement BSD flags support 2017-11-13 20:44:49 -08:00
9f2fe92db7 tst: memfs: slowio: improvements 2017-11-03 10:01:27 -07:00
d3f829b2df tools: run-tests: fsx-memfs-*-slowio 2017-11-02 21:45:08 -07:00
fa4651b3ce tst: winfsp-tests: enable slowio 2017-11-02 17:36:52 -07:00
5a44e5c04a tst: memfs: fix pending Write 2017-11-02 16:19:19 -07:00
68122b5c68 tst: winfsp-tests: enable slowiio 2017-11-02 15:59:32 -07:00
b672312c79 tst: memfs: code cleanup and testing 2017-11-02 15:43:14 -07:00
0ab35fde1a tst: memfs: slowio: minor code cleanup 2017-11-01 18:30:36 -07:00
9be2b7a2b9 tst: memfs: slowio 2017-11-01 17:12:29 -07:00
39dd7662bd Update Contributors.asciidoc 2017-11-01 09:58:11 -07:00
244afc8a3c Update memfs-main.c 2017-10-31 15:50:50 -07:00
111955db84 Update memfs.cpp 2017-10-31 15:44:24 -07:00
76ff8232bc Update memfs-main.c 2017-10-31 15:42:26 -07:00
9a3ac3c7a1 Update memfs.h 2017-10-31 15:39:19 -07:00
4adc0d4700 Update memfs-test.c 2017-10-31 15:36:09 -07:00
91c714dd53 Update fscrash-main.c 2017-10-31 15:32:12 -07:00
11cb57a0bf dll: np: pass username as argument to launcher 2017-10-27 15:12:18 -07:00
3a8ad9c8d7 sys: QueryDirectory stability:
- FspMetaCacheAddItem now handles exceptions during copy from fs buffer
- FspFsvolQueryDirectoryLengthMax is correct max length for QueryDirectory
2017-10-25 10:44:33 -07:00
fa388e57ad appveyor: add avast testing 2017-10-20 13:54:26 -07:00
1952d0d941 update changelog 2017-10-19 19:18:21 -07:00
1a02438488 sys: dirctl: fix 32-bit builds (after Avast changes) 2017-10-19 17:19:31 -07:00
07f15c236b sys: dirctl: eliminate use of SystemBuffer to work around problems with Avast 2017-10-19 16:49:10 -07:00
93af1be861 update changelog 2017-10-12 10:11:01 -07:00
b52c90f980 update changelog 2017-10-12 10:02:28 -07:00
b154c307b7 version.properties: update build to 2017.2 B2 2017-10-12 09:52:41 -07:00
697063af51 inc: winfsp.h: minor restructuring 2017-10-11 17:17:18 -07:00
436e31da34 dotnet: GetOperationProcessId 2017-10-11 17:07:38 -07:00
92e7dbad21 sys: Create and Rename requests should include the originating process PID 2017-10-11 16:28:50 -07:00
4812f5bbd0 sys: Create and Rename requests should include the originating process PID 2017-10-11 16:25:22 -07:00
045a1fa19c Update memfs-test.c 2017-10-09 14:51:18 -07:00
c9b2c0460b Update fscrash-main.c 2017-10-09 14:49:50 -07:00
1468df78a2 Update memfs.h 2017-10-09 14:48:33 -07:00
0fb6299f17 Update memfs-main.c 2017-10-09 14:47:28 -07:00
0da43fe2d4 Update memfs.cpp 2017-10-09 14:46:24 -07:00
d824ba464d version.properties: update build to 2017.2 B1 2017-10-01 11:45:23 -07:00
affca267c5 update changelog 2017-10-01 11:39:15 -07:00
4b7684122b dll: fuse: disable GetDirInfoByName when file system is case-insensitive 2017-10-01 11:07:01 -07:00
55eee2efdd dll: GetDirInfoByName: eliminate unnecessary marker check 2017-09-30 12:33:05 -07:00
f8a05eae95 memfs: fix Unicode case-insensitive comparison 2017-09-29 16:27:28 -07:00
9a4f04f46a sys: FspFsvolQueryDirectoryRetry: special handling for when pattern is filename 2017-09-29 15:44:49 -07:00
98334208b9 Revert commit c70089a176 2017-09-29 15:20:38 -07:00
aae0a5bc74 dll: fuse: GetDirInfoByName 2017-09-28 16:55:45 -07:00
2438ece1cf memfs-dotnet: GetDirInfoByName 2017-09-28 14:41:27 -07:00
487d2449fe dotnet: GetDirInfoByName 2017-09-28 14:11:58 -07:00
6430b386da dll: GetDirInfoByName: properly handle marker for kernel cached directories 2017-09-28 14:05:55 -07:00
c70089a176 sys: FSP_FILE_DESC: DirectoryNoMoreFiles optimization 2017-09-27 18:01:17 -07:00
0dff9a4c07 memfs: GetDirInfoByName 2017-09-27 17:08:41 -07:00
86c0ffa942 fsbench: file_list_single_test, file_list_none_test 2017-09-27 15:59:54 -07:00
5c613b2abd memfs: ReadDirectory: assert(0 == Pattern) 2017-09-26 14:26:57 -07:00
8a099f3faa sys: PassQueryDirectoryFileName 2017-09-26 14:19:27 -07:00
1ac172d2f8 inc,sys: PassQueryDirectoryFileName 2017-09-26 11:51:49 -07:00
34546def3c sys,dll: GetDirInfoByName 2017-09-25 19:46:36 -07:00
3ede1a5c70 memfs-dotnet: fix GetDescendantFileNames 2017-09-25 12:53:08 -07:00
5194536ec3 memfs: fix issue #103 2017-09-25 11:58:20 -07:00
c39bc81299 tools: run-tests: run FSX over passthrough-fuse 2017-09-16 11:00:07 -07:00
18bf6ca666 Merge pull request #107 from saibotu/pr-writesize
Don't decrease FileSize on write
2017-09-16 10:56:34 -07:00
7eebdbd74e Signed CONTRIBUTOR AGREEMENT 2017-09-16 17:41:17 +02:00
9a88791f61 dll: fuse: don't decrease FileSize on write 2017-09-15 13:32:08 +02:00
6e578350f4 doc: update file system libraries 2017-09-01 15:20:20 -07:00
81afac9c3a fsptool: usage 2017-07-19 23:33:53 -07:00
10081e1a69 fsptool: perm 2017-07-19 23:28:46 -07:00
8e5c40bbbe fsptool: perm 2017-07-19 23:16:05 -07:00
7745bf4cdc fsptool: usage 2017-07-19 21:55:28 -07:00
c7a779fa98 fsptool: id 2017-07-20 05:29:13 +01:00
3f90d60dc4 fsptool: id 2017-07-19 20:17:25 -07:00
f73cbc0e37 fsptool: id 2017-07-19 17:35:24 -07:00
c88a86f7c7 fsptool: id 2017-07-19 17:26:00 -07:00
dbdbdf07cf fsptool: id 2017-07-19 16:48:00 -07:00
6b2dcaef96 fsptool: getuid, getgid 2017-07-19 16:05:49 -07:00
fcae6ce018 fsptool: update Changelog 2017-07-19 15:38:03 -07:00
690d3e4c8e fsptool: lsvol 2017-07-19 15:22:43 -07:00
af37424ecc fsptool: lsvol 2017-07-19 14:56:32 -07:00
fd53e22f7e fstool: skeleton 2017-07-19 14:16:01 -07:00
3df0fa02ba build: refactor project for fsptool 2017-07-19 12:10:27 -07:00
9484b50cbd changelog: FspFileSystemOperationProcessId 2017-07-18 14:37:46 -07:00
14e6b402fe build: version.properties: MyGitRevision fix 2017-07-14 20:33:59 -07:00
2227429d8e opt: cygfuse: winpid_to_pid 2017-07-13 00:10:03 -07:00
9deb9d5319 dll: fuse: winpid_to_pid 2017-07-12 23:45:40 -07:00
193d5f4e91 tst: originating process id 2017-07-12 22:34:47 -07:00
26485ffbd6 sys: originating process id 2017-07-12 20:54:12 -07:00
7302b4baea dll: originating process id 2017-07-12 20:18:35 -07:00
fc1586eb82 dll: originating process id 2017-07-12 18:53:12 -07:00
637f461a65 sys: FspFileNodeTrySetFileInfoOnOpen 2017-07-11 15:23:03 -07:00
b35bf204db sys: FspFileNodeTrySetFileInfoOnOpen 2017-07-11 14:17:17 -07:00
3073646f29 doc: add link to queued events document 2017-06-21 14:32:18 -07:00
7f9f55de24 add queued events document 2017-06-21 14:19:56 -07:00
bb3f8d37f2 tools: run-tests: disable passthrough-cpp that is no longer included in installer 2017-06-13 11:13:04 -07:00
c72a9f2a05 build: update for release 1.1 2017-06-12 13:42:05 -07:00
9b4ab190e0 installer: do not install C++ layer 2017-06-12 13:33:45 -07:00
010ed909ec doc: update faq 2017-06-12 12:54:06 -07:00
2b4549a50d doc: update service arch doc with information about credentials 2017-06-12 12:40:50 -07:00
98a329e81b tst: memfs: atomically update FileNode::RefCount (issue #93) 2017-06-07 22:22:28 -07:00
8090b7c666 update Changelog 2017-05-22 17:42:55 -07:00
c7d720eaa0 dll: fuse: allows slashes in -o VolumePrefix=PREFIX 2017-05-22 17:02:40 -07:00
179 changed files with 7042 additions and 1541 deletions

12
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,12 @@
(Enter your issue here.)
----
Before submitting this issue please review this checklist. Ideally all checkmarks should be checked upon submitting. (Use an x inside square brackets like so: [x])
- [ ] **Issue type**: Please consider posting only bug reports or enhancement requests. Questions are better in the [WinFsp Google Group](https://groups.google.com/forum/#!forum/winfsp). Please also consult the [WinFsp Frequently Asked Questions](https://github.com/billziss-gh/winfsp/wiki/Frequently-Asked-Questions).
- [ ] **No Duplicate**: Ensure that your issue has not been filed before. (Check open and closed issues.)
- [ ] **Description**: Provide a descriptive title and a detailed explanation of the problem you are experiencing (for a bug report) or you are trying to solve (for an enhancement request).
- [ ] **Reproduce**: For bug reports provide detailed information on how to reproduce the problem. For enhancement requests you do not need to provide this information, unless you find it relevant.
- [ ] **Behaviors**: Provide information on the expected and actual behaviors.
- [ ] **Environment**: For bug reports provide information about your OS version and build (e.g. 10.0.14393) and WinFsp version and build (e.g. 2017.2 or 1.2.17341). For enhancement requests you do not need to provide this information, unless you find it relevant.

12
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,12 @@
(Enter your PR description here.)
----
Before submitting this PR please review this checklist. Ideally all checkmarks should be checked upon submitting. (Use an x inside square brackets like so: [x])
- [ ] **Contributing**: You MUST read and be willing to accept the [CONTRIBUTOR AGREEMENT](https://github.com/billziss-gh/winfsp/blob/master/Contributors.asciidoc). The agreement gives joint copyright interests in your contributions to you and the original WinFsp author. If you have already accepted the [CONTRIBUTOR AGREEMENT](https://github.com/billziss-gh/winfsp/blob/master/Contributors.asciidoc) you do not need to do so again.
- [ ] **Topic branch**: Avoid creating the PR off the master branch of your fork. Consider creating a topic branch and request a pull from that. This allows you to add commits to the master branch of your fork without affecting this PR.
- [ ] **No tabs**: Consistently use SPACES everywhere. NO TABS, unless the file format requires it (e.g. Makefile).
- [ ] **Style**: Follow the same code style as the rest of the project.
- [ ] **Tests**: Include tests to the extent that it is possible, especially if you add a new feature.
- [ ] **Quality**: Your design and code should be of high quality and something that you are proud of.

View File

@ -1,5 +1,117 @@
= Changelog = Changelog
v1.3B3 (2018.1 B3)::
Changes since v1.2POST1:
* Multiple Launcher changes:
** New `FspLaunch` API. File systems can be started, stopped, queried and listed using `FspLaunchStart`, `FspLaunchStop`, `FspLaunchGetInfo` and `FspLaunchGetNameList`. The API is available in <winfsp/launch.h>
** New Launcher registry settings `RunAs` and `WorkDirectory`. `RunAs` allows the laucher to launch a file system process under the service accounts LocalService and NetworkService. `WorkDirectory` can be used to specify the work directory for a newly launched file system process.
* `FSP_FSCTL_VOLUME_PARAMS::FlushAndPurgeOnCleanup` limits the time that Windows keeps files open after an application has closed them. This purges the cache on the last `CloseHandle`, which is a performance drawback.
** This is now the default behavior on FUSE. To revert to the previous behavior of keeping files open indefinitely use `-o KeepFileCache`.
* `FSP_FSCTL_VOLUME_PARAMS` has been extended with fine-grained timeouts: `VolumeInfoTimeout`, `DirInfoTimeout`, `SecurityTimeout`, `StreamInfoTimeout`. Set `FSP_FSCTL_VOLUME_PARAMS::Version == sizeof(FSP_FSCTL_VOLUME_PARAMS)` to access the new fields.
** New FUSE optons `VolumeInfoTimeout`, `DirInfoTimeout` complement the existing `FileInfoTimeout`.
* The FSD (File System Driver) and its interaction with the Windows MUP (Multiple UNC Provider) has been changed. In practice this eliminates the delays experienced when right-clicking on a WinFsp-backed network drive in the Windows Explorer. (GitHub issue #87.)
* The WinFsp network provider is now added first in the provider order list. Previously it was added last. (GitHub PR #131; thanks @felfert.)
* The WinFsp installer now uses the Wix `Provides` dependency extension to provide a `WinFsp` dependency key. (GitHub PR #129; thanks @felfert.)
* New FUSE `create_umask` option. (GitHub issue #138.)
* Fix C++ compilation error for WinFsp-FUSE. (GitHub PR #154; thanks @benrubson.)
* *NOTE*: Prior v1.3 betas run the MEMFS sample file systems under the LocalService account. This is no longer the case: going forward the MEMFS file systems will be running under the LocalSystem account (as in v1.2POST1).
v1.3B2 (2018.1 B2)::
Changes since v1.2POST1:
* Multiple Launcher changes:
** New `FspLaunch` API. File systems can be started, stopped, queried and listed using `FspLaunchStart`, `FspLaunchStop`, `FspLaunchGetInfo` and `FspLaunchGetNameList`.
** New Launcher registry settings `RunAs` and `WorkDirectory`. `RunAs` allows the laucher to launch a file system process under the service accounts LocalService and NetworkService. `WorkDirectory` can be used to specify the work directory for a newly launched file system process.
* The MEMFS sample file systems are now launched under the LocalService account.
* The FSD (File System Driver) and its interaction with the Windows MUP (Multiple UNC Provider) has been changed. In practice this eliminates the delays experienced when right-clicking on a WinFsp-backed network drive in the Windows Explorer. (GitHub issue #87.)
* The WinFsp network provider is now added first in the provider order list. Previously it was added last. (GitHub PR #131; thanks @felfert.)
* The WinFsp installer now uses the Wix `Provides` dependency extension to provide a `WinFsp` dependency key. (GitHub PR #129; thanks @felfert.)
v1.3B1 (2018.1 B1)::
Changes since v1.2POST1:
- The WinFsp Launcher can now be controlled by the new `FspLaunch` API. File systems can be started, stopped, queried and listed using `FspLaunchStart`, `FspLaunchStop`, `FspLaunchGetInfo` and `FspLaunchGetNameList`.
- The WinFsp launcher now supports new registry settings `RunAs` and `WorkDirectory`. `RunAs` allows the laucher to launch a file system process under the service accounts LocalService and NetworkService. `WorkDirectory` can be used to specify the work directory for a newly launched file system process.
- The MEMFS sample file systems are now launched under the LocalService account.
- The WinFsp network provider is now added first in the provider order list. Previously it was added last. (GitHub PR #131; thanks @felfert.)
- The WinFsp installer now uses the Wix `Provides` dependency extension to provide a `WinFsp` dependency key. (GitHub PR #129; thanks @felfert.)
v1.2POST1 (2017.2; issue #127)::
Changes since v1.1:
- WinFsp-FUSE now supports BSD flags (Windows file attributes) during `getattr` and `fgetattr`. It also adds the `chflags` operation. BSD flags support requires use of the `FSP_FUSE_CAP_STAT_EX` capability and the new `struct fuse_stat_ex` which includes an `st_flags` field. If the preprocessor macro `FSP_FUSE_USE_STAT_EX` is defined before inclusion of `<fuse.h>` then `struct fuse_stat` will also be defined to include the `st_flags` field.
- WinFsp-FUSE also adds the following OSXFUSE operations: `setcrtime`, `setchgtime`. These can be used to set the creation (birth) time and change (ctime) time of a file.
- New `GetDirInfoByName` file system operation adds fast queries of directory info by file name rather than pattern [e.g. `FindFirstFileW(L"foobar", FindData)`]. Tests with fsbench showed that such queries are sped up by an order of magnitude when using `GetDirInfoByName` in MEMFS. Case-sensitive FUSE file systems get this optimization for free. The .NET layer also adds `GetDirInfoByName`.
- New `FspFileSystemOperationProcessId` API adds support for getting the originating process ID (PID) during `Create`, `Open` and `Rename` calls. FUSE file systems can now access `fuse_context::pid`. The .NET layer also adds `GetOperationProcessId`.
- New command line tool `fsptool` allows command line access to some WinFsp features.
- The WinFsp launcher now passes the name of the user who launched the file system as a special parameter %U. This is useful to file systems that use the launcher infrastructure, such as SSHFS-Win. [Please note that in earlier betas the user name was passed as parameter %3; the previous method was insecure and is no longer supported.]
- Important GitHub issues fixed: #96, #97, #103, #107, #127
v1.2 (2017.2)::
Changes since v1.1:
- WinFsp-FUSE now supports BSD flags (Windows file attributes) during `getattr` and `fgetattr`. It also adds the `chflags` operation. BSD flags support requires use of the `FSP_FUSE_CAP_STAT_EX` capability and the new `struct fuse_stat_ex` which includes an `st_flags` field. If the preprocessor macro `FSP_FUSE_USE_STAT_EX` is defined before inclusion of `<fuse.h>` then `struct fuse_stat` will also be defined to include the `st_flags` field.
- WinFsp-FUSE also adds the following OSXFUSE operations: `setcrtime`, `setchgtime`. These can be used to set the creation (birth) time and change (ctime) time of a file.
- New `GetDirInfoByName` file system operation adds fast queries of directory info by file name rather than pattern [e.g. `FindFirstFileW(L"foobar", FindData)`]. Tests with fsbench showed that such queries are sped up by an order of magnitude when using `GetDirInfoByName` in MEMFS. Case-sensitive FUSE file systems get this optimization for free. The .NET layer also adds `GetDirInfoByName`.
- New `FspFileSystemOperationProcessId` API adds support for getting the originating process ID (PID) during `Create`, `Open` and `Rename` calls. FUSE file systems can now access `fuse_context::pid`. The .NET layer also adds `GetOperationProcessId`.
- New command line tool `fsptool` allows command line access to some WinFsp features.
- The WinFsp launcher now passes the name of the user who launched the file system as a special parameter %U. This is useful to file systems that use the launcher infrastructure, such as SSHFS-Win. [Please note that in earlier betas the user name was passed as parameter %3; the previous method was insecure and is no longer supported.]
- Important GitHub issues fixed: #96, #97, #103, #107
v1.2B3 (2017.2 B3)::
Changes since v1.1:
- WinFsp-FUSE now supports BSD flags (Windows file attributes) during `getattr` and `fgetattr`. It also adds the `chflags` operation. BSD flags support requires use of the `FSP_FUSE_CAP_STAT_EX` capability and the new `struct fuse_stat_ex` which includes an `st_flags` field. If the preprocessor macro `FSP_FUSE_USE_STAT_EX` is defined before inclusion of `<fuse.h>` then `struct fuse_stat` will also be defined to include the `st_flags` field.
- WinFsp-FUSE also adds the following OSXFUSE operations: `setcrtime`, `setchgtime`. These can be used to set the creation (birth) time and change (ctime) time of a file.
- New `GetDirInfoByName` file system operation adds fast queries of directory info by file name rather than pattern [e.g. `FindFirstFileW(L"foobar", FindData)`]. Tests with fsbench showed that such queries are sped up by an order of magnitude when using `GetDirInfoByName` in MEMFS. Case-sensitive FUSE file systems get this optimization for free. The .NET layer also adds `GetDirInfoByName`.
- New `FspFileSystemOperationProcessId` API adds support for getting the originating process ID (PID) during `Create`, `Open` and `Rename` calls. FUSE file systems can now access `fuse_context::pid`. The .NET layer also adds `GetOperationProcessId`.
- New command line tool `fsptool` allows command line access to some WinFsp features.
- The WinFsp launcher now passes the username of the user who launched the file system as parameter %3. This is useful to file systems that use the launcher infrastructure, such as SSHFS-Win.
- Important GitHub issues fixed: #96, #97, #103, #107
v1.2B2 (2017.2 B2)::
Changes since v1.1:
- New command line tool `fsptool` allows command line access to some WinFsp features.
- New `GetDirInfoByName` file system operation adds fast queries of directory info by file name rather than pattern [e.g. `FindFirstFileW(L"foobar", FindData)`]. Tests with fsbench showed that such queries are sped up by an order of magnitude when using `GetDirInfoByName` in MEMFS. Case-sensitive FUSE file systems get this optimization for free. The .NET layer also adds `GetDirInfoByName`.
- New `FspFileSystemOperationProcessId` API adds support for getting the originating process ID (PID) during `Create`, `Open` and `Rename` calls. FUSE file systems can now access `fuse_context::pid`. The .NET layer also adds `GetOperationProcessId`.
- Important GitHub issues fixed: #96, #97, #103, #107
v1.2B1 (2017.2 B1)::
- New command line tool `fsptool` allows command line access to some WinFsp features.
- New `GetDirInfoByName` file system operation adds fast queries of directory info by file name rather than pattern [e.g. `FindFirstFileW("foobar", FindData)`]. Tests with fsbench showed that such queries are sped up by an order of magnitude when using `GetDirInfoByName` in MEMFS.
- New `FspFileSystemOperationProcessId` API adds support for getting the originating process ID (PID) during `Create`, `Open` and `Rename` calls.
v1.1 (2017.1)::
This release brings some major new components and improvements.
- A .NET layer that allows the creation of file systems in managed mode. This is contained in the new `winfsp-msil.dll`. The new .NET layer is being tested with the WinFsp test suites and Microsoft's ifstest.
- FUSE for Cygwin is now included with the installer.
- FUSE now has a `-ovolname=VOLNAME` parameter that allows setting the volume label. Thanks @samkelly.
- A number of other FUSE improvements have been made (see issue #85).
NOTE: The C++ layer included in the v1.1 beta releases is not part of this release as it is still work in progress. It can be found in `inc/winfsp/winfsp.hpp` in the WinFsp source repository.
v1.1B3 (2017.1 B3):: v1.1B3 (2017.1 B3)::
v1.1B2 (2017.1 B2):: v1.1B2 (2017.1 B2)::

View File

@ -54,6 +54,10 @@ This CONTRIBUTOR AGREEMENT applies to any contribution that you make to the WinF
CONTRIBUTOR LIST CONTRIBUTOR LIST
---------------- ----------------
|=== |===
|Ben Rubson |ben.rubson at gmail.com
|Bill Zissimopoulos |billziss at navimatics.com |Bill Zissimopoulos |billziss at navimatics.com
|Fritz Elfert |fritz-github at fritz-elfert.de
|John Oberschelp |john at oberschelp.net
|Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com |Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com
|Tobias Urlaub |saibotu at outlook.de
|=== |===

View File

@ -30,21 +30,23 @@ WinFsp consists of a kernel mode FSD (File System Driver) and a user mode DLL (D
The project source code is organized as follows: The project source code is organized as follows:
* build/VStudio: WinFsp solution and project files. * `build/VStudio`: WinFsp solution and project files.
* doc: The WinFsp design documents and additional documentation can be found here. * `doc`: The WinFsp design documents and additional documentation can be found here.
* ext/tlib: A small test library originally from the secfs (Secure Cloud File System) project. * `ext/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. * `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.
* inc/fuse: Public headers for the FUSE compatibility layer. * `inc/winfsp`: Public headers for the WinFsp API.
* src/dll: Source code to the WinFsp DLL. * `src/dll`: Source code to the WinFsp DLL.
* src/dll/fuse: Source code to the FUSE compatibility layer. * `src/dll/fuse`: Source code to the FUSE compatibility layer.
* src/dotnet: Source code to the .NET layer. * `src/dotnet`: Source code to the .NET layer.
* src/launcher: Source code to the launcher service and the launchctl utility. * `src/fsptool`: Source code to fsptool command line utility.
* src/sys: Source code to the WinFsp FSD. * `src/launcher`: Source code to the launcher service and the launchctl utility.
* opt/cygfuse: Source code for the Cygwin FUSE package. * `src/sys`: Source code to the WinFsp FSD.
* tst/memfs*: Source code to an example file system written in C/C++ (memfs) or C# (memfs-dotnet). * `opt/cygfuse`: Source code for the Cygwin FUSE package.
* tst/passthrough*: Source code to additional example file systems. * `tst/memfs*`: Source code to an example file system written in C/C++ (memfs) or C# (memfs-dotnet).
* tst/winfsp-tests: WinFsp test suite. * `tst/passthrough*`: Source code to additional example file systems.
* `tst/winfsp-tests`: WinFsp test suite.
* `tools`: Various tools for building and testing WinFsp.
## Building and Running ## Building and Running

View File

@ -6,8 +6,10 @@ environment:
TESTING: Func TESTING: Func
- CONFIGURATION: Release - CONFIGURATION: Release
TESTING: Func TESTING: Func
- CONFIGURATION: Release #- CONFIGURATION: Release
TESTING: Perf # TESTING: Avast
#- CONFIGURATION: Release
# TESTING: Perf
install: install:
- git submodule update --init --recursive - git submodule update --init --recursive
@ -30,6 +32,9 @@ test_script:
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% - if %TESTING%==Func tools\run-tests.bat %CONFIGURATION%
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% ifstest - if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% ifstest
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% sample - if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% sample
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% compat
- if %TESTING%==Avast choco install avastfreeantivirus && fltmc instances -v "C:"
- if %TESTING%==Avast tools\run-tests.bat %CONFIGURATION% avast-tests
- if %TESTING%==Perf tools\run-perf-tests.bat %CONFIGURATION% baseline > perf-tests.csv && type perf-tests.csv & appveyor PushArtifact perf-tests.csv - if %TESTING%==Perf tools\run-perf-tests.bat %CONFIGURATION% baseline > perf-tests.csv && type perf-tests.csv & appveyor PushArtifact perf-tests.csv
- choco uninstall winfsp -y - choco uninstall winfsp -y
- if exist %SystemRoot%\memory.dmp exit 1 - if exist %SystemRoot%\memory.dmp exit 1

View File

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

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:dep="http://schemas.microsoft.com/wix/DependencyExtension">
<Product <Product
Id="*" Id="*"
Name="$(var.MyProductName) $(var.MyProductVersion)" Name="$(var.MyProductName) $(var.MyProductVersion)"
@ -53,8 +54,8 @@
Key="[P.RegistryKey]" Key="[P.RegistryKey]"
Name="InstallDir" Name="InstallDir"
Type="string" Type="string"
Value="[INSTALLDIR]" Value="[INSTALLDIR]" />
KeyPath="yes" /> <dep:Provides Key="WinFsp" />
</Component> </Component>
<Component Id="C.License.txt"> <Component Id="C.License.txt">
<File Name="License.txt" Source="..\..\..\License.txt" KeyPath="yes" /> <File Name="License.txt" Source="..\..\..\License.txt" KeyPath="yes" />
@ -158,6 +159,13 @@
<File Name="launchctl-x86.exe" KeyPath="yes" /> <File Name="launchctl-x86.exe" KeyPath="yes" />
</Component> </Component>
<Component Id="C.fsptool_x64.exe" Guid="013FE508-097D-4433-9C60-717F5446E7F4">
<File Name="fsptool-x64.exe" KeyPath="yes" />
</Component>
<Component Id="C.fsptool_x86.exe" Guid="6C16DC2C-E12F-49FB-A665-3AF0475487AD">
<File Name="fsptool-x86.exe" KeyPath="yes" />
</Component>
<Component Id="C.diag.bat"> <Component Id="C.diag.bat">
<File Name="diag.bat" Source="..\..\..\tools\diag.bat" KeyPath="yes" /> <File Name="diag.bat" Source="..\..\..\tools\diag.bat" KeyPath="yes" />
</Component> </Component>
@ -252,9 +260,12 @@
<Component Id="C.winfsp.h"> <Component Id="C.winfsp.h">
<File Name="winfsp.h" KeyPath="yes" /> <File Name="winfsp.h" KeyPath="yes" />
</Component> </Component>
<Component Id="C.winfsp.hpp"> <Component Id="C.launch.h">
<File Name="winfsp.hpp" KeyPath="yes" /> <File Name="launch.h" KeyPath="yes" />
</Component> </Component>
<!--Component Id="C.winfsp.hpp">
<File Name="winfsp.hpp" KeyPath="yes" />
</Component-->
</Directory> </Directory>
<Directory Id="INCDIR.fuse" Name="fuse"> <Directory Id="INCDIR.fuse" Name="fuse">
<Component Id="C.fuse.h"> <Component Id="C.fuse.h">
@ -303,12 +314,12 @@
<Directory Id="OPTDIR.cygfuse" Name="cygfuse" FileSource="..\..\..\opt\cygfuse\dist"> <Directory Id="OPTDIR.cygfuse" Name="cygfuse" FileSource="..\..\..\opt\cygfuse\dist">
<Directory Id="OPTDIR.cygfuse.x64" Name="x64"> <Directory Id="OPTDIR.cygfuse.x64" Name="x64">
<Component Id="C.fuse.tar.xz.x64"> <Component Id="C.fuse.tar.xz.x64">
<File Id="FILE.fuse.tar.xz.x64" Name="fuse-2.8-5.tar.xz" KeyPath="yes" /> <File Id="FILE.fuse.tar.xz.x64" Name="fuse-2.8-8.tar.xz" KeyPath="yes" />
</Component> </Component>
</Directory> </Directory>
<Directory Id="OPTDIR.cygfuse.x86" Name="x86"> <Directory Id="OPTDIR.cygfuse.x86" Name="x86">
<Component Id="C.fuse.tar.xz.x86"> <Component Id="C.fuse.tar.xz.x86">
<File Id="FILE.fuse.tar.xz.x86" Name="fuse-2.8-5.tar.xz" KeyPath="yes" /> <File Id="FILE.fuse.tar.xz.x86" Name="fuse-2.8-8.tar.xz" KeyPath="yes" />
</Component> </Component>
</Directory> </Directory>
<Component Id="C.fuse.install.sh"> <Component Id="C.fuse.install.sh">
@ -350,7 +361,7 @@
<File Name="passthrough.vcxproj.filters" KeyPath="yes" /> <File Name="passthrough.vcxproj.filters" KeyPath="yes" />
</Component> </Component>
</Directory> </Directory>
<Directory Id="SMPDIR.passthrough_cpp" Name="passthrough-cpp"> <!--Directory Id="SMPDIR.passthrough_cpp" Name="passthrough-cpp">
<Component Id="C.passthrough_cpp.cpp"> <Component Id="C.passthrough_cpp.cpp">
<File Name="passthrough-cpp.cpp" KeyPath="yes" /> <File Name="passthrough-cpp.cpp" KeyPath="yes" />
</Component> </Component>
@ -363,7 +374,7 @@
<Component Id="C.passthrough_cpp.vcxproj.filters"> <Component Id="C.passthrough_cpp.vcxproj.filters">
<File Name="passthrough-cpp.vcxproj.filters" KeyPath="yes" /> <File Name="passthrough-cpp.vcxproj.filters" KeyPath="yes" />
</Component> </Component>
</Directory> </Directory-->
<Directory Id="SMPDIR.passthrough_fuse" Name="passthrough-fuse"> <Directory Id="SMPDIR.passthrough_fuse" Name="passthrough-fuse">
<Component Id="C.passthrough_fuse.c"> <Component Id="C.passthrough_fuse.c">
<File Name="passthrough-fuse.c" KeyPath="yes" /> <File Name="passthrough-fuse.c" KeyPath="yes" />
@ -427,6 +438,12 @@
<Component Id="C.launchctl_x86.pdb"> <Component Id="C.launchctl_x86.pdb">
<File Name="launchctl-x86.pdb" Source="..\build\$(var.Configuration)\launchctl-x86.public.pdb" KeyPath="yes" /> <File Name="launchctl-x86.pdb" Source="..\build\$(var.Configuration)\launchctl-x86.public.pdb" KeyPath="yes" />
</Component> </Component>
<Component Id="C.fsptool_x64.pdb">
<File Name="fsptool-x64.pdb" Source="..\build\$(var.Configuration)\fsptool-x64.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.fsptool_x86.pdb">
<File Name="fsptool-x86.pdb" Source="..\build\$(var.Configuration)\fsptool-x86.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.memfs_x64.pdb"> <Component Id="C.memfs_x64.pdb">
<File Name="memfs-x64.pdb" Source="..\build\$(var.Configuration)\memfs-x64.public.pdb" KeyPath="yes" /> <File Name="memfs-x64.pdb" Source="..\build\$(var.Configuration)\memfs-x64.public.pdb" KeyPath="yes" />
</Component> </Component>
@ -448,13 +465,16 @@
<ComponentRef Id="C.launcher_x86.exe.svcinst" /> <ComponentRef Id="C.launcher_x86.exe.svcinst" />
<ComponentRef Id="C.launchctl_x64.exe" /> <ComponentRef Id="C.launchctl_x64.exe" />
<ComponentRef Id="C.launchctl_x86.exe" /> <ComponentRef Id="C.launchctl_x86.exe" />
<ComponentRef Id="C.fsptool_x64.exe" />
<ComponentRef Id="C.fsptool_x86.exe" />
<ComponentRef Id="C.diag.bat" /> <ComponentRef Id="C.diag.bat" />
<ComponentRef Id="C.fsreg.bat" /> <ComponentRef Id="C.fsreg.bat" />
</ComponentGroup> </ComponentGroup>
<ComponentGroup Id="C.WinFsp.inc"> <ComponentGroup Id="C.WinFsp.inc">
<ComponentRef Id="C.fsctl.h" /> <ComponentRef Id="C.fsctl.h" />
<ComponentRef Id="C.winfsp.h" /> <ComponentRef Id="C.winfsp.h" />
<ComponentRef Id="C.winfsp.hpp" /> <ComponentRef Id="C.launch.h" />
<!--ComponentRef Id="C.winfsp.hpp" /-->
<ComponentRef Id="C.fuse.h" /> <ComponentRef Id="C.fuse.h" />
<ComponentRef Id="C.fuse_common.h" /> <ComponentRef Id="C.fuse_common.h" />
<ComponentRef Id="C.fuse_opt.h" /> <ComponentRef Id="C.fuse_opt.h" />
@ -482,10 +502,10 @@
<ComponentRef Id="C.passthrough.sln" /> <ComponentRef Id="C.passthrough.sln" />
<ComponentRef Id="C.passthrough.vcxproj" /> <ComponentRef Id="C.passthrough.vcxproj" />
<ComponentRef Id="C.passthrough.vcxproj.filters" /> <ComponentRef Id="C.passthrough.vcxproj.filters" />
<ComponentRef Id="C.passthrough_cpp.cpp" /> <!--ComponentRef Id="C.passthrough_cpp.cpp" /-->
<ComponentRef Id="C.passthrough_cpp.sln" /> <!--ComponentRef Id="C.passthrough_cpp.sln" /-->
<ComponentRef Id="C.passthrough_cpp.vcxproj" /> <!--ComponentRef Id="C.passthrough_cpp.vcxproj" /-->
<ComponentRef Id="C.passthrough_cpp.vcxproj.filters" /> <!--ComponentRef Id="C.passthrough_cpp.vcxproj.filters" /-->
<ComponentRef Id="C.passthrough_fuse.c" /> <ComponentRef Id="C.passthrough_fuse.c" />
<ComponentRef Id="C.passthrough_fuse.winposix.c" /> <ComponentRef Id="C.passthrough_fuse.winposix.c" />
<ComponentRef Id="C.passthrough_fuse.winposix.h" /> <ComponentRef Id="C.passthrough_fuse.winposix.h" />
@ -504,6 +524,8 @@
<ComponentRef Id="C.launcher_x64.pdb" /> <ComponentRef Id="C.launcher_x64.pdb" />
<ComponentRef Id="C.launchctl_x64.pdb" /> <ComponentRef Id="C.launchctl_x64.pdb" />
<ComponentRef Id="C.launchctl_x86.pdb" /> <ComponentRef Id="C.launchctl_x86.pdb" />
<ComponentRef Id="C.fsptool_x64.pdb" />
<ComponentRef Id="C.fsptool_x86.pdb" />
<ComponentRef Id="C.memfs_x64.pdb" /> <ComponentRef Id="C.memfs_x64.pdb" />
<ComponentRef Id="C.memfs_x86.pdb" /> <ComponentRef Id="C.memfs_x86.pdb" />
</ComponentGroup> </ComponentGroup>

View File

@ -39,6 +39,10 @@
<HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath> <HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
<Name>WixUIExtension</Name> <Name>WixUIExtension</Name>
</WixExtension> </WixExtension>
<WixExtension Include="WixDependencyExtension">
<HintPath>$(WixExtDir)\WixDependencyExtension.dll</HintPath>
<Name>WixDependencyExtension</Name>
</WixExtension>
</ItemGroup> </ItemGroup>
<Import Project="$(WixTargetsPath)" /> <Import Project="$(WixTargetsPath)" />
<!-- <!--

View File

@ -190,6 +190,7 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\hooks.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\hooks.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\info-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\info-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\launch-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\lock-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\lock-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\memfs-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\memfs-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\mount-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\mount-test.c" />

View File

@ -85,6 +85,9 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\version-test.c"> <ClCompile Include="..\..\..\tst\winfsp-tests\version-test.c">
<Filter>Source</Filter> <Filter>Source</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\launch-test.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h"> <ClInclude Include="..\..\..\ext\tlib\testsuite.h">

View File

@ -0,0 +1,193 @@
<?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>{1E997BEC-1642-4A5C-B252-852DA094E11E}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>fsptool</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>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
</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>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
</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>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
</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>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
</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>
<ProjectReference Include="..\winfsp_dll.vcxproj">
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\fsptool\fsptool.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\src\fsptool\fsptool-version.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,23 @@
<?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>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\fsptool\fsptool.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\src\fsptool\fsptool-version.rc">
<Filter>Source</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -20,7 +20,7 @@
</ProjectConfiguration> </ProjectConfiguration>
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{73EAAEDA-557B-48D5-A137-328934720FB4}</ProjectGuid> <ProjectGuid>{264A5D09-126F-4760-A3F1-4B3B95C925AA}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>launchctl</RootNamespace> <RootNamespace>launchctl</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
@ -185,7 +185,6 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\src\launcher\launcher.h" />
<ClInclude Include="..\..\..\src\shared\minimal.h" /> <ClInclude Include="..\..\..\src\shared\minimal.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -16,9 +16,6 @@
<ClInclude Include="..\..\..\src\shared\minimal.h"> <ClInclude Include="..\..\..\src\shared\minimal.h">
<Filter>Include\shared</Filter> <Filter>Include\shared</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\src\launcher\launcher.h">
<Filter>Source</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\..\src\launcher\launchctl.c"> <ClCompile Include="..\..\..\src\launcher\launchctl.c">

View File

@ -20,7 +20,7 @@
</ProjectConfiguration> </ProjectConfiguration>
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{A5EFD487-0140-4184-8C54-FFAEC2F85E35}</ProjectGuid> <ProjectGuid>{6CDF9411-B852-4EAC-822D-8F930675F17B}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>launcher</RootNamespace> <RootNamespace>launcher</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
@ -112,7 +112,7 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -134,7 +134,7 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -159,7 +159,7 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -184,7 +184,7 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -197,7 +197,6 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\src\launcher\launcher.h" />
<ClInclude Include="..\..\..\src\shared\minimal.h" /> <ClInclude Include="..\..\..\src\shared\minimal.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -21,9 +21,6 @@
<ClInclude Include="..\..\..\src\shared\minimal.h"> <ClInclude Include="..\..\..\src\shared\minimal.h">
<Filter>Include\shared</Filter> <Filter>Include\shared</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\src\launcher\launcher.h">
<Filter>Source</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="..\..\..\src\launcher\launcher-version.rc"> <ResourceCompile Include="..\..\..\src\launcher\launcher-version.rc">

View File

@ -7,7 +7,8 @@
<!-- git revision --> <!-- git revision -->
<MyGitRoot>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), .git/HEAD))</MyGitRoot> <MyGitRoot>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), .git/HEAD))</MyGitRoot>
<MyGitHead>$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/HEAD).Trim())</MyGitHead> <MyGitHead>$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/HEAD).Trim())</MyGitHead>
<MyGitRevision Condition="$(MyGitHead.StartsWith(ref: ))">$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/$(MyGitHead.Substring(5))).Trim().Substring(0, 7))</MyGitRevision> <MyGitRevision Condition="$(MyGitHead.StartsWith(ref: )) And Exists('$(MyGitRoot)/.git/$(MyGitHead.Substring(5))')">$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/$(MyGitHead.Substring(5))).Trim().Substring(0, 7))</MyGitRevision>
<MyGitRevision Condition="$(MyGitHead.StartsWith(ref: )) And !Exists('$(MyGitRoot)/.git/$(MyGitHead.Substring(5))')">$([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText($(MyGitRoot)/.git/packed-refs)), '[0-9a-fA-F]{40,}.*$(MyGitHead.Substring(5))').Value.Substring(0, 7))</MyGitRevision>
<MyGitRevision Condition="!$(MyGitHead.StartsWith(ref: ))">$(MyGitHead.Substring(0, 7))</MyGitRevision> <MyGitRevision Condition="!$(MyGitHead.StartsWith(ref: ))">$(MyGitHead.Substring(0, 7))</MyGitRevision>
<MyProductName>WinFsp</MyProductName> <MyProductName>WinFsp</MyProductName>
@ -15,9 +16,9 @@
<MyCompanyName>Navimatics Corporation</MyCompanyName> <MyCompanyName>Navimatics Corporation</MyCompanyName>
<MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright> <MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
<MyCanonicalVersion>1.1</MyCanonicalVersion> <MyCanonicalVersion>1.3</MyCanonicalVersion>
<MyProductVersion>2017.1 B3</MyProductVersion> <MyProductVersion>2018.1 B3</MyProductVersion>
<MyProductStage>Beta</MyProductStage> <MyProductStage>Beta</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion> <MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>

View File

@ -32,19 +32,6 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "winfsp_msi", "installer\win
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomActions", "installer\CustomActions\CustomActions.vcxproj", "{95C223E6-B5F1-4FD0-9376-41CDBC824445}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomActions", "installer\CustomActions\CustomActions.vcxproj", "{95C223E6-B5F1-4FD0-9376-41CDBC824445}"
EndProject 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
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fscrash", "testing\fscrash.vcxproj", "{10757011-749D-4954-873B-AE38D8145472}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fscrash", "testing\fscrash.vcxproj", "{10757011-749D-4954-873B-AE38D8145472}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}
@ -63,6 +50,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dotnet", "dotnet", "{A998CE
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "memfs-dotnet", "testing\memfs-dotnet.csproj", "{4920E350-D496-4652-AE98-6C4208AEC1D8}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "memfs-dotnet", "testing\memfs-dotnet.csproj", "{4920E350-D496-4652-AE98-6C4208AEC1D8}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{04A4762C-FAB9-4196-9AC8-0757F3E8AB79}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launcher", "tools\launcher.vcxproj", "{6CDF9411-B852-4EAC-822D-8F930675F17B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launchctl", "tools\launchctl.vcxproj", "{264A5D09-126F-4760-A3F1-4B3B95C925AA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fsptool", "tools\fsptool.vcxproj", "{1E997BEC-1642-4A5C-B252-852DA094E11E}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -179,38 +174,6 @@ Global
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|Any CPU.ActiveCfg = Release|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|Any CPU.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x64.ActiveCfg = Release|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x64.ActiveCfg = Release|Win32
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x86.ActiveCfg = Release|Win32 {95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x86.ActiveCfg = Release|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|Any CPU.ActiveCfg = Debug|Win32
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.ActiveCfg = Debug|x64
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.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|Any CPU.ActiveCfg = Release|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|Any CPU.ActiveCfg = Release|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|Any CPU.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|Any CPU.ActiveCfg = Debug|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|Any CPU.ActiveCfg = Release|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|Any CPU.ActiveCfg = Release|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|Any CPU.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
{10757011-749D-4954-873B-AE38D8145472}.Debug|Any CPU.ActiveCfg = Debug|Win32 {10757011-749D-4954-873B-AE38D8145472}.Debug|Any CPU.ActiveCfg = Debug|Win32
{10757011-749D-4954-873B-AE38D8145472}.Debug|x64.ActiveCfg = Debug|x64 {10757011-749D-4954-873B-AE38D8145472}.Debug|x64.ActiveCfg = Debug|x64
{10757011-749D-4954-873B-AE38D8145472}.Debug|x64.Build.0 = Debug|x64 {10757011-749D-4954-873B-AE38D8145472}.Debug|x64.Build.0 = Debug|x64
@ -268,23 +231,65 @@ Global
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x86.ActiveCfg = Debug|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x86.ActiveCfg = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x86.Build.0 = Debug|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x86.Build.0 = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|Any CPU.Build.0 = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x64.ActiveCfg = Debug|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x64.ActiveCfg = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x64.Build.0 = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x86.ActiveCfg = Debug|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x86.ActiveCfg = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x86.Build.0 = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|Any CPU.ActiveCfg = Release|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|Any CPU.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|Any CPU.Build.0 = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x64.ActiveCfg = Release|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x64.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x64.Build.0 = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x86.ActiveCfg = Release|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x86.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x86.Build.0 = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|Any CPU.ActiveCfg = Release|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|Any CPU.Build.0 = Release|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|Any CPU.Build.0 = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x64.ActiveCfg = Release|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x64.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x64.Build.0 = Release|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x64.Build.0 = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.ActiveCfg = Release|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.Build.0 = Release|Any CPU {4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.Build.0 = Release|Any CPU
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Debug|Any CPU.ActiveCfg = Debug|Win32
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Debug|x64.ActiveCfg = Debug|x64
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Debug|x64.Build.0 = Debug|x64
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Debug|x86.ActiveCfg = Debug|Win32
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Debug|x86.Build.0 = Debug|Win32
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Installer.Debug|Any CPU.ActiveCfg = Release|x64
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Installer.Debug|x64.ActiveCfg = Debug|x64
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Installer.Release|Any CPU.ActiveCfg = Release|x64
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Installer.Release|x64.ActiveCfg = Release|x64
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Installer.Release|x86.ActiveCfg = Release|Win32
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Release|Any CPU.ActiveCfg = Release|Win32
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Release|x64.ActiveCfg = Release|x64
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Release|x64.Build.0 = Release|x64
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Release|x86.ActiveCfg = Release|Win32
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Release|x86.Build.0 = Release|Win32
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Debug|Any CPU.ActiveCfg = Debug|Win32
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Debug|x64.ActiveCfg = Debug|x64
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Debug|x64.Build.0 = Debug|x64
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Debug|x86.ActiveCfg = Debug|Win32
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Debug|x86.Build.0 = Debug|Win32
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Installer.Debug|Any CPU.ActiveCfg = Release|x64
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Installer.Debug|x64.ActiveCfg = Debug|x64
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Installer.Release|Any CPU.ActiveCfg = Release|x64
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Installer.Release|x64.ActiveCfg = Release|x64
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Installer.Release|x86.ActiveCfg = Release|Win32
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Release|Any CPU.ActiveCfg = Release|Win32
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Release|x64.ActiveCfg = Release|x64
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Release|x64.Build.0 = Release|x64
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Release|x86.ActiveCfg = Release|Win32
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Release|x86.Build.0 = Release|Win32
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Debug|Any CPU.ActiveCfg = Debug|Win32
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Debug|x64.ActiveCfg = Debug|x64
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Debug|x64.Build.0 = Debug|x64
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Debug|x86.ActiveCfg = Debug|Win32
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Debug|x86.Build.0 = Debug|Win32
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Installer.Debug|Any CPU.ActiveCfg = Release|x64
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Installer.Debug|x64.ActiveCfg = Debug|x64
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Installer.Debug|x86.ActiveCfg = Debug|Win32
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Installer.Release|Any CPU.ActiveCfg = Release|x64
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Installer.Release|x64.ActiveCfg = Release|x64
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Installer.Release|x86.ActiveCfg = Release|Win32
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Release|Any CPU.ActiveCfg = Release|Win32
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Release|x64.ActiveCfg = Release|x64
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Release|x64.Build.0 = Release|x64
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Release|x86.ActiveCfg = Release|Win32
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Release|x86.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -294,11 +299,12 @@ Global
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1} = {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} {D53AAC39-4C57-4CA5-A4F3-C2B24888C594} = {B464EF06-42AE-4674-81BB-FDDE80204822}
{95C223E6-B5F1-4FD0-9376-41CDBC824445} = {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}
{10757011-749D-4954-873B-AE38D8145472} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49} {10757011-749D-4954-873B-AE38D8145472} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49} {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
{94580219-CC8D-4FE5-A3BE-437B0B3481E1} = {A998CEC4-4B34-43DC-8457-F7761228BA67} {94580219-CC8D-4FE5-A3BE-437B0B3481E1} = {A998CEC4-4B34-43DC-8457-F7761228BA67}
{4920E350-D496-4652-AE98-6C4208AEC1D8} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49} {4920E350-D496-4652-AE98-6C4208AEC1D8} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
{6CDF9411-B852-4EAC-822D-8F930675F17B} = {04A4762C-FAB9-4196-9AC8-0757F3E8AB79}
{264A5D09-126F-4760-A3F1-4B3B95C925AA} = {04A4762C-FAB9-4196-9AC8-0757F3E8AB79}
{1E997BEC-1642-4A5C-B252-852DA094E11E} = {04A4762C-FAB9-4196-9AC8-0757F3E8AB79}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@ -25,6 +25,7 @@
<ClInclude Include="..\..\inc\fuse\fuse_opt.h" /> <ClInclude Include="..\..\inc\fuse\fuse_opt.h" />
<ClInclude Include="..\..\inc\fuse\winfsp_fuse.h" /> <ClInclude Include="..\..\inc\fuse\winfsp_fuse.h" />
<ClInclude Include="..\..\inc\winfsp\fsctl.h" /> <ClInclude Include="..\..\inc\winfsp\fsctl.h" />
<ClInclude Include="..\..\inc\winfsp\launch.h" />
<ClInclude Include="..\..\inc\winfsp\winfsp.h" /> <ClInclude Include="..\..\inc\winfsp\winfsp.h" />
<ClInclude Include="..\..\inc\winfsp\winfsp.hpp" /> <ClInclude Include="..\..\inc\winfsp\winfsp.hpp" />
<ClInclude Include="..\..\src\dll\fuse\library.h" /> <ClInclude Include="..\..\src\dll\fuse\library.h" />
@ -39,6 +40,7 @@
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c" /> <ClCompile Include="..\..\src\dll\fuse\fuse_intf.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_main.c" /> <ClCompile Include="..\..\src\dll\fuse\fuse_main.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_opt.c" /> <ClCompile Include="..\..\src\dll\fuse\fuse_opt.c" />
<ClCompile Include="..\..\src\dll\launch.c" />
<ClCompile Include="..\..\src\dll\np.c" /> <ClCompile Include="..\..\src\dll\np.c" />
<ClCompile Include="..\..\src\dll\posix.c" /> <ClCompile Include="..\..\src\dll\posix.c" />
<ClCompile Include="..\..\src\dll\security.c" /> <ClCompile Include="..\..\src\dll\security.c" />
@ -51,6 +53,7 @@
<ClCompile Include="..\..\src\dll\path.c" /> <ClCompile Include="..\..\src\dll\path.c" />
<ClCompile Include="..\..\src\dll\service.c" /> <ClCompile Include="..\..\src\dll\service.c" />
<ClCompile Include="..\..\src\dll\util.c" /> <ClCompile Include="..\..\src\dll\util.c" />
<ClCompile Include="..\..\src\dll\wksid.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc.in"> <CustomBuild Include="..\..\src\dll\fuse\fuse.pc.in">

View File

@ -53,6 +53,9 @@
<ClInclude Include="..\..\inc\winfsp\winfsp.hpp"> <ClInclude Include="..\..\inc\winfsp\winfsp.hpp">
<Filter>Include\winfsp</Filter> <Filter>Include\winfsp</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\inc\winfsp\launch.h">
<Filter>Include\winfsp</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\src\dll\library.c"> <ClCompile Include="..\..\src\dll\library.c">
@ -112,6 +115,12 @@
<ClCompile Include="..\..\src\dll\fuse\fuse_compat.c"> <ClCompile Include="..\..\src\dll\fuse\fuse_compat.c">
<Filter>Source\fuse</Filter> <Filter>Source\fuse</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\dll\wksid.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\launch.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\..\src\dll\library.def"> <None Include="..\..\src\dll\library.def">

View File

@ -173,6 +173,7 @@
<ClCompile Include="..\..\src\sys\ioq.c" /> <ClCompile Include="..\..\src\sys\ioq.c" />
<ClCompile Include="..\..\src\sys\lockctl.c" /> <ClCompile Include="..\..\src\sys\lockctl.c" />
<ClCompile Include="..\..\src\sys\meta.c" /> <ClCompile Include="..\..\src\sys\meta.c" />
<ClCompile Include="..\..\src\sys\mup.c" />
<ClCompile Include="..\..\src\sys\name.c" /> <ClCompile Include="..\..\src\sys\name.c" />
<ClCompile Include="..\..\src\sys\psbuffer.c" /> <ClCompile Include="..\..\src\sys\psbuffer.c" />
<ClCompile Include="..\..\src\sys\read.c" /> <ClCompile Include="..\..\src\sys\read.c" />

View File

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

View File

@ -28,7 +28,7 @@ if ($key.Count -eq 1) {
-File "$file" -File "$file"
} }
} elseif ($key.Count -eq 0) { } elseif ($key.Count -eq 0) {
Write-Warning "$packageName has already been uninstalled by other means." # Write-Warning "$packageName is not installed"
} elseif ($key.Count -gt 1) { } elseif ($key.Count -gt 1) {
Write-Warning "Too many matching packages found! Package may not be uninstalled." Write-Warning "Too many matching packages found! Package may not be uninstalled."
Write-Warning "Please alert package maintainer the following packages were matched:" Write-Warning "Please alert package maintainer the following packages were matched:"

View File

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

View File

@ -0,0 +1,4 @@
$ErrorActionPreference = 'Stop';
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
. "$toolsdir\chocolateyHelper.ps1"

View File

@ -50,7 +50,8 @@ To verify installation:
<file src="LICENSE.txt" target="tools" /> <file src="LICENSE.txt" target="tools" />
<file src="VERIFICATION.txt" target="tools" /> <file src="VERIFICATION.txt" target="tools" />
<file src="chocolateyInstall.ps1" target="tools" /> <file src="chocolateyInstall.ps1" target="tools" />
<file src="chocolateyBeforeModify.ps1" target="tools" /> <file src="chocolateyUninstall.ps1" target="tools" />
<file src="chocolateyHelper.ps1" target="tools" />
<file src="winfsp-$version$.msi" target="tools" /> <file src="winfsp-$version$.msi" target="tools" />
</files> </files>
</package> </package>

View File

@ -4,25 +4,37 @@
[qanda] [qanda]
I am running Windows 7 and I am finding that the installed driver is not signed. [@efeat]:: I am running Windows 7 and I am finding that the installed driver is not signed.::
Your Windows 7 OS is missing SHA-2 Code Signing Support. You need to install the following security advisory that will rectify the problem: Your Windows 7 OS is missing SHA-2 Code Signing Support. You need to install the following security advisory that will rectify the problem:
https://technet.microsoft.com/en-us/library/security/3033929.aspx https://technet.microsoft.com/en-us/library/security/3033929.aspx
Why is the DLL not installed in the Windows system directories? [@netheril96]:: Disconnecting (unmapping) a network drive does not work.::
You may have Dokany installed. Dokany installs its own Network Provider DLL that unfortunately interferes with the WinFsp handling of network drives. The solution is to change your system's Network Provider order and ensure that the WinFsp Network Provider runs before the Dokany one. Instructions on how to change the Network Provider order can be found in this http://blogs.interfacett.com/changing-the-network-provider-order-in-windows-10[article].
Case-sensitive file systems do not work properly when mounted as a directory.::
Windows and WinFsp support case-sensitive file systems. These file systems work properly when mounted as a drive. Unfortunately when a file system is mounted as a directory over NTFS, Windows expects it to be case-insensitive and will UPPERCASE many of the file names sent to the file system.
+
This is an unfortunate but well understood Windows limitation. Case-sensitive file systems should only be mounted as drives.
Why is the DLL not installed in the Windows system directories?::
It is true that this would make it convenient to load the DLL, because the Windows loader looks into the Windows system directories when it loads DLL's. However, in the opinion of the WinFsp author, software that does not ship with the OS should not be installing components in the system directories. It is true that this would make it convenient to load the DLL, because the Windows loader looks into the Windows system directories when it loads DLL's. However, in the opinion of the WinFsp author, software that does not ship with the OS should not be installing components in the system directories.
+ +
There are a few alternative methods to overcome this problem. WinFsp recommends marking the WinFsp DLL as "delay load" and then using `FspLoad` to dynamically load the DLL during process initialization. For more information see the WinFsp Tutorial. There are a few alternative methods to overcome this problem. WinFsp recommends marking the WinFsp DLL as "delay load" and then using `FspLoad` to dynamically load the DLL during process initialization. For more information see the WinFsp Tutorial.
Does WinFsp provide debugging symbols? [@netheril96]:: Does WinFsp provide debugging symbols?::
Public debugging symbols are already included in the installer. You need to install the "Developer" feature; the symbols can be found in the `sym` directory under the WinFsp installation directory. Public debugging symbols are already included in the installer. You need to install the "Developer" feature; the symbols can be found in the `sym` directory under the WinFsp installation directory.
Is there a maximum number of concurrent file systems? [@efeat]:: Is there a maximum number of concurrent file systems?::
WinFsp does not have a hard limit of how many file systems can be created or how many processes can create file systems. WinFsp does not have a hard limit of how many file systems can be created or how many processes can create file systems.
+ +
@ -38,7 +50,7 @@ Which version of FUSE does WinFsp-FUSE support?::
Currently it supports FUSE 2.8. Currently it supports FUSE 2.8.
FUSE on UNIX systems mounts file systems over an existing directory. When mounting a WinFsp-FUSE file system on a directory, the directory is created and later deleted when the file system goes away. What is the reason for this incompatibility? [@efeat]:: FUSE on UNIX systems mounts file systems over an existing directory. When mounting a WinFsp-FUSE file system on a directory, the directory is created and later deleted when the file system goes away. What is the reason for this incompatibility?::
It would be preferrable if WinFsp-FUSE behaved like FUSE on UNIX in this instance. However there are a number of reasons that this is not the case. It would be preferrable if WinFsp-FUSE behaved like FUSE on UNIX in this instance. However there are a number of reasons that this is not the case.
+ +
@ -49,3 +61,12 @@ With this in mind here are the reasons for the current WinFsp-FUSE behavior:
- Symmetry with mounting on a drive. On Windows drives are created when the file system comes into existence and deleted when it is gone. - Symmetry with mounting on a drive. On Windows drives are created when the file system comes into existence and deleted when it is gone.
- Inability to mount over a non-empty directory on Windows. On FUSE/UNIX this is possible, but not on Windows because NTFS disallows the creation of (mountpoint) reparse points on non-empty directories. - Inability to mount over a non-empty directory on Windows. On FUSE/UNIX this is possible, but not on Windows because NTFS disallows the creation of (mountpoint) reparse points on non-empty directories.
- Most importantly: inability to guarantee that the mount point will cease to exist if the file system crashes. WinFsp attempts to guarantee that all resources used by a file system will get cleaned up. This is certainly true for the kernel-mode FSD, but an attempt is made to do so also in user mode. For this reason, drive symbolic links are marked as temporary and (importantly for our discussion) mount directories are opened with `FILE_FLAG_DELETE_ON_CLOSE`. There is no way to guarantee the removal of a reparse point in the same way. - Most importantly: inability to guarantee that the mount point will cease to exist if the file system crashes. WinFsp attempts to guarantee that all resources used by a file system will get cleaned up. This is certainly true for the kernel-mode FSD, but an attempt is made to do so also in user mode. For this reason, drive symbolic links are marked as temporary and (importantly for our discussion) mount directories are opened with `FILE_FLAG_DELETE_ON_CLOSE`. There is no way to guarantee the removal of a reparse point in the same way.
WinFsp-FUSE does not have the ability to support multiple file systems from within the same process. Why?::
The core WinFsp layer supports multiple file systems in the same process either simultaneously or one after another. However this is not the case with WinFsp-FUSE (i.e. the FUSE layer of WinFsp).
+
File systems in Windows often need to be run as services. For this reason the WinFsp-FUSE layer provides both file system and Windows service API functionality. This way a WinFsp-FUSE file system can easily become a Windows service. There is a problem: once a Windows process starts acting as a service and then stops being a service, it cannot become a service again.
+
Having FUSE file systems being able to act as Windows services is valuable. Therefore this is not a limitation that can easily be fixed as FUSE file systems would lose the "free" ability to act as Windows services.

View File

@ -9,7 +9,7 @@ The documentation available here discusses various aspects of WinFsp.
## Programming ## Programming
- The [[Tutorial|WinFsp-Tutorial]] describes how to create a simple, but complete file system in C/C++. - The [[Tutorial|WinFsp-Tutorial]] describes how to create a simple, but complete file system in C/C++.
- The [[API Reference|winfsp.h]] describes the native WinFsp API. This external [[link|http://www.secfs.net/winfsp/apiref/]] may be easier to browse for some people. - The [[API Reference|WinFsp-API-winfsp.h]] describes the native WinFsp API. This external [[link|http://www.secfs.net/winfsp/apiref/]] may be easier to browse for some people.
- There is also a FUSE compatibility layer for native Windows and Cygwin. See fuse.h in the source repository. - There is also a FUSE compatibility layer for native Windows and Cygwin. See fuse.h in the source repository.
- This [[document|Native-API-vs-FUSE]] discusses the need for both a native API and FUSE and gives some pointers on which one to choose. - This [[document|Native-API-vs-FUSE]] discusses the need for both a native API and FUSE and gives some pointers on which one to choose.
@ -17,6 +17,7 @@ The documentation available here discusses various aspects of WinFsp.
- The [[Design|WinFsp-Design]] document describes the high-level design of WinFsp. - The [[Design|WinFsp-Design]] document describes the high-level design of WinFsp.
- The [[IPC|WinFsp-as-an-IPC-Mechanism]] document offers insights into the WinFsp Inter-Process Communication mechanism. - The [[IPC|WinFsp-as-an-IPC-Mechanism]] document offers insights into the WinFsp Inter-Process Communication mechanism.
- The [[Queued Events|Queued-Events]] document discusses a low-level synchronization primitive that is largely responsible for the excellent performance of the WinFsp IPC mechanism.
- The [[Service Architecture|WinFsp-Service-Architecture]] document discusses how to intergrate a file system into Windows as a service and the reasons to do so. - The [[Service Architecture|WinFsp-Service-Architecture]] document discusses how to intergrate a file system into Windows as a service and the reasons to do so.
- The [[SSHFS Port Case Study|SSHFS-Port-Case-Study]] document chronicles the creation of the WinFsp-FUSE compatibility layer and the decisions that led to its design. - The [[SSHFS Port Case Study|SSHFS-Port-Case-Study]] document chronicles the creation of the WinFsp-FUSE compatibility layer and the decisions that led to its design.

View File

@ -4,6 +4,9 @@ This document contains a list of known file systems and file system libraries th
== File Systems == File Systems
- https://github.com/vgough/encfs[EncFS] - an Encrypted Filesystem for FUSE
- https://github.com/ihaveamac/fuse-3ds[fuse-3ds] - FUSE Filesystem Python scripts for Nintendo 3DS files
- https://github.com/FrKaram/KS2.Drive[KS2.Drive] - Mount a webDAV/AOS server as a local drive
- https://github.com/billziss-gh/nfs-win[nfs-win] - NFS for Windows - https://github.com/billziss-gh/nfs-win[nfs-win] - NFS for Windows
- https://github.com/ncw/rclone[rclone] - rsync for cloud storage - https://github.com/ncw/rclone[rclone] - rsync for cloud storage
- https://github.com/hasse69/rar2fs[rar2fs] - FUSE file system for reading RAR archives - https://github.com/hasse69/rar2fs[rar2fs] - FUSE file system for reading RAR archives
@ -13,8 +16,7 @@ This document contains a list of known file systems and file system libraries th
== File System Libraries == File System Libraries
- https://github.com/billziss-gh/cgofuse[cgofuse] - Cross-platform FUSE library for Go - https://github.com/billziss-gh/cgofuse[Go: cgofuse] - Cross-platform FUSE library for Go
- https://github.com/DuroSoft/fuse-bindings[fuse-bindings] - Fully maintained FUSE bindings for Node that aims to cover the entire FUSE api - https://github.com/DuroSoft/fuse-bindings[Nodejs: fuse-bindings] - Fully maintained FUSE bindings for Node that aims to cover the entire FUSE api
- https://github.com/ui4j/fuse-jna[fuse-jna] - No-nonsense, actually-working Java bindings to FUSE using JNA - https://github.com/SerCeMan/jnr-fuse[Java: jnr-fuse] - FUSE implementation in Java using Java Native Runtime (JNR)
- https://github.com/billziss-gh/fusepy[fusepy] - Simple ctypes bindings for FUSE - https://github.com/billziss-gh/fusepy[Python: fusepy] - Simple ctypes bindings for FUSE
- https://github.com/yogendersolanki91/winfsp[WinFsp fork with .NET Layer] - by @yogendersolanki91

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,263 @@
= winfsp/launch.h
:author: (C) 2015-2018 Bill Zissimopoulos
:toc: preamble
:toc-title:
WinFsp Launch API.
In order to use the WinFsp Launch API a program must include <winfsp/launch.h>
and link with the winfsp$$_$$x64.dll (or winfsp$$_$$x86.dll) library.
== Launch Control
=== Functions
*FspLaunchCallLauncherPipe* - Call launcher pipe.
[source,c]
----
FSP_API NTSTATUS FspLaunchCallLauncherPipe(
WCHAR Command,
ULONG Argc,
PWSTR *Argv,
ULONG *Argl,
PWSTR Buffer,
PULONG PSize,
PULONG PLauncherError);
----
*Parameters*
- _Command_ - Launcher command to send. For example, the 'L' launcher command instructs
the launcher to list all running service instances.
- _Argc_ - Command argument count. May be 0.
- _Argv_ - Command argument array. May be NULL.
- _Argl_ - Command argument length array. May be NULL. If this is NULL all command arguments
are assumed to be NULL-terminated strings. It is also possible for specific arguments
to be NULL-terminated; in this case pass -1 in the corresponding Argl position.
- _Buffer_ - Buffer that receives the command response. May be NULL.
- _PSize_ - Pointer to a ULONG. On input it contains the size of the Buffer. On output it
contains the number of bytes transferred. May be NULL.
- _PLauncherError_ - Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
*Return Value*
STATUS$$_$$SUCCESS if the command is sent successfully to the launcher, even if the launcher
returns an error. Other status codes indicate a communication error. Launcher errors are
reported through PLauncherError.
*Discussion*
This function is used to send a command to the launcher and receive a response.
*FspLaunchGetInfo* - Get information about a service instance.
[source,c]
----
FSP_API NTSTATUS FspLaunchGetInfo(
PWSTR ClassName,
PWSTR InstanceName,
PWSTR Buffer,
PULONG PSize,
PULONG PLauncherError);
----
*Parameters*
- _ClassName_ - Class name of the service instance to stop.
- _InstanceName_ - Instance name of the service instance to stop.
- _Buffer_ - Buffer that receives the command response. May be NULL.
- _PSize_ - Pointer to a ULONG. On input it contains the size of the Buffer. On output it
contains the number of bytes transferred. May be NULL.
- _PLauncherError_ - Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
*Return Value*
STATUS$$_$$SUCCESS if the command is sent successfully to the launcher, even if the launcher
returns an error. Other status codes indicate a communication error. Launcher errors are
reported through PLauncherError.
*Discussion*
The information is a list of NULL-terminated strings: the class name of the service instance,
the instance name of the service instance and the full command line used to start the service
instance.
*FspLaunchGetNameList* - List service instances.
[source,c]
----
FSP_API NTSTATUS FspLaunchGetNameList(
PWSTR Buffer,
PULONG PSize,
PULONG PLauncherError);
----
*Parameters*
- _Buffer_ - Buffer that receives the command response. May be NULL.
- _PSize_ - Pointer to a ULONG. On input it contains the size of the Buffer. On output it
contains the number of bytes transferred. May be NULL.
- _PLauncherError_ - Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
*Return Value*
STATUS$$_$$SUCCESS if the command is sent successfully to the launcher, even if the launcher
returns an error. Other status codes indicate a communication error. Launcher errors are
reported through PLauncherError.
*Discussion*
The information is a list of pairs of NULL-terminated strings. Each pair contains the class
name and instance name of a service instance. All currently running service instances are
listed.
*FspLaunchStart* - Start a service instance.
[source,c]
----
FSP_API NTSTATUS FspLaunchStart(
PWSTR ClassName,
PWSTR InstanceName,
ULONG Argc,
PWSTR *Argv,
BOOLEAN HasSecret,
PULONG PLauncherError);
----
*Parameters*
- _ClassName_ - Class name of the service instance to start.
- _InstanceName_ - Instance name of the service instance to start.
- _Argc_ - Service instance argument count. May be 0.
- _Argv_ - Service instance argument array. May be NULL.
- _HasSecret_ - Whether the last argument in Argv is assumed to be a secret (e.g. password) or not.
Secrets are passed to service instances through standard input rather than the command
line.
- _PLauncherError_ - Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
*Return Value*
STATUS$$_$$SUCCESS if the command is sent successfully to the launcher, even if the launcher
returns an error. Other status codes indicate a communication error. Launcher errors are
reported through PLauncherError.
*FspLaunchStop* - Stop a service instance.
[source,c]
----
FSP_API NTSTATUS FspLaunchStop(
PWSTR ClassName,
PWSTR InstanceName,
PULONG PLauncherError);
----
*Parameters*
- _ClassName_ - Class name of the service instance to stop.
- _InstanceName_ - Instance name of the service instance to stop.
- _PLauncherError_ - Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
*Return Value*
STATUS$$_$$SUCCESS if the command is sent successfully to the launcher, even if the launcher
returns an error. Other status codes indicate a communication error. Launcher errors are
reported through PLauncherError.
== Service Registry
=== Functions
*FspLaunchRegFreeRecord* - Free a service registry record.
[source,c]
----
FSP_API VOID FspLaunchRegFreeRecord(
FSP_LAUNCH_REG_RECORD *Record);
----
*Parameters*
- _Record_ - The service record to free.
*See Also*
- FspLaunchRegGetRecord
*FspLaunchRegGetRecord* - Get a service registry record.
[source,c]
----
FSP_API NTSTATUS FspLaunchRegGetRecord(
PWSTR ClassName,
PWSTR Agent,
FSP_LAUNCH_REG_RECORD **PRecord);
----
*Parameters*
- _ClassName_ - The service class name.
- _Agent_ - The name of the agent that is retrieving the service record. This API matches
the supplied Agent against the Agent in the service record and it only returns
the record if they match. Pass NULL to match any Agent.
- _PRecord_ - Pointer to a record pointer. Memory for the service record will be allocated
and a pointer to it will be stored at this address. This memory must be later
freed using FspLaunchRegFreeRecord.
*Return Value*
STATUS$$_$$SUCCESS or error code.
*See Also*
- FspLaunchRegFreeRecord
*FspLaunchRegSetRecord* - Add/change/delete a service registry record.
[source,c]
----
FSP_API NTSTATUS FspLaunchRegSetRecord(
PWSTR ClassName,
const FSP_LAUNCH_REG_RECORD *Record);
----
*Parameters*
- _ClassName_ - The service class name.
- _Record_ - The record to set in the registry. If NULL, the registry record is deleted.
*Return Value*
STATUS$$_$$SUCCESS or error code.
=== Typedefs
*FSP$$_$$LAUNCH$$_$$REG$$_$$RECORD* - Service registry record.
[source,c]
----
typedef struct _FSP_LAUNCH_REG_RECORD {
PWSTR Agent;
PWSTR Executable;
PWSTR CommandLine;
PWSTR WorkDirectory;
PWSTR RunAs;
PWSTR Security;
PVOID Reserved0[6];
ULONG JobControl;
ULONG Credentials;
ULONG Reserved1[6];
UINT8 Buffer[];
} FSP_LAUNCH_REG_RECORD;
----

View File

@ -1,5 +1,5 @@
= winfsp/winfsp.h = winfsp/winfsp.h
:author: (C) 2015-2017 Bill Zissimopoulos :author: (C) 2015-2018 Bill Zissimopoulos
:toc: preamble :toc: preamble
:toc-title: :toc-title:
@ -278,6 +278,33 @@ STATUS$$_$$SUCCESS or error code.
Note that the FSD will also flush all file/volume caches prior to invoking this operation. Note that the FSD will also flush all file/volume caches prior to invoking this operation.
*GetDirInfoByName* - Get directory information for a single file or directory within a parent directory.
[source,c]
----
NTSTATUS ( *GetDirInfoByName)(
FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext,
PWSTR FileName,
FSP_FSCTL_DIR_INFO *DirInfo);
----
*Parameters*
- _FileSystem_ - The file system on which this request is posted.
- _FileContext_ - The file context of the parent directory.
- _FileName_ - The name of the file or directory to get information for. This name is relative
to the parent directory and is a single path component.
- _DirInfo_ - [out]
Pointer to a structure that will receive the directory information on successful
return from this call. This information includes the file name, but also file
attributes, file times, etc.
*Return Value*
STATUS$$_$$SUCCESS or error code.
*GetFileInfo* - Get file or directory information. *GetFileInfo* - Get file or directory information.
[source,c] [source,c]
@ -1185,6 +1212,19 @@ The current operation context is stored in thread local storage. It allows acces
Request and Response associated with this operation. Request and Response associated with this operation.
*FspFileSystemOperationProcessId* - Gets the originating process ID.
[source,c]
----
static inline UINT32 FspFileSystemOperationProcessId(
VOID)
----
*Discussion*
Valid only during Create, Open and Rename requests when the target exists.
*FspFileSystemPreflight* - Check whether creating a file system object is possible. *FspFileSystemPreflight* - Check whether creating a file system object is possible.
[source,c] [source,c]
@ -1535,6 +1575,27 @@ call. The WinFsp Launcher is a Windows service that can be configured to launch
multiple instances of a user mode file system. multiple instances of a user mode file system.
*FspServiceContextCheck* - Check if the supplied token is from the service context.
[source,c]
----
FSP_API NTSTATUS FspServiceContextCheck(
HANDLE Token,
PBOOLEAN PIsLocalSystem);
----
*Parameters*
- _Token_ - Token to check. Pass NULL to check the current process token.
- _PIsLocalSystem_ - Pointer to a boolean that will receive a TRUE value if the token belongs to LocalSystem
and FALSE otherwise. May be NULL.
*Return Value*
STATUS$$_$$SUCCESS if the token is from the service context. STATUS$$_$$ACCESS$$_$$DENIED if it is not.
Other error codes are possible.
*FspServiceCreate* - Create a service object. *FspServiceCreate* - Create a service object.
[source,c] [source,c]

View File

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

View File

@ -95,7 +95,7 @@ if (!Success)
In Release builds the +DEBUGTEST(90)+ macro will evaluate to +TRUE+ and the Cache Manager will be asked directly via +CcCanIWrite+ whether a WRITE should be deferred. In Debug builds the +DEBUGTEST(90)+ macro will evaluate to +FALSE+ sometimes (10% of the time) and the WRITE will be deferred, thus allowing us to test the retry code path. In Release builds the +DEBUGTEST(90)+ macro will evaluate to +TRUE+ and the Cache Manager will be asked directly via +CcCanIWrite+ whether a WRITE should be deferred. In Debug builds the +DEBUGTEST(90)+ macro will evaluate to +FALSE+ sometimes (10% of the time) and the WRITE will be deferred, thus allowing us to test the retry code path.
== Compatibility Testing == NTFS Compatibility Testing
WinFsp allows the creation of user mode file systems that exhibit behavior similar to NTFS. This means that Windows applications that use such a file system should not be able to tell the difference between NTFS and the WinFsp-based file system. OTOH specialized applications (such as Defrag) will not work properly on WinFsp file systems. WinFsp allows the creation of user mode file systems that exhibit behavior similar to NTFS. This means that Windows applications that use such a file system should not be able to tell the difference between NTFS and the WinFsp-based file system. OTOH specialized applications (such as Defrag) will not work properly on WinFsp file systems.
@ -123,6 +123,12 @@ The goal of performance testing is to evaluate and understand how software behav
WinFsp uses a tool called fsbench for this purpose. Fsbench is able to test specific scenarios, for example: "how long does it take to delete 1000 files?" Fsbench has been very useful for WinFsp and has helped improve its performance: in one situation it helped identify quadratic behavior with the MEMFS ReadDirectory operation, in another situation it helped fine tune the performance of the WinFsp I/O Queue. WinFsp uses a tool called fsbench for this purpose. Fsbench is able to test specific scenarios, for example: "how long does it take to delete 1000 files?" Fsbench has been very useful for WinFsp and has helped improve its performance: in one situation it helped identify quadratic behavior with the MEMFS ReadDirectory operation, in another situation it helped fine tune the performance of the WinFsp I/O Queue.
== Backwards Compatibility testing
As the WinFsp API's mature it is important to verify that they remain backwards compatible with existing file system binaries. For this purpose binaries that have been compiled against earlier versions of WinFsp are used to verify that they run correctly against the latest version.
For example, in version v1.2B3 of WinFsp an +FSP_FUSE_CAP_STAT_EX+ FUSE extension was introduced. This can change the layout of +struct fuse_stat+ and is therefore a potentially dangerous change. To test against inadvertent breakage a FUSE file system binary that was compiled against v1.2B2 is regularly used to verify backwards compatibility.
== Code Analysis == Code Analysis
WinFsp is regularly run under the Visual Studio's Code Analyzer. Any issues found are examined and if necessary acted upon. WinFsp is regularly run under the Visual Studio's Code Analyzer. Any issues found are examined and if necessary acted upon.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@
* FUSE: Filesystem in Userspace * FUSE: Filesystem in Userspace
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -39,54 +39,82 @@ typedef int (*fuse_dirfil_t)(fuse_dirh_t h, const char *name,
struct fuse_operations struct fuse_operations
{ {
int (*getattr)(const char *path, struct fuse_stat *stbuf); /* S - supported by WinFsp */
int (*getdir)(const char *path, fuse_dirh_t h, fuse_dirfil_t filler); /* S */ int (*getattr)(const char *path, struct fuse_stat *stbuf);
int (*readlink)(const char *path, char *buf, size_t size); /* S */ int (*getdir)(const char *path, fuse_dirh_t h, fuse_dirfil_t filler);
int (*mknod)(const char *path, fuse_mode_t mode, fuse_dev_t dev); /* S */ int (*readlink)(const char *path, char *buf, size_t size);
int (*mkdir)(const char *path, fuse_mode_t mode); /* S */ int (*mknod)(const char *path, fuse_mode_t mode, fuse_dev_t dev);
int (*unlink)(const char *path); /* S */ int (*mkdir)(const char *path, fuse_mode_t mode);
int (*rmdir)(const char *path); /* S */ int (*unlink)(const char *path);
int (*symlink)(const char *dstpath, const char *srcpath); /* S */ int (*rmdir)(const char *path);
int (*rename)(const char *oldpath, const char *newpath); /* S */ int (*symlink)(const char *dstpath, const char *srcpath);
int (*link)(const char *srcpath, const char *dstpath); /* S */ int (*rename)(const char *oldpath, const char *newpath);
int (*chmod)(const char *path, fuse_mode_t mode); /* _ */ int (*link)(const char *srcpath, const char *dstpath);
int (*chown)(const char *path, fuse_uid_t uid, fuse_gid_t gid); /* S */ int (*chmod)(const char *path, fuse_mode_t mode);
int (*truncate)(const char *path, fuse_off_t size); /* S */ int (*chown)(const char *path, fuse_uid_t uid, fuse_gid_t gid);
int (*utime)(const char *path, struct fuse_utimbuf *timbuf); /* S */ int (*truncate)(const char *path, fuse_off_t size);
int (*open)(const char *path, struct fuse_file_info *fi); /* S */ int (*utime)(const char *path, struct fuse_utimbuf *timbuf);
int (*read)(const char *path, char *buf, size_t size, fuse_off_t off, /* S */ int (*open)(const char *path, struct fuse_file_info *fi);
/* S */ int (*read)(const char *path, char *buf, size_t size, fuse_off_t off,
struct fuse_file_info *fi); struct fuse_file_info *fi);
int (*write)(const char *path, const char *buf, size_t size, fuse_off_t off, /* S */ int (*write)(const char *path, const char *buf, size_t size, fuse_off_t off,
struct fuse_file_info *fi); struct fuse_file_info *fi);
int (*statfs)(const char *path, struct fuse_statvfs *stbuf); /* S */ int (*statfs)(const char *path, struct fuse_statvfs *stbuf);
int (*flush)(const char *path, struct fuse_file_info *fi); /* S */ int (*flush)(const char *path, struct fuse_file_info *fi);
int (*release)(const char *path, struct fuse_file_info *fi); /* S */ int (*release)(const char *path, struct fuse_file_info *fi);
int (*fsync)(const char *path, int datasync, struct fuse_file_info *fi); /* S */ 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 (*setxattr)(const char *path, const char *name, const char *value, size_t size,
int flags); int flags);
int (*getxattr)(const char *path, const char *name, char *value, size_t size); /* _ */ int (*getxattr)(const char *path, const char *name, char *value, size_t size);
int (*listxattr)(const char *path, char *namebuf, size_t size); /* _ */ int (*listxattr)(const char *path, char *namebuf, size_t size);
int (*removexattr)(const char *path, const char *name); /* _ */ int (*removexattr)(const char *path, const char *name);
int (*opendir)(const char *path, struct fuse_file_info *fi); /* S */ 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, /* S */ int (*readdir)(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
struct fuse_file_info *fi); struct fuse_file_info *fi);
int (*releasedir)(const char *path, struct fuse_file_info *fi); /* S */ int (*releasedir)(const char *path, struct fuse_file_info *fi);
int (*fsyncdir)(const char *path, int datasync, struct fuse_file_info *fi); /* S */ int (*fsyncdir)(const char *path, int datasync, struct fuse_file_info *fi);
void *(*init)(struct fuse_conn_info *conn); /* S */ void *(*init)(struct fuse_conn_info *conn);
void (*destroy)(void *data); /* S */ void (*destroy)(void *data);
int (*access)(const char *path, int mask); /* _ */ int (*access)(const char *path, int mask);
int (*create)(const char *path, fuse_mode_t mode, struct fuse_file_info *fi); /* S */ 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); /* S */ 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); /* S */ 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 (*lock)(const char *path,
int (*utimens)(const char *path, const struct fuse_timespec tv[2]); struct fuse_file_info *fi, int cmd, struct fuse_flock *lock);
int (*bmap)(const char *path, size_t blocksize, uint64_t *idx); /* S */ int (*utimens)(const char *path, const struct fuse_timespec tv[2]);
unsigned int flag_nullpath_ok:1; /* _ */ int (*bmap)(const char *path, size_t blocksize, uint64_t *idx);
unsigned int flag_reserved:31; /* _ */ unsigned int flag_nullpath_ok:1;
int (*ioctl)(const char *path, int cmd, void *arg, struct fuse_file_info *fi, /* _ */ unsigned int flag_nopath:1;
/* _ */ unsigned int flag_utime_omit_ok:1;
/* _ */ unsigned int flag_reserved:29;
/* _ */ int (*ioctl)(const char *path, int cmd, void *arg, struct fuse_file_info *fi,
unsigned int flags, void *data); unsigned int flags, void *data);
int (*poll)(const char *path, struct fuse_file_info *fi, /* _ */ int (*poll)(const char *path, struct fuse_file_info *fi,
struct fuse_pollhandle *ph, unsigned *reventsp); struct fuse_pollhandle *ph, unsigned *reventsp);
/* FUSE 2.9 */
/* _ */ int (*write_buf)(const char *path,
struct fuse_bufvec *buf, fuse_off_t off, struct fuse_file_info *fi);
/* _ */ int (*read_buf)(const char *path,
struct fuse_bufvec **bufp, size_t size, fuse_off_t off, struct fuse_file_info *fi);
/* _ */ int (*flock)(const char *path, struct fuse_file_info *, int op);
/* _ */ int (*fallocate)(const char *path, int mode, fuse_off_t off, fuse_off_t len,
struct fuse_file_info *fi);
/* OSXFUSE */
/* _ */ int (*reserved00)();
/* _ */ int (*reserved01)();
/* _ */ int (*reserved02)();
/* _ */ int (*statfs_x)(const char *path, struct fuse_statfs *stbuf);
/* _ */ int (*setvolname)(const char *volname);
/* _ */ int (*exchange)(const char *oldpath, const char *newpath, unsigned long flags);
/* _ */ int (*getxtimes)(const char *path,
struct fuse_timespec *bkuptime, struct fuse_timespec *crtime);
/* _ */ int (*setbkuptime)(const char *path, const struct fuse_timespec *tv);
/* S */ int (*setchgtime)(const char *path, const struct fuse_timespec *tv);
/* S */ int (*setcrtime)(const char *path, const struct fuse_timespec *tv);
/* S */ int (*chflags)(const char *path, uint32_t flags);
/* _ */ int (*setattr_x)(const char *path, struct fuse_setattr_x *attr);
/* _ */ int (*fsetattr_x)(const char *path, struct fuse_setattr_x *attr,
struct fuse_file_info *fi);
}; };
struct fuse_context struct fuse_context

View File

@ -6,7 +6,7 @@
* FUSE: Filesystem in Userspace * FUSE: Filesystem in Userspace
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -49,6 +49,7 @@ extern "C" {
#define FSP_FUSE_CAP_READDIR_PLUS (1 << 21) /* file system supports enhanced readdir */ #define FSP_FUSE_CAP_READDIR_PLUS (1 << 21) /* file system supports enhanced readdir */
#define FSP_FUSE_CAP_READ_ONLY (1 << 22) /* file system is marked read-only */ #define FSP_FUSE_CAP_READ_ONLY (1 << 22) /* file system is marked read-only */
#define FSP_FUSE_CAP_STAT_EX (1 << 23) /* file system supports fuse_stat_ex */
#define FSP_FUSE_CAP_CASE_INSENSITIVE FUSE_CAP_CASE_INSENSITIVE #define FSP_FUSE_CAP_CASE_INSENSITIVE FUSE_CAP_CASE_INSENSITIVE
#define FUSE_IOCTL_COMPAT (1 << 0) #define FUSE_IOCTL_COMPAT (1 << 0)
@ -56,6 +57,24 @@ extern "C" {
#define FUSE_IOCTL_RETRY (1 << 2) #define FUSE_IOCTL_RETRY (1 << 2)
#define FUSE_IOCTL_MAX_IOV 256 #define FUSE_IOCTL_MAX_IOV 256
/* from FreeBSD */
#define FSP_FUSE_UF_HIDDEN 0x00008000
#define FSP_FUSE_UF_READONLY 0x00001000
#define FSP_FUSE_UF_SYSTEM 0x00000080
#define FSP_FUSE_UF_ARCHIVE 0x00000800
#if !defined(UF_HIDDEN)
#define UF_HIDDEN FSP_FUSE_UF_HIDDEN
#endif
#if !defined(UF_READONLY)
#define UF_READONLY FSP_FUSE_UF_READONLY
#endif
#if !defined(UF_SYSTEM)
#define UF_SYSTEM FSP_FUSE_UF_SYSTEM
#endif
#if !defined(UF_ARCHIVE)
#define UF_ARCHIVE FSP_FUSE_UF_ARCHIVE
#endif
struct fuse_file_info struct fuse_file_info
{ {
int flags; int flags;
@ -85,6 +104,9 @@ struct fuse_conn_info
struct fuse_session; struct fuse_session;
struct fuse_chan; struct fuse_chan;
struct fuse_pollhandle; struct fuse_pollhandle;
struct fuse_bufvec;
struct fuse_statfs;
struct fuse_setattr_x;
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_version)(struct fsp_fuse_env *env); 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, FSP_FUSE_API struct fuse_chan *FSP_FUSE_API_NAME(fsp_fuse_mount)(struct fsp_fuse_env *env,

View File

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

View File

@ -2,7 +2,7 @@
* @file fuse/winfsp_fuse.h * @file fuse/winfsp_fuse.h
* WinFsp FUSE compatible API. * WinFsp FUSE compatible API.
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -65,6 +65,27 @@ extern "C" {
* to be usable from Cygwin. * to be usable from Cygwin.
*/ */
#define FSP_FUSE_STAT_FIELD_DEFN \
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;
#define FSP_FUSE_STAT_EX_FIELD_DEFN \
FSP_FUSE_STAT_FIELD_DEFN \
uint32_t st_flags; \
uint32_t st_reserved32[3]; \
uint64_t st_reserved64[2];
#if defined(_WIN64) || defined(_WIN32) #if defined(_WIN64) || defined(_WIN32)
typedef uint32_t fuse_uid_t; typedef uint32_t fuse_uid_t;
@ -111,23 +132,17 @@ struct fuse_timespec
}; };
#endif #endif
#if !defined(FSP_FUSE_USE_STAT_EX)
struct fuse_stat struct fuse_stat
{ {
fuse_dev_t st_dev; FSP_FUSE_STAT_FIELD_DEFN
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;
}; };
#else
struct fuse_stat
{
FSP_FUSE_STAT_EX_FIELD_DEFN
};
#endif
#if defined(_WIN64) #if defined(_WIN64)
struct fuse_statvfs struct fuse_statvfs
@ -178,6 +193,7 @@ struct fuse_flock
fsp_fuse_daemonize, \ fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \ fsp_fuse_set_signal_handlers, \
0/*conv_to_win_path*/, \ 0/*conv_to_win_path*/, \
0/*winpid_to_pid*/, \
{ 0 }, \ { 0 }, \
} }
#else #else
@ -188,6 +204,7 @@ struct fuse_flock
fsp_fuse_daemonize, \ fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \ fsp_fuse_set_signal_handlers, \
0/*conv_to_win_path*/, \ 0/*conv_to_win_path*/, \
0/*winpid_to_pid*/, \
{ 0 }, \ { 0 }, \
} }
#endif #endif
@ -220,7 +237,14 @@ struct fuse_flock
#define fuse_utimbuf utimbuf #define fuse_utimbuf utimbuf
#define fuse_timespec timespec #define fuse_timespec timespec
#if !defined(FSP_FUSE_USE_STAT_EX)
#define fuse_stat stat #define fuse_stat stat
#else
struct fuse_stat
{
FSP_FUSE_STAT_EX_FIELD_DEFN
};
#endif
#define fuse_statvfs statvfs #define fuse_statvfs statvfs
#define fuse_flock flock #define fuse_flock flock
@ -231,6 +255,7 @@ struct fuse_flock
fsp_fuse_daemonize, \ fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \ fsp_fuse_set_signal_handlers, \
fsp_fuse_conv_to_win_path, \ fsp_fuse_conv_to_win_path, \
fsp_fuse_winpid_to_pid, \
{ 0 }, \ { 0 }, \
} }
@ -243,6 +268,11 @@ struct fuse_flock
#error unsupported environment #error unsupported environment
#endif #endif
struct fuse_stat_ex
{
FSP_FUSE_STAT_EX_FIELD_DEFN
};
struct fsp_fuse_env struct fsp_fuse_env
{ {
unsigned environment; unsigned environment;
@ -251,7 +281,8 @@ struct fsp_fuse_env
int (*daemonize)(int); int (*daemonize)(int);
int (*set_signal_handlers)(void *); int (*set_signal_handlers)(void *);
char *(*conv_to_win_path)(const char *); char *(*conv_to_win_path)(const char *);
void (*reserved[3])(); fuse_pid_t (*winpid_to_pid)(uint32_t);
void (*reserved[2])();
}; };
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_signal_handler)(int sig); FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_signal_handler)(int sig);
@ -358,10 +389,17 @@ static inline int fsp_fuse_set_signal_handlers(void *se)
static inline char *fsp_fuse_conv_to_win_path(const char *path) static inline char *fsp_fuse_conv_to_win_path(const char *path)
{ {
void *cygwin_create_path(unsigned, const void *); void *cygwin_create_path(unsigned, const void *);
return cygwin_create_path( return (char *)cygwin_create_path(
0/*CCP_POSIX_TO_WIN_A*/ | 0x100/*CCP_RELATIVE*/, 0/*CCP_POSIX_TO_WIN_A*/ | 0x100/*CCP_RELATIVE*/,
path); path);
} }
static inline fuse_pid_t fsp_fuse_winpid_to_pid(uint32_t winpid)
{
pid_t cygwin_winpid_to_pid(int winpid);
pid_t pid = cygwin_winpid_to_pid(winpid);
return -1 != pid ? pid : (fuse_pid_t)winpid;
}
#endif #endif

View File

@ -1,7 +1,7 @@
/** /**
* @file winfsp/fsctl.h * @file winfsp/fsctl.h
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -34,6 +34,7 @@ extern "C" {
#define FSP_FSCTL_DRIVER_NAME "WinFsp" #define FSP_FSCTL_DRIVER_NAME "WinFsp"
#define FSP_FSCTL_DISK_DEVICE_NAME "WinFsp.Disk" #define FSP_FSCTL_DISK_DEVICE_NAME "WinFsp.Disk"
#define FSP_FSCTL_NET_DEVICE_NAME "WinFsp.Net" #define FSP_FSCTL_NET_DEVICE_NAME "WinFsp.Net"
#define FSP_FSCTL_MUP_DEVICE_NAME "WinFsp.Mup"
// {6F9D25FA-6DEE-4A9D-80F5-E98E14F35E54} // {6F9D25FA-6DEE-4A9D-80F5-E98E14F35E54}
extern const __declspec(selectany) GUID FspFsctlDeviceClassGuid = extern const __declspec(selectany) GUID FspFsctlDeviceClassGuid =
@ -78,6 +79,9 @@ FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024) #define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024)
#define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX #define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX
#define FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(T) ((HANDLE)((T) & 0xffffffff))
#define FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(T) ((UINT32)(((T) >> 32) & 0xffffffff))
/* marshalling */ /* marshalling */
#pragma warning(push) #pragma warning(push)
#pragma warning(disable:4200) /* zero-sized array in struct/union */ #pragma warning(disable:4200) /* zero-sized array in struct/union */
@ -120,42 +124,64 @@ enum
FspFsctlIrpCapacityMaximum = 1000, FspFsctlIrpCapacityMaximum = 1000,
FspFsctlIrpCapacityDefault = 1000, FspFsctlIrpCapacityDefault = 1000,
}; };
#define FSP_FSCTL_VOLUME_PARAMS_V0_FIELD_DEFN\
UINT16 Version; /* set to 0 or sizeof(FSP_FSCTL_VOLUME_PARAMS) */\
/* volume information */\
UINT16 SectorSize;\
UINT16 SectorsPerAllocationUnit;\
UINT16 MaxComponentLength; /* maximum file name component length (bytes) */\
UINT64 VolumeCreationTime;\
UINT32 VolumeSerialNumber;\
/* I/O timeouts, capacity, etc. */\
UINT32 TransactTimeout; /* FSP_FSCTL_TRANSACT timeout (millis; 1 sec - 10 sec) */\
UINT32 IrpTimeout; /* pending IRP timeout (millis; 1 min - 10 min) */\
UINT32 IrpCapacity; /* maximum number of pending IRP's (100 - 1000)*/\
UINT32 FileInfoTimeout; /* FileInfo/Security/VolumeInfo timeout (millis) */\
/* FILE_FS_ATTRIBUTE_INFORMATION::FileSystemAttributes */\
UINT32 CaseSensitiveSearch:1; /* file system supports case-sensitive file names */\
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 */\
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 PostCleanupWhenModifiedOnly:1; /* post Cleanup when a file was modified/deleted */\
UINT32 PassQueryDirectoryPattern:1; /* pass Pattern during QueryDirectory operations */\
UINT32 AlwaysUseDoubleBuffering:1;\
UINT32 PassQueryDirectoryFileName:1; /* pass FileName during QueryDirectory (GetDirInfoByName) */\
UINT32 FlushAndPurgeOnCleanup:1; /* keeps file off "standby" list */\
UINT32 KmReservedFlags:1;\
/* user-mode flags */\
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */\
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */\
UINT32 UmReservedFlags:14;\
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */\
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
#define FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN\
/* additional fields; specify .Version == sizeof(FSP_FSCTL_VOLUME_PARAMS) */\
UINT32 VolumeInfoTimeoutValid:1; /* VolumeInfoTimeout field is valid */\
UINT32 DirInfoTimeoutValid:1; /* DirInfoTimeout field is valid */\
UINT32 SecurityTimeoutValid:1; /* SecurityTimeout field is valid*/\
UINT32 StreamInfoTimeoutValid:1; /* StreamInfoTimeout field is valid */\
UINT32 KmAdditionalReservedFlags:28;\
UINT32 VolumeInfoTimeout; /* volume info timeout (millis); overrides FileInfoTimeout */\
UINT32 DirInfoTimeout; /* dir info timeout (millis); overrides FileInfoTimeout */\
UINT32 SecurityTimeout; /* security info timeout (millis); overrides FileInfoTimeout */\
UINT32 StreamInfoTimeout; /* stream info timeout (millis); overrides FileInfoTimeout */\
UINT32 Reserved32[3];\
UINT64 Reserved64[2];
typedef struct typedef struct
{ {
UINT16 Version; /* set to 0 */ FSP_FSCTL_VOLUME_PARAMS_V0_FIELD_DEFN
/* volume information */ } FSP_FSCTL_VOLUME_PARAMS_V0;
UINT16 SectorSize; typedef struct
UINT16 SectorsPerAllocationUnit; {
UINT16 MaxComponentLength; /* maximum file name component length (bytes) */ FSP_FSCTL_VOLUME_PARAMS_V0_FIELD_DEFN
UINT64 VolumeCreationTime; FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN
UINT32 VolumeSerialNumber;
/* I/O timeouts, capacity, etc. */
UINT32 TransactTimeout; /* FSP_FSCTL_TRANSACT timeout (millis; 1 sec - 10 sec) */
UINT32 IrpTimeout; /* pending IRP timeout (millis; 1 min - 10 min) */
UINT32 IrpCapacity; /* maximum number of pending IRP's (100 - 1000)*/
UINT32 FileInfoTimeout; /* FileInfo/Security/VolumeInfo timeout (millis) */
/* FILE_FS_ATTRIBUTE_INFORMATION::FileSystemAttributes */
UINT32 CaseSensitiveSearch:1; /* file system supports case-sensitive file names */
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 */
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 PostCleanupWhenModifiedOnly:1; /* post Cleanup when a file was modified/deleted */
UINT32 PassQueryDirectoryPattern:1; /* pass Pattern during QueryDirectory operations */
UINT32 AlwaysUseDoubleBuffering:1;
UINT32 KmReservedFlags:3;
/* user-mode flags */
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */
UINT32 UmReservedFlags:14;
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
} FSP_FSCTL_VOLUME_PARAMS; } FSP_FSCTL_VOLUME_PARAMS;
typedef struct typedef struct
{ {
@ -222,7 +248,7 @@ typedef struct
UINT32 FileAttributes; /* file attributes for new files */ UINT32 FileAttributes; /* file attributes for new files */
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* security descriptor for new files */ FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* security descriptor for new files */
UINT64 AllocationSize; /* initial allocation size */ UINT64 AllocationSize; /* initial allocation size */
UINT64 AccessToken; /* request access token (HANDLE) */ UINT64 AccessToken; /* request access token (PID,HANDLE) */
UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */ UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */ UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */ UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */
@ -315,7 +341,7 @@ typedef struct
struct struct
{ {
FSP_FSCTL_TRANSACT_BUF NewFileName; FSP_FSCTL_TRANSACT_BUF NewFileName;
UINT64 AccessToken; /* request access token (HANDLE) */ UINT64 AccessToken; /* request access token (PID,HANDLE) */
} Rename; } Rename;
} Info; } Info;
} SetInformation; } SetInformation;
@ -344,6 +370,7 @@ typedef struct
FSP_FSCTL_TRANSACT_BUF Pattern; FSP_FSCTL_TRANSACT_BUF Pattern;
FSP_FSCTL_TRANSACT_BUF Marker; FSP_FSCTL_TRANSACT_BUF Marker;
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */ UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
UINT32 PatternIsFileName:1; /* Pattern does not contain wildcards */
} QueryDirectory; } QueryDirectory;
struct struct
{ {

276
inc/winfsp/launch.h Normal file
View File

@ -0,0 +1,276 @@
/**
* @file winfsp/launch.h
* WinFsp Launch API.
*
* In order to use the WinFsp Launch API a program must include &lt;winfsp/launch.h&gt;
* and link with the winfsp_x64.dll (or winfsp_x86.dll) library.
*
* @copyright 2015-2018 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_LAUNCH_H_INCLUDED
#define WINFSP_LAUNCH_H_INCLUDED
#include <winfsp/winfsp.h>
#ifdef __cplusplus
extern "C" {
#endif
#define FSP_LAUNCH_REGKEY "Software\\WinFsp\\Services"
#define FSP_LAUNCH_REGKEY_WOW64 KEY_WOW64_32KEY
#define FSP_LAUNCH_PIPE_NAME "\\\\.\\pipe\\WinFsp.{14E7137D-22B4-437A-B0C1-D21D1BDF3767}"
#define FSP_LAUNCH_PIPE_BUFFER_SIZE 4096
#define FSP_LAUNCH_PIPE_OWNER ((PSID)WinLocalSystemSid)
/*
* 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 FSP_LAUNCH_PIPE_SDDL "O:SYG:SYD:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRDCCR;;;WD)"
/*
* 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 FSP_LAUNCH_SERVICE_DEFAULT_SDDL "D:P(A;;RPWPLC;;;SY)(A;;RPWPLC;;;BA)"
#define FSP_LAUNCH_SERVICE_WORLD_SDDL "D:P(A;;RPWPLC;;;WD)"
enum
{
FspLaunchCmdStart = 'S', /* requires: SERVICE_START */
FspLaunchCmdStartWithSecret = 'X', /* requires: SERVICE_START */
FspLaunchCmdStop = 'T', /* requires: SERVICE_STOP */
FspLaunchCmdGetInfo = 'I', /* requires: SERVICE_QUERY_STATUS */
FspLaunchCmdGetNameList = 'L', /* requires: none*/
FspLaunchCmdDefineDosDevice = 'D', /* internal: do not use! */
FspLaunchCmdQuit = 'Q', /* DEBUG version only */
};
enum
{
FspLaunchCmdSuccess = '$',
FspLaunchCmdFailure = '!',
};
/**
* @group Launch Control
*/
/**
* Call launcher pipe.
*
* This function is used to send a command to the launcher and receive a response.
*
* @param Command
* Launcher command to send. For example, the 'L' launcher command instructs
* the launcher to list all running service instances.
* @param Argc
* Command argument count. May be 0.
* @param Argv
* Command argument array. May be NULL.
* @param Argl
* Command argument length array. May be NULL. If this is NULL all command arguments
* are assumed to be NULL-terminated strings. It is also possible for specific arguments
* to be NULL-terminated; in this case pass -1 in the corresponding Argl position.
* @param Buffer
* Buffer that receives the command response. May be NULL.
* @param PSize
* Pointer to a ULONG. On input it contains the size of the Buffer. On output it
* contains the number of bytes transferred. May be NULL.
* @param PLauncherError
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
* @return
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
* returns an error. Other status codes indicate a communication error. Launcher errors are
* reported through PLauncherError.
*/
FSP_API NTSTATUS FspLaunchCallLauncherPipe(
WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl,
PWSTR Buffer, PULONG PSize, PULONG PLauncherError);
/**
* Start a service instance.
*
* @param ClassName
* Class name of the service instance to start.
* @param InstanceName
* Instance name of the service instance to start.
* @param Argc
* Service instance argument count. May be 0.
* @param Argv
* Service instance argument array. May be NULL.
* @param HasSecret
* Whether the last argument in Argv is assumed to be a secret (e.g. password) or not.
* Secrets are passed to service instances through standard input rather than the command
* line.
* @param PLauncherError
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
* @return
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
* returns an error. Other status codes indicate a communication error. Launcher errors are
* reported through PLauncherError.
*/
FSP_API NTSTATUS FspLaunchStart(
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv,
BOOLEAN HasSecret,
PULONG PLauncherError);
/**
* Stop a service instance.
*
* @param ClassName
* Class name of the service instance to stop.
* @param InstanceName
* Instance name of the service instance to stop.
* @param PLauncherError
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
* @return
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
* returns an error. Other status codes indicate a communication error. Launcher errors are
* reported through PLauncherError.
*/
FSP_API NTSTATUS FspLaunchStop(
PWSTR ClassName, PWSTR InstanceName,
PULONG PLauncherError);
/**
* Get information about a service instance.
*
* The information is a list of NULL-terminated strings: the class name of the service instance,
* the instance name of the service instance and the full command line used to start the service
* instance.
*
* @param ClassName
* Class name of the service instance to stop.
* @param InstanceName
* Instance name of the service instance to stop.
* @param Buffer
* Buffer that receives the command response. May be NULL.
* @param PSize
* Pointer to a ULONG. On input it contains the size of the Buffer. On output it
* contains the number of bytes transferred. May be NULL.
* @param PLauncherError
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
* @return
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
* returns an error. Other status codes indicate a communication error. Launcher errors are
* reported through PLauncherError.
*/
FSP_API NTSTATUS FspLaunchGetInfo(
PWSTR ClassName, PWSTR InstanceName,
PWSTR Buffer, PULONG PSize,
PULONG PLauncherError);
/**
* List service instances.
*
* The information is a list of pairs of NULL-terminated strings. Each pair contains the class
* name and instance name of a service instance. All currently running service instances are
* listed.
*
* @param Buffer
* Buffer that receives the command response. May be NULL.
* @param PSize
* Pointer to a ULONG. On input it contains the size of the Buffer. On output it
* contains the number of bytes transferred. May be NULL.
* @param PLauncherError
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
* @return
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
* returns an error. Other status codes indicate a communication error. Launcher errors are
* reported through PLauncherError.
*/
FSP_API NTSTATUS FspLaunchGetNameList(
PWSTR Buffer, PULONG PSize,
PULONG PLauncherError);
/**
* @group Service Registry
*/
#pragma warning(push)
#pragma warning(disable:4200) /* zero-sized array in struct/union */
/**
* Service registry record.
*/
typedef struct _FSP_LAUNCH_REG_RECORD
{
PWSTR Agent;
PWSTR Executable;
PWSTR CommandLine;
PWSTR WorkDirectory;
PWSTR RunAs;
PWSTR Security;
PVOID Reserved0[6];
ULONG JobControl;
ULONG Credentials;
ULONG Reserved1[6];
UINT8 Buffer[];
} FSP_LAUNCH_REG_RECORD;
#pragma warning(pop)
/**
* Add/change/delete a service registry record.
*
* @param ClassName
* The service class name.
* @param Record
* The record to set in the registry. If NULL, the registry record is deleted.
* @return
* STATUS_SUCCESS or error code.
*/
FSP_API NTSTATUS FspLaunchRegSetRecord(
PWSTR ClassName,
const FSP_LAUNCH_REG_RECORD *Record);
/**
* Get a service registry record.
*
* @param ClassName
* The service class name.
* @param Agent
* The name of the agent that is retrieving the service record. This API matches
* the supplied Agent against the Agent in the service record and it only returns
* the record if they match. Pass NULL to match any Agent.
* @param PRecord
* Pointer to a record pointer. Memory for the service record will be allocated
* and a pointer to it will be stored at this address. This memory must be later
* freed using FspLaunchRegFreeRecord.
* @return
* STATUS_SUCCESS or error code.
* @see
* FspLaunchRegFreeRecord
*/
FSP_API NTSTATUS FspLaunchRegGetRecord(
PWSTR ClassName, PWSTR Agent,
FSP_LAUNCH_REG_RECORD **PRecord);
/**
* Free a service registry record.
*
* @param Record
* The service record to free.
* @see
* FspLaunchRegGetRecord
*/
FSP_API VOID FspLaunchRegFreeRecord(
FSP_LAUNCH_REG_RECORD *Record);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -5,7 +5,7 @@
* In order to use the WinFsp API the user mode file system must include &lt;winfsp/winfsp.h&gt; * In order to use the WinFsp API the user mode file system must include &lt;winfsp/winfsp.h&gt;
* and link with the winfsp_x64.dll (or winfsp_x86.dll) library. * and link with the winfsp_x64.dll (or winfsp_x86.dll) library.
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -802,12 +802,32 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
NTSTATUS (*GetStreamInfo)(FSP_FILE_SYSTEM *FileSystem, NTSTATUS (*GetStreamInfo)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PVOID Buffer, ULONG Length, PVOID FileContext, PVOID Buffer, ULONG Length,
PULONG PBytesTransferred); PULONG PBytesTransferred);
/**
* Get directory information for a single file or directory within a parent directory.
*
* @param FileSystem
* The file system on which this request is posted.
* @param FileContext
* The file context of the parent directory.
* @param FileName
* The name of the file or directory to get information for. This name is relative
* to the parent directory and is a single path component.
* @param DirInfo [out]
* Pointer to a structure that will receive the directory information on successful
* return from this call. This information includes the file name, but also file
* attributes, file times, etc.
* @return
* STATUS_SUCCESS or error code.
*/
NTSTATUS (*GetDirInfoByName)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PWSTR FileName,
FSP_FSCTL_DIR_INFO *DirInfo);
/* /*
* This ensures that this interface will always contain 64 function pointers. * This ensures that this interface will always contain 64 function pointers.
* Please update when changing the interface as it is important for future compatibility. * Please update when changing the interface as it is important for future compatibility.
*/ */
NTSTATUS (*Reserved[40])(); NTSTATUS (*Reserved[39])();
} FSP_FILE_SYSTEM_INTERFACE; } FSP_FILE_SYSTEM_INTERFACE;
FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()), FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries."); "FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
@ -961,14 +981,12 @@ FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
* The current operation context. * The current operation context.
*/ */
FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID); FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID);
FSP_API PWSTR FspFileSystemMountPointF(FSP_FILE_SYSTEM *FileSystem);
static inline static inline
PWSTR FspFileSystemMountPoint(FSP_FILE_SYSTEM *FileSystem) PWSTR FspFileSystemMountPoint(FSP_FILE_SYSTEM *FileSystem)
{ {
return FileSystem->MountPoint; return FileSystem->MountPoint;
} }
FSP_API NTSTATUS FspFileSystemEnterOperationF(FSP_FILE_SYSTEM *FileSystem, FSP_API PWSTR FspFileSystemMountPointF(FSP_FILE_SYSTEM *FileSystem);
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
static inline static inline
NTSTATUS FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem, NTSTATUS FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response) FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
@ -978,7 +996,7 @@ NTSTATUS FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem,
return FileSystem->EnterOperation(FileSystem, Request, Response); return FileSystem->EnterOperation(FileSystem, Request, Response);
} }
FSP_API NTSTATUS FspFileSystemLeaveOperationF(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspFileSystemEnterOperationF(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
static inline static inline
NTSTATUS FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem, NTSTATUS FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem,
@ -989,9 +1007,8 @@ NTSTATUS FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem,
return FileSystem->LeaveOperation(FileSystem, Request, Response); return FileSystem->LeaveOperation(FileSystem, Request, Response);
} }
FSP_API VOID FspFileSystemSetOperationGuardF(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspFileSystemLeaveOperationF(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation, FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
FSP_FILE_SYSTEM_OPERATION_GUARD *LeaveOperation);
static inline static inline
VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation, FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation,
@ -1000,6 +1017,9 @@ VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
FileSystem->EnterOperation = EnterOperation; FileSystem->EnterOperation = EnterOperation;
FileSystem->LeaveOperation = LeaveOperation; FileSystem->LeaveOperation = LeaveOperation;
} }
FSP_API VOID FspFileSystemSetOperationGuardF(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation,
FSP_FILE_SYSTEM_OPERATION_GUARD *LeaveOperation);
/** /**
* Set file system locking strategy. * Set file system locking strategy.
* *
@ -1010,17 +1030,14 @@ VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
* @see * @see
* FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY * FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY
*/ */
FSP_API VOID FspFileSystemSetOperationGuardStrategyF(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy);
static inline static inline
VOID FspFileSystemSetOperationGuardStrategy(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetOperationGuardStrategy(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy) FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy)
{ {
FileSystem->OpGuardStrategy = GuardStrategy; FileSystem->OpGuardStrategy = GuardStrategy;
} }
FSP_API VOID FspFileSystemSetOperationF(FSP_FILE_SYSTEM *FileSystem, FSP_API VOID FspFileSystemSetOperationGuardStrategyF(FSP_FILE_SYSTEM *FileSystem,
ULONG Index, FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy);
FSP_FILE_SYSTEM_OPERATION *Operation);
static inline static inline
VOID FspFileSystemSetOperation(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetOperation(FSP_FILE_SYSTEM *FileSystem,
ULONG Index, ULONG Index,
@ -1028,8 +1045,9 @@ VOID FspFileSystemSetOperation(FSP_FILE_SYSTEM *FileSystem,
{ {
FileSystem->Operations[Index] = Operation; FileSystem->Operations[Index] = Operation;
} }
FSP_API VOID FspFileSystemGetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem, FSP_API VOID FspFileSystemSetOperationF(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS *PDispatcherResult); ULONG Index,
FSP_FILE_SYSTEM_OPERATION *Operation);
static inline static inline
VOID FspFileSystemGetDispatcherResult(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemGetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS *PDispatcherResult) NTSTATUS *PDispatcherResult)
@ -1038,8 +1056,8 @@ VOID FspFileSystemGetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
*PDispatcherResult = FileSystem->DispatcherResult; *PDispatcherResult = FileSystem->DispatcherResult;
MemoryBarrier(); MemoryBarrier();
} }
FSP_API VOID FspFileSystemSetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem, FSP_API VOID FspFileSystemGetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS DispatcherResult); NTSTATUS *PDispatcherResult);
static inline static inline
VOID FspFileSystemSetDispatcherResult(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS DispatcherResult) NTSTATUS DispatcherResult)
@ -1048,15 +1066,16 @@ VOID FspFileSystemSetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
return; return;
InterlockedCompareExchange(&FileSystem->DispatcherResult, DispatcherResult, 0); InterlockedCompareExchange(&FileSystem->DispatcherResult, DispatcherResult, 0);
} }
FSP_API VOID FspFileSystemSetDebugLogF(FSP_FILE_SYSTEM *FileSystem, FSP_API VOID FspFileSystemSetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem,
UINT32 DebugLog); NTSTATUS DispatcherResult);
static inline static inline
VOID FspFileSystemSetDebugLog(FSP_FILE_SYSTEM *FileSystem, VOID FspFileSystemSetDebugLog(FSP_FILE_SYSTEM *FileSystem,
UINT32 DebugLog) UINT32 DebugLog)
{ {
FileSystem->DebugLog = DebugLog; FileSystem->DebugLog = DebugLog;
} }
FSP_API BOOLEAN FspFileSystemIsOperationCaseSensitiveF(VOID); FSP_API VOID FspFileSystemSetDebugLogF(FSP_FILE_SYSTEM *FileSystem,
UINT32 DebugLog);
static inline static inline
BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID) BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID)
{ {
@ -1065,6 +1084,29 @@ BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID)
FspFsctlTransactCreateKind == Request->Kind && Request->Req.Create.CaseSensitive || FspFsctlTransactCreateKind == Request->Kind && Request->Req.Create.CaseSensitive ||
FspFsctlTransactQueryDirectoryKind == Request->Kind && Request->Req.QueryDirectory.CaseSensitive; FspFsctlTransactQueryDirectoryKind == Request->Kind && Request->Req.QueryDirectory.CaseSensitive;
} }
FSP_API BOOLEAN FspFileSystemIsOperationCaseSensitiveF(VOID);
/**
* Gets the originating process ID.
*
* Valid only during Create, Open and Rename requests when the target exists.
*/
static inline
UINT32 FspFileSystemOperationProcessId(VOID)
{
FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request;
switch (Request->Kind)
{
case FspFsctlTransactCreateKind:
return FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.Create.AccessToken);
case FspFsctlTransactSetInformationKind:
if (10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass)
return FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.SetInformation.Info.Rename.AccessToken);
/* fall through! */
default:
return 0;
}
}
FSP_API UINT32 FspFileSystemOperationProcessIdF(VOID);
/* /*
* Operations * Operations
@ -1430,6 +1472,21 @@ NTSTATUS FspPosixMapPosixToWindowsPath(const char *PosixPath, PWSTR *PWindowsPat
FSP_API VOID FspPosixDeletePath(void *Path); FSP_API VOID FspPosixDeletePath(void *Path);
FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size); FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size);
FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size); FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size);
static inline
VOID FspPosixFileTimeToUnixTime(UINT64 FileTime0, __int3264 UnixTime[2])
{
INT64 FileTime = (INT64)FileTime0 - 116444736000000000LL;
UnixTime[0] = (__int3264)(FileTime / 10000000);
UnixTime[1] = (__int3264)(FileTime % 10000000 * 100);
/* may produce negative nsec for times before UNIX epoch; strictly speaking this is incorrect */
}
static inline
VOID FspPosixUnixTimeToFileTime(const __int3264 UnixTime[2], PUINT64 PFileTime)
{
INT64 FileTime = (INT64)UnixTime[0] * 10000000 + (INT64)UnixTime[1] / 100 +
116444736000000000LL;
*PFileTime = FileTime;
}
/* /*
* Path Handling * Path Handling
@ -1618,6 +1675,19 @@ FSP_API VOID FspServiceStop(FSP_SERVICE *Service);
* TRUE if the process is running in running user interactive mode. * TRUE if the process is running in running user interactive mode.
*/ */
FSP_API BOOLEAN FspServiceIsInteractive(VOID); FSP_API BOOLEAN FspServiceIsInteractive(VOID);
/**
* Check if the supplied token is from the service context.
*
* @param Token
* Token to check. Pass NULL to check the current process token.
* @param PIsLocalSystem
* Pointer to a boolean that will receive a TRUE value if the token belongs to LocalSystem
* and FALSE otherwise. May be NULL.
* @return
* STATUS_SUCCESS if the token is from the service context. STATUS_ACCESS_DENIED if it is not.
* Other error codes are possible.
*/
FSP_API NTSTATUS FspServiceContextCheck(HANDLE Token, PBOOLEAN PIsLocalSystem);
/** /**
* Log a service message. * Log a service message.
* *
@ -1643,6 +1713,7 @@ FSP_API VOID FspEventLogV(ULONG Type, PWSTR Format, va_list ap);
FSP_API VOID FspDebugLogSetHandle(HANDLE Handle); FSP_API VOID FspDebugLogSetHandle(HANDLE Handle);
FSP_API VOID FspDebugLog(const char *Format, ...); FSP_API VOID FspDebugLog(const char *Format, ...);
FSP_API VOID FspDebugLogSD(const char *Format, PSECURITY_DESCRIPTOR SecurityDescriptor); FSP_API VOID FspDebugLogSD(const char *Format, PSECURITY_DESCRIPTOR SecurityDescriptor);
FSP_API VOID FspDebugLogSid(const char *format, PSID Sid);
FSP_API VOID FspDebugLogFT(const char *Format, PFILETIME FileTime); FSP_API VOID FspDebugLogFT(const char *Format, PFILETIME FileTime);
FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request); FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request);
FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response); FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response);

View File

@ -2,7 +2,7 @@
* @file winfsp/winfsp.hpp * @file winfsp/winfsp.hpp
* WinFsp C++ Layer. * WinFsp C++ Layer.
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.

View File

@ -22,7 +22,9 @@ cygport:
dist: cygport dist: cygport
case $(shell uname -m) in \ case $(shell uname -m) in \
x86_64)\ x86_64)\
mkdir -p dist/x64 && \
cp fuse-*/dist/fuse/fuse-*[0-9].tar.xz dist/x64 ;;\ cp fuse-*/dist/fuse/fuse-*[0-9].tar.xz dist/x64 ;;\
*)\ *)\
mkdir -p dist/x86 && \
cp fuse-*/dist/fuse/fuse-*[0-9].tar.xz dist/x86 ;;\ cp fuse-*/dist/fuse/fuse-*[0-9].tar.xz dist/x86 ;;\
esac esac

View File

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

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

View File

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

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/debug.c * @file dll/debug.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -63,6 +63,21 @@ FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDesc
FspDebugLog(format, "invalid security descriptor"); FspDebugLog(format, "invalid security descriptor");
} }
FSP_API VOID FspDebugLogSid(const char *format, PSID Sid)
{
char *S;
if (0 == Sid)
FspDebugLog(format, "null SID");
else if (ConvertSidToStringSidA(Sid, &S))
{
FspDebugLog(format, S);
LocalFree(S);
}
else
FspDebugLog(format, "invalid SID");
}
FSP_API VOID FspDebugLogFT(const char *format, PFILETIME FileTime) FSP_API VOID FspDebugLogFT(const char *format, PFILETIME FileTime)
{ {
SYSTEMTIME SystemTime; SYSTEMTIME SystemTime;
@ -302,7 +317,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c%c%c] \"%S\", " FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c%c%c] \"%S\", "
"%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, " "%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, "
"AllocationSize=%lx:%lx, " "AllocationSize=%lx:%lx, "
"AccessToken=%p, DesiredAccess=%lx, GrantedAccess=%lx, " "AccessToken=%p[PID=%lx], DesiredAccess=%lx, GrantedAccess=%lx, "
"ShareAccess=%lx\n", "ShareAccess=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint, FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->Req.Create.UserMode ? 'U' : 'K', Request->Req.Create.UserMode ? 'U' : 'K',
@ -319,7 +334,8 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
Sddl ? Sddl : "NULL", Sddl ? Sddl : "NULL",
Sddl ? "\"" : "", Sddl ? "\"" : "",
MAKE_UINT32_PAIR(Request->Req.Create.AllocationSize), MAKE_UINT32_PAIR(Request->Req.Create.AllocationSize),
(PVOID)Request->Req.Create.AccessToken, FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.Create.AccessToken),
Request->Req.Create.DesiredAccess, Request->Req.Create.DesiredAccess,
Request->Req.Create.GrantedAccess, Request->Req.Create.GrantedAccess,
Request->Req.Create.ShareAccess); Request->Req.Create.ShareAccess);
@ -459,7 +475,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break; break;
case 10/*FileRenameInformation*/: case 10/*FileRenameInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Rename] %s%S%s%s, " FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Rename] %s%S%s%s, "
"NewFileName=\"%S\", AccessToken=%p\n", "NewFileName=\"%S\", AccessToken=%p[PID=%lx]\n",
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint, FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "", Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"", Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
@ -468,7 +484,8 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2, Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
UserContextBuf), UserContextBuf),
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset), (PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
(PVOID)Request->Req.SetInformation.Info.Rename.AccessToken); FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.SetInformation.Info.Rename.AccessToken),
FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.SetInformation.Info.Rename.AccessToken));
break; break;
default: default:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [INVALID] %s%S%s%s\n", FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [INVALID] %s%S%s%s\n",

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/fs.c * @file dll/fs.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -187,17 +187,62 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem)
MemFree(FileSystem); MemFree(FileSystem);
} }
static NTSTATUS FspFileSystemLauncherDefineDosDevice(
WCHAR Sign, PWSTR MountPoint, PWSTR VolumeName)
{
if (2 != lstrlenW(MountPoint) ||
FSP_FSCTL_VOLUME_NAME_SIZEMAX / sizeof(WCHAR) <= lstrlenW(VolumeName))
return STATUS_INVALID_PARAMETER;
WCHAR Argv0[4];
PWSTR Argv[2];
NTSTATUS Result;
ULONG ErrorCode;
Argv0[0] = Sign;
Argv0[1] = MountPoint[0];
Argv0[2] = MountPoint[1];
Argv0[3] = L'\0';
Argv[0] = Argv0;
Argv[1] = VolumeName;
Result = FspLaunchCallLauncherPipe(FspLaunchCmdDefineDosDevice, 2, Argv, 0, 0, 0, &ErrorCode);
return !NT_SUCCESS(Result) ? Result : FspNtStatusFromWin32(ErrorCode);
}
static NTSTATUS FspFileSystemSetMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName, static NTSTATUS FspFileSystemSetMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName,
PHANDLE PMountHandle) PHANDLE PMountHandle)
{ {
NTSTATUS Result;
BOOLEAN IsLocalSystem, IsServiceContext;
*PMountHandle = 0; *PMountHandle = 0;
if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, VolumeName)) Result = FspServiceContextCheck(0, &IsLocalSystem);
return FspNtStatusFromWin32(GetLastError()); IsServiceContext = NT_SUCCESS(Result) && !IsLocalSystem;
if (IsServiceContext)
{
/*
* If the current process is in the service context but not LocalSystem,
* ask the launcher to DefineDosDevice for us. This is because the launcher
* runs in the LocalSystem context and can create global drives.
*
* In this case the launcher will also add DELETE access to the drive symlink
* for us, so that we can make it temporary below.
*/
Result = FspFileSystemLauncherDefineDosDevice(L'+', MountPoint, VolumeName);
if (!NT_SUCCESS(Result))
return Result;
}
else
{
if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, VolumeName))
return FspNtStatusFromWin32(GetLastError());
}
if (0 != FspNtOpenSymbolicLinkObject) if (0 != FspNtOpenSymbolicLinkObject)
{ {
NTSTATUS Result;
WCHAR SymlinkBuf[6]; WCHAR SymlinkBuf[6];
UNICODE_STRING Symlink; UNICODE_STRING Symlink;
OBJECT_ATTRIBUTES Obja; OBJECT_ATTRIBUTES Obja;
@ -224,6 +269,13 @@ static NTSTATUS FspFileSystemSetMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeN
} }
} }
/* HACK:
*
* Handles do not use the low 2 bits (unless they are console handles).
* Abuse this fact to remember that we are running in the service context.
*/
*PMountHandle = (HANDLE)(UINT_PTR)((DWORD)(UINT_PTR)*PMountHandle | IsServiceContext);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -411,8 +463,18 @@ exit:
static VOID FspFileSystemRemoveMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName, HANDLE MountHandle) static VOID FspFileSystemRemoveMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName, HANDLE MountHandle)
{ {
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, BOOLEAN IsServiceContext = 0 != ((DWORD)(UINT_PTR)MountHandle & 1);
MountPoint, VolumeName); MountHandle = (HANDLE)(UINT_PTR)((DWORD)(UINT_PTR)MountHandle & ~1);
if (IsServiceContext)
/*
* If the current process is in the service context but not LocalSystem,
* ask the launcher to DefineDosDevice for us. This is because the launcher
* runs in the LocalSystem context and can remove global drives.
*/
FspFileSystemLauncherDefineDosDevice(L'-', MountPoint, VolumeName);
else
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
MountPoint, VolumeName);
if (0 != MountHandle) if (0 != MountHandle)
FspNtClose(MountHandle); FspNtClose(MountHandle);
@ -683,3 +745,8 @@ FSP_API BOOLEAN FspFileSystemIsOperationCaseSensitiveF(VOID)
{ {
return FspFileSystemIsOperationCaseSensitive(); return FspFileSystemIsOperationCaseSensitive();
} }
FSP_API UINT32 FspFileSystemOperationProcessIdF(VOID)
{
return FspFileSystemOperationProcessId();
}

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/fsctl.c * @file dll/fsctl.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -31,7 +31,7 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
{ {
NTSTATUS Result; NTSTATUS Result;
PWSTR DeviceRoot; PWSTR DeviceRoot;
SIZE_T DeviceRootSize, DevicePathSize; SIZE_T DeviceRootSize, DevicePathSize, VolumeParamsSize;
WCHAR DevicePathBuf[MAX_PATH + sizeof *VolumeParams], *DevicePathPtr, *DevicePathEnd; WCHAR DevicePathBuf[MAX_PATH + sizeof *VolumeParams], *DevicePathPtr, *DevicePathEnd;
HANDLE VolumeHandle = INVALID_HANDLE_VALUE; HANDLE VolumeHandle = INVALID_HANDLE_VALUE;
DWORD Bytes; DWORD Bytes;
@ -55,8 +55,11 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
memcpy(DevicePathPtr, DevicePath, DevicePathSize); memcpy(DevicePathPtr, DevicePath, DevicePathSize);
DevicePathPtr = (PVOID)((PUINT8)DevicePathPtr + DevicePathSize); DevicePathPtr = (PVOID)((PUINT8)DevicePathPtr + DevicePathSize);
memcpy(DevicePathPtr, PREFIXW, PREFIXW_SIZE); memcpy(DevicePathPtr, PREFIXW, PREFIXW_SIZE);
VolumeParamsSize = 0 == VolumeParams->Version ?
sizeof(FSP_FSCTL_VOLUME_PARAMS_V0) :
VolumeParams->Version;
DevicePathPtr = (PVOID)((PUINT8)DevicePathPtr + PREFIXW_SIZE); DevicePathPtr = (PVOID)((PUINT8)DevicePathPtr + PREFIXW_SIZE);
DevicePathEnd = (PVOID)((PUINT8)DevicePathPtr + sizeof *VolumeParams * sizeof(WCHAR)); DevicePathEnd = (PVOID)((PUINT8)DevicePathPtr + VolumeParamsSize * sizeof(WCHAR));
for (PUINT8 VolumeParamsPtr = (PVOID)VolumeParams; for (PUINT8 VolumeParamsPtr = (PVOID)VolumeParams;
DevicePathEnd > DevicePathPtr; DevicePathPtr++, VolumeParamsPtr++) DevicePathEnd > DevicePathPtr; DevicePathPtr++, VolumeParamsPtr++)
{ {
@ -284,7 +287,7 @@ static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
* This function adds an ACE that allows Everyone to start a service. * This function adds an ACE that allows Everyone to start a service.
*/ */
PSID WorldSid = 0; PSID WorldSid;
PSECURITY_DESCRIPTOR SecurityDescriptor = 0; PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PSECURITY_DESCRIPTOR NewSecurityDescriptor = 0; PSECURITY_DESCRIPTOR NewSecurityDescriptor = 0;
EXPLICIT_ACCESSW AccessEntry; EXPLICIT_ACCESSW AccessEntry;
@ -296,18 +299,12 @@ static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
NTSTATUS Result; NTSTATUS Result;
/* get the Everyone (World) SID */ /* get the Everyone (World) SID */
Size = SECURITY_MAX_SID_SIZE; WorldSid = FspWksidGet(WinWorldSid);
WorldSid = MemAlloc(Size);
if (0 == WorldSid) if (0 == WorldSid)
{ {
Result = STATUS_INSUFFICIENT_RESOURCES; Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit; goto exit;
} }
if (!CreateWellKnownSid(WinWorldSid, 0, WorldSid, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
/* get the service security descriptor DACL */ /* get the service security descriptor DACL */
Size = 0; Size = 0;
@ -394,7 +391,6 @@ static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
exit: exit:
LocalFree(NewSecurityDescriptor); LocalFree(NewSecurityDescriptor);
MemFree(SecurityDescriptor); MemFree(SecurityDescriptor);
MemFree(WorldSid);
return Result; return Result;
} }

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/fsop.c * @file dll/fsop.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -1121,6 +1121,36 @@ FSP_API NTSTATUS FspFileSystemOpSetVolumeInformation(FSP_FILE_SYSTEM *FileSystem
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS FspFileSystemOpQueryDirectory_GetDirInfoByName(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PWSTR FileName,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
NTSTATUS Result;
union
{
FSP_FSCTL_DIR_INFO V;
UINT8 B[sizeof(FSP_FSCTL_DIR_INFO) + 255 * sizeof(WCHAR)];
} DirInfoBuf;
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.V;
/* The FSD will never send us a Marker that we need to worry about! */
memset(DirInfo, 0, sizeof *DirInfo);
Result = FileSystem->Interface->GetDirInfoByName(FileSystem, FileContext, FileName, DirInfo);
if (NT_SUCCESS(Result))
{
if (FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred))
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
}
else if (STATUS_OBJECT_NAME_NOT_FOUND == Result)
{
Result = STATUS_SUCCESS;
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
}
return Result;
}
FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response) FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{ {
@ -1131,15 +1161,24 @@ FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
return STATUS_INVALID_DEVICE_REQUEST; return STATUS_INVALID_DEVICE_REQUEST;
BytesTransferred = 0; BytesTransferred = 0;
Result = FileSystem->Interface->ReadDirectory(FileSystem, if (0 != FileSystem->Interface->GetDirInfoByName &&
(PVOID)ValOfFileContext(Request->Req.QueryDirectory), 0 != Request->Req.QueryDirectory.Pattern.Size && Request->Req.QueryDirectory.PatternIsFileName)
0 != Request->Req.QueryDirectory.Pattern.Size ? Result = FspFileSystemOpQueryDirectory_GetDirInfoByName(FileSystem,
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : 0, (PVOID)ValOfFileContext(Request->Req.QueryDirectory),
0 != Request->Req.QueryDirectory.Marker.Size ? (PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset),
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset) : 0, (PVOID)Request->Req.QueryDirectory.Address,
(PVOID)Request->Req.QueryDirectory.Address, Request->Req.QueryDirectory.Length,
Request->Req.QueryDirectory.Length, &BytesTransferred);
&BytesTransferred); else
Result = FileSystem->Interface->ReadDirectory(FileSystem,
(PVOID)ValOfFileContext(Request->Req.QueryDirectory),
0 != Request->Req.QueryDirectory.Pattern.Size ?
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : 0,
0 != Request->Req.QueryDirectory.Marker.Size ?
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset) : 0,
(PVOID)Request->Req.QueryDirectory.Address,
Request->Req.QueryDirectory.Length,
&BytesTransferred);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/fuse/fuse.c * @file dll/fuse/fuse.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -34,11 +34,16 @@ struct fsp_fuse_core_opt_data
int help, debug; int help, debug;
HANDLE DebugLogHandle; HANDLE DebugLogHandle;
int set_umask, umask, int set_umask, umask,
set_create_umask, create_umask,
set_uid, uid, set_uid, uid,
set_gid, gid, set_gid, gid,
set_attr_timeout, attr_timeout, set_attr_timeout, attr_timeout,
rellinks; rellinks;
int set_FileInfoTimeout; int set_FileInfoTimeout,
set_DirInfoTimeout,
set_VolumeInfoTimeout,
set_KeepFileCache;
unsigned ThreadCount;
FSP_FSCTL_VOLUME_PARAMS VolumeParams; FSP_FSCTL_VOLUME_PARAMS VolumeParams;
UINT16 VolumeLabelLength; UINT16 VolumeLabelLength;
WCHAR VolumeLabel[sizeof ((FSP_FSCTL_VOLUME_INFO *)0)->VolumeLabel / sizeof(WCHAR)]; WCHAR VolumeLabel[sizeof ((FSP_FSCTL_VOLUME_INFO *)0)->VolumeLabel / sizeof(WCHAR)];
@ -69,6 +74,8 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FUSE_OPT_KEY("noauto_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=", set_umask, 1),
FSP_FUSE_CORE_OPT("umask=%o", umask, 0), FSP_FUSE_CORE_OPT("umask=%o", umask, 0),
FSP_FUSE_CORE_OPT("create_umask=", set_create_umask, 1),
FSP_FUSE_CORE_OPT("create_umask=%o", create_umask, 0),
FSP_FUSE_CORE_OPT("uid=", set_uid, 1), FSP_FUSE_CORE_OPT("uid=", set_uid, 1),
FSP_FUSE_CORE_OPT("uid=%d", uid, 0), FSP_FUSE_CORE_OPT("uid=%d", uid, 0),
FSP_FUSE_CORE_OPT("gid=", set_gid, 1), FSP_FUSE_CORE_OPT("gid=", set_gid, 1),
@ -96,6 +103,12 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FSP_FUSE_CORE_OPT("VolumeSerialNumber=%lx", VolumeParams.VolumeSerialNumber, 0), FSP_FUSE_CORE_OPT("VolumeSerialNumber=%lx", VolumeParams.VolumeSerialNumber, 0),
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1), FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0), FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
FSP_FUSE_CORE_OPT("DirInfoTimeout=", set_DirInfoTimeout, 1),
FSP_FUSE_CORE_OPT("DirInfoTimeout=%d", VolumeParams.DirInfoTimeout, 0),
FSP_FUSE_CORE_OPT("VolumeInfoTimeout=", set_VolumeInfoTimeout, 1),
FSP_FUSE_CORE_OPT("VolumeInfoTimeout=%d", VolumeParams.VolumeInfoTimeout, 0),
FSP_FUSE_CORE_OPT("KeepFileCache=", set_KeepFileCache, 1),
FSP_FUSE_CORE_OPT("ThreadCount=%u", ThreadCount, 0),
FUSE_OPT_KEY("UNC=", 'U'), FUSE_OPT_KEY("UNC=", 'U'),
FUSE_OPT_KEY("--UNC=", 'U'), FUSE_OPT_KEY("--UNC=", 'U'),
FUSE_OPT_KEY("VolumePrefix=", 'U'), FUSE_OPT_KEY("VolumePrefix=", 'U'),
@ -283,6 +296,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
context->private_data = f->data; context->private_data = f->data;
context->uid = -1; context->uid = -1;
context->gid = -1; context->gid = -1;
context->pid = -1;
memset(&conn, 0, sizeof conn); memset(&conn, 0, sizeof conn);
conn.proto_major = 7; /* pretend that we are FUSE kernel protocol 7.12 */ conn.proto_major = 7; /* pretend that we are FUSE kernel protocol 7.12 */
@ -298,12 +312,21 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
FUSE_CAP_DONT_MASK | FUSE_CAP_DONT_MASK |
FSP_FUSE_CAP_READDIR_PLUS | FSP_FUSE_CAP_READDIR_PLUS |
FSP_FUSE_CAP_READ_ONLY | FSP_FUSE_CAP_READ_ONLY |
FSP_FUSE_CAP_STAT_EX |
FSP_FUSE_CAP_CASE_INSENSITIVE; FSP_FUSE_CAP_CASE_INSENSITIVE;
if (0 != f->ops.init) if (0 != f->ops.init)
{ {
context->private_data = f->data = f->ops.init(&conn); context->private_data = f->data = f->ops.init(&conn);
f->VolumeParams.ReadOnlyVolume = 0 != (conn.want & FSP_FUSE_CAP_READ_ONLY); f->VolumeParams.ReadOnlyVolume = 0 != (conn.want & FSP_FUSE_CAP_READ_ONLY);
f->VolumeParams.CaseSensitiveSearch = 0 == (conn.want & FSP_FUSE_CAP_CASE_INSENSITIVE); f->VolumeParams.CaseSensitiveSearch = 0 == (conn.want & FSP_FUSE_CAP_CASE_INSENSITIVE);
if (!f->VolumeParams.CaseSensitiveSearch)
/*
* Disable GetDirInfoByName when file system is case-insensitive.
* The reason is that Windows always sends us queries with uppercase
* file names in GetDirInfoByName and we have no way in FUSE to normalize
* those file names when embedding them in FSP_FSCTL_DIR_INFO.
*/
f->VolumeParams.PassQueryDirectoryFileName = FALSE;
f->conn_want = conn.want; f->conn_want = conn.want;
} }
f->fsinit = TRUE; f->fsinit = TRUE;
@ -331,7 +354,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
} }
if (0 != f->ops.getattr) if (0 != f->ops.getattr)
{ {
struct fuse_stat stbuf; struct fuse_stat_ex stbuf;
int err; int err;
memset(&stbuf, 0, sizeof stbuf); memset(&stbuf, 0, sizeof stbuf);
@ -345,14 +368,12 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
if (0 == f->VolumeParams.VolumeCreationTime) if (0 == f->VolumeParams.VolumeCreationTime)
{ {
if (0 != stbuf.st_birthtim.tv_sec) if (0 != stbuf.st_birthtim.tv_sec)
f->VolumeParams.VolumeCreationTime = FspPosixUnixTimeToFileTime((void *)&stbuf.st_birthtim,
Int32x32To64(stbuf.st_birthtim.tv_sec, 10000000) + 116444736000000000 + &f->VolumeParams.VolumeCreationTime);
stbuf.st_birthtim.tv_nsec / 100;
else else
if (0 != stbuf.st_ctim.tv_sec) if (0 != stbuf.st_ctim.tv_sec)
f->VolumeParams.VolumeCreationTime = FspPosixUnixTimeToFileTime((void *)&stbuf.st_ctim,
Int32x32To64(stbuf.st_ctim.tv_sec, 10000000) + 116444736000000000 + &f->VolumeParams.VolumeCreationTime);
stbuf.st_ctim.tv_nsec / 100;
} }
} }
@ -405,7 +426,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
} }
} }
Result = FspFileSystemStartDispatcher(f->FileSystem, 0); Result = FspFileSystemStartDispatcher(f->FileSystem, f->ThreadCount);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
{ {
FspServiceLog(EVENTLOG_ERROR_TYPE, FspServiceLog(EVENTLOG_ERROR_TYPE,
@ -460,25 +481,27 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
default: default:
return 1; return 1;
case 'h': case 'h':
/* Note: The limit on FspServiceLog messages is 1024 bytes. This is getting close. */ /* Note: The limit on FspServiceLog messages is 1024 bytes. */
FspServiceLog(EVENTLOG_ERROR_TYPE, L"" FspServiceLog(EVENTLOG_ERROR_TYPE, L""
FSP_FUSE_LIBRARY_NAME " options:\n" FSP_FUSE_LIBRARY_NAME " options:\n"
" -o umask=MASK set file permissions (octal)\n" " -o umask=MASK set file permissions (octal)\n"
" -o create_umask=MASK set newly created file permissions (octal)\n"
" -o uid=N set file owner (-1 for mounting user id)\n" " -o uid=N set file owner (-1 for mounting user id)\n"
" -o gid=N set file group (-1 for mounting user group)\n" " -o gid=N set file group (-1 for mounting user group)\n"
" -o rellinks interpret absolute symlinks as volume relative\n" " -o rellinks interpret absolute symlinks as volume relative\n"
" -o volname=NAME set volume label\n" " -o volname=NAME set volume label\n"
" -o VolumePrefix=UNC set UNC prefix (\\Server\\Share)\n" " -o VolumePrefix=UNC set UNC prefix (/Server/Share)\n"
" --VolumePrefix=UNC set UNC prefix (\\Server\\Share)\n"
" -o FileSystemName=NAME set file system name\n" " -o FileSystemName=NAME set file system name\n"
" -o DebugLog=FILE debug log file (requires -d)\n" " -o DebugLog=FILE debug log file (requires -d)\n"
"\n" );
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
FSP_FUSE_LIBRARY_NAME " advanced options:\n" FSP_FUSE_LIBRARY_NAME " advanced options:\n"
" -o FileInfoTimeout=N metadata timeout (millis, -1 for data caching)\n" " -o FileInfoTimeout=N metadata timeout (millis, -1 for data caching)\n"
" -o SectorSize=N sector size for Windows (512-4096, deflt: 4096)\n" " -o DirInfoTimeout=N directory info timeout (millis)\n"
" -o SectorsPerAllocationUnit=N sectors per allocation unit (deflt: 1)\n" " -o VolumeInfoTimeout=N volume info timeout (millis)\n"
" -o MaxComponentLength=N max file name component length (deflt: 255)\n" " -o KeepFileCache do not discard cache when files are closed\n"
" -o VolumeCreationTime=T volume creation time (FILETIME hex format)\n" " -o ThreadCount number of file system dispatcher threads\n"
" -o VolumeSerialNumber=N volume serial number (32-bit wide)\n"
); );
opt_data->help = 1; opt_data->help = 1;
return 1; return 1;
@ -513,6 +536,9 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
return -1; return -1;
opt_data->VolumeParams.Prefix opt_data->VolumeParams.Prefix
[sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR) - 1] = L'\0'; [sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR) - 1] = L'\0';
for (PWSTR P = opt_data->VolumeParams.Prefix; *P; P++)
if (L'/' == *P)
*P = '\\';
return 0; return 0;
case 'F': case 'F':
if ('f' == arg[0]) if ('f' == arg[0])
@ -556,7 +582,9 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
memset(&opt_data, 0, sizeof opt_data); memset(&opt_data, 0, sizeof opt_data);
opt_data.env = env; opt_data.env = env;
opt_data.DebugLogHandle = GetStdHandle(STD_ERROR_HANDLE); opt_data.DebugLogHandle = GetStdHandle(STD_ERROR_HANDLE);
opt_data.VolumeParams.FileInfoTimeout = 1000; /* default FileInfoTimeout for FUSE file systems */ opt_data.VolumeParams.Version = sizeof(FSP_FSCTL_VOLUME_PARAMS);
opt_data.VolumeParams.FileInfoTimeout = 1000;
opt_data.VolumeParams.FlushAndPurgeOnCleanup = TRUE;
if (-1 == fsp_fuse_opt_parse(env, args, &opt_data, fsp_fuse_core_opts, fsp_fuse_core_opt_proc)) if (-1 == fsp_fuse_opt_parse(env, args, &opt_data, fsp_fuse_core_opts, fsp_fuse_core_opt_proc))
return 0; return 0;
@ -596,14 +624,22 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
} }
if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout) if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout)
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000; opt_data.VolumeParams.FileInfoTimeout = opt_data.attr_timeout * 1000;
if (opt_data.set_DirInfoTimeout)
opt_data.VolumeParams.DirInfoTimeoutValid = 1;
if (opt_data.set_VolumeInfoTimeout)
opt_data.VolumeParams.VolumeInfoTimeoutValid = 1;
if (opt_data.set_KeepFileCache)
opt_data.VolumeParams.FlushAndPurgeOnCleanup = FALSE;
opt_data.VolumeParams.CaseSensitiveSearch = TRUE; opt_data.VolumeParams.CaseSensitiveSearch = TRUE;
opt_data.VolumeParams.CasePreservedNames = TRUE;
opt_data.VolumeParams.PersistentAcls = TRUE; opt_data.VolumeParams.PersistentAcls = TRUE;
opt_data.VolumeParams.ReparsePoints = TRUE; opt_data.VolumeParams.ReparsePoints = TRUE;
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE; opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
opt_data.VolumeParams.NamedStreams = FALSE; opt_data.VolumeParams.NamedStreams = FALSE;
opt_data.VolumeParams.ReadOnlyVolume = FALSE; opt_data.VolumeParams.ReadOnlyVolume = FALSE;
opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE; opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
opt_data.VolumeParams.PassQueryDirectoryFileName = TRUE;
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE; opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
if (L'\0' == opt_data.VolumeParams.FileSystemName[0]) if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR)); memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
@ -614,9 +650,11 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
f->env = env; f->env = env;
f->set_umask = opt_data.set_umask; f->umask = opt_data.umask; f->set_umask = opt_data.set_umask; f->umask = opt_data.umask;
f->set_create_umask = opt_data.set_create_umask; f->create_umask = opt_data.create_umask;
f->set_uid = opt_data.set_uid; f->uid = opt_data.uid; 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->set_gid = opt_data.set_gid; f->gid = opt_data.gid;
f->rellinks = opt_data.rellinks; f->rellinks = opt_data.rellinks;
f->ThreadCount = opt_data.ThreadCount;
memcpy(&f->ops, ops, opsize); memcpy(&f->ops, ops, opsize);
f->data = data; f->data = data;
f->DebugLog = opt_data.debug ? -1 : 0; f->DebugLog = opt_data.debug ? -1 : 0;
@ -733,7 +771,6 @@ FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env)
return 0; return 0;
context = FSP_FUSE_CONTEXT_FROM_HDR(contexthdr); context = FSP_FUSE_CONTEXT_FROM_HDR(contexthdr);
context->pid = -1;
TlsSetValue(fsp_fuse_tlskey, context); TlsSetValue(fsp_fuse_tlskey, context);
} }

View File

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

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/fuse/fuse_intf.c * @file dll/fuse/fuse_intf.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -112,10 +112,10 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
struct fuse_context *context; struct fuse_context *context;
struct fsp_fuse_context_header *contexthdr; struct fsp_fuse_context_header *contexthdr;
char *PosixPath = 0; char *PosixPath = 0;
UINT32 Uid = -1, Gid = -1; UINT32 Uid = -1, Gid = -1, Pid = -1;
PWSTR FileName = 0, Suffix; PWSTR FileName = 0, Suffix;
WCHAR Root[2] = L"\\"; WCHAR Root[2] = L"\\";
HANDLE Token = 0; UINT64 AccessToken = 0;
NTSTATUS Result; NTSTATUS Result;
if (FspFsctlTransactCreateKind == Request->Kind) if (FspFsctlTransactCreateKind == Request->Kind)
@ -124,13 +124,13 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
FspPathSuffix((PWSTR)Request->Buffer, &FileName, &Suffix, Root); FspPathSuffix((PWSTR)Request->Buffer, &FileName, &Suffix, Root);
else else
FileName = (PWSTR)Request->Buffer; FileName = (PWSTR)Request->Buffer;
Token = (HANDLE)Request->Req.Create.AccessToken; AccessToken = Request->Req.Create.AccessToken;
} }
else if (FspFsctlTransactSetInformationKind == Request->Kind && else if (FspFsctlTransactSetInformationKind == Request->Kind &&
10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass) 10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass)
{ {
FileName = (PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset); FileName = (PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset);
Token = (HANDLE)Request->Req.SetInformation.Info.Rename.AccessToken; AccessToken = Request->Req.SetInformation.Info.Rename.AccessToken;
} }
if (0 != FileName) if (0 != FileName)
@ -142,11 +142,16 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
goto exit; goto exit;
} }
if (0 != Token) if (0 != AccessToken)
{ {
Result = fsp_fuse_get_token_uidgid(Token, TokenUser, &Uid, &Gid); Result = fsp_fuse_get_token_uidgid(
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(AccessToken),
TokenUser,
&Uid, &Gid);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
Pid = FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(AccessToken);
} }
context = fsp_fuse_get_context(f->env); context = fsp_fuse_get_context(f->env);
@ -162,6 +167,7 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
context->private_data = f->data; context->private_data = f->data;
context->uid = Uid; context->uid = Uid;
context->gid = Gid; context->gid = Gid;
context->pid = 0 != f->env->winpid_to_pid ? f->env->winpid_to_pid(Pid) : Pid;
contexthdr = FSP_FUSE_HDR_FROM_CONTEXT(context); contexthdr = FSP_FUSE_HDR_FROM_CONTEXT(context);
contexthdr->PosixPath = PosixPath; contexthdr->PosixPath = PosixPath;
@ -189,6 +195,7 @@ NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem,
context->private_data = 0; context->private_data = 0;
context->uid = -1; context->uid = -1;
context->gid = -1; context->gid = -1;
context->pid = -1;
contexthdr = FSP_FUSE_HDR_FROM_CONTEXT(context); contexthdr = FSP_FUSE_HDR_FROM_CONTEXT(context);
if (0 != contexthdr->PosixPath) if (0 != contexthdr->PosixPath)
@ -212,7 +219,7 @@ static NTSTATUS fsp_fuse_intf_NewHiddenName(FSP_FILE_SYSTEM *FileSystem,
struct { UINT32 V[4]; } Values; struct { UINT32 V[4]; } Values;
UUID Uuid; UUID Uuid;
} UuidBuf; } UuidBuf;
struct fuse_stat stbuf; struct fuse_stat_ex stbuf;
int err, maxtries = 3; int err, maxtries = 3;
*PPosixHiddenPath = 0; *PPosixHiddenPath = 0;
@ -284,7 +291,7 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
struct fuse *f = FileSystem->UserContext; struct fuse *f = FileSystem->UserContext;
char *PosixDotPath = 0; char *PosixDotPath = 0;
size_t Length; size_t Length;
struct fuse_stat stbuf; struct fuse_stat_ex stbuf;
int err; int err;
BOOLEAN Result = FALSE; BOOLEAN Result = FALSE;
@ -297,6 +304,7 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
PosixDotPath[Length + 1] = '.'; PosixDotPath[Length + 1] = '.';
PosixDotPath[Length + 2] = '\0'; PosixDotPath[Length + 2] = '\0';
memset(&stbuf, 0, sizeof stbuf);
if (0 != f->ops.getattr) if (0 != f->ops.getattr)
err = f->ops.getattr(PosixDotPath, (void *)&stbuf); err = f->ops.getattr(PosixDotPath, (void *)&stbuf);
else else
@ -310,25 +318,57 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
return Result; return Result;
} }
static inline uint32_t fsp_fuse_intf_MapFileAttributesToFlags(UINT32 FileAttributes)
{
uint32_t flags = 0;
if (FileAttributes & FILE_ATTRIBUTE_READONLY)
flags |= FSP_FUSE_UF_READONLY;
if (FileAttributes & FILE_ATTRIBUTE_HIDDEN)
flags |= FSP_FUSE_UF_HIDDEN;
if (FileAttributes & FILE_ATTRIBUTE_SYSTEM)
flags |= FSP_FUSE_UF_SYSTEM;
if (FileAttributes & FILE_ATTRIBUTE_ARCHIVE)
flags |= FSP_FUSE_UF_ARCHIVE;
return flags;
}
static inline UINT32 fsp_fuse_intf_MapFlagsToFileAttributes(uint32_t flags)
{
UINT32 FileAttributes = 0;
if (flags & FSP_FUSE_UF_READONLY)
FileAttributes |= FILE_ATTRIBUTE_READONLY;
if (flags & FSP_FUSE_UF_HIDDEN)
FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
if (flags & FSP_FUSE_UF_SYSTEM)
FileAttributes |= FILE_ATTRIBUTE_SYSTEM;
if (flags & FSP_FUSE_UF_ARCHIVE)
FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
return FileAttributes;
}
#define fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, fi, PUid, PGid, PMode, FileInfo)\ #define fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, fi, PUid, PGid, PMode, FileInfo)\
fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, FileInfo) fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, FileInfo)
static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
const char *PosixPath, struct fuse_file_info *fi, const struct fuse_stat *stbufp, const char *PosixPath, struct fuse_file_info *fi, const void *stbufp,
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode, PUINT32 PDev, PUINT32 PUid, PUINT32 PGid, PUINT32 PMode, PUINT32 PDev,
FSP_FSCTL_FILE_INFO *FileInfo) FSP_FSCTL_FILE_INFO *FileInfo)
{ {
struct fuse *f = FileSystem->UserContext; struct fuse *f = FileSystem->UserContext;
UINT64 AllocationUnit; UINT64 AllocationUnit;
struct fuse_stat stbuf; struct fuse_stat_ex stbuf;
BOOLEAN StatEx = 0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX);
memset(&stbuf, 0, sizeof stbuf);
if (0 != stbufp) if (0 != stbufp)
memcpy(&stbuf, stbufp, sizeof stbuf); memcpy(&stbuf, stbufp, StatEx ? sizeof(struct fuse_stat_ex) : sizeof(struct fuse_stat));
else else
{ {
int err; int err;
memset(&stbuf, 0, sizeof stbuf);
if (0 != f->ops.fgetattr && 0 != fi && -1 != fi->fh) if (0 != f->ops.fgetattr && 0 != fi && -1 != fi->fh)
err = f->ops.fgetattr(PosixPath, (void *)&stbuf, fi); err = f->ops.fgetattr(PosixPath, (void *)&stbuf, fi);
else if (0 != f->ops.getattr) else if (0 != f->ops.getattr)
@ -383,21 +423,15 @@ static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
FileInfo->ReparseTag = 0; FileInfo->ReparseTag = 0;
break; break;
} }
if (StatEx)
FileInfo->FileAttributes |= fsp_fuse_intf_MapFlagsToFileAttributes(stbuf.st_flags);
FileInfo->FileSize = stbuf.st_size; FileInfo->FileSize = stbuf.st_size;
FileInfo->AllocationSize = FileInfo->AllocationSize =
(FileInfo->FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit; (FileInfo->FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
FileInfo->CreationTime = FspPosixUnixTimeToFileTime((void *)&stbuf.st_birthtim, &FileInfo->CreationTime);
Int32x32To64(stbuf.st_birthtim.tv_sec, 10000000) + 116444736000000000 + FspPosixUnixTimeToFileTime((void *)&stbuf.st_atim, &FileInfo->LastAccessTime);
stbuf.st_birthtim.tv_nsec / 100; FspPosixUnixTimeToFileTime((void *)&stbuf.st_mtim, &FileInfo->LastWriteTime);
FileInfo->LastAccessTime = FspPosixUnixTimeToFileTime((void *)&stbuf.st_ctim, &FileInfo->ChangeTime);
Int32x32To64(stbuf.st_atim.tv_sec, 10000000) + 116444736000000000 +
stbuf.st_atim.tv_nsec / 100;
FileInfo->LastWriteTime =
Int32x32To64(stbuf.st_mtim.tv_sec, 10000000) + 116444736000000000 +
stbuf.st_mtim.tv_nsec / 100;
FileInfo->ChangeTime =
Int32x32To64(stbuf.st_ctim.tv_sec, 10000000) + 116444736000000000 +
stbuf.st_ctim.tv_nsec / 100;
FileInfo->IndexNumber = stbuf.st_ino; FileInfo->IndexNumber = stbuf.st_ino;
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -677,14 +711,16 @@ static NTSTATUS fsp_fuse_intf_GetSecurityByName(FSP_FILE_SYSTEM *FileSystem,
Result = fsp_fuse_intf_GetSecurityEx(FileSystem, PosixPath, 0, Result = fsp_fuse_intf_GetSecurityEx(FileSystem, PosixPath, 0,
PFileAttributes, SecurityDescriptorBuf, PSecurityDescriptorSize); PFileAttributes, SecurityDescriptorBuf, PSecurityDescriptorSize);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result) &&
STATUS_OBJECT_NAME_NOT_FOUND != Result &&
STATUS_OBJECT_PATH_NOT_FOUND != Result)
goto exit; goto exit;
if (FSP_FUSE_HAS_SYMLINKS(f) && if (FSP_FUSE_HAS_SYMLINKS(f) &&
FspFileSystemFindReparsePoint(FileSystem, fsp_fuse_intf_GetReparsePointByName, 0, FspFileSystemFindReparsePoint(FileSystem, fsp_fuse_intf_GetReparsePointByName, 0,
FileName, PFileAttributes)) FileName, PFileAttributes))
Result = STATUS_REPARSE; Result = STATUS_REPARSE;
else else if (NT_SUCCESS(Result))
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
exit: exit:
@ -728,12 +764,14 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
goto exit; goto exit;
} }
Mode &= ~context->umask; Mode &= ~context->umask;
if (f->set_create_umask)
Mode = 0777 & ~f->create_umask;
memset(&fi, 0, sizeof fi); memset(&fi, 0, sizeof fi);
if ('C' == f->env->environment) /* Cygwin */ if ('C' == f->env->environment) /* Cygwin */
fi.flags = 0x0200 | 2 /*O_CREAT|O_RDWR*/; fi.flags = 0x0200 | 0x0800 | 2 /*O_CREAT|O_EXCL|O_RDWR*/;
else else
fi.flags = 0x0100 | 2 /*O_CREAT|O_RDWR*/; fi.flags = 0x0100 | 0x0400 | 2 /*O_CREAT|O_EXCL|O_RDWR*/;
if (CreateOptions & FILE_DIRECTORY_FILE) if (CreateOptions & FILE_DIRECTORY_FILE)
{ {
@ -787,22 +825,30 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
Opened = TRUE; Opened = TRUE;
if (Uid != context->uid || Gid != context->gid) if (0 != FileAttributes &&
if (0 != f->ops.chown) 0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX) && 0 != f->ops.chflags)
{ {
err = f->ops.chown(contexthdr->PosixPath, Uid, Gid); err = f->ops.chflags(contexthdr->PosixPath,
if (0 != err) fsp_fuse_intf_MapFileAttributesToFlags(CreateOptions & FILE_DIRECTORY_FILE ?
{ FileAttributes : FileAttributes | FILE_ATTRIBUTE_ARCHIVE));
Result = fsp_fuse_ntstatus_from_errno(f->env, err); Result = fsp_fuse_ntstatus_from_errno(f->env, err);
goto exit; if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result)
} goto exit;
} }
if ((Uid != context->uid || Gid != context->gid) &&
0 != f->ops.chown)
{
err = f->ops.chown(contexthdr->PosixPath, Uid, Gid);
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result)
goto exit;
}
/* /*
* Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache * Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache.
* WinFsp does not currently support disabling the cache manager * NOTE: Originally WinFsp dit not support disabling the cache manager
* for an individual file although it should not be hard to add * for an individual file. This is now possible and we should revisit.
* if required.
* *
* Ignore fuse_file_info::nonseekable. * Ignore fuse_file_info::nonseekable.
*/ */
@ -982,6 +1028,22 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
if (0 != FileAttributes &&
0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX) && 0 != f->ops.chflags)
{
/*
* The code below is not strictly correct. File attributes should be
* replaced when ReplaceFileAttributes is TRUE and merged (or'ed) when
* ReplaceFileAttributes is FALSE. I am punting on this detail for now.
*/
err = f->ops.chflags(filedesc->PosixPath,
fsp_fuse_intf_MapFileAttributesToFlags(FileAttributes | FILE_ATTRIBUTE_ARCHIVE));
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result)
return Result;
}
return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi,
&Uid, &Gid, &Mode, FileInfo); &Uid, &Gid, &Mode, FileInfo);
} }
@ -1141,7 +1203,8 @@ static NTSTATUS fsp_fuse_intf_Write(FSP_FILE_SYSTEM *FileSystem,
AllocationUnit = (UINT64)f->VolumeParams.SectorSize * AllocationUnit = (UINT64)f->VolumeParams.SectorSize *
(UINT64)f->VolumeParams.SectorsPerAllocationUnit; (UINT64)f->VolumeParams.SectorsPerAllocationUnit;
FileInfoBuf.FileSize = Offset + bytes; if (Offset + bytes > FileInfoBuf.FileSize)
FileInfoBuf.FileSize = Offset + bytes;
FileInfoBuf.AllocationSize = FileInfoBuf.AllocationSize =
(FileInfoBuf.FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit; (FileInfoBuf.FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
@ -1234,67 +1297,74 @@ static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
int err; int err;
NTSTATUS Result; NTSTATUS Result;
if (0 == f->ops.utimens && 0 == f->ops.utime)
return STATUS_SUCCESS; /* liar! */
/* no way to set FileAttributes, CreationTime! */
if (0 == LastAccessTime && 0 == LastWriteTime)
return STATUS_SUCCESS;
memset(&fi, 0, sizeof fi); memset(&fi, 0, sizeof fi);
fi.flags = filedesc->OpenFlags; fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle; fi.fh = filedesc->FileHandle;
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, if (INVALID_FILE_ATTRIBUTES != FileAttributes &&
&Uid, &Gid, &Mode, &FileInfoBuf); 0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX) && 0 != f->ops.chflags)
if (!NT_SUCCESS(Result))
return Result;
if (0 != LastAccessTime)
FileInfoBuf.LastAccessTime = LastAccessTime;
if (0 != LastWriteTime)
FileInfoBuf.LastWriteTime = LastWriteTime;
/* UNIX epoch in 100-ns intervals */
LastAccessTime = FileInfoBuf.LastAccessTime - 116444736000000000;
LastWriteTime = FileInfoBuf.LastWriteTime - 116444736000000000;
if (0 != f->ops.utimens)
{ {
#if defined(_WIN64) err = f->ops.chflags(filedesc->PosixPath,
tv[0].tv_sec = (int64_t)(LastAccessTime / 10000000); fsp_fuse_intf_MapFileAttributesToFlags(FileAttributes));
tv[0].tv_nsec = (int64_t)(LastAccessTime % 10000000) * 100;
tv[1].tv_sec = (int64_t)(LastWriteTime / 10000000);
tv[1].tv_nsec = (int64_t)(LastWriteTime % 10000000) * 100;
#else
tv[0].tv_sec = (int32_t)(LastAccessTime / 10000000);
tv[0].tv_nsec = (int32_t)(LastAccessTime % 10000000) * 100;
tv[1].tv_sec = (int32_t)(LastWriteTime / 10000000);
tv[1].tv_nsec = (int32_t)(LastWriteTime % 10000000) * 100;
#endif
err = f->ops.utimens(filedesc->PosixPath, tv);
Result = fsp_fuse_ntstatus_from_errno(f->env, err); Result = fsp_fuse_ntstatus_from_errno(f->env, err);
if (!NT_SUCCESS(Result))
return Result;
} }
else
if ((0 != LastAccessTime || 0 != LastWriteTime) &&
(0 != f->ops.utimens || 0 != f->ops.utime))
{ {
#if defined(_WIN64) if (0 == LastAccessTime || 0 == LastWriteTime)
timbuf.actime = (int64_t)(LastAccessTime / 10000000); {
timbuf.modtime = (int64_t)(LastWriteTime / 10000000); Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi,
#else &Uid, &Gid, &Mode, &FileInfoBuf);
timbuf.actime = (int32_t)(LastAccessTime / 10000000); if (!NT_SUCCESS(Result))
timbuf.modtime = (int32_t)(LastWriteTime / 10000000); return Result;
#endif
err = f->ops.utime(filedesc->PosixPath, &timbuf); if (0 == LastAccessTime)
Result = fsp_fuse_ntstatus_from_errno(f->env, err); LastAccessTime = FileInfoBuf.LastAccessTime;
if (0 == LastWriteTime)
LastWriteTime = FileInfoBuf.LastWriteTime;
}
FspPosixFileTimeToUnixTime(LastAccessTime, (void *)&tv[0]);
FspPosixFileTimeToUnixTime(LastWriteTime, (void *)&tv[1]);
if (0 != f->ops.utimens)
{
err = f->ops.utimens(filedesc->PosixPath, tv);
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
}
else
{
timbuf.actime = tv[0].tv_sec;
timbuf.modtime = tv[1].tv_sec;
err = f->ops.utime(filedesc->PosixPath, &timbuf);
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
}
if (!NT_SUCCESS(Result))
return Result;
} }
if (!NT_SUCCESS(Result))
return Result;
memcpy(FileInfo, &FileInfoBuf, sizeof FileInfoBuf); if (0 != CreationTime && 0 != f->ops.setcrtime)
{
FspPosixFileTimeToUnixTime(CreationTime, (void *)&tv[0]);
err = f->ops.setcrtime(filedesc->PosixPath, &tv[0]);
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
if (!NT_SUCCESS(Result))
return Result;
}
return STATUS_SUCCESS; if (0 != ChangeTime && 0 != f->ops.setchgtime)
{
FspPosixFileTimeToUnixTime(ChangeTime, (void *)&tv[0]);
err = f->ops.setchgtime(filedesc->PosixPath, &tv[0]);
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
if (!NT_SUCCESS(Result))
return Result;
}
return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi,
&Uid, &Gid, &Mode, FileInfo);
} }
static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem,
@ -1582,7 +1652,8 @@ static int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
memset(DirInfo, 0, sizeof *DirInfo); memset(DirInfo, 0, sizeof *DirInfo);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + SizeW * sizeof(WCHAR)); DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + SizeW * sizeof(WCHAR));
if (dh->ReaddirPlus && 0 != stbuf) if (dh->ReaddirPlus && 0 != stbuf &&
0120000/* S_IFLNK */ != (stbuf->st_mode & 0170000))
{ {
UINT32 Uid, Gid, Mode; UINT32 Uid, Gid, Mode;
NTSTATUS Result0; NTSTATUS Result0;
@ -1749,6 +1820,63 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS fsp_fuse_intf_GetDirInfoByName(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, PWSTR FileName,
FSP_FSCTL_DIR_INFO *DirInfo)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileNode;
char *PosixName = 0;
char PosixPath[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
int ParentLength, FSlashLength, PosixNameLength;
UINT32 Uid, Gid, Mode;
NTSTATUS Result;
Result = FspPosixMapWindowsToPosixPath(FileName, &PosixName);
if (!NT_SUCCESS(Result))
{
Result = STATUS_OBJECT_NAME_NOT_FOUND; //Result?
goto exit;
}
ParentLength = lstrlenA(filedesc->PosixPath);
FSlashLength = 1 < ParentLength;
PosixNameLength = lstrlenA(PosixName);
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX <= (ParentLength + FSlashLength + PosixNameLength) * sizeof(WCHAR))
{
Result = STATUS_OBJECT_NAME_NOT_FOUND; //STATUS_OBJECT_NAME_INVALID?
goto exit;
}
memcpy(PosixPath, filedesc->PosixPath, ParentLength);
memcpy(PosixPath + ParentLength, "/", FSlashLength);
memcpy(PosixPath + ParentLength + FSlashLength, PosixName, PosixNameLength + 1);
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0,
&Uid, &Gid, &Mode, &DirInfo->FileInfo);
if (!NT_SUCCESS(Result))
{
Result = STATUS_OBJECT_NAME_NOT_FOUND; //Result?
goto exit;
}
/*
* FUSE does not do FileName normalization; so just return the FileName as given to us!
*/
//memset(DirInfo->Padding, 0, sizeof DirInfo->Padding);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + lstrlenW(FileName) * sizeof(WCHAR));
memcpy(DirInfo->FileNameBuf, FileName, DirInfo->Size - sizeof(FSP_FSCTL_DIR_INFO));
Result = STATUS_SUCCESS;
exit:
if (0 != PosixName)
FspPosixDeletePath(PosixName);
return Result;
}
static NTSTATUS fsp_fuse_intf_ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS fsp_fuse_intf_ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent, PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent,
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize) PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize)
@ -2022,6 +2150,8 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
fsp_fuse_intf_GetReparsePoint, fsp_fuse_intf_GetReparsePoint,
fsp_fuse_intf_SetReparsePoint, fsp_fuse_intf_SetReparsePoint,
fsp_fuse_intf_DeleteReparsePoint, fsp_fuse_intf_DeleteReparsePoint,
0,
fsp_fuse_intf_GetDirInfoByName,
}; };
/* /*

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/fuse/library.h * @file dll/fuse/library.h
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -35,9 +35,11 @@ struct fuse
{ {
struct fsp_fuse_env *env; struct fsp_fuse_env *env;
int set_umask, umask; int set_umask, umask;
int set_create_umask, create_umask;
int set_uid, uid; int set_uid, uid;
int set_gid, gid; int set_gid, gid;
int rellinks; int rellinks;
unsigned ThreadCount;
struct fuse_operations ops; struct fuse_operations ops;
void *data; void *data;
unsigned conn_want; unsigned conn_want;

449
src/dll/launch.c Normal file
View File

@ -0,0 +1,449 @@
/**
* @file dll/launch.c
*
* @copyright 2015-2018 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>
FSP_API NTSTATUS FspLaunchCallLauncherPipe(
WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl,
PWSTR Buffer, PULONG PSize, PULONG PLauncherError)
{
PWSTR PipeBuf = 0, P;
ULONG Length, BytesTransferred;
NTSTATUS Result;
ULONG ErrorCode;
*PLauncherError = 0;
PipeBuf = MemAlloc(FSP_LAUNCH_PIPE_BUFFER_SIZE);
if (0 == PipeBuf)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
P = PipeBuf;
*P++ = Command;
for (ULONG I = 0; Argc > I; I++)
if (0 != Argv[I])
{
Length = 0 == Argl || -1 == Argl[I] ? lstrlenW(Argv[I]) : Argl[I];
if (FSP_LAUNCH_PIPE_BUFFER_SIZE < ((ULONG)(P - PipeBuf) + Length + 1) * sizeof(WCHAR))
{
Result = STATUS_INVALID_PARAMETER;
goto exit;
}
memcpy(P, Argv[I], Length * sizeof(WCHAR)); P += Length; *P++ = L'\0';
}
Result = FspCallNamedPipeSecurely(L"" FSP_LAUNCH_PIPE_NAME,
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), PipeBuf, FSP_LAUNCH_PIPE_BUFFER_SIZE,
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, FSP_LAUNCH_PIPE_OWNER);
if (!NT_SUCCESS(Result))
goto exit;
Result = STATUS_SUCCESS;
ErrorCode = ERROR_BROKEN_PIPE; /* protocol error! */
if (sizeof(WCHAR) <= BytesTransferred)
{
if (FspLaunchCmdSuccess == PipeBuf[0])
{
ErrorCode = 0;
if (0 != PSize)
{
BytesTransferred -= sizeof(WCHAR);
memcpy(Buffer, PipeBuf + 1, *PSize < BytesTransferred ? *PSize : BytesTransferred);
*PSize = BytesTransferred;
}
}
else if (FspLaunchCmdFailure == PipeBuf[0])
{
ErrorCode = 0;
for (PWSTR P = PipeBuf + 1, EndP = PipeBuf + BytesTransferred / sizeof(WCHAR); EndP > P; P++)
{
if (L'0' > *P || *P > L'9')
break;
ErrorCode = 10 * ErrorCode + (*P - L'0');
}
if (0 == ErrorCode)
ErrorCode = ERROR_BROKEN_PIPE; /* protocol error! */
}
}
*PLauncherError = ErrorCode;
exit:
if (!NT_SUCCESS(Result) && 0 != PSize)
*PSize = 0;
MemFree(PipeBuf);
return Result;
}
FSP_API NTSTATUS FspLaunchStart(
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv0,
BOOLEAN HasSecret,
PULONG PLauncherError)
{
PWSTR Argv[9 + 2];
if (9 < Argc)
return STATUS_INVALID_PARAMETER;
Argv[0] = ClassName;
Argv[1] = InstanceName;
memcpy(Argv + 2, Argv0, Argc * sizeof(PWSTR));
return FspLaunchCallLauncherPipe(
HasSecret ? FspLaunchCmdStartWithSecret : FspLaunchCmdStart,
Argc + 2, Argv, 0, 0, 0, PLauncherError);
}
FSP_API NTSTATUS FspLaunchStop(
PWSTR ClassName, PWSTR InstanceName,
PULONG PLauncherError)
{
PWSTR Argv[2];
Argv[0] = ClassName;
Argv[1] = InstanceName;
return FspLaunchCallLauncherPipe(FspLaunchCmdStop,
2, Argv, 0, 0, 0, PLauncherError);
}
FSP_API NTSTATUS FspLaunchGetInfo(
PWSTR ClassName, PWSTR InstanceName,
PWSTR Buffer, PULONG PSize,
PULONG PLauncherError)
{
PWSTR Argv[2];
Argv[0] = ClassName;
Argv[1] = InstanceName;
return FspLaunchCallLauncherPipe(FspLaunchCmdGetInfo,
2, Argv, 0, Buffer, PSize, PLauncherError);
}
FSP_API NTSTATUS FspLaunchGetNameList(
PWSTR Buffer, PULONG PSize,
PULONG PLauncherError)
{
return FspLaunchCallLauncherPipe(FspLaunchCmdGetNameList,
0, 0, 0, Buffer, PSize, PLauncherError);
}
FSP_API NTSTATUS FspLaunchRegSetRecord(
PWSTR ClassName,
const FSP_LAUNCH_REG_RECORD *Record)
{
#define SETFIELD(FieldName) \
do \
{ \
if (0 != Record->FieldName) \
{ \
RegResult = RegSetValueExW(RegKey,\
L"" #FieldName, 0, REG_SZ,\
(PVOID)Record->FieldName, (lstrlenW(Record->FieldName) + 1) * sizeof(WCHAR));\
if (ERROR_SUCCESS != RegResult)\
{ \
Result = FspNtStatusFromWin32(RegResult);\
goto exit; \
} \
} \
else \
{ \
RegResult = RegDeleteValueW(RegKey,\
L"" #FieldName);\
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)\
{ \
Result = FspNtStatusFromWin32(RegResult);\
goto exit; \
} \
} \
} while (0,0)
#define SETFIELDI(FieldName, Deflt) \
do \
{ \
if (Deflt != Record->FieldName) \
{ \
RegResult = RegSetValueExW(RegKey,\
L"" #FieldName, 0, REG_DWORD,\
(PVOID)&Record->FieldName, sizeof Record->FieldName);\
if (ERROR_SUCCESS != RegResult)\
{ \
Result = FspNtStatusFromWin32(RegResult);\
goto exit; \
} \
} \
else \
{ \
RegResult = RegDeleteValueW(RegKey,\
L"" #FieldName);\
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)\
{ \
Result = FspNtStatusFromWin32(RegResult);\
goto exit; \
} \
} \
} while (0,0)
NTSTATUS Result;
ULONG ClassNameLen;
WCHAR RegPath[MAX_PATH];
HKEY RegKey = 0;
DWORD RegResult;
if (0 != Record && 0 == Record->Executable)
{
Result = STATUS_INVALID_PARAMETER;
goto exit;
}
ClassNameLen = lstrlenW(ClassName);
if (sizeof RegPath - sizeof L"" FSP_LAUNCH_REGKEY <= (ClassNameLen + 1) * sizeof(WCHAR))
{
Result = STATUS_INVALID_PARAMETER;
goto exit;
}
memcpy(RegPath, L"" FSP_LAUNCH_REGKEY, sizeof L"" FSP_LAUNCH_REGKEY - sizeof(WCHAR));
RegPath[sizeof L"" FSP_LAUNCH_REGKEY / sizeof(WCHAR) - 1] = L'\\';
memcpy(RegPath + sizeof L"" FSP_LAUNCH_REGKEY / sizeof(WCHAR),
ClassName, (ClassNameLen + 1) * sizeof(WCHAR));
if (0 != Record)
{
RegResult = RegCreateKeyExW(HKEY_LOCAL_MACHINE, RegPath,
0, 0, 0, FSP_LAUNCH_REGKEY_WOW64 | KEY_SET_VALUE, 0, &RegKey, 0);
if (ERROR_SUCCESS != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);
goto exit;
}
SETFIELD(Agent);
SETFIELD(Executable);
SETFIELD(CommandLine);
SETFIELD(WorkDirectory);
SETFIELD(RunAs);
SETFIELD(Security);
SETFIELDI(JobControl, ~0); /* JobControl default is 1; but we treat as without default */
SETFIELDI(Credentials, 0);
}
else
{
RegResult = RegDeleteKeyEx(HKEY_LOCAL_MACHINE, RegPath,
FSP_LAUNCH_REGKEY_WOW64, 0);
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);
goto exit;
}
}
Result = STATUS_SUCCESS;
exit:
if (0 != RegKey)
RegCloseKey(RegKey);
return Result;
#undef SETFIELD
#undef SETFIELDI
}
FSP_API NTSTATUS FspLaunchRegGetRecord(
PWSTR ClassName, PWSTR Agent,
FSP_LAUNCH_REG_RECORD **PRecord)
{
#define GETFIELD(FieldName) \
do \
{ \
RegSize = sizeof RegBuf - RegMark;\
RegResult = RegQueryValueEx(RegKey,\
L"" #FieldName, 0, &RegType,\
(PVOID)(RegBuf + RegMark), &RegSize);\
if (ERROR_SUCCESS != RegResult) \
{ \
if (ERROR_FILE_NOT_FOUND != RegResult)\
{ \
Result = FspNtStatusFromWin32(RegResult);\
goto exit; \
} \
} \
else if (REG_SZ != RegType || \
sizeof(WCHAR) > RegSize || \
L'\0' != *(PWSTR)(RegBuf + RegMark + RegSize - sizeof(WCHAR)))\
{ \
Result = STATUS_OBJECT_NAME_NOT_FOUND;\
goto exit; \
} \
else \
{ \
Record->FieldName = (PWSTR)(RegBuf + RegMark);\
RegMark += RegSize; \
} \
} while (0,0)
#define GETFIELDI(FieldName) \
do \
{ \
RegSize = sizeof RegDword; \
RegResult = RegQueryValueEx(RegKey,\
L"" #FieldName, 0, &RegType,\
(PVOID)&RegDword, &RegSize);\
if (ERROR_SUCCESS != RegResult) \
{ \
if (ERROR_FILE_NOT_FOUND != RegResult)\
{ \
Result = FspNtStatusFromWin32(RegResult);\
goto exit; \
} \
} \
else if (REG_DWORD != RegType) \
{ \
Result = STATUS_OBJECT_NAME_NOT_FOUND;\
goto exit; \
} \
else \
Record->FieldName = RegDword;\
} while (0,0)
NTSTATUS Result;
ULONG ClassNameLen;
WCHAR RegPath[MAX_PATH];
FSP_LAUNCH_REG_RECORD RecordBuf, *Record = &RecordBuf;
HKEY RegKey = 0;
DWORD RegResult, RegDword, RegType, RegSize, RegMark;
UINT8 RegBuf[2 * 1024];
PWSTR P, Part;
BOOLEAN FoundAgent;
*PRecord = 0;
ClassNameLen = lstrlenW(ClassName);
if (sizeof RegPath - sizeof L"" FSP_LAUNCH_REGKEY <= (ClassNameLen + 1) * sizeof(WCHAR))
{
Result = STATUS_INVALID_PARAMETER;
goto exit;
}
memcpy(RegPath, L"" FSP_LAUNCH_REGKEY, sizeof L"" FSP_LAUNCH_REGKEY - sizeof(WCHAR));
RegPath[sizeof L"" FSP_LAUNCH_REGKEY / sizeof(WCHAR) - 1] = L'\\';
memcpy(RegPath + sizeof L"" FSP_LAUNCH_REGKEY / sizeof(WCHAR),
ClassName, (ClassNameLen + 1) * sizeof(WCHAR));
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, RegPath,
0, FSP_LAUNCH_REGKEY_WOW64 | KEY_QUERY_VALUE, &RegKey);
if (ERROR_SUCCESS != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);
goto exit;
}
memset(Record, 0, sizeof *Record);
Record->JobControl = 1; /* default is YES! */
RegMark = 0;
GETFIELD(Agent);
if (0 != Agent && L'\0' != Agent[0] &&
0 != Record->Agent && L'\0' != Record->Agent[0])
{
FoundAgent = FALSE;
P = Record->Agent, Part = P;
do
{
if (L',' == *P || '\0' == *P)
{
if (0 == invariant_wcsnicmp(Part, Agent, P - Part))
{
FoundAgent = TRUE;
break;
}
else
Part = P + 1;
}
} while (L'\0' != *P++);
if (!FoundAgent)
{
Result = STATUS_OBJECT_NAME_NOT_FOUND;
goto exit;
}
}
GETFIELD(Executable);
GETFIELD(CommandLine);
GETFIELD(WorkDirectory);
GETFIELD(RunAs);
GETFIELD(Security);
GETFIELDI(JobControl);
GETFIELDI(Credentials);
if (0 == Record->Executable)
{
Result = STATUS_OBJECT_NAME_NOT_FOUND;
goto exit;
}
Record = MemAlloc(FIELD_OFFSET(FSP_LAUNCH_REG_RECORD, Buffer) + RegMark);
if (0 == Record)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
memset(Record, 0, sizeof *Record);
memcpy(Record->Buffer, RegBuf, RegMark);
Record->Agent = 0 != RecordBuf.Agent ?
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.Agent - RegBuf)) : 0;
Record->Executable = 0 != RecordBuf.Executable ?
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.Executable - RegBuf)) : 0;
Record->CommandLine = 0 != RecordBuf.CommandLine ?
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.CommandLine - RegBuf)) : 0;
Record->WorkDirectory = 0 != RecordBuf.WorkDirectory ?
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.WorkDirectory - RegBuf)) : 0;
Record->RunAs = 0 != RecordBuf.RunAs ?
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.RunAs - RegBuf)) : 0;
Record->Security = 0 != RecordBuf.Security ?
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.Security - RegBuf)) : 0;
Record->JobControl = RecordBuf.JobControl;
Record->Credentials = RecordBuf.Credentials;
*PRecord = Record;
Result = STATUS_SUCCESS;
exit:
if (0 != RegKey)
RegCloseKey(RegKey);
return Result;
#undef GETFIELDI
#undef GETFIELD
}
FSP_API VOID FspLaunchRegFreeRecord(
FSP_LAUNCH_REG_RECORD *Record)
{
MemFree(Record);
}

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/library.c * @file dll/library.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -44,6 +44,7 @@ BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
FspServiceFinalize(Dynamic); FspServiceFinalize(Dynamic);
FspEventLogFinalize(Dynamic); FspEventLogFinalize(Dynamic);
FspPosixFinalize(Dynamic); FspPosixFinalize(Dynamic);
FspWksidFinalize(Dynamic);
break; break;
case DLL_THREAD_DETACH: case DLL_THREAD_DETACH:

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/library.h * @file dll/library.h
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -20,6 +20,7 @@
#define WINFSP_DLL_INTERNAL #define WINFSP_DLL_INTERNAL
#include <winfsp/winfsp.h> #include <winfsp/winfsp.h>
#include <winfsp/launch.h>
#include <shared/minimal.h> #include <shared/minimal.h>
#include <strsafe.h> #include <strsafe.h>
@ -31,11 +32,15 @@
FspDebugLog("[U] " LIBRARY_NAME "!" __FUNCTION__ ": " fmt "\n", __VA_ARGS__) FspDebugLog("[U] " LIBRARY_NAME "!" __FUNCTION__ ": " fmt "\n", __VA_ARGS__)
#define DEBUGLOGSD(fmt, SD) \ #define DEBUGLOGSD(fmt, SD) \
FspDebugLogSD("[U] " LIBRARY_NAME "!" __FUNCTION__ ": " fmt "\n", SD) FspDebugLogSD("[U] " LIBRARY_NAME "!" __FUNCTION__ ": " fmt "\n", SD)
#define DEBUGLOGSID(fmt, Sid) \
FspDebugLogSid("[U] " LIBRARY_NAME "!" __FUNCTION__ ": " fmt "\n", Sid)
#else #else
#define DEBUGLOG(fmt, ...) ((void)0) #define DEBUGLOG(fmt, ...) ((void)0)
#define DEBUGLOGSD(fmt, SD) ((void)0) #define DEBUGLOGSD(fmt, SD) ((void)0)
#define DEBUGLOGSID(fmt, Sid) ((void)0)
#endif #endif
VOID FspWksidFinalize(BOOLEAN Dynamic);
VOID FspPosixFinalize(BOOLEAN Dynamic); VOID FspPosixFinalize(BOOLEAN Dynamic);
VOID FspEventLogFinalize(BOOLEAN Dynamic); VOID FspEventLogFinalize(BOOLEAN Dynamic);
VOID FspServiceFinalize(BOOLEAN Dynamic); VOID FspServiceFinalize(BOOLEAN Dynamic);
@ -49,6 +54,9 @@ NTSTATUS FspNpUnregister(VOID);
NTSTATUS FspEventLogRegister(VOID); NTSTATUS FspEventLogRegister(VOID);
NTSTATUS FspEventLogUnregister(VOID); NTSTATUS FspEventLogUnregister(VOID);
PSID FspWksidNew(WELL_KNOWN_SID_TYPE WellKnownSidType, PNTSTATUS PResult);
PSID FspWksidGet(WELL_KNOWN_SID_TYPE WellKnownSidType);
PWSTR FspDiagIdent(VOID); PWSTR FspDiagIdent(VOID);
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer, VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/np.c * @file dll/np.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -16,7 +16,6 @@
*/ */
#include <dll/library.h> #include <dll/library.h>
#include <launcher/launcher.h>
#include <npapi.h> #include <npapi.h>
#include <wincred.h> #include <wincred.h>
@ -35,6 +34,12 @@
*/ */
#define FSP_NP_CREDENTIAL_MANAGER #define FSP_NP_CREDENTIAL_MANAGER
/*
* Define the following macro to register ourselves as the first network provider.
* Otherwise we will be registered as the last network provider.
*/
#define FSP_NP_ORDER_FIRST
enum enum
{ {
FSP_NP_CREDENTIALS_NONE = 0, FSP_NP_CREDENTIALS_NONE = 0,
@ -147,7 +152,7 @@ static inline BOOLEAN FspNpParseRemoteName(PWSTR RemoteName,
return TRUE; return TRUE;
} }
static inline BOOLEAN FspNpParseUserName(PWSTR RemoteName, static inline BOOLEAN FspNpParseRemoteUserName(PWSTR RemoteName,
PWSTR UserName, ULONG UserNameSize/* in chars */) PWSTR UserName, ULONG UserNameSize/* in chars */)
{ {
PWSTR ClassName, InstanceName, P; PWSTR ClassName, InstanceName, P;
@ -168,39 +173,17 @@ static inline BOOLEAN FspNpParseUserName(PWSTR RemoteName,
return FALSE; return FALSE;
} }
static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize) static inline DWORD FspNpCallLauncherPipe(
WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl,
PWSTR Buffer, PULONG PSize)
{ {
DWORD NpResult;
NTSTATUS Result; NTSTATUS Result;
DWORD BytesTransferred; ULONG ErrorCode;
Result = FspCallNamedPipeSecurely(L"" LAUNCHER_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize, Result = FspLaunchCallLauncherPipe(Command, Argc, Argv, Argl, Buffer, PSize, &ErrorCode);
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, LAUNCHER_PIPE_OWNER); return !NT_SUCCESS(Result) ?
WN_NO_NETWORK :
if (!NT_SUCCESS(Result)) (ERROR_BROKEN_PIPE == ErrorCode ? WN_NO_NETWORK : ErrorCode);
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( static NTSTATUS FspNpGetVolumeList(
@ -264,14 +247,13 @@ static WCHAR FspNpGetDriveLetter(PDWORD PLogicalDrives, PWSTR VolumeName)
return 0; return 0;
} }
static DWORD FspNpGetCredentialsKind(PWSTR RemoteName, PDWORD PCredentialsKind) static DWORD FspNpGetRemoteInfo(PWSTR RemoteName, PDWORD PCredentialsKind)
{ {
HKEY RegKey = 0;
DWORD NpResult, RegSize;
DWORD Credentials;
PWSTR ClassName, InstanceName; PWSTR ClassName, InstanceName;
ULONG ClassNameLen, InstanceNameLen; ULONG ClassNameLen, InstanceNameLen;
WCHAR ClassNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)]; WCHAR ClassNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
FSP_LAUNCH_REG_RECORD *Record;
NTSTATUS Result;
*PCredentialsKind = FSP_NP_CREDENTIALS_NONE; *PCredentialsKind = FSP_NP_CREDENTIALS_NONE;
@ -284,34 +266,22 @@ static DWORD FspNpGetCredentialsKind(PWSTR RemoteName, PDWORD PCredentialsKind)
memcpy(ClassNameBuf, ClassName, ClassNameLen * sizeof(WCHAR)); memcpy(ClassNameBuf, ClassName, ClassNameLen * sizeof(WCHAR));
ClassNameBuf[ClassNameLen] = '\0'; ClassNameBuf[ClassNameLen] = '\0';
NpResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY, Result = FspLaunchRegGetRecord(ClassNameBuf, L"" FSP_NP_NAME, &Record);
0, LAUNCHER_REGKEY_WOW64 | KEY_READ, &RegKey); if (!NT_SUCCESS(Result))
if (ERROR_SUCCESS != NpResult) return WN_NO_NETWORK;
goto exit;
RegSize = sizeof Credentials; switch (Record->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_NONE:
case FSP_NP_CREDENTIALS_PASSWORD: case FSP_NP_CREDENTIALS_PASSWORD:
case FSP_NP_CREDENTIALS_USERPASS: case FSP_NP_CREDENTIALS_USERPASS:
*PCredentialsKind = Credentials; *PCredentialsKind = Record->Credentials;
break; break;
} }
NpResult = ERROR_SUCCESS; FspLaunchRegFreeRecord(Record);
exit: return WN_SUCCESS;
if (0 != RegKey)
RegCloseKey(RegKey);
return NpResult;
} }
static DWORD FspNpGetCredentials( static DWORD FspNpGetCredentials(
@ -426,7 +396,7 @@ DWORD APIENTRY NPGetConnection(
Result = FspNpGetVolumeList(&VolumeListBuf, &VolumeListSize); Result = FspNpGetVolumeList(&VolumeListBuf, &VolumeListSize);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return WN_OUT_OF_MEMORY; return WN_NOT_CONNECTED;
NpResult = WN_NOT_CONNECTED; NpResult = WN_NOT_CONNECTED;
for (P = VolumeListBuf, VolumeListBufEnd = (PVOID)((PUINT8)P + VolumeListSize), VolumeName = P; for (P = VolumeListBuf, VolumeListBufEnd = (PVOID)((PUINT8)P + VolumeListSize), VolumeName = P;
@ -490,7 +460,9 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
PWSTR ClassName, InstanceName, RemoteName, P; PWSTR ClassName, InstanceName, RemoteName, P;
ULONG ClassNameLen, InstanceNameLen; ULONG ClassNameLen, InstanceNameLen;
DWORD CredentialsKind; DWORD CredentialsKind;
PWSTR PipeBuf = 0; ULONG Argc;
PWSTR Argv[6];
ULONG Argl[6];
#if defined(FSP_NP_CREDENTIAL_MANAGER) #if defined(FSP_NP_CREDENTIAL_MANAGER)
PCREDENTIALW Credential = 0; PCREDENTIALW Credential = 0;
#endif #endif
@ -517,7 +489,9 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
return WN_ALREADY_CONNECTED; return WN_ALREADY_CONNECTED;
} }
FspNpGetCredentialsKind(lpRemoteName, &CredentialsKind); NpResult = FspNpGetRemoteInfo(lpRemoteName, &CredentialsKind);
if (WN_SUCCESS != NpResult)
return NpResult;
#if defined(FSP_NP_CREDENTIAL_MANAGER) #if defined(FSP_NP_CREDENTIAL_MANAGER)
/* if we need credentials and none were passed check with the credential manager */ /* if we need credentials and none were passed check with the credential manager */
@ -556,32 +530,23 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
} }
} }
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE); Argc = 0;
if (0 == PipeBuf) Argv[Argc] = ClassName; Argl[Argc] = ClassNameLen; Argc++;
{ Argv[Argc] = InstanceName; Argl[Argc] = InstanceNameLen; Argc++;
NpResult = WN_OUT_OF_MEMORY; Argv[Argc] = RemoteName; Argl[Argc] = -1; Argc++;
goto exit; Argv[Argc] = LocalNameBuf; Argl[Argc] = -1; Argc++;
}
/* 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) if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
{ {
lstrcpyW(P, lpUserName); P += lstrlenW(lpUserName) + 1; Argv[Argc] = lpUserName; Argl[Argc] = -1; Argc++;
} }
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind) if (FSP_NP_CREDENTIALS_NONE != CredentialsKind)
{ {
lstrcpyW(P, lpPassword); P += lstrlenW(lpPassword) + 1; Argv[Argc] = lpPassword; Argl[Argc] = -1; Argc++;
} }
NpResult = FspNpCallLauncherPipe( NpResult = FspNpCallLauncherPipe(
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE); FSP_NP_CREDENTIALS_NONE != CredentialsKind ? FspLaunchCmdStartWithSecret : FspLaunchCmdStart,
Argc, Argv, Argl, 0, 0);
switch (NpResult) switch (NpResult)
{ {
case WN_SUCCESS: case WN_SUCCESS:
@ -627,13 +592,13 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
break; break;
} }
P = PipeBuf; Argc = 0;
*P++ = LauncherSvcInstanceInfo; Argv[Argc] = ClassName; Argl[Argc] = ClassNameLen; Argc++;
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0'; Argv[Argc] = InstanceName; Argl[Argc] = InstanceNameLen; Argc++;
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
if (WN_SUCCESS != FspNpCallLauncherPipe( if (WN_SUCCESS != FspNpCallLauncherPipe(
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE)) FspLaunchCmdGetInfo,
Argc, Argv, Argl, 0, 0))
{ {
/* looks like the file system is gone! */ /* looks like the file system is gone! */
NpResult = WN_NO_NETWORK; NpResult = WN_NO_NETWORK;
@ -677,8 +642,6 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
} }
exit: exit:
MemFree(PipeBuf);
#if defined(FSP_NP_CREDENTIAL_MANAGER) #if defined(FSP_NP_CREDENTIAL_MANAGER)
if (0 != Credential) if (0 != Credential)
CredFree(Credential); CredFree(Credential);
@ -712,7 +675,9 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
return NpResult; return NpResult;
} }
FspNpGetCredentialsKind(RemoteName, &CredentialsKind); NpResult = FspNpGetRemoteInfo(RemoteName, &CredentialsKind);
if (WN_SUCCESS != NpResult)
return NpResult;
if (FSP_NP_CREDENTIALS_NONE == CredentialsKind) if (FSP_NP_CREDENTIALS_NONE == CredentialsKind)
return WN_CANCEL; return WN_CANCEL;
@ -721,7 +686,7 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
lstrcpyW(UserName, L"UNSPECIFIED"); lstrcpyW(UserName, L"UNSPECIFIED");
Password[0] = L'\0'; Password[0] = L'\0';
if (FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind) if (FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind)
FspNpParseUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]); FspNpParseRemoteUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]);
do do
{ {
NpResult = FspNpGetCredentials( NpResult = FspNpGetCredentials(
@ -767,9 +732,11 @@ DWORD APIENTRY NPCancelConnection(LPWSTR lpName, BOOL fForce)
DWORD NpResult; DWORD NpResult;
WCHAR RemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)]; WCHAR RemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
DWORD RemoteNameSize; DWORD RemoteNameSize;
PWSTR ClassName, InstanceName, RemoteName, P; PWSTR ClassName, InstanceName, RemoteName;
ULONG ClassNameLen, InstanceNameLen; ULONG ClassNameLen, InstanceNameLen;
PWSTR PipeBuf = 0; ULONG Argc;
PWSTR Argv[2];
ULONG Argl[2];
if (FspNpCheckLocalName(lpName)) if (FspNpCheckLocalName(lpName))
{ {
@ -789,17 +756,13 @@ DWORD APIENTRY NPCancelConnection(LPWSTR lpName, BOOL fForce)
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen)) &ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
return WN_BAD_NETNAME; return WN_BAD_NETNAME;
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE); Argc = 0;
if (0 == PipeBuf) Argv[Argc] = ClassName; Argl[Argc] = ClassNameLen; Argc++;
return WN_OUT_OF_MEMORY; Argv[Argc] = InstanceName; Argl[Argc] = InstanceNameLen; Argc++;
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( NpResult = FspNpCallLauncherPipe(
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE); FspLaunchCmdStop,
Argc, Argv, Argl, 0, 0);
switch (NpResult) switch (NpResult)
{ {
case WN_SUCCESS: case WN_SUCCESS:
@ -812,8 +775,6 @@ DWORD APIENTRY NPCancelConnection(LPWSTR lpName, BOOL fForce)
break; break;
} }
MemFree(PipeBuf);
return NpResult; return NpResult;
} }
@ -1016,7 +977,7 @@ NTSTATUS FspNpRegister(VOID)
WCHAR ProviderPath[MAX_PATH]; WCHAR ProviderPath[MAX_PATH];
WCHAR RegBuffer[1024]; WCHAR RegBuffer[1024];
PWSTR P, Part; PWSTR P, Part;
DWORD RegResult, RegType, RegBufferSize; DWORD RegResult, RegType, RegBufferSize, RegBufferOffset;
HKEY RegKey; HKEY RegKey;
BOOLEAN FoundProvider; BOOLEAN FoundProvider;
@ -1073,6 +1034,13 @@ NTSTATUS FspNpRegister(VOID)
if (ERROR_SUCCESS != RegResult) if (ERROR_SUCCESS != RegResult)
goto close_and_exit; goto close_and_exit;
RegResult = RegSetValueExW(RegKey,
L"DeviceName", 0, REG_SZ,
(PVOID)L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME,
sizeof L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME);
if (ERROR_SUCCESS != RegResult)
goto close_and_exit;
RegCloseKey(RegKey); RegCloseKey(RegKey);
RegResult = RegOpenKeyExW( RegResult = RegOpenKeyExW(
@ -1082,15 +1050,20 @@ NTSTATUS FspNpRegister(VOID)
return FspNtStatusFromWin32(RegResult); return FspNtStatusFromWin32(RegResult);
RegBufferSize = sizeof RegBuffer - sizeof L"," FSP_NP_NAME; RegBufferSize = sizeof RegBuffer - sizeof L"," FSP_NP_NAME;
#ifdef FSP_NP_ORDER_FIRST
RegBufferOffset = sizeof "" FSP_NP_NAME;
#else
RegBufferOffset = 0;
#endif
RegResult = RegQueryValueExW(RegKey, RegResult = RegQueryValueExW(RegKey,
L"ProviderOrder", 0, &RegType, (PVOID)RegBuffer, &RegBufferSize); L"ProviderOrder", 0, &RegType, (PVOID)&RegBuffer[RegBufferOffset], &RegBufferSize);
if (ERROR_SUCCESS != RegResult) if (ERROR_SUCCESS != RegResult)
goto close_and_exit; goto close_and_exit;
RegBufferSize /= sizeof(WCHAR); RegBufferSize /= sizeof(WCHAR);
FoundProvider = FALSE; FoundProvider = FALSE;
RegBuffer[RegBufferSize] = L'\0'; RegBuffer[RegBufferSize + RegBufferOffset] = L'\0';
P = RegBuffer, Part = P; P = &RegBuffer[RegBufferOffset], Part = P;
do do
{ {
if (L',' == *P || '\0' == *P) if (L',' == *P || '\0' == *P)
@ -1107,8 +1080,11 @@ NTSTATUS FspNpRegister(VOID)
if (!FoundProvider) if (!FoundProvider)
{ {
P--; #ifdef FSP_NP_ORDER_FIRST
memcpy(P, L"," FSP_NP_NAME, sizeof L"," FSP_NP_NAME); memcpy((PWSTR)RegBuffer, L"" FSP_NP_NAME ",", sizeof L"" FSP_NP_NAME);
#else
memcpy(--P, L"," FSP_NP_NAME, sizeof L"," FSP_NP_NAME);
#endif
RegBufferSize = lstrlenW(RegBuffer); RegBufferSize = lstrlenW(RegBuffer);
RegBufferSize++; RegBufferSize++;

View File

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

View File

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

View File

@ -14,7 +14,7 @@
* [SNAME] * [SNAME]
* https://www.cygwin.com/cygwin-ug-net/using-specialnames.html * https://www.cygwin.com/cygwin-ug-net/using-specialnames.html
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -453,9 +453,12 @@ FSP_API NTSTATUS FspPosixMapPermissionsToSecurityDescriptor(
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
Result = FspPosixMapUidToSid(0x10100, &WorldSid); WorldSid = FspWksidGet(WinWorldSid);
if (!NT_SUCCESS(Result)) if (0 == WorldSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit; goto exit;
}
OwnerPerm = (Mode & 0700) >> 6; OwnerPerm = (Mode & 0700) >> 6;
GroupPerm = (Mode & 0070) >> 3; GroupPerm = (Mode & 0070) >> 3;
@ -579,9 +582,6 @@ exit:
MemFree(Acl); MemFree(Acl);
if (0 != WorldSid)
FspDeleteSid(WorldSid, FspPosixMapUidToSid);
if (0 != GroupSid) if (0 != GroupSid)
FspDeleteSid(GroupSid, FspPosixMapUidToSid); FspDeleteSid(GroupSid, FspPosixMapUidToSid);
@ -649,13 +649,19 @@ FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
if (0 != Acl) if (0 != Acl)
{ {
Result = FspPosixMapUidToSid(0x10100, &WorldSid); WorldSid = FspWksidGet(WinWorldSid);
if (!NT_SUCCESS(Result)) if (0 == WorldSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit; goto exit;
}
Result = FspPosixMapUidToSid(11, &AuthUsersSid); AuthUsersSid = FspWksidGet(WinAuthenticatedUserSid);
if (!NT_SUCCESS(Result)) if (0 == AuthUsersSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit; goto exit;
}
OwnerAllow = OwnerDeny = GroupAllow = GroupDeny = WorldAllow = WorldDeny = 0; OwnerAllow = OwnerDeny = GroupAllow = GroupDeny = WorldAllow = WorldDeny = 0;
@ -771,12 +777,6 @@ FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
exit: exit:
if (0 != AuthUsersSid)
FspDeleteSid(AuthUsersSid, FspPosixMapUidToSid);
if (0 != WorldSid)
FspDeleteSid(WorldSid, FspPosixMapUidToSid);
return Result; return Result;
lasterror: lasterror:

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/security.c * @file dll/security.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -172,8 +172,12 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
if (0 < SecurityDescriptorSize) if (0 < SecurityDescriptorSize)
{ {
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, FILE_TRAVERSE, if (AccessCheck(SecurityDescriptor,
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, &TraverseAccess, &AccessStatus)) FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
FILE_TRAVERSE,
&FspFileGenericMapping,
PrivilegeSet, &PrivilegeSetLength,
&TraverseAccess, &AccessStatus))
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED; Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
else else
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());
@ -202,8 +206,12 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
{ {
if (0 == DesiredAccess) if (0 == DesiredAccess)
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
else if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess, else if (AccessCheck(SecurityDescriptor,
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus)) FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
DesiredAccess,
&FspFileGenericMapping,
PrivilegeSet, &PrivilegeSetLength,
PGrantedAccess, &AccessStatus))
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED; Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
else else
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());
@ -244,8 +252,12 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
((FILE_LIST_DIRECTORY & ParentAccess) ? FILE_READ_ATTRIBUTES : 0)); ((FILE_LIST_DIRECTORY & ParentAccess) ? FILE_READ_ATTRIBUTES : 0));
if (0 != DesiredAccess2) if (0 != DesiredAccess2)
{ {
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess2, if (AccessCheck(SecurityDescriptor,
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus)) FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
DesiredAccess2,
&FspFileGenericMapping,
PrivilegeSet, &PrivilegeSetLength,
PGrantedAccess, &AccessStatus))
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED; Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
else else
/* any failure just becomes ACCESS DENIED at this point */ /* any failure just becomes ACCESS DENIED at this point */
@ -396,7 +408,7 @@ FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
(PSECURITY_DESCRIPTOR)(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset) : 0, (PSECURITY_DESCRIPTOR)(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset) : 0,
PSecurityDescriptor, PSecurityDescriptor,
0 != (Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE), 0 != (Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE),
(HANDLE)Request->Req.Create.AccessToken, FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
&FspFileGenericMapping)) &FspFileGenericMapping))
return FspNtStatusFromWin32(GetLastError()); return FspNtStatusFromWin32(GetLastError());

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/service.c * @file dll/service.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -566,6 +566,106 @@ FSP_API BOOLEAN FspServiceIsInteractive(VOID)
return IsInteractive; return IsInteractive;
} }
FSP_API NTSTATUS FspServiceContextCheck(HANDLE Token, PBOOLEAN PIsLocalSystem)
{
NTSTATUS Result;
PSID LocalSystemSid, ServiceSid;
BOOLEAN IsLocalSystem = FALSE;
BOOL HasServiceSid = FALSE;
HANDLE ProcessToken = 0, ImpersonationToken = 0;
DWORD SessionId, Size;
union
{
TOKEN_USER V;
UINT8 B[128];
} UserInfoBuf;
PTOKEN_USER UserInfo = &UserInfoBuf.V;
LocalSystemSid = FspWksidGet(WinLocalSystemSid);
ServiceSid = FspWksidGet(WinServiceSid);
if (0 == LocalSystemSid || 0 == ServiceSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (0 == Token)
{
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE, &ProcessToken) ||
!DuplicateToken(ProcessToken, SecurityImpersonation, &ImpersonationToken))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Token = ImpersonationToken;
}
if (!GetTokenInformation(Token, TokenSessionId, &SessionId, sizeof SessionId, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (0 != SessionId)
{
Result = STATUS_ACCESS_DENIED;
goto exit;
}
if (!GetTokenInformation(Token, TokenUser, UserInfo, sizeof UserInfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
UserInfo = MemAlloc(Size);
if (0 == UserInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenUser, UserInfo, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
IsLocalSystem = EqualSid(LocalSystemSid, UserInfo->User.Sid);
if (IsLocalSystem)
{
Result = STATUS_SUCCESS;
goto exit;
}
if (!CheckTokenMembership(Token, ServiceSid, &HasServiceSid))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Result = HasServiceSid ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
exit:
if (0 != PIsLocalSystem)
*PIsLocalSystem = NT_SUCCESS(Result) ? IsLocalSystem : FALSE;
if (UserInfo != &UserInfoBuf.V)
MemFree(UserInfo);
if (0 != ImpersonationToken)
CloseHandle(ImpersonationToken);
if (0 != ProcessToken)
CloseHandle(ProcessToken);
return Result;
}
FSP_API VOID FspServiceLog(ULONG Type, PWSTR Format, ...) FSP_API VOID FspServiceLog(ULONG Type, PWSTR Format, ...)
{ {
va_list ap; va_list ap;

View File

@ -1,7 +1,7 @@
/** /**
* @file dll/util.c * @file dll/util.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -97,24 +97,14 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
{ {
PSECURITY_DESCRIPTOR SecurityDescriptor = 0; PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PSID OwnerSid, WellKnownSid = 0; PSID OwnerSid, WellKnownSid = 0;
DWORD SidSize, LastError; DWORD LastError;
/* if it is a small number treat it like a well known SID */ /* if it is a small number treat it like a well known SID */
if (1024 > (INT_PTR)Sid) if (1024 > (INT_PTR)Sid)
{ {
SidSize = SECURITY_MAX_SID_SIZE; WellKnownSid = FspWksidNew((INT_PTR)Sid, &Result);
WellKnownSid = MemAlloc(SidSize);
if (0 == WellKnownSid) if (0 == WellKnownSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto sid_exit; goto sid_exit;
}
if (!CreateWellKnownSid((INT_PTR)Sid, 0, WellKnownSid, &SidSize))
{
Result = FspNtStatusFromWin32(GetLastError());
goto sid_exit;
}
} }
LastError = GetSecurityInfo(Pipe, SE_FILE_OBJECT, LastError = GetSecurityInfo(Pipe, SE_FILE_OBJECT,

108
src/dll/wksid.c Normal file
View File

@ -0,0 +1,108 @@
/**
* @file dll/wksid.c
*
* @copyright 2015-2018 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>
static INIT_ONCE FspWksidInitOnce = INIT_ONCE_STATIC_INIT;
static PSID FspWksidWorld;
static PSID FspWksidAuthenticatedUser;
static PSID FspWksidLocalSystem;
static PSID FspWksidService;
static BOOL WINAPI FspWksidInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
FspWksidWorld = FspWksidNew(WinWorldSid, 0);
FspWksidAuthenticatedUser = FspWksidNew(WinAuthenticatedUserSid, 0);
FspWksidLocalSystem = FspWksidNew(WinLocalSystemSid, 0);
FspWksidService = FspWksidNew(WinServiceSid, 0);
//DEBUGLOGSID("FspWksidWorld=%s", FspWksidWorld);
//DEBUGLOGSID("FspWksidAuthenticatedUser=%s", FspWksidAuthenticatedUser);
//DEBUGLOGSID("FspWksidLocalSystem=%s", FspWksidLocalSystem);
//DEBUGLOGSID("FspWksidService=%s", FspWksidService);
return TRUE;
}
VOID FspWksidFinalize(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)
{
MemFree(FspWksidWorld); FspWksidWorld = 0;
MemFree(FspWksidAuthenticatedUser); FspWksidAuthenticatedUser = 0;
MemFree(FspWksidLocalSystem); FspWksidLocalSystem = 0;
MemFree(FspWksidService); FspWksidService = 0;
}
}
PSID FspWksidNew(WELL_KNOWN_SID_TYPE WellKnownSidType, PNTSTATUS PResult)
{
NTSTATUS Result;
PSID Sid;
DWORD Size;
Size = SECURITY_MAX_SID_SIZE;
Sid = MemAlloc(Size);
if (0 == Sid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!CreateWellKnownSid(WellKnownSidType, 0, Sid, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
MemFree(Sid); Sid = 0;
goto exit;
}
Result = STATUS_SUCCESS;
exit:
if (0 != PResult)
*PResult = Result;
return Sid;
}
PSID FspWksidGet(WELL_KNOWN_SID_TYPE WellKnownSidType)
{
InitOnceExecuteOnce(&FspWksidInitOnce, FspWksidInitialize, 0, 0);
switch (WellKnownSidType)
{
case WinWorldSid:
return FspWksidWorld;
case WinAuthenticatedUserSid:
return FspWksidAuthenticatedUser;
case WinLocalSystemSid:
return FspWksidLocalSystem;
case WinServiceSid:
return FspWksidService;
default:
return 0;
}
}

View File

@ -1,7 +1,7 @@
/* /*
* dotnet/FileSystemBase+Const.cs * dotnet/FileSystemBase+Const.cs
* *
* Copyright 2015-2017 Bill Zissimopoulos * Copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/* /*
* dotnet/FileSystemBase.cs * dotnet/FileSystemBase.cs
* *
* Copyright 2015-2017 Bill Zissimopoulos * Copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -935,6 +935,37 @@ namespace Fsp
StreamAllocationSize = default(UInt64); StreamAllocationSize = default(UInt64);
return false; return false;
} }
/// <summary>
/// Gets directory information for a single file or directory within a parent directory.
/// </summary>
/// <param name="FileNode">
/// The file node of the parent directory.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the parent directory.
/// </param>
/// <param name="FileName">
/// The name of the file or directory to get information for. This name is relative
/// to the parent directory and is a single path component.
/// </param>
/// <param name="NormalizedName">
/// Receives the normalized name from the directory entry.
/// </param>
/// <param name="FileInfo">
/// Receives the file information.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 GetDirInfoByName(
Object FileNode,
Object FileDesc,
String FileName,
out String NormalizedName,
out FileInfo FileInfo)
{
NormalizedName = default(String);
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
/* helpers */ /* helpers */
/// <summary> /// <summary>
@ -952,6 +983,16 @@ namespace Fsp
return Api.FspWin32FromNtStatus(Status); return Api.FspWin32FromNtStatus(Status);
} }
/// <summary> /// <summary>
/// Gets the originating process ID.
/// </summary>
/// <remarks>
/// Valid only during Create, Open and Rename requests when the target exists.
/// </remarks>
public static int GetOperationProcessId()
{
return (int)Api.FspFileSystemOperationProcessId();
}
/// <summary>
/// Modifies a security descriptor. /// Modifies a security descriptor.
/// </summary> /// </summary>
/// <remarks> /// <remarks>

View File

@ -1,7 +1,7 @@
/* /*
* dotnet/FileSystemHost.cs * dotnet/FileSystemHost.cs
* *
* Copyright 2015-2017 Bill Zissimopoulos * Copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -189,6 +189,11 @@ namespace Fsp
get { return 0 != (_VolumeParams.Flags & VolumeParams.PassQueryDirectoryPattern); } get { return 0 != (_VolumeParams.Flags & VolumeParams.PassQueryDirectoryPattern); }
set { _VolumeParams.Flags |= (value ? VolumeParams.PassQueryDirectoryPattern : 0); } set { _VolumeParams.Flags |= (value ? VolumeParams.PassQueryDirectoryPattern : 0); }
} }
public Boolean PassQueryDirectoryFileName
{
get { return 0 != (_VolumeParams.Flags & VolumeParams.PassQueryDirectoryFileName); }
set { _VolumeParams.Flags |= (value ? VolumeParams.PassQueryDirectoryFileName : 0); }
}
/// <summary> /// <summary>
/// Gets or sets the prefix for a network file system. /// Gets or sets the prefix for a network file system.
/// </summary> /// </summary>
@ -987,6 +992,34 @@ namespace Fsp
return ExceptionHandler(FileSystem, ex); return ExceptionHandler(FileSystem, ex);
} }
} }
private static Int32 GetDirInfoByName(
IntPtr FileSystemPtr,
ref FullContext FullContext,
String FileName,
out DirInfo DirInfo)
{
FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr);
try
{
Object FileNode, FileDesc;
String NormalizedName;
Api.GetFullContext(ref FullContext, out FileNode, out FileDesc);
DirInfo = default(DirInfo);
Int32 Result = FileSystem.GetDirInfoByName(
FileNode,
FileDesc,
FileName,
out NormalizedName,
out DirInfo.FileInfo);
DirInfo.SetFileNameBuf(NormalizedName);
return Result;
}
catch (Exception ex)
{
DirInfo = default(DirInfo);
return ExceptionHandler(FileSystem, ex);
}
}
static FileSystemHost() static FileSystemHost()
{ {
@ -1014,6 +1047,7 @@ namespace Fsp
_FileSystemInterface.SetReparsePoint = SetReparsePoint; _FileSystemInterface.SetReparsePoint = SetReparsePoint;
_FileSystemInterface.DeleteReparsePoint = DeleteReparsePoint; _FileSystemInterface.DeleteReparsePoint = DeleteReparsePoint;
_FileSystemInterface.GetStreamInfo = GetStreamInfo; _FileSystemInterface.GetStreamInfo = GetStreamInfo;
_FileSystemInterface.GetDirInfoByName = GetDirInfoByName;
_FileSystemInterfacePtr = Marshal.AllocHGlobal(FileSystemInterface.Size); _FileSystemInterfacePtr = Marshal.AllocHGlobal(FileSystemInterface.Size);
Marshal.StructureToPtr(_FileSystemInterface, _FileSystemInterfacePtr, false); Marshal.StructureToPtr(_FileSystemInterface, _FileSystemInterfacePtr, false);

View File

@ -1,7 +1,7 @@
/* /*
* dotnet/Interop.cs * dotnet/Interop.cs
* *
* Copyright 2015-2017 Bill Zissimopoulos * Copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -42,6 +42,7 @@ namespace Fsp.Interop
internal const UInt32 PostCleanupWhenModifiedOnly = 0x00000400; internal const UInt32 PostCleanupWhenModifiedOnly = 0x00000400;
internal const UInt32 PassQueryDirectoryPattern = 0x00000800; internal const UInt32 PassQueryDirectoryPattern = 0x00000800;
internal const UInt32 AlwaysUseDoubleBuffering = 0x00001000; internal const UInt32 AlwaysUseDoubleBuffering = 0x00001000;
internal const UInt32 PassQueryDirectoryFileName = 0x00002000;
internal const UInt32 UmFileContextIsUserContext2 = 0x00010000; internal const UInt32 UmFileContextIsUserContext2 = 0x00010000;
internal const UInt32 UmFileContextIsFullContext = 0x00020000; internal const UInt32 UmFileContextIsFullContext = 0x00020000;
internal const int PrefixSize = 192; internal const int PrefixSize = 192;
@ -450,6 +451,12 @@ namespace Fsp.Interop
IntPtr Buffer, IntPtr Buffer,
UInt32 Length, UInt32 Length,
out UInt32 PBytesTransferred); out UInt32 PBytesTransferred);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 GetDirInfoByName(
IntPtr FileSystem,
ref FullContext FullContext,
[MarshalAs(UnmanagedType.LPWStr)] String FileName,
out DirInfo DirInfo);
} }
internal static int Size = IntPtr.Size * 64; internal static int Size = IntPtr.Size * 64;
@ -478,7 +485,8 @@ namespace Fsp.Interop
internal Proto.SetReparsePoint SetReparsePoint; internal Proto.SetReparsePoint SetReparsePoint;
internal Proto.DeleteReparsePoint DeleteReparsePoint; internal Proto.DeleteReparsePoint DeleteReparsePoint;
internal Proto.GetStreamInfo GetStreamInfo; internal Proto.GetStreamInfo GetStreamInfo;
/* NTSTATUS (*Reserved[40])(); */ internal Proto.GetDirInfoByName GetDirInfoByName;
/* NTSTATUS (*Reserved[39])(); */
} }
[SuppressUnmanagedCodeSecurity] [SuppressUnmanagedCodeSecurity]
@ -531,6 +539,8 @@ namespace Fsp.Interop
IntPtr FileSystem, IntPtr FileSystem,
UInt32 DebugLog); UInt32 DebugLog);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate UInt32 FspFileSystemOperationProcessIdF();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U1)] [return: MarshalAs(UnmanagedType.U1)]
internal delegate Boolean FspFileSystemAddDirInfo( internal delegate Boolean FspFileSystemAddDirInfo(
IntPtr DirInfo, IntPtr DirInfo,
@ -698,6 +708,7 @@ namespace Fsp.Interop
internal static Proto.FspFileSystemMountPointF FspFileSystemMountPoint; internal static Proto.FspFileSystemMountPointF FspFileSystemMountPoint;
internal static Proto.FspFileSystemSetOperationGuardStrategyF FspFileSystemSetOperationGuardStrategy; internal static Proto.FspFileSystemSetOperationGuardStrategyF FspFileSystemSetOperationGuardStrategy;
internal static Proto.FspFileSystemSetDebugLogF FspFileSystemSetDebugLog; internal static Proto.FspFileSystemSetDebugLogF FspFileSystemSetDebugLog;
internal static Proto.FspFileSystemOperationProcessIdF FspFileSystemOperationProcessId;
internal static Proto.FspFileSystemAddDirInfo _FspFileSystemAddDirInfo; internal static Proto.FspFileSystemAddDirInfo _FspFileSystemAddDirInfo;
internal static Proto.FspFileSystemFindReparsePoint FspFileSystemFindReparsePoint; internal static Proto.FspFileSystemFindReparsePoint FspFileSystemFindReparsePoint;
internal static Proto.FspFileSystemResolveReparsePoints FspFileSystemResolveReparsePoints; internal static Proto.FspFileSystemResolveReparsePoints FspFileSystemResolveReparsePoints;
@ -1007,6 +1018,7 @@ namespace Fsp.Interop
FspFileSystemMountPoint = GetEntryPoint<Proto.FspFileSystemMountPointF>(Module); FspFileSystemMountPoint = GetEntryPoint<Proto.FspFileSystemMountPointF>(Module);
FspFileSystemSetOperationGuardStrategy = GetEntryPoint<Proto.FspFileSystemSetOperationGuardStrategyF>(Module); FspFileSystemSetOperationGuardStrategy = GetEntryPoint<Proto.FspFileSystemSetOperationGuardStrategyF>(Module);
FspFileSystemSetDebugLog = GetEntryPoint<Proto.FspFileSystemSetDebugLogF>(Module); FspFileSystemSetDebugLog = GetEntryPoint<Proto.FspFileSystemSetDebugLogF>(Module);
FspFileSystemOperationProcessId = GetEntryPoint<Proto.FspFileSystemOperationProcessIdF>(Module);
_FspFileSystemAddDirInfo = GetEntryPoint<Proto.FspFileSystemAddDirInfo>(Module); _FspFileSystemAddDirInfo = GetEntryPoint<Proto.FspFileSystemAddDirInfo>(Module);
FspFileSystemFindReparsePoint = GetEntryPoint<Proto.FspFileSystemFindReparsePoint>(Module); FspFileSystemFindReparsePoint = GetEntryPoint<Proto.FspFileSystemFindReparsePoint>(Module);
FspFileSystemResolveReparsePoints = GetEntryPoint<Proto.FspFileSystemResolveReparsePoints>(Module); FspFileSystemResolveReparsePoints = GetEntryPoint<Proto.FspFileSystemResolveReparsePoints>(Module);

View File

@ -1,7 +1,7 @@
/* /*
* dotnet/Service.cs * dotnet/Service.cs
* *
* Copyright 2015-2017 Bill Zissimopoulos * Copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.

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(MyFullVersion)
VALUE "InternalName", "fsptool.exe"
VALUE "LegalCopyright", STR(MyCopyright)
VALUE "OriginalFilename", "fsptool.exe"
VALUE "ProductName", STR(MyProductName)
VALUE "ProductVersion", STR(MyProductVersion)
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

602
src/fsptool/fsptool.c Normal file
View File

@ -0,0 +1,602 @@
/**
* @file fsptool/fsptool.c
*
* @copyright 2015-2018 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <winfsp/winfsp.h>
#include <shared/minimal.h>
#include <aclapi.h>
#include <sddl.h>
#define PROGNAME "fsptool"
#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 unsigned wcstoint(const wchar_t *p, const wchar_t **endp, int base)
{
unsigned v;
int maxdig, maxalp;
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;
}
}
if (0 != endp)
*endp = (wchar_t *)p;
return v;
}
static void usage(void)
{
fatal(ERROR_INVALID_PARAMETER,
"usage: %s COMMAND ARGS\n"
"\n"
"commands:\n"
" lsvol list file system devices (volumes)\n"
//" list list running file system processes\n"
//" kill kill file system process\n"
" id [NAME|SID|UID] print user id\n"
" perm [PATH|SDDL|UID:GID:MODE] print permissions\n",
PROGNAME);
}
static NTSTATUS FspToolGetVolumeList(PWSTR DeviceName,
PWCHAR *PVolumeListBuf, PSIZE_T PVolumeListSize)
{
NTSTATUS Result;
PWCHAR VolumeListBuf;
SIZE_T VolumeListSize;
*PVolumeListBuf = 0;
*PVolumeListSize = 0;
for (VolumeListSize = 1024;; VolumeListSize *= 2)
{
VolumeListBuf = MemAlloc(VolumeListSize);
if (0 == VolumeListBuf)
return STATUS_INSUFFICIENT_RESOURCES;
Result = FspFsctlGetVolumeList(DeviceName,
VolumeListBuf, &VolumeListSize);
if (NT_SUCCESS(Result))
{
*PVolumeListBuf = VolumeListBuf;
*PVolumeListSize = VolumeListSize;
return Result;
}
MemFree(VolumeListBuf);
if (STATUS_BUFFER_TOO_SMALL != Result)
return Result;
}
}
static WCHAR FspToolGetDriveLetter(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 == invariant_wcscmp(VolumeNameBuf, VolumeName))
{
*PLogicalDrives &= ~(1 << (Drive - 'A'));
return Drive;
}
}
}
return 0;
}
NTSTATUS FspToolGetTokenInfo(HANDLE Token,
TOKEN_INFORMATION_CLASS TokenInformationClass, PVOID *PInfo)
{
PVOID Info = 0;
DWORD Size;
NTSTATUS Result;
if (GetTokenInformation(Token, TokenInformationClass, 0, 0, &Size))
{
Result = STATUS_INVALID_PARAMETER;
goto exit;
}
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Info = MemAlloc(Size);
if (0 == Info)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenInformationClass, Info, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
*PInfo = Info;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
MemFree(Info);
return Result;
}
NTSTATUS FspToolGetNameFromSid(PSID Sid, PWSTR *PName)
{
WCHAR Name[256], Domn[256];
DWORD NameSize, DomnSize;
SID_NAME_USE Use;
PWSTR P;
NameSize = sizeof Name / sizeof Name[0];
DomnSize = sizeof Domn / sizeof Domn[0];
if (!LookupAccountSidW(0, Sid, Name, &NameSize, Domn, &DomnSize, &Use))
{
Name[0] = L'\0';
Domn[0] = L'\0';
}
NameSize = lstrlenW(Name);
DomnSize = lstrlenW(Domn);
P = *PName = MemAlloc((DomnSize + 1 + NameSize + 1) * sizeof(WCHAR));
if (0 == P)
return STATUS_INSUFFICIENT_RESOURCES;
if (0 < DomnSize)
{
memcpy(P, Domn, DomnSize * sizeof(WCHAR));
P[DomnSize] = L'\\';
P += DomnSize + 1;
}
memcpy(P, Name, NameSize * sizeof(WCHAR));
P[NameSize] = L'\0';
return STATUS_SUCCESS;
}
NTSTATUS FspToolGetSidFromName(PWSTR Name, PSID *PSid)
{
PSID Sid;
WCHAR Domn[256];
DWORD SidSize, DomnSize;
SID_NAME_USE Use;
SidSize = 0;
DomnSize = sizeof Domn / sizeof Domn[0];
if (LookupAccountNameW(0, Name, 0, &SidSize, Domn, &DomnSize, &Use))
return STATUS_INVALID_PARAMETER;
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
return FspNtStatusFromWin32(GetLastError());
Sid = MemAlloc(SidSize);
if (0 == Sid)
return STATUS_INSUFFICIENT_RESOURCES;
DomnSize = sizeof Domn / sizeof Domn[0];
if (!LookupAccountNameW(0, Name, Sid, &SidSize, Domn, &DomnSize, &Use))
{
MemFree(Sid);
return FspNtStatusFromWin32(GetLastError());
}
*PSid = Sid;
return STATUS_SUCCESS;
}
static NTSTATUS lsvol_dev(PWSTR DeviceName)
{
NTSTATUS Result;
PWCHAR VolumeListBuf, VolumeListBufEnd;
SIZE_T VolumeListSize;
DWORD LogicalDrives;
WCHAR Drive[3] = L"\0:";
Result = FspToolGetVolumeList(DeviceName, &VolumeListBuf, &VolumeListSize);
if (!NT_SUCCESS(Result))
return Result;
VolumeListBufEnd = (PVOID)((PUINT8)VolumeListBuf + VolumeListSize);
LogicalDrives = GetLogicalDrives();
for (PWCHAR P = VolumeListBuf, VolumeName = P; VolumeListBufEnd > P; P++)
if (L'\0' == *P)
{
Drive[0] = FspToolGetDriveLetter(&LogicalDrives, VolumeName);
info("%-4S%S", Drive[0] ? Drive : L"", VolumeName);
VolumeName = P + 1;
}
MemFree(VolumeListBuf);
return STATUS_SUCCESS;
}
static int lsvol(int argc, wchar_t **argv)
{
if (1 != argc)
usage();
NTSTATUS Result;
Result = lsvol_dev(L"" FSP_FSCTL_DISK_DEVICE_NAME);
if (!NT_SUCCESS(Result))
return FspWin32FromNtStatus(Result);
Result = lsvol_dev(L"" FSP_FSCTL_NET_DEVICE_NAME);
if (!NT_SUCCESS(Result))
return FspWin32FromNtStatus(Result);
return 0;
}
static NTSTATUS id_print_sid(const char *format, PSID Sid)
{
PWSTR Str = 0;
PWSTR Name = 0;
UINT32 Uid;
NTSTATUS Result;
if (!ConvertSidToStringSidW(Sid, &Str))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Result = FspToolGetNameFromSid(Sid, &Name);
if (!NT_SUCCESS(Result))
goto exit;
Result = FspPosixMapSidToUid(Sid, &Uid);
if (!NT_SUCCESS(Result))
goto exit;
info(format, Str, Name, Uid);
Result = STATUS_SUCCESS;
exit:
MemFree(Name);
LocalFree(Str);
return Result;
}
static NTSTATUS id_name(PWSTR Name)
{
PSID Sid = 0;
NTSTATUS Result;
Result = FspToolGetSidFromName(Name, &Sid);
if (!NT_SUCCESS(Result))
return Result;
id_print_sid("%S(%S) (uid=%u)", Sid);
MemFree(Sid);
return STATUS_SUCCESS;
}
static NTSTATUS id_sid(PWSTR SidStr)
{
PSID Sid = 0;
if (!ConvertStringSidToSid(SidStr, &Sid))
return FspNtStatusFromWin32(GetLastError());
id_print_sid("%S(%S) (uid=%u)", Sid);
LocalFree(Sid);
return STATUS_SUCCESS;
}
static NTSTATUS id_uid(PWSTR UidStr)
{
PSID Sid = 0;
UINT32 Uid;
NTSTATUS Result;
Uid = wcstoint(UidStr, &UidStr, 10);
if (L'\0' != *UidStr)
return STATUS_INVALID_PARAMETER;
Result = FspPosixMapUidToSid(Uid, &Sid);
if (!NT_SUCCESS(Result))
return Result;
id_print_sid("%S(%S) (uid=%u)", Sid);
FspDeleteSid(Sid, FspPosixMapUidToSid);
return STATUS_SUCCESS;
}
static NTSTATUS id_user(void)
{
HANDLE Token = 0;
TOKEN_USER *Uinfo = 0;
TOKEN_OWNER *Oinfo = 0;
TOKEN_PRIMARY_GROUP *Ginfo = 0;
NTSTATUS Result;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Result = FspToolGetTokenInfo(Token, TokenUser, &Uinfo);
if (!NT_SUCCESS(Result))
goto exit;
Result = FspToolGetTokenInfo(Token, TokenOwner, &Oinfo);
if (!NT_SUCCESS(Result))
goto exit;
Result = FspToolGetTokenInfo(Token, TokenPrimaryGroup, &Ginfo);
if (!NT_SUCCESS(Result))
goto exit;
id_print_sid("User=%S(%S) (uid=%u)", Uinfo->User.Sid);
id_print_sid("Owner=%S(%S) (uid=%u)", Oinfo->Owner);
id_print_sid("Group=%S(%S) (gid=%u)", Ginfo->PrimaryGroup);
Result = STATUS_SUCCESS;
exit:
MemFree(Ginfo);
MemFree(Oinfo);
MemFree(Uinfo);
if (0 != Token)
CloseHandle(Token);
return Result;
}
static int id(int argc, wchar_t **argv)
{
if (2 < argc)
usage();
NTSTATUS Result;
if (2 == argc)
{
if (L'S' == argv[1][0] && L'-' == argv[1][1] && L'1' == argv[1][2] && L'-' == argv[1][3])
Result = id_sid(argv[1]);
else
{
Result = id_uid(argv[1]);
if (STATUS_INVALID_PARAMETER == Result)
Result = id_name(argv[1]);
}
}
else
Result = id_user();
return FspWin32FromNtStatus(Result);
}
static NTSTATUS perm_print_sd(PSECURITY_DESCRIPTOR SecurityDescriptor)
{
UINT32 Uid, Gid, Mode;
PWSTR Sddl = 0;
NTSTATUS Result;
Result = FspPosixMapSecurityDescriptorToPermissions(SecurityDescriptor, &Uid, &Gid, &Mode);
if (!NT_SUCCESS(Result))
return Result;
if (!ConvertSecurityDescriptorToStringSecurityDescriptorW(
SecurityDescriptor, SDDL_REVISION_1,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
&Sddl, 0))
return FspNtStatusFromWin32(GetLastError());
info("%S (perm=%u:%u:%d%d%d%d)",
Sddl, Uid, Gid, (Mode >> 9) & 7, (Mode >> 6) & 7, (Mode >> 3) & 7, Mode & 7);
LocalFree(Sddl);
return STATUS_SUCCESS;
}
static NTSTATUS perm_path(PWSTR Path)
{
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
int ErrorCode;
ErrorCode = GetNamedSecurityInfoW(Path, SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
0, 0, 0, 0, &SecurityDescriptor);
if (0 != ErrorCode)
return FspNtStatusFromWin32(ErrorCode);
perm_print_sd(SecurityDescriptor);
LocalFree(SecurityDescriptor);
return STATUS_SUCCESS;
}
static NTSTATUS perm_sddl(PWSTR Sddl)
{
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
Sddl, SDDL_REVISION_1, &SecurityDescriptor, 0))
return FspNtStatusFromWin32(GetLastError());
perm_print_sd(SecurityDescriptor);
LocalFree(SecurityDescriptor);
return STATUS_SUCCESS;
}
static NTSTATUS perm_mode(PWSTR PermStr)
{
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
UINT32 Uid, Gid, Mode;
NTSTATUS Result;
Uid = wcstoint(PermStr, &PermStr, 10);
if (L':' != *PermStr)
return STATUS_INVALID_PARAMETER;
Gid = wcstoint(PermStr + 1, &PermStr, 10);
if (L':' != *PermStr)
return STATUS_INVALID_PARAMETER;
Mode = wcstoint(PermStr + 1, &PermStr, 8);
if (L'\0' != *PermStr)
return STATUS_INVALID_PARAMETER;
Result = FspPosixMapPermissionsToSecurityDescriptor(Uid, Gid, Mode, &SecurityDescriptor);
if (!NT_SUCCESS(Result))
return Result;
perm_print_sd(SecurityDescriptor);
FspDeleteSecurityDescriptor(SecurityDescriptor,
FspPosixMapPermissionsToSecurityDescriptor);
return STATUS_SUCCESS;
}
static int perm(int argc, wchar_t **argv)
{
if (2 != argc)
usage();
NTSTATUS Result;
PWSTR P;
for (P = argv[1]; *P; P++)
if (L'\\' == *P)
break;
if (L'\\' == *P)
Result = perm_path(argv[1]);
else
{
Result = perm_mode(argv[1]);
if (STATUS_INVALID_PARAMETER == Result)
Result = perm_sddl(argv[1]);
}
return FspWin32FromNtStatus(Result);
}
int wmain(int argc, wchar_t **argv)
{
argc--;
argv++;
if (0 == argc)
usage();
if (0 == invariant_wcscmp(L"lsvol", argv[0]))
return lsvol(argc, argv);
else
if (0 == invariant_wcscmp(L"id", argv[0]))
return id(argc, argv);
else
if (0 == invariant_wcscmp(L"perm", argv[0]))
return perm(argc, argv);
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

@ -1,7 +1,7 @@
/** /**
* @file launcher/launchctl.c * @file launcher/launchctl.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -15,7 +15,8 @@
* software. * software.
*/ */
#include <launcher/launcher.h> #include <winfsp/launch.h>
#include <shared/minimal.h>
#define PROGNAME "launchctl" #define PROGNAME "launchctl"
@ -67,15 +68,15 @@ static int call_pipe_and_report(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
NTSTATUS Result; NTSTATUS Result;
DWORD LastError, BytesTransferred; DWORD LastError, BytesTransferred;
Result = FspCallNamedPipeSecurely(L"" LAUNCHER_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize, Result = FspCallNamedPipeSecurely(L"" FSP_LAUNCH_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize,
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, LAUNCHER_PIPE_OWNER); &BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, FSP_LAUNCH_PIPE_OWNER);
LastError = FspWin32FromNtStatus(Result); LastError = FspWin32FromNtStatus(Result);
if (0 != LastError) if (0 != LastError)
warn("KO CallNamedPipe = %ld", LastError); warn("KO CallNamedPipe = %ld", LastError);
else if (sizeof(WCHAR) > BytesTransferred) else if (sizeof(WCHAR) > BytesTransferred)
warn("KO launcher: empty buffer"); warn("KO launcher: empty buffer");
else if (LauncherSuccess == PipeBuf[0]) else if (FspLaunchCmdSuccess == PipeBuf[0])
{ {
if (sizeof(WCHAR) == BytesTransferred) if (sizeof(WCHAR) == BytesTransferred)
info("OK"); info("OK");
@ -100,7 +101,7 @@ static int call_pipe_and_report(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
info("OK\n%S", PipeBuf + 1); info("OK\n%S", PipeBuf + 1);
} }
} }
else if (LauncherFailure == PipeBuf[0]) else if (FspLaunchCmdFailure == PipeBuf[0])
{ {
if (BytesTransferred < RecvSize) if (BytesTransferred < RecvSize)
PipeBuf[BytesTransferred / sizeof(WCHAR)] = L'\0'; PipeBuf[BytesTransferred / sizeof(WCHAR)] = L'\0';
@ -132,7 +133,7 @@ int start(PWSTR PipeBuf, ULONG PipeBufSize,
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
P = PipeBuf; P = PipeBuf;
*P++ = HasSecret ? LauncherSvcInstanceStartWithSecret : LauncherSvcInstanceStart; *P++ = HasSecret ? FspLaunchCmdStartWithSecret : FspLaunchCmdStart;
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize; memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize; memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
for (DWORD Argi = 0; Argc > Argi; Argi++) for (DWORD Argi = 0; Argc > Argi; Argi++)
@ -157,7 +158,7 @@ int stop(PWSTR PipeBuf, ULONG PipeBufSize,
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
P = PipeBuf; P = PipeBuf;
*P++ = LauncherSvcInstanceStop; *P++ = FspLaunchCmdStop;
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize; memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize; memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
@ -177,7 +178,7 @@ int getinfo(PWSTR PipeBuf, ULONG PipeBufSize,
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
P = PipeBuf; P = PipeBuf;
*P++ = LauncherSvcInstanceInfo; *P++ = FspLaunchCmdGetInfo;
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize; memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize; memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
@ -192,7 +193,7 @@ int list(PWSTR PipeBuf, ULONG PipeBufSize)
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
P = PipeBuf; P = PipeBuf;
*P++ = LauncherSvcInstanceList; *P++ = FspLaunchCmdGetNameList;
return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize); return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize);
} }
@ -207,7 +208,7 @@ int quit(PWSTR PipeBuf, ULONG PipeBufSize)
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
P = PipeBuf; P = PipeBuf;
*P++ = LauncherQuit; *P++ = FspLaunchCmdQuit;
return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize); return call_pipe_and_report(PipeBuf, (ULONG)((P - PipeBuf) * sizeof(WCHAR)), PipeBufSize);
} }
@ -217,7 +218,7 @@ int wmain(int argc, wchar_t **argv)
PWSTR PipeBuf = 0; PWSTR PipeBuf = 0;
/* allocate our PipeBuf early on; freed on process exit by the system */ /* allocate our PipeBuf early on; freed on process exit by the system */
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE); PipeBuf = MemAlloc(FSP_LAUNCH_PIPE_BUFFER_SIZE);
if (0 == PipeBuf) if (0 == PipeBuf)
return ERROR_NO_SYSTEM_RESOURCES; return ERROR_NO_SYSTEM_RESOURCES;
@ -232,7 +233,7 @@ int wmain(int argc, wchar_t **argv)
if (3 > argc || argc > 12) if (3 > argc || argc > 12)
usage(); usage();
return start(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3, return start(PipeBuf, FSP_LAUNCH_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3,
FALSE); FALSE);
} }
else else
@ -241,7 +242,7 @@ int wmain(int argc, wchar_t **argv)
if (4 > argc || argc > 13) if (4 > argc || argc > 13)
usage(); usage();
return start(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3, return start(PipeBuf, FSP_LAUNCH_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3,
TRUE); TRUE);
} }
else else
@ -250,7 +251,7 @@ int wmain(int argc, wchar_t **argv)
if (3 != argc) if (3 != argc)
usage(); usage();
return stop(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2]); return stop(PipeBuf, FSP_LAUNCH_PIPE_BUFFER_SIZE, argv[1], argv[2]);
} }
else else
if (0 == invariant_wcscmp(L"info", argv[0])) if (0 == invariant_wcscmp(L"info", argv[0]))
@ -258,7 +259,7 @@ int wmain(int argc, wchar_t **argv)
if (3 != argc) if (3 != argc)
usage(); usage();
return getinfo(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2]); return getinfo(PipeBuf, FSP_LAUNCH_PIPE_BUFFER_SIZE, argv[1], argv[2]);
} }
else else
if (0 == invariant_wcscmp(L"list", argv[0])) if (0 == invariant_wcscmp(L"list", argv[0]))
@ -266,7 +267,7 @@ int wmain(int argc, wchar_t **argv)
if (1 != argc) if (1 != argc)
usage(); usage();
return list(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE); return list(PipeBuf, FSP_LAUNCH_PIPE_BUFFER_SIZE);
} }
else else
if (0 == invariant_wcscmp(L"quit", argv[0])) if (0 == invariant_wcscmp(L"quit", argv[0]))
@ -275,7 +276,7 @@ int wmain(int argc, wchar_t **argv)
usage(); usage();
/* works only against DEBUG version of launcher */ /* works only against DEBUG version of launcher */
return quit(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE); return quit(PipeBuf, FSP_LAUNCH_PIPE_BUFFER_SIZE);
} }
else else
usage(); usage();

View File

@ -1,7 +1,7 @@
/** /**
* @file launcher/launcher.c * @file launcher/launcher.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -15,18 +15,32 @@
* software. * software.
*/ */
#include <launcher/launcher.h> #include <winfsp/launch.h>
#include <shared/minimal.h>
#include <aclapi.h>
#include <sddl.h> #include <sddl.h>
#include <userenv.h>
#define PROGNAME "WinFsp.Launcher" #define PROGNAME "WinFsp.Launcher"
BOOL CreateOverlappedPipe( static NTSTATUS (NTAPI *SvcNtOpenSymbolicLinkObject)(
PHANDLE PReadPipe, PHANDLE PWritePipe, PSECURITY_ATTRIBUTES SecurityAttributes, DWORD Size, PHANDLE LinkHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes);
static NTSTATUS (NTAPI *SvcNtClose)(
HANDLE Handle);
static BOOL CreateOverlappedPipe(
PHANDLE PReadPipe, PHANDLE PWritePipe,
DWORD Size,
BOOL ReadInherit, BOOL WriteInherit,
DWORD ReadMode, DWORD WriteMode) DWORD ReadMode, DWORD WriteMode)
{ {
RPC_STATUS RpcStatus; RPC_STATUS RpcStatus;
UUID Uuid; UUID Uuid;
WCHAR PipeNameBuf[MAX_PATH]; WCHAR PipeNameBuf[MAX_PATH];
SECURITY_ATTRIBUTES ReadSecurityAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, ReadInherit };
SECURITY_ATTRIBUTES WriteSecurityAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, WriteInherit };
HANDLE ReadPipe, WritePipe; HANDLE ReadPipe, WritePipe;
DWORD LastError; DWORD LastError;
@ -46,13 +60,13 @@ BOOL CreateOverlappedPipe(
ReadPipe = CreateNamedPipeW(PipeNameBuf, ReadPipe = CreateNamedPipeW(PipeNameBuf,
PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | ReadMode, PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | ReadMode,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
1, Size, Size, 120 * 1000, SecurityAttributes); 1, Size, Size, 120 * 1000, &ReadSecurityAttributes);
if (INVALID_HANDLE_VALUE == ReadPipe) if (INVALID_HANDLE_VALUE == ReadPipe)
return FALSE; return FALSE;
WritePipe = CreateFileW(PipeNameBuf, WritePipe = CreateFileW(PipeNameBuf,
GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
SecurityAttributes, OPEN_EXISTING, WriteMode, 0); &WriteSecurityAttributes, OPEN_EXISTING, WriteMode, 0);
if (INVALID_HANDLE_VALUE == WritePipe) if (INVALID_HANDLE_VALUE == WritePipe)
{ {
LastError = GetLastError(); LastError = GetLastError();
@ -67,6 +81,279 @@ BOOL CreateOverlappedPipe(
return TRUE; return TRUE;
} }
static NTSTATUS GetTokenUserName(HANDLE Token, PWSTR *PUserName)
{
union
{
TOKEN_USER V;
UINT8 B[128];
} UserInfoBuf;
PTOKEN_USER UserInfo = &UserInfoBuf.V;
WCHAR Name[256], Domn[256];
DWORD UserSize, NameSize, DomnSize;
SID_NAME_USE Use;
PWSTR P;
NTSTATUS Result;
*PUserName = 0;
if (!GetTokenInformation(Token, TokenUser, UserInfo, sizeof UserInfoBuf, &UserSize))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
UserInfo = MemAlloc(UserSize);
if (0 == UserInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenUser, UserInfo, UserSize, &UserSize))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
NameSize = sizeof Name / sizeof Name[0];
DomnSize = sizeof Domn / sizeof Domn[0];
if (!LookupAccountSidW(0, UserInfo->User.Sid, Name, &NameSize, Domn, &DomnSize, &Use))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
NameSize = lstrlenW(Name);
DomnSize = lstrlenW(Domn);
P = *PUserName = MemAlloc((DomnSize + 1 + NameSize + 1) * sizeof(WCHAR));
if (0 == P)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (0 < DomnSize)
{
memcpy(P, Domn, DomnSize * sizeof(WCHAR));
P[DomnSize] = L'\\';
P += DomnSize + 1;
}
memcpy(P, Name, NameSize * sizeof(WCHAR));
P[NameSize] = L'\0';
Result = STATUS_SUCCESS;
exit:
if (UserInfo != &UserInfoBuf.V)
MemFree(UserInfo);
return Result;
}
static NTSTATUS AddAccessForTokenUser(HANDLE Handle, DWORD Access, HANDLE Token)
{
union
{
TOKEN_USER V;
UINT8 B[128];
} UserInfoBuf;
PTOKEN_USER UserInfo = &UserInfoBuf.V;
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PSECURITY_DESCRIPTOR NewSecurityDescriptor = 0;
EXPLICIT_ACCESSW AccessEntry;
DWORD Size, LastError;
NTSTATUS Result;
if (!GetTokenInformation(Token, TokenUser, UserInfo, sizeof UserInfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
UserInfo = MemAlloc(Size);
if (0 == UserInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenUser, UserInfo, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
if (GetKernelObjectSecurity(Handle, DACL_SECURITY_INFORMATION, 0, 0, &Size))
{
Result = STATUS_INVALID_PARAMETER;
goto exit;
}
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
SecurityDescriptor = MemAlloc(Size);
if (0 == SecurityDescriptor)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetKernelObjectSecurity(Handle, DACL_SECURITY_INFORMATION, SecurityDescriptor, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
AccessEntry.grfAccessPermissions = Access;
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 = UserInfo->User.Sid;
LastError = BuildSecurityDescriptorW(0, 0, 1, &AccessEntry, 0, 0, SecurityDescriptor,
&Size, &NewSecurityDescriptor);
if (0 != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
if (!SetKernelObjectSecurity(Handle, DACL_SECURITY_INFORMATION, NewSecurityDescriptor))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Result = STATUS_SUCCESS;
exit:
LocalFree(NewSecurityDescriptor);
MemFree(SecurityDescriptor);
if (UserInfo != &UserInfoBuf.V)
MemFree(UserInfo);
return Result;
}
static BOOL LogonCreateProcess(
PWSTR UserName,
LPCWSTR ApplicationName,
LPWSTR CommandLine,
LPSECURITY_ATTRIBUTES ProcessAttributes,
LPSECURITY_ATTRIBUTES ThreadAttributes,
BOOL InheritHandles,
DWORD CreationFlags,
LPVOID Environment,
LPCWSTR CurrentDirectory,
LPSTARTUPINFOW StartupInfo,
LPPROCESS_INFORMATION ProcessInformation)
{
PWSTR DomainName = 0;
if (0 != UserName)
{
if (0 == invariant_wcsicmp(UserName, L"LocalSystem"))
UserName = 0;
else
if (0 == invariant_wcsicmp(UserName, L"LocalService") ||
0 == invariant_wcsicmp(UserName, L"NetworkService"))
DomainName = L"NT AUTHORITY";
else
{
SetLastError(ERROR_ACCESS_DENIED);
return FALSE;
}
}
if (0 == UserName)
/* without a user name go ahead and call CreateProcessW */
return CreateProcessW(
ApplicationName,
CommandLine,
ProcessAttributes,
ThreadAttributes,
InheritHandles,
CreationFlags,
Environment,
CurrentDirectory,
StartupInfo,
ProcessInformation);
HANDLE LogonToken = 0;
PVOID EnvironmentBlock = 0;
DWORD LastError;
BOOL Success;
Success = LogonUserW(
UserName,
DomainName,
0,
LOGON32_LOGON_SERVICE,
LOGON32_PROVIDER_DEFAULT,
&LogonToken);
if (!Success)
goto exit;
if (0 == Environment)
{
Success = CreateEnvironmentBlock(&EnvironmentBlock, LogonToken, FALSE);
if (!Success)
goto exit;
CreationFlags |= CREATE_UNICODE_ENVIRONMENT;
Environment = EnvironmentBlock;
}
Success = ImpersonateLoggedOnUser(LogonToken);
if (!Success)
goto exit;
Success = CreateProcessAsUserW(
LogonToken,
ApplicationName,
CommandLine,
ProcessAttributes,
ThreadAttributes,
InheritHandles,
CreationFlags,
Environment,
CurrentDirectory,
StartupInfo,
ProcessInformation);
if (!RevertToSelf())
/* should not happen! */
ExitProcess(GetLastError());
exit:
if (!Success)
LastError = GetLastError();
if (0 != EnvironmentBlock)
DestroyEnvironmentBlock(EnvironmentBlock);
if (0 != LogonToken)
CloseHandle(LogonToken);
if (!Success)
SetLastError(LastError);
return Success;
}
typedef struct typedef struct
{ {
HANDLE Process; HANDLE Process;
@ -75,7 +362,7 @@ typedef struct
static VOID CALLBACK KillProcessWait(PVOID Context, BOOLEAN Timeout); static VOID CALLBACK KillProcessWait(PVOID Context, BOOLEAN Timeout);
VOID KillProcess(ULONG ProcessId, HANDLE Process, ULONG Timeout) static VOID KillProcess(ULONG ProcessId, HANDLE Process, ULONG Timeout)
{ {
if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, ProcessId)) if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, ProcessId))
{ {
@ -124,6 +411,11 @@ static VOID CALLBACK KillProcessWait(PVOID Context, BOOLEAN Timeout)
MemFree(KillProcessData); MemFree(KillProcessData);
} }
#define LAUNCHER_PIPE_DEFAULT_TIMEOUT (2 * 15000 + 1000)
#define LAUNCHER_START_WITH_SECRET_TIMEOUT 15000
#define LAUNCHER_STOP_TIMEOUT 5500
#define LAUNCHER_KILL_TIMEOUT 5000
typedef struct typedef struct
{ {
LONG RefCount; LONG RefCount;
@ -142,6 +434,17 @@ typedef struct
static CRITICAL_SECTION SvcInstanceLock; static CRITICAL_SECTION SvcInstanceLock;
static HANDLE SvcInstanceEvent; static HANDLE SvcInstanceEvent;
static LIST_ENTRY SvcInstanceList = { &SvcInstanceList, &SvcInstanceList }; static LIST_ENTRY SvcInstanceList = { &SvcInstanceList, &SvcInstanceList };
static DWORD SvcInstanceTlsKey = TLS_OUT_OF_INDEXES;
static inline PWSTR SvcInstanceUserName(VOID)
{
return TlsGetValue(SvcInstanceTlsKey);
}
static inline VOID SvcInstanceSetUserName(PWSTR UserName)
{
TlsSetValue(SvcInstanceTlsKey, UserName);
}
static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Timeout); static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Timeout);
@ -210,6 +513,14 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
else else
Length += SvcInstanceArgumentLength(EmptyArg); Length += SvcInstanceArgumentLength(EmptyArg);
} }
else
if (L'U' == *P)
{
if (0 != SvcInstanceUserName())
Length += SvcInstanceArgumentLength(SvcInstanceUserName());
else
Length += SvcInstanceArgumentLength(EmptyArg);
}
else else
Length++; Length++;
break; break;
@ -236,6 +547,14 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
else else
Q = SvcInstanceArgumentCopy(Q, EmptyArg); Q = SvcInstanceArgumentCopy(Q, EmptyArg);
} }
else
if (L'U' == *P)
{
if (0 != SvcInstanceUserName())
Q = SvcInstanceArgumentCopy(Q, SvcInstanceUserName());
else
Q = SvcInstanceArgumentCopy(Q, EmptyArg);
}
else else
*Q++ = *P; *Q++ = *P;
break; break;
@ -251,6 +570,67 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS SvcInstanceAddUserRights(HANDLE Token,
PSECURITY_DESCRIPTOR SecurityDescriptor, PSECURITY_DESCRIPTOR *PNewSecurityDescriptor)
{
PSECURITY_DESCRIPTOR NewSecurityDescriptor;
TOKEN_USER *User = 0;
EXPLICIT_ACCESSW AccessEntry;
DWORD Size, LastError;
NTSTATUS Result;
*PNewSecurityDescriptor = 0;
if (GetTokenInformation(Token, TokenUser, 0, 0, &Size))
{
Result = STATUS_INVALID_PARAMETER;
goto exit;
}
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
User = MemAlloc(Size);
if (0 == User)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenUser, User, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
AccessEntry.grfAccessPermissions = SERVICE_QUERY_STATUS | SERVICE_STOP;
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 = User->User.Sid;
LastError = BuildSecurityDescriptorW(0, 0, 1, &AccessEntry, 0, 0, SecurityDescriptor,
&Size, &NewSecurityDescriptor);
if (0 != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
*PNewSecurityDescriptor = NewSecurityDescriptor;
Result = STATUS_SUCCESS;
exit:
MemFree(User);
return Result;
}
static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess, static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess,
PSECURITY_DESCRIPTOR SecurityDescriptor) PSECURITY_DESCRIPTOR SecurityDescriptor)
{ {
@ -279,18 +659,35 @@ static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess,
return Result; return Result;
} }
NTSTATUS SvcInstanceCreateProcess(PWSTR Executable, PWSTR CommandLine, static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName,
PWSTR Executable, PWSTR CommandLine, PWSTR WorkDirectory,
HANDLE StdioHandles[2], HANDLE StdioHandles[2],
PPROCESS_INFORMATION ProcessInfo) PPROCESS_INFORMATION ProcessInfo)
{ {
WCHAR WorkDirectoryBuf[MAX_PATH];
STARTUPINFOEXW StartupInfoEx; STARTUPINFOEXW StartupInfoEx;
HANDLE ChildHandles[3] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0/* DO NOT CLOSE!*/ }; HANDLE ChildHandles[3] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0/* DO NOT CLOSE!*/ };
HANDLE ParentHandles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; HANDLE ParentHandles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
SECURITY_ATTRIBUTES PipeAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, TRUE };
PPROC_THREAD_ATTRIBUTE_LIST AttrList = 0; PPROC_THREAD_ATTRIBUTE_LIST AttrList = 0;
SIZE_T Size; SIZE_T Size;
NTSTATUS Result; NTSTATUS Result;
if (0 != WorkDirectory && L'.' == WorkDirectory[0] && L'\0' == WorkDirectory[1])
{
PWSTR Backslash = 0, P;
if (0 == GetModuleFileNameW(0, WorkDirectoryBuf, MAX_PATH))
return FspNtStatusFromWin32(GetLastError());
for (P = WorkDirectoryBuf; *P; P++)
if (L'\\' == *P)
Backslash = P;
if (0 != Backslash && WorkDirectoryBuf < Backslash && L':' != Backslash[-1])
*Backslash = L'\0';
WorkDirectory = WorkDirectoryBuf;
}
memset(&StartupInfoEx, 0, sizeof StartupInfoEx); memset(&StartupInfoEx, 0, sizeof StartupInfoEx);
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo; StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo;
@ -304,16 +701,16 @@ NTSTATUS SvcInstanceCreateProcess(PWSTR Executable, PWSTR CommandLine,
*/ */
/* create stdin read/write ends; make them inheritable */ /* create stdin read/write ends; make them inheritable */
if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0], &PipeAttributes, 0, if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0],
0, 0)) 0, TRUE, FALSE, 0, 0))
{ {
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());
goto exit; goto exit;
} }
/* create stdout read/write ends; make them inheritable */ /* create stdout read/write ends; make them inheritable */
if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1], &PipeAttributes, 0, if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1],
FILE_FLAG_OVERLAPPED, 0)) 0, FALSE, TRUE, FILE_FLAG_OVERLAPPED, 0))
{ {
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());
goto exit; goto exit;
@ -357,18 +754,44 @@ NTSTATUS SvcInstanceCreateProcess(PWSTR Executable, PWSTR CommandLine,
StartupInfoEx.StartupInfo.hStdOutput = ChildHandles[1]; StartupInfoEx.StartupInfo.hStdOutput = ChildHandles[1];
StartupInfoEx.StartupInfo.hStdError = ChildHandles[2]; StartupInfoEx.StartupInfo.hStdError = ChildHandles[2];
if (!CreateProcessW(Executable, CommandLine, 0, 0, TRUE, if (!LogonCreateProcess(UserName,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT, 0, 0, Executable, CommandLine, 0, 0, TRUE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT,
0, WorkDirectory,
&StartupInfoEx.StartupInfo, ProcessInfo)) &StartupInfoEx.StartupInfo, ProcessInfo))
{ {
Result = FspNtStatusFromWin32(GetLastError()); if (ERROR_NO_SYSTEM_RESOURCES != GetLastError())
goto exit; {
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
/*
* On Win7 CreateProcessW with EXTENDED_STARTUPINFO_PRESENT
* may fail with ERROR_NO_SYSTEM_RESOURCES.
*
* In that case go ahead and retry with a CreateProcessW with
* bInheritHandles==TRUE, but without EXTENDED_STARTUPINFO_PRESENT.
* Not ideal, but...
*/
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo;
if (!LogonCreateProcess(UserName,
Executable, CommandLine, 0, 0, TRUE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP,
0, WorkDirectory,
&StartupInfoEx.StartupInfo, ProcessInfo))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
} }
} }
else else
{ {
if (!CreateProcessW(Executable, CommandLine, 0, 0, FALSE, if (!LogonCreateProcess(UserName,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP, 0, 0, Executable, CommandLine, 0, 0, FALSE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP,
0, WorkDirectory,
&StartupInfoEx.StartupInfo, ProcessInfo)) &StartupInfoEx.StartupInfo, ProcessInfo))
{ {
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());
@ -411,10 +834,11 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
HKEY RegKey = 0; HKEY RegKey = 0;
DWORD RegResult, RegSize; DWORD RegResult, RegSize;
DWORD ClassNameSize, InstanceNameSize; DWORD ClassNameSize, InstanceNameSize;
WCHAR Executable[MAX_PATH], CommandLineBuf[512], SecurityBuf[512]; WCHAR Executable[MAX_PATH], CommandLineBuf[512], WorkDirectory[MAX_PATH],
SecurityBuf[512], RunAsBuf[64];
PWSTR CommandLine, Security; PWSTR CommandLine, Security;
DWORD JobControl, Credentials; DWORD JobControl, Credentials;
PSECURITY_DESCRIPTOR SecurityDescriptor = 0; PSECURITY_DESCRIPTOR SecurityDescriptor = 0, NewSecurityDescriptor;
PWSTR Argv[10]; PWSTR Argv[10];
PROCESS_INFORMATION ProcessInfo; PROCESS_INFORMATION ProcessInfo;
NTSTATUS Result; NTSTATUS Result;
@ -440,8 +864,8 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
goto exit; goto exit;
} }
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY, RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" FSP_LAUNCH_REGKEY,
0, LAUNCHER_REGKEY_WOW64 | KEY_READ, &RegKey); 0, FSP_LAUNCH_REGKEY_WOW64 | KEY_READ, &RegKey);
if (ERROR_SUCCESS != RegResult) if (ERROR_SUCCESS != RegResult)
{ {
Result = FspNtStatusFromWin32(RegResult); Result = FspNtStatusFromWin32(RegResult);
@ -488,6 +912,16 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
CommandLine[-1] = L'\0'; CommandLine[-1] = L'\0';
CommandLine = CommandLineBuf; CommandLine = CommandLineBuf;
RegSize = sizeof WorkDirectory;
WorkDirectory[0] = L'\0';
RegResult = RegGetValueW(RegKey, ClassName, L"WorkDirectory", RRF_RT_REG_SZ, 0,
WorkDirectory, &RegSize);
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);
goto exit;
}
Security = SecurityBuf + lstrlenW(SecurityBuf); Security = SecurityBuf + lstrlenW(SecurityBuf);
RegSize = (DWORD)(sizeof SecurityBuf - (Security - SecurityBuf) * sizeof(WCHAR)); RegSize = (DWORD)(sizeof SecurityBuf - (Security - SecurityBuf) * sizeof(WCHAR));
RegResult = RegGetValueW(RegKey, ClassName, L"Security", RRF_RT_REG_SZ, 0, RegResult = RegGetValueW(RegKey, ClassName, L"Security", RRF_RT_REG_SZ, 0,
@ -498,6 +932,16 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
goto exit; goto exit;
} }
RegSize = sizeof RunAsBuf;
RunAsBuf[0] = L'\0';
RegResult = RegGetValueW(RegKey, ClassName, L"RunAs", RRF_RT_REG_SZ, 0,
RunAsBuf, &RegSize);
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);
goto exit;
}
RegSize = sizeof JobControl; RegSize = sizeof JobControl;
JobControl = 1; /* default is YES! */ JobControl = 1; /* default is YES! */
RegResult = RegGetValueW(RegKey, ClassName, L"JobControl", RRF_RT_REG_DWORD, 0, RegResult = RegGetValueW(RegKey, ClassName, L"JobControl", RRF_RT_REG_DWORD, 0,
@ -512,7 +956,7 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
RegKey = 0; RegKey = 0;
if (L'\0' == Security[0]) if (L'\0' == Security[0])
lstrcpyW(Security, L"" SVC_INSTANCE_DEFAULT_SDDL); lstrcpyW(Security, L"" FSP_LAUNCH_SERVICE_DEFAULT_SDDL);
if (L'D' == Security[0] && L':' == Security[1]) if (L'D' == Security[0] && L':' == Security[1])
Security = SecurityBuf; Security = SecurityBuf;
@ -529,6 +973,14 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
Result = SvcInstanceAddUserRights(ClientToken, SecurityDescriptor, &NewSecurityDescriptor);
if (!NT_SUCCESS(Result))
goto exit;
LocalFree(SecurityDescriptor);
SecurityDescriptor = NewSecurityDescriptor;
//FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityDescriptor);
ClassNameSize = (lstrlenW(ClassName) + 1) * sizeof(WCHAR); ClassNameSize = (lstrlenW(ClassName) + 1) * sizeof(WCHAR);
InstanceNameSize = (lstrlenW(InstanceName) + 1) * sizeof(WCHAR); InstanceNameSize = (lstrlenW(InstanceName) + 1) * sizeof(WCHAR);
@ -553,7 +1005,8 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
Result = SvcInstanceCreateProcess(Executable, SvcInstance->CommandLine, Result = SvcInstanceCreateProcess(L'\0' != RunAsBuf[0] ? RunAsBuf : 0,
Executable, SvcInstance->CommandLine, L'\0' != WorkDirectory[0] ? WorkDirectory : 0,
RedirectStdio ? SvcInstance->StdioHandles : 0, &ProcessInfo); RedirectStdio ? SvcInstance->StdioHandles : 0, &ProcessInfo);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
@ -624,6 +1077,9 @@ exit:
LeaveCriticalSection(&SvcInstanceLock); LeaveCriticalSection(&SvcInstanceLock);
FspServiceLog(EVENTLOG_INFORMATION_TYPE,
L"create %s\\%s = %lx", ClassName, InstanceName, Result);
return Result; return Result;
} }
@ -657,6 +1113,9 @@ static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Timeout)
{ {
SVC_INSTANCE *SvcInstance = Context; SVC_INSTANCE *SvcInstance = Context;
FspServiceLog(EVENTLOG_INFORMATION_TYPE,
L"terminated %s\\%s", SvcInstance->ClassName, SvcInstance->InstanceName);
SvcInstanceRelease(SvcInstance); SvcInstanceRelease(SvcInstance);
} }
@ -752,6 +1211,10 @@ exit:
SvcInstanceRelease(SvcInstance); SvcInstanceRelease(SvcInstance);
if (STATUS_TIMEOUT == Result)
/* convert to an error! */
Result = 0x80070000 | ERROR_TIMEOUT;
return Result; return Result;
} }
@ -885,6 +1348,53 @@ NTSTATUS SvcInstanceStopAndWaitAll(VOID)
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS SvcDefineDosDevice(HANDLE ClientToken,
PWSTR DeviceName, PWSTR TargetPath)
{
NTSTATUS Result;
if (L'+' != DeviceName[0] && L'-' != DeviceName[0])
return STATUS_INVALID_PARAMETER;
Result = FspServiceContextCheck(ClientToken, 0);
if (!NT_SUCCESS(Result))
return Result;
if (!DefineDosDeviceW(
DDD_RAW_TARGET_PATH |
(L'+' == DeviceName[0] ? 0 : DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE),
DeviceName + 1, TargetPath))
return FspNtStatusFromWin32(GetLastError());
if (L'+' == DeviceName[0] && 0 != SvcNtOpenSymbolicLinkObject)
{
/* The drive symlink now exists; add DELETE access to it for the ClientToken. */
WCHAR SymlinkBuf[6];
UNICODE_STRING Symlink;
OBJECT_ATTRIBUTES Obja;
HANDLE MountHandle;
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
SymlinkBuf[4] = DeviceName[1];
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 = SvcNtOpenSymbolicLinkObject(&MountHandle, READ_CONTROL | WRITE_DAC, &Obja);
if (NT_SUCCESS(Result))
{
AddAccessForTokenUser(MountHandle, DELETE, ClientToken);
SvcNtClose(MountHandle);
}
}
return STATUS_SUCCESS;
}
static HANDLE SvcJob, SvcThread, SvcEvent; static HANDLE SvcJob, SvcThread, SvcEvent;
static DWORD SvcThreadId; static DWORD SvcThreadId;
static HANDLE SvcPipe = INVALID_HANDLE_VALUE; static HANDLE SvcPipe = INVALID_HANDLE_VALUE;
@ -908,7 +1418,7 @@ static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
SecurityAttributes.nLength = sizeof SecurityAttributes; SecurityAttributes.nLength = sizeof SecurityAttributes;
SecurityAttributes.bInheritHandle = FALSE; SecurityAttributes.bInheritHandle = FALSE;
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(L"" LAUNCHER_PIPE_SDDL, SDDL_REVISION_1, if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(L"" FSP_LAUNCH_PIPE_SDDL, SDDL_REVISION_1,
&SecurityAttributes.lpSecurityDescriptor, 0)) &SecurityAttributes.lpSecurityDescriptor, 0))
goto fail; goto fail;
@ -918,6 +1428,10 @@ static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
if (0 == SvcInstanceEvent) if (0 == SvcInstanceEvent)
goto fail; goto fail;
SvcInstanceTlsKey = TlsAlloc();
if (TLS_OUT_OF_INDEXES == SvcInstanceTlsKey)
goto fail;
SvcJob = CreateJobObjectW(0, 0); SvcJob = CreateJobObjectW(0, 0);
if (0 != SvcJob) if (0 != SvcJob)
{ {
@ -941,11 +1455,11 @@ static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
if (0 == SvcOverlapped.hEvent) if (0 == SvcOverlapped.hEvent)
goto fail; goto fail;
SvcPipe = CreateNamedPipeW(L"" LAUNCHER_PIPE_NAME, SvcPipe = CreateNamedPipeW(L"" FSP_LAUNCH_PIPE_NAME,
PIPE_ACCESS_DUPLEX | PIPE_ACCESS_DUPLEX |
FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
1, LAUNCHER_PIPE_BUFFER_SIZE, LAUNCHER_PIPE_BUFFER_SIZE, LAUNCHER_PIPE_DEFAULT_TIMEOUT, 1, FSP_LAUNCH_PIPE_BUFFER_SIZE, FSP_LAUNCH_PIPE_BUFFER_SIZE, LAUNCHER_PIPE_DEFAULT_TIMEOUT,
&SecurityAttributes); &SecurityAttributes);
if (INVALID_HANDLE_VALUE == SvcPipe) if (INVALID_HANDLE_VALUE == SvcPipe)
goto fail; goto fail;
@ -980,6 +1494,9 @@ fail:
if (0 != SvcJob) if (0 != SvcJob)
CloseHandle(SvcJob); CloseHandle(SvcJob);
if (TLS_OUT_OF_INDEXES != SvcInstanceTlsKey)
TlsFree(SvcInstanceTlsKey);
if (0 != SvcInstanceEvent) if (0 != SvcInstanceEvent)
CloseHandle(SvcInstanceEvent); CloseHandle(SvcInstanceEvent);
@ -1023,6 +1540,9 @@ static NTSTATUS SvcStop(FSP_SERVICE *Service)
if (0 != SvcJob) if (0 != SvcJob)
CloseHandle(SvcJob); CloseHandle(SvcJob);
if (TLS_OUT_OF_INDEXES != SvcInstanceTlsKey)
TlsFree(SvcInstanceTlsKey);
if (0 != SvcInstanceEvent) if (0 != SvcInstanceEvent)
CloseHandle(SvcInstanceEvent); CloseHandle(SvcInstanceEvent);
@ -1067,7 +1587,7 @@ static DWORD WINAPI SvcPipeServer(PVOID Context)
HANDLE ClientToken; HANDLE ClientToken;
DWORD LastError, BytesTransferred; DWORD LastError, BytesTransferred;
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE); PipeBuf = MemAlloc(FSP_LAUNCH_PIPE_BUFFER_SIZE);
if (0 == PipeBuf) if (0 == PipeBuf)
{ {
FspServiceSetExitCode(Service, ERROR_NO_SYSTEM_RESOURCES); FspServiceSetExitCode(Service, ERROR_NO_SYSTEM_RESOURCES);
@ -1090,7 +1610,7 @@ static DWORD WINAPI SvcPipeServer(PVOID Context)
} }
LastError = SvcPipeWaitResult( LastError = SvcPipeWaitResult(
ReadFile(SvcPipe, PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, &BytesTransferred, &SvcOverlapped), ReadFile(SvcPipe, PipeBuf, FSP_LAUNCH_PIPE_BUFFER_SIZE, &BytesTransferred, &SvcOverlapped),
SvcEvent, SvcPipe, &SvcOverlapped, &BytesTransferred); SvcEvent, SvcPipe, &SvcOverlapped, &BytesTransferred);
if (-1 == LastError) if (-1 == LastError)
break; break;
@ -1180,11 +1700,11 @@ static inline VOID SvcPipeTransactResult(NTSTATUS Result, PWSTR PipeBuf, PULONG
{ {
if (NT_SUCCESS(Result)) if (NT_SUCCESS(Result))
{ {
*PipeBuf = LauncherSuccess; *PipeBuf = FspLaunchCmdSuccess;
*PSize += sizeof(WCHAR); *PSize += sizeof(WCHAR);
} }
else else
*PSize = (wsprintfW(PipeBuf, L"%c%ld", LauncherFailure, FspWin32FromNtStatus(Result)) + 1) * *PSize = (wsprintfW(PipeBuf, L"%c%ld", FspLaunchCmdFailure, FspWin32FromNtStatus(Result)) + 1) *
sizeof(WCHAR); sizeof(WCHAR);
} }
@ -1194,19 +1714,23 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
return; return;
PWSTR P = PipeBuf, PipeBufEnd = PipeBuf + *PSize / sizeof(WCHAR); PWSTR P = PipeBuf, PipeBufEnd = PipeBuf + *PSize / sizeof(WCHAR);
PWSTR ClassName, InstanceName; PWSTR ClassName, InstanceName, UserName;
PWSTR DeviceName, TargetPath;
ULONG Argc; PWSTR Argv[9]; ULONG Argc; PWSTR Argv[9];
BOOLEAN HasSecret = FALSE; BOOLEAN HasSecret = FALSE;
NTSTATUS Result; NTSTATUS Result;
*PSize = 0; *PSize = 0;
GetTokenUserName(ClientToken, &UserName);
SvcInstanceSetUserName(UserName);
switch (*P++) switch (*P++)
{ {
case LauncherSvcInstanceStartWithSecret: case FspLaunchCmdStartWithSecret:
HasSecret = TRUE; HasSecret = TRUE;
/* fall through! */ /* fall through! */
case LauncherSvcInstanceStart: case FspLaunchCmdStart:
ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd); ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd);
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd); InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
for (Argc = 0; sizeof Argv / sizeof Argv[0] > Argc; Argc++) for (Argc = 0; sizeof Argv / sizeof Argv[0] > Argc; Argc++)
@ -1221,7 +1745,7 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
SvcPipeTransactResult(Result, PipeBuf, PSize); SvcPipeTransactResult(Result, PipeBuf, PSize);
break; break;
case LauncherSvcInstanceStop: case FspLaunchCmdStop:
ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd); ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd);
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd); InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
@ -1232,29 +1756,40 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
SvcPipeTransactResult(Result, PipeBuf, PSize); SvcPipeTransactResult(Result, PipeBuf, PSize);
break; break;
case LauncherSvcInstanceInfo: case FspLaunchCmdGetInfo:
ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd); ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd);
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd); InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
Result = STATUS_INVALID_PARAMETER; Result = STATUS_INVALID_PARAMETER;
if (0 != ClassName && 0 != InstanceName) if (0 != ClassName && 0 != InstanceName)
{ {
*PSize = LAUNCHER_PIPE_BUFFER_SIZE - 1; *PSize = FSP_LAUNCH_PIPE_BUFFER_SIZE - 1;
Result = SvcInstanceGetInfo(ClientToken, ClassName, InstanceName, PipeBuf + 1, PSize); Result = SvcInstanceGetInfo(ClientToken, ClassName, InstanceName, PipeBuf + 1, PSize);
} }
SvcPipeTransactResult(Result, PipeBuf, PSize); SvcPipeTransactResult(Result, PipeBuf, PSize);
break; break;
case LauncherSvcInstanceList: case FspLaunchCmdGetNameList:
*PSize = LAUNCHER_PIPE_BUFFER_SIZE - 1; *PSize = FSP_LAUNCH_PIPE_BUFFER_SIZE - 1;
Result = SvcInstanceGetNameList(ClientToken, PipeBuf + 1, PSize); Result = SvcInstanceGetNameList(ClientToken, PipeBuf + 1, PSize);
SvcPipeTransactResult(Result, PipeBuf, PSize); SvcPipeTransactResult(Result, PipeBuf, PSize);
break; break;
case FspLaunchCmdDefineDosDevice:
DeviceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
TargetPath = SvcPipeTransactGetPart(&P, PipeBufEnd);
Result = STATUS_INVALID_PARAMETER;
if (0 != DeviceName && 0 != TargetPath)
Result = SvcDefineDosDevice(ClientToken, DeviceName, TargetPath);
SvcPipeTransactResult(Result, PipeBuf, PSize);
break;
#if !defined(NDEBUG) #if !defined(NDEBUG)
case LauncherQuit: case FspLaunchCmdQuit:
SetEvent(SvcEvent); SetEvent(SvcEvent);
SvcPipeTransactResult(STATUS_SUCCESS, PipeBuf, PSize); SvcPipeTransactResult(STATUS_SUCCESS, PipeBuf, PSize);
@ -1264,10 +1799,26 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
SvcPipeTransactResult(STATUS_INVALID_PARAMETER, PipeBuf, PSize); SvcPipeTransactResult(STATUS_INVALID_PARAMETER, PipeBuf, PSize);
break; break;
} }
SvcInstanceSetUserName(0);
MemFree(UserName);
} }
int wmain(int argc, wchar_t **argv) int wmain(int argc, wchar_t **argv)
{ {
HANDLE Handle = GetModuleHandleW(L"ntdll.dll");
if (0 != Handle)
{
SvcNtOpenSymbolicLinkObject = (PVOID)GetProcAddress(Handle, "NtOpenSymbolicLinkObject");
SvcNtClose = (PVOID)GetProcAddress(Handle, "NtClose");
if (0 == SvcNtOpenSymbolicLinkObject || 0 == SvcNtClose)
{
SvcNtOpenSymbolicLinkObject = 0;
SvcNtClose = 0;
}
}
return FspServiceRun(L"" PROGNAME, SvcStart, SvcStop, 0); return FspServiceRun(L"" PROGNAME, SvcStart, SvcStop, 0);
} }

View File

@ -1,71 +0,0 @@
/**
* @file launcher/launcher.h
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#ifndef WINFSP_LAUNCHER_LAUNCHER_H_INCLUDED
#define WINFSP_LAUNCHER_LAUNCHER_H_INCLUDED
#include <winfsp/winfsp.h>
#include <shared/minimal.h>
#define LAUNCHER_REGKEY "Software\\WinFsp\\Services"
#define LAUNCHER_REGKEY_WOW64 KEY_WOW64_32KEY
#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

View File

@ -1,7 +1,7 @@
/** /**
* @file shared/minimal.h * @file shared/minimal.h
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.

View File

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

View File

@ -1,7 +1,7 @@
/** /**
* @file sys/cleanup.c * @file sys/cleanup.c
* *
* @copyright 2015-2017 Bill Zissimopoulos * @copyright 2015-2018 Bill Zissimopoulos
*/ */
/* /*
* This file is part of WinFsp. * This file is part of WinFsp.
@ -123,6 +123,8 @@ static NTSTATUS FspFsvolCleanup(
FspFileNodeSetOwner(FileNode, Full, Request); FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp; FspIopRequestContext(Request, RequestIrp) = Irp;
FspFileNodeCleanupFlush(FileNode, FileObject);
if (Request->Req.Cleanup.Delete || if (Request->Req.Cleanup.Delete ||
Request->Req.Cleanup.SetAllocationSize || Request->Req.Cleanup.SetAllocationSize ||
Request->Req.Cleanup.SetArchiveBit || Request->Req.Cleanup.SetArchiveBit ||

View File

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

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