Compare commits
467 Commits
Author | SHA1 | Date | |
---|---|---|---|
a2ec40008f | |||
f3819ba839 | |||
ead599e337 | |||
eb88f25f40 | |||
c2b066a054 | |||
266e0f4bab | |||
d02030897d | |||
c87ff75b8f | |||
2ca33665ef | |||
391dcf8a21 | |||
69d68eb22f | |||
d58f4b84a5 | |||
61935e4671 | |||
41838627c0 | |||
0b67329fc2 | |||
5c962c8fc5 | |||
a9080208d9 | |||
3cc9697248 | |||
9f45d513ca | |||
77349c1330 | |||
7c11a45e6e | |||
48ad297df1 | |||
3d2de57e9d | |||
658d873efb | |||
efc93cacd3 | |||
41b54ef57a | |||
fd662ee848 | |||
895bf67691 | |||
e06fe4153d | |||
9f2fe92db7 | |||
d3f829b2df | |||
fa4651b3ce | |||
5a44e5c04a | |||
68122b5c68 | |||
b672312c79 | |||
0ab35fde1a | |||
9be2b7a2b9 | |||
39dd7662bd | |||
244afc8a3c | |||
111955db84 | |||
76ff8232bc | |||
9a3ac3c7a1 | |||
4adc0d4700 | |||
91c714dd53 | |||
11cb57a0bf | |||
3a8ad9c8d7 | |||
fa388e57ad | |||
1952d0d941 | |||
1a02438488 | |||
07f15c236b | |||
93af1be861 | |||
b52c90f980 | |||
b154c307b7 | |||
697063af51 | |||
436e31da34 | |||
92e7dbad21 | |||
4812f5bbd0 | |||
045a1fa19c | |||
c9b2c0460b | |||
1468df78a2 | |||
0fb6299f17 | |||
0da43fe2d4 | |||
d824ba464d | |||
affca267c5 | |||
4b7684122b | |||
55eee2efdd | |||
f8a05eae95 | |||
9a4f04f46a | |||
98334208b9 | |||
aae0a5bc74 | |||
2438ece1cf | |||
487d2449fe | |||
6430b386da | |||
c70089a176 | |||
0dff9a4c07 | |||
86c0ffa942 | |||
5c613b2abd | |||
8a099f3faa | |||
1ac172d2f8 | |||
34546def3c | |||
3ede1a5c70 | |||
5194536ec3 | |||
c39bc81299 | |||
18bf6ca666 | |||
7eebdbd74e | |||
9a88791f61 | |||
6e578350f4 | |||
81afac9c3a | |||
10081e1a69 | |||
8e5c40bbbe | |||
7745bf4cdc | |||
c7a779fa98 | |||
3f90d60dc4 | |||
f73cbc0e37 | |||
c88a86f7c7 | |||
dbdbdf07cf | |||
6b2dcaef96 | |||
fcae6ce018 | |||
690d3e4c8e | |||
af37424ecc | |||
fd53e22f7e | |||
3df0fa02ba | |||
9484b50cbd | |||
14e6b402fe | |||
2227429d8e | |||
9deb9d5319 | |||
193d5f4e91 | |||
26485ffbd6 | |||
7302b4baea | |||
fc1586eb82 | |||
637f461a65 | |||
b35bf204db | |||
3073646f29 | |||
7f9f55de24 | |||
bb3f8d37f2 | |||
c72a9f2a05 | |||
9b4ab190e0 | |||
010ed909ec | |||
2b4549a50d | |||
98a329e81b | |||
8090b7c666 | |||
c7d720eaa0 | |||
8320160d73 | |||
ce057b49b8 | |||
a60c989089 | |||
0f6371f0d8 | |||
1a4bbbe09a | |||
4e891dc2a8 | |||
18a77d63c3 | |||
4ea9c6e362 | |||
9d77c192a8 | |||
6d5401d911 | |||
330d6e79f8 | |||
ed58b7a63c | |||
f6853114c1 | |||
8ec7285d32 | |||
c183c0fe89 | |||
38ad8fd27d | |||
de85070e73 | |||
5b8ebd6e1d | |||
db530cb5e5 | |||
7cd4d4faab | |||
2560a513dc | |||
1ee95be5d7 | |||
bd7546559c | |||
d18a2c8b75 | |||
0ebae0adc1 | |||
d70c49ccd0 | |||
5846939116 | |||
f124e74f01 | |||
05abb93e4b | |||
5839d46b7a | |||
bce0d63f7d | |||
14b9f5affc | |||
035a430470 | |||
0af9e46e76 | |||
c4530f1252 | |||
9f78a17583 | |||
eea0b1bc79 | |||
8338a6e066 | |||
ddba49dbea | |||
a6ff8a87de | |||
bf64bcf9ba | |||
8c5d9bda20 | |||
f1ac28b0aa | |||
ff725f931d | |||
31519ba416 | |||
0bca8f851c | |||
acf175da60 | |||
23eac24c84 | |||
0f9ef3bd51 | |||
2bdd54536e | |||
060ebcca0d | |||
b38a89e485 | |||
b5bfeee027 | |||
f36cacaf84 | |||
4278cec465 | |||
151627091b | |||
2ee3f02928 | |||
d77d3ccccf | |||
1e0c91658e | |||
568096b560 | |||
b2e175a991 | |||
757c4f151d | |||
8b71e18972 | |||
4e7f988371 | |||
eb04d7ab90 | |||
d6c3b7304d | |||
1ee563cd13 | |||
8787f2c528 | |||
4c102ab57c | |||
bf87c539fd | |||
d5802f3a5f | |||
c144d4d303 | |||
9770efde14 | |||
197ce7c30a | |||
5d8384a508 | |||
8bb46a5f86 | |||
a3087cb696 | |||
92b1a8c00d | |||
bbf641e721 | |||
539ab9ce63 | |||
a29390412b | |||
739eb80cfb | |||
f9a470a0f0 | |||
44358e118c | |||
2a7ee146f1 | |||
0ddeb02235 | |||
26d8ea1c1c | |||
fa4aaf2fb7 | |||
7645a0185b | |||
dcf38cdf08 | |||
c7ca500dd5 | |||
d9fcc8ca1c | |||
259f2bf1c1 | |||
67711082b0 | |||
f2d98bbf25 | |||
e40505adb5 | |||
ac7b7f4a1b | |||
aa53b1e5ef | |||
c4b73c8eda | |||
332bce6322 | |||
5ef1de2647 | |||
de60e76b1d | |||
8f8e8fe086 | |||
0ac9a83026 | |||
b8c97caec0 | |||
f9b8bfc020 | |||
f938bf5e3f | |||
a0df9babf9 | |||
0d9d8ef5a2 | |||
668948ebc1 | |||
83c9351d38 | |||
aa1e32494c | |||
6365a553dc | |||
1245a29be6 | |||
c79785c2db | |||
f117a89697 | |||
33f5b8c05b | |||
9a02a46cf4 | |||
4d6fc3c848 | |||
964f2eed69 | |||
b45cff2881 | |||
f219885939 | |||
0cfc730745 | |||
a3643f8b02 | |||
de61eaf6b8 | |||
075a2b6e4c | |||
37affbf572 | |||
20b3ecd0cd | |||
c782c4d668 | |||
d545b8df26 | |||
08e520e0ec | |||
a5db7a2cca | |||
74c2494bbd | |||
858f77cdf7 | |||
30dae34700 | |||
36d50facd7 | |||
55dd8797d8 | |||
27114184d2 | |||
1980f511ce | |||
4cbee05849 | |||
f2391d99d5 | |||
fa9ff37de9 | |||
39b60c1348 | |||
5bc15a7e54 | |||
81bc200fe7 | |||
89324d2327 | |||
47b81a8025 | |||
02cec420e7 | |||
8e7e959d8a | |||
fc51b7cc22 | |||
ff5850847f | |||
ab462fb546 | |||
a5eadc50a7 | |||
afe7f8d728 | |||
c137d49dcd | |||
b70337bac3 | |||
c9b5f25ffc | |||
96f6c28885 | |||
deb8aed91f | |||
fac270e596 | |||
0189adac8f | |||
af772d7a86 | |||
96554cc0ca | |||
ddb3698c89 | |||
9657ae31c3 | |||
0795774e9e | |||
763f256e1f | |||
367f450e30 | |||
7afdee7c01 | |||
87c5f19ce1 | |||
00d1a3176e | |||
6318e7b0ef | |||
5d23b1fef8 | |||
44fe02d2fd | |||
1f0de20b7f | |||
bfd2e106ac | |||
b1848e963f | |||
a29611fa2a | |||
8a369bd48a | |||
9ca7424d27 | |||
4f640755bc | |||
c085a91991 | |||
83cd3cab99 | |||
67dff84a13 | |||
c702a86fbf | |||
f335a990af | |||
ba68ab845b | |||
db0566701e | |||
433e62f813 | |||
6777de6569 | |||
63ee24235b | |||
c3eb46813e | |||
bee0fa79b2 | |||
d907bf2769 | |||
38bcece5ce | |||
193de36301 | |||
c080e86f11 | |||
79811a2faa | |||
b1e287727d | |||
2def18e271 | |||
3ddc2249f6 | |||
709ead9e06 | |||
7c574da261 | |||
0980365082 | |||
ba46d9fef8 | |||
4c0386bf8d | |||
6774c34422 | |||
3215d8e26a | |||
7911f1354f | |||
28f97c2619 | |||
4b43cc590f | |||
441c45c77f | |||
c246acb2d3 | |||
50ed020e16 | |||
12704a3a4a | |||
186f7cd9ee | |||
50830f0bf2 | |||
86025aa30b | |||
31e6f15eaf | |||
5ce6d74e90 | |||
02ffa6afb2 | |||
712870ddd9 | |||
35d1adb360 | |||
3b9f9ce93b | |||
a7c5e4f80c | |||
0b826f04c2 | |||
69d53b7a28 | |||
877bd97ba8 | |||
559b7e80a3 | |||
495c78eb25 | |||
cf69d6a08d | |||
0d95bb9b14 | |||
cf48d19759 | |||
14c602ccd8 | |||
2d45082d80 | |||
25cf527af4 | |||
76d081937e | |||
ccd4bb869c | |||
46d5c98926 | |||
1726ca8ccb | |||
b8c257f996 | |||
53e6894298 | |||
10d1ba707e | |||
c234e2af2a | |||
fa652cdb56 | |||
aeaeba0dd6 | |||
b299027f6e | |||
5edd9eb548 | |||
fbc24bcca9 | |||
4ef6dcb71d | |||
b8f0d08672 | |||
5c82044295 | |||
e3b5426e45 | |||
d34f262c02 | |||
ede72e4c5f | |||
9c4b73dac1 | |||
9ecfc64178 | |||
fbe46d8c81 | |||
2a12ed490d | |||
c6d9e68c3f | |||
bfc41127d0 | |||
6e70500afc | |||
dca3cb93f3 | |||
2f0061b4ba | |||
3fcef3b0fa | |||
6a0574e309 | |||
0c945b67f3 | |||
25b3e111fa | |||
09101129a3 | |||
3700b375a7 | |||
22fccdb575 | |||
c4932f7c7e | |||
303cadb55d | |||
5617d09edc | |||
eefaad241d | |||
11dce32baa | |||
3b8396dc27 | |||
da7082030a | |||
7425eba8af | |||
acf6ce1008 | |||
06f6c192ed | |||
b7a06c7046 | |||
edb675d2d4 | |||
9533815931 | |||
fe74fc4013 | |||
5bd6c1a122 | |||
7b15d32c33 | |||
c186289672 | |||
ff649e05c5 | |||
9a9d3cd4e8 | |||
d1bb65a998 | |||
178200fd63 | |||
396d9d97d2 | |||
1d35069aab | |||
4421c82ce0 | |||
36f0978971 | |||
dae4bad732 | |||
75744571ff | |||
0494726f52 | |||
a964ab1b73 | |||
796010c9fe | |||
dc343ecbe5 | |||
706fa2cc07 | |||
c0aaebd0a5 | |||
9c2b4e5631 | |||
206b85c278 | |||
075d1821a2 | |||
c252382204 | |||
a91e5b01ab | |||
473914d45f | |||
e12e3630bb | |||
960c627924 | |||
f97ef5704f | |||
41605a3d5a | |||
e4f0406c4f | |||
b5bf84b618 | |||
3c340345c0 | |||
63c23f382b | |||
de5ef0c81d | |||
7288605f65 | |||
55a7864173 | |||
4fe72ab332 | |||
76a2926116 | |||
7843c73d34 | |||
ebad86387c | |||
5475c414b3 | |||
e3e111ab27 | |||
9cd6710438 | |||
a5f8736b1e | |||
2ced698256 | |||
53a4bdc478 | |||
eea92e89ef | |||
d519145f61 | |||
2809f56217 | |||
8cb76783ad | |||
117ab9c3e4 | |||
61a001baf1 | |||
d0c700eb0f | |||
b774aea4f4 | |||
f8e4c1bbc4 | |||
3bbff30f14 | |||
2fe4e18d9c | |||
b65322c2ac | |||
7764663386 | |||
c6ae62f301 |
@ -1,6 +1,110 @@
|
||||
= Changelog
|
||||
|
||||
|
||||
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.1B2 (2017.1 B2)::
|
||||
|
||||
v1.1B1 (2017.1 BETA)::
|
||||
|
||||
This release brings some major new components and improvements.
|
||||
|
||||
- A .NET layer that allows the creation of file systems in managed mode. This is contained in the new `winfsp-msil.dll`. The new .NET layer is being tested with the WinFsp test suites and Microsoft's ifstest.
|
||||
- A simple C++ layer can be found in `inc/winfsp/winfsp.hpp`.
|
||||
- FUSE for Cygwin is now included with the installer.
|
||||
- FUSE now has a `-ovolname=VOLNAME` parameter that allows setting the volume label. Thanks @samkelly.
|
||||
|
||||
|
||||
v1.0::
|
||||
|
||||
This is the WinFsp 2017 release! :tada:
|
||||
|
||||
- The API is now *FROZEN*. Breaking API changes will receive a major version update (`2.0`). Incremental API changes will receive a minor version update (`1.x`).
|
||||
- Adds chocolatey package. Try `choco install winfsp` (note: pending approval from chocolatey.org).
|
||||
- FUSE `-d` output now always goes to stderr. There is also a new `-oDebugLog=FILE` switch to specify a debug output file.
|
||||
- FUSE now provides a default `statfs` implementation if a file system does not provide one.
|
||||
- The WinFsp DLL now exports `fuse_*` symbols in addition to the `fsp_fuse_*` symbols. These symbols are for use with programs that use FFI technology such as jnr-fuse and fusepy *ONLY*. They are not supposed to be used by native C/C++ programs. Such programs are supposed to include the `<fuse.h>` headers.
|
||||
|
||||
|
||||
v1.0RC3::
|
||||
|
||||
This is the WinFsp 2017 Release Candidate 3, which should be the last Release Candidate according to the current plan. This release fixes a major issue with some file systems and includes a few smaller changes:
|
||||
|
||||
- Fixes GitHub issue #55. Prior to this fix it was possible for a rogue process (or faulty file system) to crash Windows using WinFsp. For full details read http://www.osronline.com/showthread.cfm?link=282037[this thread].
|
||||
- Introduces the `FspFileSystemSetMountPointEx` API, which allows the specification of a security descriptor when mounting over a directory.
|
||||
- Introduces the `FspVersion` API, which allows the retrieval of the WinFsp DLL version. Currently this reports `0x00010000` (version `1.0`).
|
||||
- Introduces the `FSP_FUSE_CAP_CASE_INSENSITIVE` and `FSP_FUSE_CAP_READDIR_PLUS` WinFsp-FUSE flags. The `FSP_FUSE_CAP_CASE_INSENSITIVE` flag allows a file system to mark itself as case-insensitive. The `FSP_FUSE_CAP_READDIR_PLUS` flag allows a file system to include full `stat` details when responding to the `readdir` operation (thus avoiding extraneous `getattr` calls).
|
||||
- When using WinFsp-FUSE over Cygwin, POSIX paths can be used as mountpoints.
|
||||
- Fixes GitHub issue #45. Prior to this fix, file systems that do not properly implement `Cleanup` (including FUSE file systems) would at times disallow renaming of directories.
|
||||
|
||||
|
||||
v1.0RC2::
|
||||
|
||||
This is the WinFsp 2017 Release Candidate 2. Some important changes included below:
|
||||
|
||||
- WinFsp is now available under the GPLv3 with a special exception for Free/Libre and Open Source Software.
|
||||
- The location of the WinFsp launcher registry entries is now `HKEY_LOCAL_MACHINE\Software\WinFsp\Services`. [On Win64 the actual location is `HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\WinFsp\Services`.] This change was necessary to avoid loss of third party file system registry entries during WinFsp uninstallation. [See GitHub issue #31.]
|
||||
- Despite stating in the previous release that the API has been finalized the `ReadDirectory` `FSP_FILE_SYSTEM_INTERFACE` operation has been changed. Extensive testing with multiple file systems has shown that `ReadDirectory` was hard to implement correctly. The new definition should make implementation easier for most file systems. [See GitHub issue #34.]
|
||||
- Some API's to facilitate `ReadDirectory` implementation have been added. Look for `FspFileSystem*DirectoryBuffer` symbols.
|
||||
- The installer now (optionally) installs a sample file system called "passthrough". This is a simple file system that passes all operations to an underlying file system. There is also a tutorial for this file system (in the doc directory).
|
||||
- The installer now (optionally) installs a sample file system called "passthrough-fuse". This file system performs the same function as the "passthrough" file system, but uses the FUSE compatibility layer. It builds and runs on both Windows and Cygwin.
|
||||
|
||||
|
||||
v1.0RC1::
|
||||
|
||||
This is the WinFsp 2017 Release Candidate 1. It has been tested extensively in a variety of scenarios for stability and correct file system semantics. Some of the more important changes:
|
||||
|
@ -54,5 +54,8 @@ This CONTRIBUTOR AGREEMENT applies to any contribution that you make to the WinF
|
||||
CONTRIBUTOR LIST
|
||||
----------------
|
||||
|===
|
||||
|Bill Zissimopoulos |billziss at navimatics.com
|
||||
|Bill Zissimopoulos |billziss at navimatics.com
|
||||
|John Oberschelp |john at oberschelp.net
|
||||
|Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com
|
||||
|Tobias Urlaub |saibotu at outlook.de
|
||||
|===
|
||||
|
31
License.txt
@ -1,8 +1,35 @@
|
||||
The WinFsp project is Copyright (C) Bill Zissimopoulos. It is licensed
|
||||
under the terms of the GPLv3. The full text of this license follows
|
||||
below. Commercial licensing options are also available: Please contact
|
||||
under the terms of the GPLv3.
|
||||
|
||||
As a special exception to GPLv3, Bill Zissimopoulos grants additional
|
||||
permissions to Free/Libre and Open Source Software ("FLOSS") without requiring
|
||||
that such software is covered by the GPLv3.
|
||||
|
||||
1. Permission to link with a platform specific version of the WinFsp DLL
|
||||
(one of: winfsp-x64.dll, winfsp-x86.dll, winfsp-msil.dll).
|
||||
|
||||
2. Permission to distribute unmodified binary releases of the WinFsp
|
||||
installer (as released by the WinFsp project).
|
||||
|
||||
These permissions (and no other) are granted provided that the software:
|
||||
|
||||
1. Is distributed under a license that satisfies the Free Software
|
||||
Definition Version 1.141 (https://www.gnu.org/philosophy/free-sw.en.html)
|
||||
or the Open Source Definition Version 1.9 (https://opensource.org/osd).
|
||||
|
||||
2. Includes the copyright notice "WinFsp - Windows File System Proxy,
|
||||
Copyright (C) Bill Zissimopoulos" and a link to the WinFsp repository in
|
||||
its user-interface and any user-facing documentation.
|
||||
|
||||
3. Is not linked or distributed with proprietary (non-FLOSS) software.
|
||||
[You cannot mix FLOSS and proprietary software while using WinFsp under
|
||||
this special exception.]
|
||||
|
||||
Commercial licensing options are also available: Please contact
|
||||
Bill Zissimopoulos <billziss at navimatics.com>.
|
||||
|
||||
The full text of the GPLv3 license follows below.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
57
README.md
@ -2,6 +2,13 @@
|
||||
|
||||

|
||||
|
||||
|
||||
<a href="https://github.com/billziss-gh/winfsp/releases/latest"><img src="http://www.secfs.net/winfsp/resources/Download-WinFsp.png" alt="Download WinFsp Installer" width="244" height="34"></a>
|
||||
 
|
||||
<a href="https://chocolatey.org/packages/winfsp"><img src="http://www.secfs.net/winfsp/resources/Choco-WinFsp.png" alt="choco install winfsp" width="244" height="34"></a>
|
||||
|
||||
|
||||
|
||||
WinFsp is a set of software components for Windows computers that allows the creation of user mode file systems. In this sense it is similar to FUSE (Filesystem in Userspace), which provides the same functionality on UNIX-like computers.
|
||||
|
||||
Some of the benefits of using WinFsp are listed below:
|
||||
@ -9,10 +16,11 @@ Some of the benefits of using WinFsp are listed below:
|
||||
* Very well-tested and stable. Read about its [Testing Strategy](doc/WinFsp-Testing.asciidoc).
|
||||
* Very fast. Read about its [Performance](doc/WinFsp-Performance-Testing.asciidoc).
|
||||
* Strives for compatibility with NTFS. Read about its [Compatibility](doc/NTFS-Compatibility.asciidoc ).
|
||||
* Easy to understand but comprehensive API. Consult the [API Reference](http://www.secfs.net/winfsp/apiref/).
|
||||
* Easy to understand but comprehensive API. Consult the [API Reference](http://www.secfs.net/winfsp/apiref/). There is also a simple [Tutorial](doc/WinFsp-Tutorial.asciidoc).
|
||||
* FUSE compatibility layer for native Windows and Cygwin. See [fuse.h](inc/fuse/fuse.h).
|
||||
* .NET layer for managed development. See [src/dotnet](src/dotnet).
|
||||
* Signed drivers provided on every release.
|
||||
* Available under the GPLv3.
|
||||
* Available under the [GPLv3](License.txt) license with a special exception for Free/Libre and Open Source Software.
|
||||
|
||||
To learn more about WinFsp, please visit its website: http://www.secfs.net/winfsp/
|
||||
|
||||
@ -22,37 +30,44 @@ WinFsp consists of a kernel mode FSD (File System Driver) and a user mode DLL (D
|
||||
|
||||
The project source code is organized as follows:
|
||||
|
||||
* build/VStudio: WinFsp solution and project files.
|
||||
* doc: The WinFsp design documents and additional documentation can be found here.
|
||||
* ext/tlib: A small test library originally from the secfs (Secure Cloud File System) project.
|
||||
* ext/test: Submodule pointing to the secfs.test project, which contains a number of tools for testing Windows and POSIX file systems.
|
||||
* inc/winfsp: Public headers for the WinFsp API.
|
||||
* inc/fuse: Public headers for the FUSE compatibility layer.
|
||||
* src/dll: Source code to the WinFsp DLL.
|
||||
* src/dll/fuse: Source code to the FUSE compatibility layer.
|
||||
* src/launcher: Source code to the launcher service and the launchctl utility.
|
||||
* src/sys: Source code to the WinFsp FSD.
|
||||
* opt/cygfuse: Source code for the Cygwin FUSE package.
|
||||
* tst/memfs: Source code to an example file system written in C++ (memfs).
|
||||
* tst/winfsp-tests: WinFsp test suite.
|
||||
* `build/VStudio`: WinFsp solution and project files.
|
||||
* `doc`: The WinFsp design documents and additional documentation can be found here.
|
||||
* `ext/tlib`: A small test library originally from the secfs (Secure Cloud File System) project.
|
||||
* `ext/test`: Submodule pointing to the secfs.test project, which contains a number of tools for testing Windows and POSIX file systems.
|
||||
* `inc/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/fuse`: Source code to the FUSE compatibility layer.
|
||||
* `src/dotnet`: Source code to the .NET layer.
|
||||
* `src/fsptool`: Source code to fsptool command line utility.
|
||||
* `src/launcher`: Source code to the launcher service and the launchctl utility.
|
||||
* `src/sys`: Source code to the WinFsp FSD.
|
||||
* `opt/cygfuse`: Source code for the Cygwin FUSE package.
|
||||
* `tst/memfs*`: Source code to an example file system written in C/C++ (memfs) or C# (memfs-dotnet).
|
||||
* `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
|
||||
|
||||
In order to build WinFsp you will need the following:
|
||||
|
||||
* Windows 10
|
||||
* Visual Studio 2015
|
||||
* Windows Driver Kit (WDK) 10
|
||||
* [Wix toolset](http://wixtoolset.org)
|
||||
|
||||
If you build the driver yourself it will not be signed and Windows will refuse to load it unless you enable "testsigning". You can enable "testsigning" using the command `bcdedit.exe -set testsigning`. For more information see this [document](http://www.secfs.net/winfsp/develop/debug/).
|
||||
To fully build WinFsp (including the installer) you must use `tools\build.bat`. By default it builds a Release build, but you can choose either the Debug or Release configuration by using the syntax:
|
||||
|
||||
WinFsp is designed to run on Vista and above. It has been tested on the following platforms so far:
|
||||
tools\build.bat CONFIGURATION
|
||||
|
||||
If you build the driver yourself it will not be signed and Windows will refuse to load it unless you enable "testsigning". You can enable "testsigning" using the command `bcdedit.exe -set testsigning on`. For more information see this [document](http://www.secfs.net/winfsp/develop/debug/).
|
||||
|
||||
WinFsp is designed to run on Windows 7 and above. It has been tested on the following platforms:
|
||||
|
||||
* Windows 7 Enterprise
|
||||
* Windows 8 Pro
|
||||
* Windows 10 Pro
|
||||
* Windows Server 2012
|
||||
* Windows 10 Pro
|
||||
* Windows Server 2016
|
||||
|
||||
## How to Help
|
||||
@ -60,7 +75,7 @@ WinFsp is designed to run on Vista and above. It has been tested on the followin
|
||||
I am looking for help in the following areas:
|
||||
|
||||
* If you have a file system that runs on FUSE please consider porting it to WinFsp. WinFsp has a native API, but it also has a FUSE (high-level) API.
|
||||
* If you are working with a language other than C/C++ (e.g. Delphi, C#, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you.
|
||||
* If you are working with a language other than C/C++ (e.g. Delphi, Java, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you.
|
||||
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues). Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart.
|
||||
|
||||
In all cases I can provide ideas and/or support.
|
||||
@ -74,4 +89,4 @@ If you wish to discuss WinFsp there are now two options:
|
||||
|
||||
## License
|
||||
|
||||
WinFsp is available under the [GPLv3](http://www.gnu.org/licenses/gpl-3.0.html) license. If you find the constraints of the GPLv3 too onerous, a commercial license is also available. Please contact Bill Zissimopoulos <billziss at navimatics.com> for more details.
|
||||
WinFsp is available under the [GPLv3](License.txt) license with a special exception for Free/Libre and Open Source Software. A commercial license is also available. Please contact Bill Zissimopoulos \<billziss at navimatics.com> for more details.
|
||||
|
13
appveyor.yml
@ -6,8 +6,10 @@ environment:
|
||||
TESTING: Func
|
||||
- CONFIGURATION: Release
|
||||
TESTING: Func
|
||||
- CONFIGURATION: Release
|
||||
TESTING: Perf
|
||||
#- CONFIGURATION: Release
|
||||
# TESTING: Avast
|
||||
#- CONFIGURATION: Release
|
||||
# TESTING: Perf
|
||||
|
||||
install:
|
||||
- git submodule update --init --recursive
|
||||
@ -23,13 +25,18 @@ build_script:
|
||||
- tools\build.bat %CONFIGURATION%
|
||||
|
||||
test_script:
|
||||
- for %%f in ("build\VStudio\build\%CONFIGURATION%\winfsp-*.msi") do start /wait msiexec /i %%f /qn INSTALLLEVEL=1000
|
||||
- choco install winfsp -s build\VStudio\build\%CONFIGURATION% -y
|
||||
- if %TESTING%==Func appveyor DownloadFile http://www.secfs.net/winfsp/resources/Test.Filter.Driver.zip && 7z x Test.Filter.Driver.zip
|
||||
- if %TESTING%==Func start /wait msiexec /i "Test.Filter.Driver\HCK Filter.Driver Content-x86_en-us.msi" /qn
|
||||
- if %TESTING%==Func tools\nmake-ext-test.bat %CONFIGURATION%
|
||||
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION%
|
||||
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% ifstest
|
||||
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% sample
|
||||
- if %TESTING%==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
|
||||
- choco uninstall winfsp -y
|
||||
- if exist %SystemRoot%\memory.dmp exit 1
|
||||
|
||||
on_finish:
|
||||
|
1
build/VStudio/.gitignore
vendored
@ -3,3 +3,4 @@ build
|
||||
*.suo
|
||||
*.vcproj.*
|
||||
*.vcxproj.user
|
||||
*.csproj.user
|
||||
|
113
build/VStudio/dotnet/winfsp.net.csproj
Normal file
@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\version.properties" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{94580219-CC8D-4FE5-A3BE-437B0B3481E1}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<ProjectName>winfsp.net</ProjectName>
|
||||
<RootNamespace>Fsp</RootNamespace>
|
||||
<AssemblyName>winfsp-msil</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
||||
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
|
||||
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DocumentationFile>$(BaseIntermediateOutputPath)$(Configuration)\winfsp-msil.xml</DocumentationFile>
|
||||
<NoWarn>1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
||||
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
|
||||
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DocumentationFile>$(BaseIntermediateOutputPath)$(Configuration)\winfsp-msil.xml</DocumentationFile>
|
||||
<NoWarn>1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>winfsp.net.snk</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\src\dotnet\FileSystemBase+Const.cs">
|
||||
<Link>FileSystemBase+Const.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\src\dotnet\FileSystemBase.cs">
|
||||
<Link>FileSystemBase.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\src\dotnet\FileSystemHost.cs">
|
||||
<Link>FileSystemHost.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\src\dotnet\Interop.cs">
|
||||
<Link>Interop.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\src\dotnet\Service.cs">
|
||||
<Link>Service.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="winfsp.net.snk" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<Target Name="BeforeBuild">
|
||||
<ItemGroup>
|
||||
<AssemblyInfo Include="using System.Reflection%3b" />
|
||||
<AssemblyInfo Include="[assembly: AssemblyProduct("$(MyProductName)")]" />
|
||||
<AssemblyInfo Include="[assembly: AssemblyTitle("$(MyDescription)")]" />
|
||||
<AssemblyInfo Include="[assembly: AssemblyCompany("$(MyCompanyName)")]" />
|
||||
<AssemblyInfo Include="[assembly: AssemblyCopyright("$(MyCopyright)")]" />
|
||||
<AssemblyInfo Include="[assembly: AssemblyVersion("$(MyAssemblyVersion)")]" />
|
||||
<AssemblyInfo Include="[assembly: AssemblyFileVersion("$(MyVersion)")]" />
|
||||
</ItemGroup>
|
||||
<MakeDir Directories="$(IntermediateOutputPath)" />
|
||||
<WriteLinesToFile File="$(IntermediateOutputPath)AssemblyInfo.cs" Lines="@(AssemblyInfo)" Overwrite="true" />
|
||||
<ItemGroup>
|
||||
<Compile Include="$(IntermediateOutputPath)AssemblyInfo.cs" />
|
||||
<FileWrites Include="$(IntermediateOutputPath)AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>exit /b 0
|
||||
|
||||
set TargetName=$(TargetName)
|
||||
set MyAssemblyPolicyVersion=$(MyAssemblyPolicyVersion)
|
||||
set MyAssemblyVersion=$(MyAssemblyVersion)
|
||||
|
||||
setlocal EnableDelayedExpansion
|
||||
if exist $(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).config del $(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).config
|
||||
for /f "delims=" %25%25l in ($(ProjectDir)winfsp.net.policy.config) do (
|
||||
set line=%25%25l
|
||||
echo !line! >>$(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).config
|
||||
)
|
||||
|
||||
"$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.0A\Bin\al.exe" /product:"$(MyProductName)" /title:"$(MyDescription)" /company:"$(MyCompanyName)" /copyright:"$(MyCopyright)" /version:"$(MyAssemblyPolicyVersion)" /fileversion:"$(MyVersion)" /link:$(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).config /out:$(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).dll /keyfile:$(ProjectDir)$(ProjectName).snk
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
10
build/VStudio/dotnet/winfsp.net.policy.config
Normal file
@ -0,0 +1,10 @@
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="!TargetName!" publicKeyToken="b099876d8fa9b1f3" culture="neutral" />
|
||||
<bindingRedirect oldVersion="!MyAssemblyPolicyVersion!.0.0-!MyAssemblyVersion!" newVersion="!MyAssemblyVersion!" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
BIN
build/VStudio/dotnet/winfsp.net.snk
Normal file
@ -22,7 +22,7 @@
|
||||
<Media Id="1" Cabinet="WinFsp.cab" EmbedCab="yes" />
|
||||
|
||||
<Property Id="P.LauncherName">$(var.MyProductName).Launcher</Property>
|
||||
<Property Id="P.LauncherRegistryKey">SYSTEM\\CurrentControlSet\\Services\\$(var.MyProductName).Launcher\\Services</Property>
|
||||
<Property Id="P.LauncherRegistryKey">Software\$(var.MyProductName)\Services</Property>
|
||||
<Property Id="P.RegistryKey">Software\$(var.MyProductName)</Property>
|
||||
<Property Id="INSTALLDIR">
|
||||
<RegistrySearch
|
||||
@ -39,6 +39,7 @@
|
||||
<Directory Id="BINDIR" Name="bin" />
|
||||
<Directory Id="INCDIR" Name="inc" />
|
||||
<Directory Id="LIBDIR" Name="lib" />
|
||||
<Directory Id="OPTDIR" Name="opt" />
|
||||
<Directory Id="SMPDIR" Name="samples" />
|
||||
<Directory Id="SYMDIR" Name="sym" />
|
||||
</Directory>
|
||||
@ -55,6 +56,9 @@
|
||||
Value="[INSTALLDIR]"
|
||||
KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.License.txt">
|
||||
<File Name="License.txt" Source="..\..\..\License.txt" KeyPath="yes" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="BINDIR" FileSource="..\build\$(var.Configuration)">
|
||||
<Component Id="C.winfsp_x64.sys">
|
||||
@ -84,6 +88,23 @@
|
||||
<Condition>NOT VersionNT64</Condition>
|
||||
</Component>
|
||||
|
||||
<!-- install assembly -->
|
||||
<Component Id="C.winfsp_msil.dll" Guid="0D8BA6AE-9F87-402B-AE1A-95B0AE3BE179">
|
||||
<File Id="FILE.winfsp_msil.dll" Name="winfsp-msil.dll" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.winfsp_msil.xml" Guid="1657F707-C112-454C-91AE-0FDEBBF454AB">
|
||||
<File Id="FILE.winfsp_msil.xml" Name="winfsp-msil.xml" KeyPath="yes" />
|
||||
</Component>
|
||||
<!--
|
||||
<Component Id="C.winfsp_msil.dll.GAC" Guid="6469467D-8C90-4889-8138-4028F9DA6E85">
|
||||
<File Id="FILE.winfsp_msil.dll.GAC" Name="winfsp-msil.dll" KeyPath="yes" Assembly=".net" />
|
||||
</Component>
|
||||
<Component Id="C.policy.winfsp_msil.dll.GAC">
|
||||
<File Name="policy.1.0.winfsp-msil.dll" KeyPath="yes" Assembly=".net" />
|
||||
<File Name="policy.1.0.winfsp-msil.config" KeyPath="no" />
|
||||
</Component>
|
||||
-->
|
||||
|
||||
<!-- On Win64 ServiceInstall launcher-x64.exe -->
|
||||
<Component Id="C.launcher_x64.exe.svcinst">
|
||||
<File Id="launcher_x64.exe.svcinst" Name="launcher-x64.exe" KeyPath="yes" />
|
||||
@ -137,9 +158,19 @@
|
||||
<File Name="launchctl-x86.exe" KeyPath="yes" />
|
||||
</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">
|
||||
<File Name="diag.bat" Source="..\..\..\tools\diag.bat" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.fsreg.bat">
|
||||
<File Name="fsreg.bat" Source="..\..\..\tools\fsreg.bat" KeyPath="yes" />
|
||||
</Component>
|
||||
|
||||
<Component Id="C.memfs_x64.exe">
|
||||
<File Name="memfs-x64.exe" KeyPath="yes" />
|
||||
@ -193,6 +224,32 @@
|
||||
</RegistryKey>
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
<Component Id="C.memfs_dotnet_msil.exe">
|
||||
<File Name="memfs-dotnet-msil.exe" KeyPath="yes" />
|
||||
<RegistryKey
|
||||
Root="HKLM"
|
||||
Key="[P.LauncherRegistryKey]">
|
||||
<RegistryKey
|
||||
Key="memfs-dotnet">
|
||||
<RegistryValue
|
||||
Type="string"
|
||||
Name="Executable"
|
||||
Value="[BINDIR]memfs-dotnet-msil.exe" />
|
||||
<RegistryValue
|
||||
Type="string"
|
||||
Name="CommandLine"
|
||||
Value="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2" />
|
||||
<RegistryValue
|
||||
Type="string"
|
||||
Name="Security"
|
||||
Value="D:P(A;;RPWPLC;;;WD)" />
|
||||
<RegistryValue
|
||||
Type="integer"
|
||||
Name="JobControl"
|
||||
Value="1" />
|
||||
</RegistryKey>
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="INCDIR" FileSource="..\..\..\inc">
|
||||
<Directory Id="INCDIR.winfsp" Name="winfsp">
|
||||
@ -202,6 +259,9 @@
|
||||
<Component Id="C.winfsp.h">
|
||||
<File Name="winfsp.h" KeyPath="yes" />
|
||||
</Component>
|
||||
<!--Component Id="C.winfsp.hpp">
|
||||
<File Name="winfsp.hpp" KeyPath="yes" />
|
||||
</Component-->
|
||||
</Directory>
|
||||
<Directory Id="INCDIR.fuse" Name="fuse">
|
||||
<Component Id="C.fuse.h">
|
||||
@ -246,6 +306,26 @@
|
||||
<Condition>NOT VersionNT64</Condition>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="OPTDIR">
|
||||
<Directory Id="OPTDIR.cygfuse" Name="cygfuse" FileSource="..\..\..\opt\cygfuse\dist">
|
||||
<Directory Id="OPTDIR.cygfuse.x64" Name="x64">
|
||||
<Component Id="C.fuse.tar.xz.x64">
|
||||
<File Id="FILE.fuse.tar.xz.x64" Name="fuse-2.8-7.tar.xz" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
<Directory Id="OPTDIR.cygfuse.x86" Name="x86">
|
||||
<Component Id="C.fuse.tar.xz.x86">
|
||||
<File Id="FILE.fuse.tar.xz.x86" Name="fuse-2.8-7.tar.xz" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
<Component Id="C.fuse.install.sh">
|
||||
<File Name="install.sh" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.fuse.uninstall.sh">
|
||||
<File Name="uninstall.sh" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="SMPDIR" FileSource="..\..\..\tst">
|
||||
<Directory Id="SMPDIR.memfs" Name="memfs">
|
||||
<Component Id="C.memfs.h">
|
||||
@ -258,6 +338,76 @@
|
||||
<File Name="memfs-main.c" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
<Directory Id="SMPDIR.memfs_dotnet" Name="memfs-dotnet">
|
||||
<Component Id="C.memfs_dotnet.Program.cs">
|
||||
<File Id="FILE.memfs_dotnet.Program.cs" Name="Program.cs" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
<Directory Id="SMPDIR.passthrough" Name="passthrough">
|
||||
<Component Id="C.passthrough.c">
|
||||
<File Name="passthrough.c" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough.sln">
|
||||
<File Name="passthrough.sln" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough.vcxproj">
|
||||
<File Name="passthrough.vcxproj" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough.vcxproj.filters">
|
||||
<File Name="passthrough.vcxproj.filters" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
<!--Directory Id="SMPDIR.passthrough_cpp" Name="passthrough-cpp">
|
||||
<Component Id="C.passthrough_cpp.cpp">
|
||||
<File Name="passthrough-cpp.cpp" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough_cpp.sln">
|
||||
<File Name="passthrough-cpp.sln" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough_cpp.vcxproj">
|
||||
<File Name="passthrough-cpp.vcxproj" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough_cpp.vcxproj.filters">
|
||||
<File Name="passthrough-cpp.vcxproj.filters" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory-->
|
||||
<Directory Id="SMPDIR.passthrough_fuse" Name="passthrough-fuse">
|
||||
<Component Id="C.passthrough_fuse.c">
|
||||
<File Name="passthrough-fuse.c" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough_fuse.winposix.c">
|
||||
<File Name="winposix.c" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough_fuse.winposix.h">
|
||||
<File Name="winposix.h" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough_fuse.sln">
|
||||
<File Name="passthrough-fuse.sln" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough_fuse.vcxproj">
|
||||
<File Name="passthrough-fuse.vcxproj" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough_fuse.vcxproj.filters">
|
||||
<File Name="passthrough-fuse.vcxproj.filters" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough_fuse.Makefile">
|
||||
<File Name="Makefile" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough_fuse.README.md">
|
||||
<File Name="README.md" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
<Directory Id="SMPDIR.passthrough_dotnet" Name="passthrough-dotnet">
|
||||
<Component Id="C.passthrough_dotnet.Program.cs">
|
||||
<File Id="FILE.passthrough_dotnet.Program.cs" Name="Program.cs" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough_dotnet.sln">
|
||||
<File Name="passthrough-dotnet.sln" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.passthrough_dotnet.csproj">
|
||||
<File Name="passthrough-dotnet.csproj" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="SYMDIR">
|
||||
<Component Id="C.winfsp_x64.sys.pdb">
|
||||
@ -284,6 +434,12 @@
|
||||
<Component Id="C.launchctl_x86.pdb">
|
||||
<File Name="launchctl-x86.pdb" Source="..\build\$(var.Configuration)\launchctl-x86.public.pdb" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.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">
|
||||
<File Name="memfs-x64.pdb" Source="..\build\$(var.Configuration)\memfs-x64.public.pdb" KeyPath="yes" />
|
||||
</Component>
|
||||
@ -305,11 +461,15 @@
|
||||
<ComponentRef Id="C.launcher_x86.exe.svcinst" />
|
||||
<ComponentRef Id="C.launchctl_x64.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.fsreg.bat" />
|
||||
</ComponentGroup>
|
||||
<ComponentGroup Id="C.WinFsp.inc">
|
||||
<ComponentRef Id="C.fsctl.h" />
|
||||
<ComponentRef Id="C.winfsp.h" />
|
||||
<!--ComponentRef Id="C.winfsp.hpp" /-->
|
||||
<ComponentRef Id="C.fuse.h" />
|
||||
<ComponentRef Id="C.fuse_common.h" />
|
||||
<ComponentRef Id="C.fuse_opt.h" />
|
||||
@ -321,12 +481,34 @@
|
||||
<ComponentRef Id="C.fuse_x64.pc" />
|
||||
<ComponentRef Id="C.fuse_x86.pc" />
|
||||
</ComponentGroup>
|
||||
<ComponentGroup Id="C.WinFsp.opt.fuse">
|
||||
<ComponentRef Id="C.fuse.tar.xz.x64" />
|
||||
<ComponentRef Id="C.fuse.tar.xz.x86" />
|
||||
<ComponentRef Id="C.fuse.install.sh" />
|
||||
<ComponentRef Id="C.fuse.uninstall.sh" />
|
||||
</ComponentGroup>
|
||||
<ComponentGroup Id="C.WinFsp.smp">
|
||||
<ComponentRef Id="C.memfs_x64.exe" />
|
||||
<ComponentRef Id="C.memfs_x86.exe" />
|
||||
<ComponentRef Id="C.memfs.h" />
|
||||
<ComponentRef Id="C.memfs.cpp" />
|
||||
<ComponentRef Id="C.memfs_main.c" />
|
||||
<ComponentRef Id="C.passthrough.c" />
|
||||
<ComponentRef Id="C.passthrough.sln" />
|
||||
<ComponentRef Id="C.passthrough.vcxproj" />
|
||||
<ComponentRef Id="C.passthrough.vcxproj.filters" />
|
||||
<!--ComponentRef Id="C.passthrough_cpp.cpp" /-->
|
||||
<!--ComponentRef Id="C.passthrough_cpp.sln" /-->
|
||||
<!--ComponentRef Id="C.passthrough_cpp.vcxproj" /-->
|
||||
<!--ComponentRef Id="C.passthrough_cpp.vcxproj.filters" /-->
|
||||
<ComponentRef Id="C.passthrough_fuse.c" />
|
||||
<ComponentRef Id="C.passthrough_fuse.winposix.c" />
|
||||
<ComponentRef Id="C.passthrough_fuse.winposix.h" />
|
||||
<ComponentRef Id="C.passthrough_fuse.sln" />
|
||||
<ComponentRef Id="C.passthrough_fuse.vcxproj" />
|
||||
<ComponentRef Id="C.passthrough_fuse.vcxproj.filters" />
|
||||
<ComponentRef Id="C.passthrough_fuse.Makefile" />
|
||||
<ComponentRef Id="C.passthrough_fuse.README.md" />
|
||||
</ComponentGroup>
|
||||
<ComponentGroup Id="C.WinFsp.sym">
|
||||
<ComponentRef Id="C.winfsp_x64.sys.pdb" />
|
||||
@ -337,9 +519,26 @@
|
||||
<ComponentRef Id="C.launcher_x64.pdb" />
|
||||
<ComponentRef Id="C.launchctl_x64.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_x86.pdb" />
|
||||
</ComponentGroup>
|
||||
<ComponentGroup Id="C.WinFsp.net">
|
||||
<ComponentRef Id="C.winfsp_msil.dll" />
|
||||
<ComponentRef Id="C.winfsp_msil.xml" />
|
||||
<!--
|
||||
<ComponentRef Id="C.winfsp_msil.dll.GAC" />
|
||||
<ComponentRef Id="C.policy.winfsp_msil.dll.GAC" />
|
||||
-->
|
||||
</ComponentGroup>
|
||||
<ComponentGroup Id="C.WinFsp.smp.net">
|
||||
<ComponentRef Id="C.memfs_dotnet_msil.exe" />
|
||||
<ComponentRef Id="C.memfs_dotnet.Program.cs" />
|
||||
<ComponentRef Id="C.passthrough_dotnet.Program.cs" />
|
||||
<ComponentRef Id="C.passthrough_dotnet.sln" />
|
||||
<ComponentRef Id="C.passthrough_dotnet.csproj" />
|
||||
</ComponentGroup>
|
||||
|
||||
<Feature
|
||||
Id="F.Main"
|
||||
@ -352,6 +551,7 @@
|
||||
InstallDefault="local"
|
||||
Absent="disallow">
|
||||
<ComponentRef Id="C.INSTALLDIR" />
|
||||
<ComponentRef Id="C.License.txt" />
|
||||
<Feature
|
||||
Id="F.User"
|
||||
Level="1"
|
||||
@ -361,7 +561,20 @@
|
||||
InstallDefault="local"
|
||||
Absent="disallow">
|
||||
<ComponentGroupRef Id="C.WinFsp.bin" />
|
||||
<ComponentGroupRef Id="C.WinFsp.net" />
|
||||
</Feature>
|
||||
<!--
|
||||
<Feature
|
||||
Id="F.Net"
|
||||
Level="10"
|
||||
Title=".NET"
|
||||
Description="The managed $(var.MyProductName) files."
|
||||
AllowAdvertise="no"
|
||||
InstallDefault="local"
|
||||
Absent="allow">
|
||||
<ComponentGroupRef Id="C.WinFsp.net" />
|
||||
</Feature>
|
||||
-->
|
||||
<Feature
|
||||
Id="F.Developer"
|
||||
Level="1000"
|
||||
@ -373,8 +586,19 @@
|
||||
<ComponentGroupRef Id="C.WinFsp.inc" />
|
||||
<ComponentGroupRef Id="C.WinFsp.lib" />
|
||||
<ComponentGroupRef Id="C.WinFsp.smp" />
|
||||
<ComponentGroupRef Id="C.WinFsp.smp.net" />
|
||||
<ComponentGroupRef Id="C.WinFsp.sym" />
|
||||
</Feature>
|
||||
<Feature
|
||||
Id="F.Cygfuse"
|
||||
Level="1000"
|
||||
Title="FUSE for Cygwin"
|
||||
Description="From a Cygwin prompt change to <InstallDir>/opt/cygfuse and run install.sh."
|
||||
AllowAdvertise="no"
|
||||
InstallDefault="local"
|
||||
Absent="allow">
|
||||
<ComponentGroupRef Id="C.WinFsp.opt.fuse" />
|
||||
</Feature>
|
||||
</Feature>
|
||||
|
||||
<WixVariable Id="WixUIBannerBmp" Value="wixbanner.bmp" />
|
||||
|
63
build/VStudio/testing/memfs-dotnet.csproj
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{4920E350-D496-4652-AE98-6C4208AEC1D8}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<ProjectName>memfs-dotnet</ProjectName>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>memfs</RootNamespace>
|
||||
<AssemblyName>memfs-dotnet-msil</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
||||
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
|
||||
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
||||
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
|
||||
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\tst\memfs-dotnet\Program.cs">
|
||||
<Link>Program.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\dotnet\winfsp.net.csproj">
|
||||
<Project>{94580219-cc8d-4fe5-a3be-437b0b3481e1}</Project>
|
||||
<Name>winfsp.net</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
@ -182,8 +182,10 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\create-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\dirctl-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\exec-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\hooks.c" />
|
||||
@ -200,6 +202,7 @@
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\security-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\version-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\winfsp-tests.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -212,6 +215,9 @@
|
||||
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\..\..\tst\winfsp-tests\helper\winfsp-tests-helper.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
@ -76,6 +76,15 @@
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\oplock-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\exec-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\version-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
||||
@ -88,4 +97,9 @@
|
||||
<Filter>Source</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\..\..\tst\winfsp-tests\helper\winfsp-tests-helper.rc">
|
||||
<Filter>Source</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
193
build/VStudio/tools/fsptool.vcxproj
Normal 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>
|
23
build/VStudio/tools/fsptool.vcxproj.filters
Normal 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>
|
@ -20,7 +20,7 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{73EAAEDA-557B-48D5-A137-328934720FB4}</ProjectGuid>
|
||||
<ProjectGuid>{264A5D09-126F-4760-A3F1-4B3B95C925AA}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>launchctl</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
@ -20,7 +20,7 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{A5EFD487-0140-4184-8C54-FFAEC2F85E35}</ProjectGuid>
|
||||
<ProjectGuid>{6CDF9411-B852-4EAC-822D-8F930675F17B}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>launcher</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
@ -7,7 +7,8 @@
|
||||
<!-- git revision -->
|
||||
<MyGitRoot>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), .git/HEAD))</MyGitRoot>
|
||||
<MyGitHead>$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/HEAD).Trim())</MyGitHead>
|
||||
<MyGitRevision Condition="$(MyGitHead.StartsWith(ref: ))">$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/$(MyGitHead.Substring(5))).Trim().Substring(0, 7))</MyGitRevision>
|
||||
<MyGitRevision Condition="$(MyGitHead.StartsWith(ref: )) 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>
|
||||
|
||||
<MyProductName>WinFsp</MyProductName>
|
||||
@ -15,14 +16,17 @@
|
||||
<MyCompanyName>Navimatics Corporation</MyCompanyName>
|
||||
<MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
|
||||
|
||||
<MyCanonicalVersion>1.0</MyCanonicalVersion>
|
||||
<MyCanonicalVersion>1.2</MyCanonicalVersion>
|
||||
|
||||
<MyProductVersion>2017 RC1</MyProductVersion>
|
||||
<MyProductStage>RC</MyProductStage>
|
||||
<MyProductVersion>2017.2</MyProductVersion>
|
||||
<MyProductStage>Gold</MyProductStage>
|
||||
|
||||
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
||||
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
||||
<MyFullVersion>$(MyCanonicalVersion).$(MyBuildNumber).$(MyGitRevision)</MyFullVersion>
|
||||
|
||||
<MyAssemblyPolicyVersion>$(MyCanonicalVersion.Substring(0,$(MyVersion.IndexOf('.')))).0</MyAssemblyPolicyVersion>
|
||||
<MyAssemblyVersion>$(MyAssemblyPolicyVersion).0.0</MyAssemblyVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
|
@ -32,19 +32,6 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "winfsp_msi", "installer\win
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomActions", "installer\CustomActions\CustomActions.vcxproj", "{95C223E6-B5F1-4FD0-9376-41CDBC824445}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "launcher", "launcher", "{FD28A504-431E-49B9-BB8C-DCA0E7019F66}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launcher", "launcher\launcher.vcxproj", "{A5EFD487-0140-4184-8C54-FFAEC2F85E35}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332} = {C85C26BA-8C22-4D30-83DA-46C3548E6332}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launchctl", "launcher\launchctl.vcxproj", "{73EAAEDA-557B-48D5-A137-328934720FB4}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {A5EFD487-0140-4184-8C54-FFAEC2F85E35}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fscrash", "testing\fscrash.vcxproj", "{10757011-749D-4954-873B-AE38D8145472}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}
|
||||
@ -53,146 +40,256 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fscrash", "testing\fscrash.
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fsbench", "testing\fsbench.vcxproj", "{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winfsp.net", "dotnet\winfsp.net.csproj", "{94580219-CC8D-4FE5-A3BE-437B0B3481E1}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332} = {C85C26BA-8C22-4D30-83DA-46C3548E6332}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dotnet", "dotnet", "{A998CEC4-4B34-43DC-8457-F7761228BA67}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "memfs-dotnet", "testing\memfs-dotnet.csproj", "{4920E350-D496-4652-AE98-6C4208AEC1D8}"
|
||||
EndProject
|
||||
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
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Installer.Debug|Any CPU = Installer.Debug|Any CPU
|
||||
Installer.Debug|x64 = Installer.Debug|x64
|
||||
Installer.Debug|x86 = Installer.Debug|x86
|
||||
Installer.Release|Any CPU = Installer.Release|Any CPU
|
||||
Installer.Release|x64 = Installer.Release|x64
|
||||
Installer.Release|x86 = Installer.Release|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x64.Build.0 = Debug|x64
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Debug|x86.Build.0 = Debug|Win32
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x64.ActiveCfg = Release|x64
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x64.Build.0 = Release|x64
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x86.ActiveCfg = Release|Win32
|
||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}.Release|x86.Build.0 = Release|Win32
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x64.Build.0 = Debug|x64
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Debug|x86.Build.0 = Debug|Win32
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x64.ActiveCfg = Release|x64
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x64.Build.0 = Release|x64
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x86.ActiveCfg = Release|Win32
|
||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332}.Release|x86.Build.0 = Release|Win32
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x64.Build.0 = Debug|x64
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Debug|x86.Build.0 = Debug|Win32
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x64.ActiveCfg = Release|x64
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x64.Build.0 = Release|x64
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x86.ActiveCfg = Release|Win32
|
||||
{262DF8CC-E7A8-4460-A22C-683CBA322C32}.Release|x86.Build.0 = Release|Win32
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x64.Build.0 = Debug|x64
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Debug|x86.Build.0 = Debug|Win32
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x64.ActiveCfg = Release|x64
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x64.Build.0 = Release|x64
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x86.ActiveCfg = Release|Win32
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}.Release|x86.Build.0 = Release|Win32
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Debug|x64.ActiveCfg = Debug|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|Any CPU.ActiveCfg = Release|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|Any CPU.Build.0 = Release|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x64.ActiveCfg = Release|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x64.Build.0 = Release|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x86.ActiveCfg = Debug|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Debug|x86.Build.0 = Debug|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|Any CPU.Build.0 = Release|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x64.ActiveCfg = Release|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x64.Build.0 = Release|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x86.ActiveCfg = Release|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Installer.Release|x86.Build.0 = Release|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Release|x64.ActiveCfg = Release|x86
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594}.Release|x86.ActiveCfg = Release|x86
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|Any CPU.Build.0 = Release|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x64.ActiveCfg = Release|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x64.Build.0 = Release|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Debug|x86.Build.0 = Debug|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|Any CPU.Build.0 = Release|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x64.ActiveCfg = Release|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x64.Build.0 = Release|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Installer.Release|x86.Build.0 = Release|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x64.ActiveCfg = Release|Win32
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x86.ActiveCfg = Release|Win32
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.Build.0 = Debug|x64
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x86.Build.0 = Debug|Win32
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x64.ActiveCfg = Release|x64
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x64.Build.0 = Release|x64
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x86.ActiveCfg = Release|Win32
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x86.Build.0 = Release|Win32
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x64.Build.0 = Debug|x64
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x86.Build.0 = Debug|Win32
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.ActiveCfg = Release|x64
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.Build.0 = Release|x64
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.ActiveCfg = Release|Win32
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.Build.0 = Release|Win32
|
||||
{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.Build.0 = Debug|x64
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Debug|x86.Build.0 = Debug|Win32
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.Build.0 = Debug|x64
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.Build.0 = Debug|Win32
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.Build.0 = Release|x64
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.Build.0 = Release|Win32
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Release|x64.ActiveCfg = Release|x64
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Release|x64.Build.0 = Release|x64
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Release|x86.ActiveCfg = Release|Win32
|
||||
{10757011-749D-4954-873B-AE38D8145472}.Release|x86.Build.0 = Release|Win32
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x64.Build.0 = Debug|x64
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x86.Build.0 = Debug|Win32
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x64.Build.0 = Debug|x64
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x86.Build.0 = Debug|Win32
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x64.Build.0 = Release|x64
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x86.Build.0 = Release|Win32
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x64.ActiveCfg = Release|x64
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x64.Build.0 = Release|x64
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x86.ActiveCfg = Release|Win32
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x86.Build.0 = Release|Win32
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Installer.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Installer.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Installer.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Installer.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Installer.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Installer.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x86.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|x64.ActiveCfg = Release|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.Build.0 = Release|Any CPU
|
||||
{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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -202,9 +299,12 @@ Global
|
||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594} = {B464EF06-42AE-4674-81BB-FDDE80204822}
|
||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445} = {B464EF06-42AE-4674-81BB-FDDE80204822}
|
||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
|
||||
{73EAAEDA-557B-48D5-A137-328934720FB4} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
|
||||
{10757011-749D-4954-873B-AE38D8145472} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1} = {A998CEC4-4B34-43DC-8457-F7761228BA67}
|
||||
{4920E350-D496-4652-AE98-6C4208AEC1D8} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
||||
{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
|
||||
EndGlobal
|
||||
|
@ -26,13 +26,16 @@
|
||||
<ClInclude Include="..\..\inc\fuse\winfsp_fuse.h" />
|
||||
<ClInclude Include="..\..\inc\winfsp\fsctl.h" />
|
||||
<ClInclude Include="..\..\inc\winfsp\winfsp.h" />
|
||||
<ClInclude Include="..\..\inc\winfsp\winfsp.hpp" />
|
||||
<ClInclude Include="..\..\src\dll\fuse\library.h" />
|
||||
<ClInclude Include="..\..\src\dll\library.h" />
|
||||
<ClInclude Include="..\..\src\shared\minimal.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\dll\dirbuf.c" />
|
||||
<ClCompile Include="..\..\src\dll\eventlog.c" />
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse.c" />
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_compat.c" />
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c" />
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_main.c" />
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_opt.c" />
|
||||
@ -50,7 +53,7 @@
|
||||
<ClCompile Include="..\..\src\dll\util.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc">
|
||||
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc.in">
|
||||
<FileType>Document</FileType>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">echo arch=$(PlatformTarget) >$(OutDir)fuse-$(PlatformTarget).pc
|
||||
copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(PlatformTarget).pc >nul</Command>
|
||||
|
@ -50,6 +50,9 @@
|
||||
<ClInclude Include="..\..\src\dll\fuse\library.h">
|
||||
<Filter>Source\fuse</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\winfsp\winfsp.hpp">
|
||||
<Filter>Include\winfsp</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\dll\library.c">
|
||||
@ -103,6 +106,12 @@
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c">
|
||||
<Filter>Source\fuse</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\dll\dirbuf.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_compat.c">
|
||||
<Filter>Source\fuse</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\src\dll\library.def">
|
||||
@ -118,7 +127,7 @@
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc">
|
||||
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc.in">
|
||||
<Filter>Source\fuse</Filter>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
|
@ -174,6 +174,7 @@
|
||||
<ClCompile Include="..\..\src\sys\lockctl.c" />
|
||||
<ClCompile Include="..\..\src\sys\meta.c" />
|
||||
<ClCompile Include="..\..\src\sys\name.c" />
|
||||
<ClCompile Include="..\..\src\sys\psbuffer.c" />
|
||||
<ClCompile Include="..\..\src\sys\read.c" />
|
||||
<ClCompile Include="..\..\src\sys\security.c" />
|
||||
<ClCompile Include="..\..\src\sys\shutdown.c" />
|
||||
|
@ -98,6 +98,9 @@
|
||||
<ClCompile Include="..\..\src\sys\statistics.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\sys\psbuffer.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\sys\driver.h">
|
||||
@ -113,8 +116,8 @@
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\src\sys\driver.inf.in">
|
||||
<CustomBuild Include="..\..\src\sys\driver.inf.in">
|
||||
<Filter>Source</Filter>
|
||||
</None>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
</Project>
|
4
build/choco/LICENSE.txt
Normal file
@ -0,0 +1,4 @@
|
||||
From: https://github.com/billziss-gh/winfsp/blob/master/License.txt
|
||||
|
||||
LICENSE
|
||||
|
15
build/choco/VERIFICATION.txt
Normal file
@ -0,0 +1,15 @@
|
||||
VERIFICATION
|
||||
Verification is intended to assist the Chocolatey moderators and community
|
||||
in verifying that this package's contents are trustworthy.
|
||||
|
||||
WinFsp GitHub repository: https://github.com/billziss-gh/winfsp
|
||||
WinFsp MSI releases : https://github.com/billziss-gh/winfsp/releases
|
||||
|
||||
You may use the Windows certutil utility to confirm the hash of the MSI
|
||||
included in this package against the WinFsp MSI release of the same version.
|
||||
For example, for WinFsp version 1.0.17072 the command line to use is:
|
||||
|
||||
certutil -hashfile winfsp-1.0.17072.msi SHA256
|
||||
|
||||
The certutil output of the MSI in this package is included below.
|
||||
|
36
build/choco/chocolateyHelper.ps1
Normal file
@ -0,0 +1,36 @@
|
||||
$ErrorActionPreference = 'Stop';
|
||||
|
||||
$packageName = 'winfsp'
|
||||
$softwareName = 'WinFsp*'
|
||||
$installerType = 'msi'
|
||||
$silentArgs = '/qn /norestart'
|
||||
$validExitCodes = @(0, 3010, 1605, 1614, 1641)
|
||||
|
||||
[array]$key = Get-UninstallRegistryKey -SoftwareName $softwareName
|
||||
|
||||
if ($key.Count -eq 1) {
|
||||
$key | % {
|
||||
# The Product Code GUID is all that should be passed for MSI, and very
|
||||
# FIRST, because it comes directly after /x, which is already set in the
|
||||
# Uninstall-ChocolateyPackage msiargs (facepalm).
|
||||
$silentArgs = "$($_.PSChildName) $silentArgs"
|
||||
|
||||
# Don't pass anything for file, it is ignored for msi (facepalm number 2)
|
||||
# Alternatively if you need to pass a path to an msi, determine that and
|
||||
# use it instead of the above in silentArgs, still very first
|
||||
$file = ''
|
||||
|
||||
Uninstall-ChocolateyPackage `
|
||||
-PackageName $packageName `
|
||||
-FileType $installerType `
|
||||
-SilentArgs "$silentArgs" `
|
||||
-ValidExitCodes $validExitCodes `
|
||||
-File "$file"
|
||||
}
|
||||
} elseif ($key.Count -eq 0) {
|
||||
# Write-Warning "$packageName is not installed"
|
||||
} elseif ($key.Count -gt 1) {
|
||||
Write-Warning "Too many matching packages found! Package may not be uninstalled."
|
||||
Write-Warning "Please alert package maintainer the following packages were matched:"
|
||||
$key | % {Write-Warning "- $_"}
|
||||
}
|
14
build/choco/chocolateyInstall.ps1
Normal file
@ -0,0 +1,14 @@
|
||||
$ErrorActionPreference = 'Stop';
|
||||
|
||||
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
|
||||
. "$toolsdir\chocolateyHelper.ps1"
|
||||
|
||||
$packageArgs = @{
|
||||
packageName = 'winfsp'
|
||||
fileType = 'msi'
|
||||
file = @(Get-ChildItem $toolsDir -filter winfsp-*.msi)[0].FullName
|
||||
silentArgs = "/qn /norestart INSTALLLEVEL=1000"
|
||||
validExitCodes = @(0, 3010, 1641)
|
||||
}
|
||||
Install-ChocolateyInstallPackage @packageArgs
|
||||
Remove-Item -Force $packageArgs.file
|
4
build/choco/chocolateyUninstall.ps1
Normal file
@ -0,0 +1,4 @@
|
||||
$ErrorActionPreference = 'Stop';
|
||||
|
||||
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
|
||||
. "$toolsdir\chocolateyHelper.ps1"
|
57
build/choco/winfsp.nuspec
Normal file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>winfsp</id>
|
||||
<version>$version$</version>
|
||||
<packageSourceUrl>https://github.com/billziss-gh/winfsp/tree/master/build/choco</packageSourceUrl>
|
||||
<owners>Bill Zissimopoulos</owners>
|
||||
|
||||
<title>WinFsp</title>
|
||||
<authors>Bill Zissimopoulos</authors>
|
||||
<projectUrl>https://github.com/billziss-gh/winfsp</projectUrl>
|
||||
<iconUrl>https://github.com/billziss-gh/winfsp/raw/master/art/winfsp-solid.png</iconUrl>
|
||||
<copyright>Bill Zissimopoulos</copyright>
|
||||
<licenseUrl>https://github.com/billziss-gh/winfsp/blob/master/License.txt</licenseUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<projectSourceUrl>https://github.com/billziss-gh/winfsp</projectSourceUrl>
|
||||
<docsUrl>https://github.com/billziss-gh/winfsp/tree/master/doc</docsUrl>
|
||||
<mailingListUrl>https://groups.google.com/forum/#!forum/winfsp</mailingListUrl>
|
||||
<bugTrackerUrl>https://github.com/billziss-gh/winfsp/issues</bugTrackerUrl>
|
||||
<tags>driver filesystem fuse gplv3 windows-kernel admin</tags>
|
||||
<summary>Windows File System Proxy - FUSE for Windows</summary>
|
||||
<description>
|
||||
WinFsp is a set of software components for Windows computers that allows the creation of user mode file systems. In this sense it is similar to FUSE (Filesystem in Userspace), which provides the same functionality on UNIX-like computers.
|
||||
|
||||
Some of the benefits of using WinFsp are listed below:
|
||||
|
||||
* Very well-tested and stable.
|
||||
* Very fast.
|
||||
* Strives for compatibility with NTFS.
|
||||
* Easy to understand but comprehensive API.
|
||||
* FUSE compatibility layer for native Windows and Cygwin.
|
||||
* Signed drivers provided on every release.
|
||||
* Available under the GPLv3 license with a special exception for Free/Libre and Open Source Software.
|
||||
|
||||
To verify installation:
|
||||
|
||||
* For 64-bit Windows: `net use m: \\memfs64\share` from the command prompt.
|
||||
* For 32-bit Windows: `net use m: \\memfs32\share`
|
||||
* For Cygwin: `net use m: '\\memfs64\share'`
|
||||
* To delete the drive: `net use m: /delete`
|
||||
</description>
|
||||
<releaseNotes>https://github.com/billziss-gh/winfsp/blob/master/Changelog.asciidoc</releaseNotes>
|
||||
|
||||
<!--<dependencies>
|
||||
<dependency id="chocolatey-uninstall.extension" />
|
||||
</dependencies>-->
|
||||
</metadata>
|
||||
|
||||
<files>
|
||||
<file src="LICENSE.txt" target="tools" />
|
||||
<file src="VERIFICATION.txt" target="tools" />
|
||||
<file src="chocolateyInstall.ps1" target="tools" />
|
||||
<file src="chocolateyUninstall.ps1" target="tools" />
|
||||
<file src="chocolateyHelper.ps1" target="tools" />
|
||||
<file src="winfsp-$version$.msi" target="tools" />
|
||||
</files>
|
||||
</package>
|
56
doc/Frequently-Asked-Questions.asciidoc
Normal file
@ -0,0 +1,56 @@
|
||||
= Frequently Asked Questions
|
||||
|
||||
== General
|
||||
|
||||
[qanda]
|
||||
|
||||
I am running Windows 7 and I am finding that the installed driver is not signed. [@efeat]::
|
||||
|
||||
Your Windows 7 OS is missing SHA-2 Code Signing Support. You need to install the following security advisory that will rectify the problem:
|
||||
https://technet.microsoft.com/en-us/library/security/3033929.aspx
|
||||
|
||||
|
||||
Disconnecting (unmapping) a network drive does not work. [@carlreinke]::
|
||||
|
||||
You may have Dokany installed. Dokany installs its own Network Provider DLL that unfortunately interferes with the WinFsp handling of network drives. The solution is to change your system's Network Provider order and ensure that the WinFsp Network Provider runs before the Dokany one. Instructions on how to change the Network Provider order can be found in this http://blogs.interfacett.com/changing-the-network-provider-order-in-windows-10[article].
|
||||
|
||||
|
||||
Why is the DLL not installed in the Windows system directories? [@netheril96]::
|
||||
|
||||
It is true that this would make it convenient to load the DLL, because the Windows loader looks into the Windows system directories when it loads DLL's. However, in the opinion of the WinFsp author, software that does not ship with the OS should not be installing components in the system directories.
|
||||
+
|
||||
There are a few alternative methods to overcome this problem. WinFsp recommends marking the WinFsp DLL as "delay load" and then using `FspLoad` to dynamically load the DLL during process initialization. For more information see the WinFsp Tutorial.
|
||||
|
||||
|
||||
Does WinFsp provide debugging symbols? [@netheril96]::
|
||||
|
||||
Public debugging symbols are already included in the installer. You need to install the "Developer" feature; the symbols can be found in the `sym` directory under the WinFsp installation directory.
|
||||
|
||||
|
||||
Is there a maximum number of concurrent file systems? [@efeat]::
|
||||
|
||||
WinFsp does not have a hard limit of how many file systems can be created or how many processes can create file systems.
|
||||
+
|
||||
As of the commits required to fix issue #55, there is however a hash table inside the FSD that uses PID's (Process ID's) as keys. This hash table currently expects that in general there will not be more than 50 processes creating file systems. However this is not a hard limit.
|
||||
|
||||
|
||||
== FUSE
|
||||
|
||||
[qanda]
|
||||
|
||||
Which version of FUSE does WinFsp-FUSE support?::
|
||||
|
||||
Currently it supports FUSE 2.8.
|
||||
|
||||
|
||||
FUSE on UNIX systems mounts file systems over an existing directory. When mounting a WinFsp-FUSE file system on a directory, the directory is created and later deleted when the file system goes away. What is the reason for this incompatibility? [@efeat]::
|
||||
|
||||
It would be preferrable if WinFsp-FUSE behaved like FUSE on UNIX in this instance. However there are a number of reasons that this is not the case.
|
||||
+
|
||||
When mounting over directories in Windows, WinFsp-FUSE uses a special construct called a reparse point. Reparse points are a general mechanism for adding special behavior to files and directories. One of the possible reparse points is the "mountpoint" reparse point (often called "junction"), which converts a directory into a mount point.
|
||||
+
|
||||
With this in mind here are the reasons for the current WinFsp-FUSE behavior:
|
||||
+
|
||||
- Symmetry with mounting on a drive. On Windows drives are created when the file system comes into existence and deleted when it is gone.
|
||||
- Inability to mount over a non-empty directory on Windows. On FUSE/UNIX this is possible, but not on Windows because NTFS disallows the creation of (mountpoint) reparse points on non-empty directories.
|
||||
- Most importantly: inability to guarantee that the mount point will cease to exist if the file system crashes. WinFsp attempts to guarantee that all resources used by a file system will get cleaned up. This is certainly true for the kernel-mode FSD, but an attempt is made to do so also in user mode. For this reason, drive symbolic links are marked as temporary and (importantly for our discussion) mount directories are opened with `FILE_FLAG_DELETE_ON_CLOSE`. There is no way to guarantee the removal of a reparse point in the same way.
|
33
doc/Home.md
Normal file
@ -0,0 +1,33 @@
|
||||
# WinFsp - Windows File System Proxy
|
||||
|
||||
[[WinFsp-Icon.png]]
|
||||
|
||||
Developing file systems is a challenging proposition. Developing file systems for Windows is an order of magnitude more difficult. WinFsp eases the task of writing a new file system for Windows. WinFsp file systems are user mode programs and they can be written in a variety of languages and frameworks.
|
||||
|
||||
The documentation available here discusses various aspects of WinFsp.
|
||||
|
||||
## Programming
|
||||
|
||||
- The [[Tutorial|WinFsp-Tutorial]] describes how to create a simple, but complete file system in C/C++.
|
||||
- The [[API Reference|winfsp.h]] describes the native WinFsp API. This external [[link|http://www.secfs.net/winfsp/apiref/]] may be easier to browse for some people.
|
||||
- There is also a FUSE compatibility layer for native Windows and Cygwin. See fuse.h in the source repository.
|
||||
- This [[document|Native-API-vs-FUSE]] discusses the need for both a native API and FUSE and gives some pointers on which one to choose.
|
||||
|
||||
## Design
|
||||
|
||||
- The [[Design|WinFsp-Design]] document describes the high-level design of WinFsp.
|
||||
- The [[IPC|WinFsp-as-an-IPC-Mechanism]] document offers insights into the WinFsp Inter-Process Communication mechanism.
|
||||
- The [[Queued Events|Queued-Events]] document discusses a low-level synchronization primitive that is largely responsible for the excellent performance of the WinFsp IPC mechanism.
|
||||
- The [[Service Architecture|WinFsp-Service-Architecture]] document discusses how to intergrate a file system into Windows as a service and the reasons to do so.
|
||||
- The [[SSHFS Port Case Study|SSHFS-Port-Case-Study]] document chronicles the creation of the WinFsp-FUSE compatibility layer and the decisions that led to its design.
|
||||
|
||||
## Testing
|
||||
|
||||
- The [[Testing|WinFsp-Testing]] document discusses the WinFsp testing strategy and how WinFsp achieves correctness and stability.
|
||||
- The [[Performance|WinFsp-Performance-Testing]] document compares WinFsp performance against other file systems.
|
||||
|
||||
## Compatibility
|
||||
|
||||
- The [[Compatibility|NTFS-Compatibility]] document discusses current WinFsp compatibility with NTFS.
|
||||
|
||||
WinFsp is available under the GPLv3 license with a special exception for Free/Libre and Open Source Software.
|
21
doc/Known-File-Systems.asciidoc
Normal file
@ -0,0 +1,21 @@
|
||||
= Known File Systems and File System Libraries
|
||||
|
||||
This document contains a list of known file systems and file system libraries that run on WinFsp. Please contact the WinFsp project to have your file system solution added to this list.
|
||||
|
||||
== File Systems
|
||||
|
||||
- https://github.com/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/ncw/rclone[rclone] - rsync for cloud storage
|
||||
- https://github.com/hasse69/rar2fs[rar2fs] - FUSE file system for reading RAR archives
|
||||
- https://github.com/billziss-gh/redditfs[redditfs] - ls -l /r/programming
|
||||
- https://github.com/netheril96/securefs[securefs] - Filesystem in userspace (FUSE) with transparent authenticated encryption
|
||||
- https://github.com/billziss-gh/sshfs-win[sshfs-win] - SSHFS for Windows
|
||||
|
||||
== File System Libraries
|
||||
|
||||
- https://github.com/billziss-gh/cgofuse[Go: cgofuse] - Cross-platform FUSE library for Go
|
||||
- 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/SerCeMan/jnr-fuse[Java: jnr-fuse] - FUSE implementation in Java using Java Native Runtime (JNR)
|
||||
- https://github.com/billziss-gh/fusepy[Python: fusepy] - Simple ctypes bindings for FUSE
|
105
doc/Queued-Events.asciidoc
Normal 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!
|
||||
|
BIN
doc/Queued-Events/states.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
doc/Queued-Events/transitions.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
doc/WinFsp-Icon.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
@ -20,23 +20,25 @@ In order to overcome the issue with launching multiple instances of a particular
|
||||
|
||||
Services that wish to be controlled by the WinFsp.Launcher must add themselves under the following registry key:
|
||||
|
||||
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services
|
||||
HKEY_LOCAL_MACHINE\Software\WinFsp\Services
|
||||
|
||||
For example, the MEMFS sample adds the following registry entries under this key:
|
||||
NOTE: Please note that in a 64-bit system the actual location is `HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\WinFsp\Services`.
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services\memfs32]
|
||||
For example, the MEMFS sample adds the following registry entries in a 64-bit system:
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\WinFsp\Services\memfs32]
|
||||
"Executable"="C:\\Program Files (x86)\\WinFsp\\bin\\memfs-x86.exe"
|
||||
"CommandLine"="-u %1 -m %2"
|
||||
"CommandLine"="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2"
|
||||
"Security"="D:P(A;;RPWPLC;;;WD)"
|
||||
"JobControl"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services\memfs64]
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\WinFsp\Services\memfs64]
|
||||
"Executable"="C:\\Program Files (x86)\\WinFsp\\bin\\memfs-x64.exe"
|
||||
"CommandLine"="-u %1 -m %2"
|
||||
"CommandLine"="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2"
|
||||
"Security"="D:P(A;;RPWPLC;;;WD)"
|
||||
"JobControl"=dword:00000001
|
||||
|
||||
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.
|
||||
|
||||
@ -44,4 +46,14 @@ One final note regarding security. Notice the `Security` registry value in the e
|
||||
|
||||
WinFsp includes a Network Provider that integrates with Windows and can be used to start and stop user mode file systems from the Windows shell. To achieve this the Network Provider (implemented as part of the WinFsp DLL) works closely with the WinFsp.Launcher service.
|
||||
|
||||
For example, if a user uses the Windows Explorer to map `\\memfs64\share` to the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to start an instance of the memfs64 service with command line `-u \\memfs64\share -m Z:`. When the user disconnects the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to stop the previously started instance of the memfs64 service.
|
||||
For example, if a user uses the Windows Explorer to map `\\memfs64\share` to the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to start an instance of the memfs64 service with command line `-i -F NTFS -n 65536 -s 67108864 -u \\memfs64\share -m Z:`. When the user disconnects the `Z:` drive, the Network Provider will instruct the WinFsp.Launcher to stop the previously started instance of the memfs64 service.
|
||||
|
||||
== 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.
|
@ -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.
|
||||
|
||||
== 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.
|
||||
|
||||
@ -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.
|
||||
|
||||
== 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
|
||||
|
||||
WinFsp is regularly run under the Visual Studio's Code Analyzer. Any issues found are examined and if necessary acted upon.
|
||||
|
1326
doc/WinFsp-Tutorial.asciidoc
Normal file
BIN
doc/WinFsp-Tutorial/EntryExit.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
doc/WinFsp-Tutorial/Explorer.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
doc/WinFsp-Tutorial/FirstRun.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
doc/WinFsp-Tutorial/Installer.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
doc/WinFsp-Tutorial/MissingDll.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
doc/WinFsp-Tutorial/NetUse.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
doc/WinFsp-Tutorial/NewProject.png
Normal file
After Width: | Height: | Size: 20 KiB |
1741
doc/winfsp.h.asciidoc
Normal file
121
inc/fuse/fuse.h
@ -39,54 +39,82 @@ typedef int (*fuse_dirfil_t)(fuse_dirh_t h, const char *name,
|
||||
|
||||
struct fuse_operations
|
||||
{
|
||||
int (*getattr)(const char *path, struct fuse_stat *stbuf);
|
||||
int (*getdir)(const char *path, fuse_dirh_t h, fuse_dirfil_t filler);
|
||||
int (*readlink)(const char *path, char *buf, size_t size);
|
||||
int (*mknod)(const char *path, fuse_mode_t mode, fuse_dev_t dev);
|
||||
int (*mkdir)(const char *path, fuse_mode_t mode);
|
||||
int (*unlink)(const char *path);
|
||||
int (*rmdir)(const char *path);
|
||||
int (*symlink)(const char *dstpath, const char *srcpath);
|
||||
int (*rename)(const char *oldpath, const char *newpath);
|
||||
int (*link)(const char *srcpath, const char *dstpath);
|
||||
int (*chmod)(const char *path, fuse_mode_t mode);
|
||||
int (*chown)(const char *path, fuse_uid_t uid, fuse_gid_t gid);
|
||||
int (*truncate)(const char *path, fuse_off_t size);
|
||||
int (*utime)(const char *path, struct fuse_utimbuf *timbuf);
|
||||
int (*open)(const char *path, struct fuse_file_info *fi);
|
||||
int (*read)(const char *path, char *buf, size_t size, fuse_off_t off,
|
||||
/* S - supported by WinFsp */
|
||||
/* S */ int (*getattr)(const char *path, struct fuse_stat *stbuf);
|
||||
/* S */ int (*getdir)(const char *path, fuse_dirh_t h, fuse_dirfil_t filler);
|
||||
/* S */ int (*readlink)(const char *path, char *buf, size_t size);
|
||||
/* S */ int (*mknod)(const char *path, fuse_mode_t mode, fuse_dev_t dev);
|
||||
/* S */ int (*mkdir)(const char *path, fuse_mode_t mode);
|
||||
/* S */ int (*unlink)(const char *path);
|
||||
/* S */ int (*rmdir)(const char *path);
|
||||
/* S */ int (*symlink)(const char *dstpath, const char *srcpath);
|
||||
/* S */ int (*rename)(const char *oldpath, const char *newpath);
|
||||
/* _ */ int (*link)(const char *srcpath, const char *dstpath);
|
||||
/* S */ int (*chmod)(const char *path, fuse_mode_t mode);
|
||||
/* S */ int (*chown)(const char *path, fuse_uid_t uid, fuse_gid_t gid);
|
||||
/* S */ int (*truncate)(const char *path, fuse_off_t size);
|
||||
/* S */ int (*utime)(const char *path, struct fuse_utimbuf *timbuf);
|
||||
/* 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);
|
||||
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);
|
||||
int (*statfs)(const char *path, struct fuse_statvfs *stbuf);
|
||||
int (*flush)(const char *path, struct fuse_file_info *fi);
|
||||
int (*release)(const char *path, struct fuse_file_info *fi);
|
||||
int (*fsync)(const char *path, int datasync, struct fuse_file_info *fi);
|
||||
int (*setxattr)(const char *path, const char *name, const char *value, size_t size,
|
||||
/* S */ int (*statfs)(const char *path, struct fuse_statvfs *stbuf);
|
||||
/* S */ int (*flush)(const char *path, struct fuse_file_info *fi);
|
||||
/* S */ int (*release)(const char *path, 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 flags);
|
||||
int (*getxattr)(const char *path, const char *name, char *value, size_t size);
|
||||
int (*listxattr)(const char *path, char *namebuf, size_t size);
|
||||
int (*removexattr)(const char *path, const char *name);
|
||||
int (*opendir)(const char *path, struct fuse_file_info *fi);
|
||||
int (*readdir)(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
|
||||
/* _ */ int (*getxattr)(const char *path, const char *name, char *value, size_t size);
|
||||
/* _ */ int (*listxattr)(const char *path, char *namebuf, size_t size);
|
||||
/* _ */ int (*removexattr)(const char *path, const char *name);
|
||||
/* S */ int (*opendir)(const char *path, struct fuse_file_info *fi);
|
||||
/* S */ int (*readdir)(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
|
||||
struct fuse_file_info *fi);
|
||||
int (*releasedir)(const char *path, struct fuse_file_info *fi);
|
||||
int (*fsyncdir)(const char *path, int datasync, struct fuse_file_info *fi);
|
||||
void *(*init)(struct fuse_conn_info *conn);
|
||||
void (*destroy)(void *data);
|
||||
int (*access)(const char *path, int mask);
|
||||
int (*create)(const char *path, fuse_mode_t mode, struct fuse_file_info *fi);
|
||||
int (*ftruncate)(const char *path, fuse_off_t off, struct fuse_file_info *fi);
|
||||
int (*fgetattr)(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi);
|
||||
int (*lock)(const char *path, struct fuse_file_info *fi, int cmd, struct fuse_flock *lock);
|
||||
int (*utimens)(const char *path, const struct fuse_timespec tv[2]);
|
||||
int (*bmap)(const char *path, size_t blocksize, uint64_t *idx);
|
||||
unsigned int flag_nullpath_ok:1;
|
||||
unsigned int flag_reserved:31;
|
||||
int (*ioctl)(const char *path, int cmd, void *arg, struct fuse_file_info *fi,
|
||||
/* S */ int (*releasedir)(const char *path, struct fuse_file_info *fi);
|
||||
/* S */ int (*fsyncdir)(const char *path, int datasync, struct fuse_file_info *fi);
|
||||
/* S */ void *(*init)(struct fuse_conn_info *conn);
|
||||
/* S */ void (*destroy)(void *data);
|
||||
/* _ */ int (*access)(const char *path, int mask);
|
||||
/* S */ int (*create)(const char *path, fuse_mode_t mode, struct fuse_file_info *fi);
|
||||
/* S */ int (*ftruncate)(const char *path, fuse_off_t off, 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);
|
||||
/* S */ int (*utimens)(const char *path, const struct fuse_timespec tv[2]);
|
||||
/* _ */ int (*bmap)(const char *path, size_t blocksize, uint64_t *idx);
|
||||
/* _ */ unsigned int flag_nullpath_ok:1;
|
||||
/* _ */ unsigned int flag_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);
|
||||
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);
|
||||
/* 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
|
||||
@ -118,6 +146,8 @@ FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_loop_mt)(struct fsp_fuse_env *env,
|
||||
struct fuse *f);
|
||||
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_exit)(struct fsp_fuse_env *env,
|
||||
struct fuse *f);
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_exited)(struct fsp_fuse_env *env,
|
||||
struct fuse *f);
|
||||
FSP_FUSE_API struct fuse_context *FSP_FUSE_API_NAME(fsp_fuse_get_context)(struct fsp_fuse_env *env);
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
@ -171,6 +201,13 @@ void fuse_exit(struct fuse *f),
|
||||
(fsp_fuse_env(), f);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
int fuse_exited(struct fuse *f),
|
||||
{
|
||||
return FSP_FUSE_API_CALL(fsp_fuse_exited)
|
||||
(fsp_fuse_env(), f);
|
||||
})
|
||||
|
||||
FSP_FUSE_SYM(
|
||||
struct fuse_context *fuse_get_context(void),
|
||||
{
|
||||
|
@ -41,12 +41,40 @@ extern "C" {
|
||||
#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
|
||||
#define FUSE_CAP_BIG_WRITES (1 << 5)
|
||||
#define FUSE_CAP_DONT_MASK (1 << 6)
|
||||
#define FUSE_CAP_ALLOCATE (1 << 27) /* reserved (OSXFUSE) */
|
||||
#define FUSE_CAP_EXCHANGE_DATA (1 << 28) /* reserved (OSXFUSE) */
|
||||
#define FUSE_CAP_CASE_INSENSITIVE (1 << 29) /* file system is case insensitive */
|
||||
#define FUSE_CAP_VOL_RENAME (1 << 30) /* reserved (OSXFUSE) */
|
||||
#define FUSE_CAP_XTIMES (1 << 31) /* reserved (OSXFUSE) */
|
||||
|
||||
#define FSP_FUSE_CAP_READDIR_PLUS (1 << 21) /* file system supports enhanced readdir */
|
||||
#define FSP_FUSE_CAP_READ_ONLY (1 << 22) /* file system is marked read-only */
|
||||
#define FSP_FUSE_CAP_STAT_EX (1 << 23) /* file system supports fuse_stat_ex */
|
||||
#define FSP_FUSE_CAP_CASE_INSENSITIVE FUSE_CAP_CASE_INSENSITIVE
|
||||
|
||||
#define FUSE_IOCTL_COMPAT (1 << 0)
|
||||
#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
|
||||
#define FUSE_IOCTL_RETRY (1 << 2)
|
||||
#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
|
||||
{
|
||||
int flags;
|
||||
@ -76,6 +104,9 @@ struct fuse_conn_info
|
||||
struct fuse_session;
|
||||
struct fuse_chan;
|
||||
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 struct fuse_chan *FSP_FUSE_API_NAME(fsp_fuse_mount)(struct fsp_fuse_env *env,
|
||||
|
@ -65,6 +65,27 @@ extern "C" {
|
||||
* 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)
|
||||
|
||||
typedef uint32_t fuse_uid_t;
|
||||
@ -111,23 +132,17 @@ struct fuse_timespec
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !defined(FSP_FUSE_USE_STAT_EX)
|
||||
struct fuse_stat
|
||||
{
|
||||
fuse_dev_t st_dev;
|
||||
fuse_ino_t st_ino;
|
||||
fuse_mode_t st_mode;
|
||||
fuse_nlink_t st_nlink;
|
||||
fuse_uid_t st_uid;
|
||||
fuse_gid_t st_gid;
|
||||
fuse_dev_t st_rdev;
|
||||
fuse_off_t st_size;
|
||||
struct fuse_timespec st_atim;
|
||||
struct fuse_timespec st_mtim;
|
||||
struct fuse_timespec st_ctim;
|
||||
fuse_blksize_t st_blksize;
|
||||
fuse_blkcnt_t st_blocks;
|
||||
struct fuse_timespec st_birthtim;
|
||||
FSP_FUSE_STAT_FIELD_DEFN
|
||||
};
|
||||
#else
|
||||
struct fuse_stat
|
||||
{
|
||||
FSP_FUSE_STAT_EX_FIELD_DEFN
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
struct fuse_statvfs
|
||||
@ -177,6 +192,9 @@ struct fuse_flock
|
||||
MemAlloc, MemFree, \
|
||||
fsp_fuse_daemonize, \
|
||||
fsp_fuse_set_signal_handlers, \
|
||||
0/*conv_to_win_path*/, \
|
||||
0/*winpid_to_pid*/, \
|
||||
{ 0 }, \
|
||||
}
|
||||
#else
|
||||
#define FSP_FUSE_ENV_INIT \
|
||||
@ -185,6 +203,9 @@ struct fuse_flock
|
||||
malloc, free, \
|
||||
fsp_fuse_daemonize, \
|
||||
fsp_fuse_set_signal_handlers, \
|
||||
0/*conv_to_win_path*/, \
|
||||
0/*winpid_to_pid*/, \
|
||||
{ 0 }, \
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -216,7 +237,14 @@ struct fuse_flock
|
||||
#define fuse_utimbuf utimbuf
|
||||
#define fuse_timespec timespec
|
||||
|
||||
#if !defined(FSP_FUSE_USE_STAT_EX)
|
||||
#define fuse_stat stat
|
||||
#else
|
||||
struct fuse_stat
|
||||
{
|
||||
FSP_FUSE_STAT_EX_FIELD_DEFN
|
||||
};
|
||||
#endif
|
||||
#define fuse_statvfs statvfs
|
||||
#define fuse_flock flock
|
||||
|
||||
@ -226,6 +254,9 @@ struct fuse_flock
|
||||
malloc, free, \
|
||||
fsp_fuse_daemonize, \
|
||||
fsp_fuse_set_signal_handlers, \
|
||||
fsp_fuse_conv_to_win_path, \
|
||||
fsp_fuse_winpid_to_pid, \
|
||||
{ 0 }, \
|
||||
}
|
||||
|
||||
/*
|
||||
@ -237,6 +268,11 @@ struct fuse_flock
|
||||
#error unsupported environment
|
||||
#endif
|
||||
|
||||
struct fuse_stat_ex
|
||||
{
|
||||
FSP_FUSE_STAT_EX_FIELD_DEFN
|
||||
};
|
||||
|
||||
struct fsp_fuse_env
|
||||
{
|
||||
unsigned environment;
|
||||
@ -244,7 +280,9 @@ struct fsp_fuse_env
|
||||
void (*memfree)(void *);
|
||||
int (*daemonize)(int);
|
||||
int (*set_signal_handlers)(void *);
|
||||
void (*reserved[4])();
|
||||
char *(*conv_to_win_path)(const char *);
|
||||
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);
|
||||
@ -348,6 +386,20 @@ static inline int fsp_fuse_set_signal_handlers(void *se)
|
||||
#undef FSP_FUSE_SET_SIGNAL_HANDLER
|
||||
}
|
||||
|
||||
static inline char *fsp_fuse_conv_to_win_path(const char *path)
|
||||
{
|
||||
void *cygwin_create_path(unsigned, const void *);
|
||||
return cygwin_create_path(
|
||||
0/*CCP_POSIX_TO_WIN_A*/ | 0x100/*CCP_RELATIVE*/,
|
||||
path);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
@ -78,6 +78,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_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 */
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4200) /* zero-sized array in struct/union */
|
||||
@ -147,7 +150,10 @@ typedef struct
|
||||
UINT32 ReadOnlyVolume:1;
|
||||
/* kernel-mode flags */
|
||||
UINT32 PostCleanupWhenModifiedOnly:1; /* post Cleanup when a file was modified/deleted */
|
||||
UINT32 KmReservedFlags:5;
|
||||
UINT32 PassQueryDirectoryPattern:1; /* pass Pattern during QueryDirectory operations */
|
||||
UINT32 AlwaysUseDoubleBuffering:1;
|
||||
UINT32 PassQueryDirectoryFileName:1; /* pass FileName during QueryDirectory (GetDirInfoByName) */
|
||||
UINT32 KmReservedFlags:2;
|
||||
/* user-mode flags */
|
||||
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
|
||||
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */
|
||||
@ -185,8 +191,7 @@ typedef struct
|
||||
{
|
||||
UINT16 Size;
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
UINT64 NextOffset;
|
||||
UINT8 Padding[16];
|
||||
UINT8 Padding[24];
|
||||
/* make struct as big as FILE_ID_BOTH_DIR_INFORMATION; allows for in-place copying */
|
||||
WCHAR FileNameBuf[];
|
||||
} FSP_FSCTL_DIR_INFO;
|
||||
@ -221,7 +226,7 @@ typedef struct
|
||||
UINT32 FileAttributes; /* file attributes for new files */
|
||||
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* security descriptor for new files */
|
||||
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 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
||||
UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */
|
||||
@ -314,7 +319,7 @@ typedef struct
|
||||
struct
|
||||
{
|
||||
FSP_FSCTL_TRANSACT_BUF NewFileName;
|
||||
UINT64 AccessToken; /* request access token (HANDLE) */
|
||||
UINT64 AccessToken; /* request access token (PID,HANDLE) */
|
||||
} Rename;
|
||||
} Info;
|
||||
} SetInformation;
|
||||
@ -339,10 +344,11 @@ typedef struct
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
UINT64 Address;
|
||||
UINT64 Offset;
|
||||
UINT32 Length;
|
||||
FSP_FSCTL_TRANSACT_BUF Pattern;
|
||||
FSP_FSCTL_TRANSACT_BUF Marker;
|
||||
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
|
||||
UINT32 PatternIsFileName:1; /* Pattern does not contain wildcards */
|
||||
} QueryDirectory;
|
||||
struct
|
||||
{
|
||||
|
@ -26,7 +26,10 @@
|
||||
#include <windows.h>
|
||||
#undef WIN32_NO_STATUS
|
||||
#include <winternl.h>
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4005) /* macro redefinition */
|
||||
#include <ntstatus.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#if defined(WINFSP_DLL_INTERNAL)
|
||||
#define FSP_API __declspec(dllexport)
|
||||
@ -647,30 +650,18 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
||||
* The file system on which this request is posted.
|
||||
* @param FileContext
|
||||
* The file context of the directory to be read.
|
||||
* @param Buffer
|
||||
* Pointer to a buffer that will receive the results of the read operation.
|
||||
* @param Offset
|
||||
* Offset within the directory to read from. The kernel does not interpret this value
|
||||
* which is used solely by the file system to locate directory entries. However the
|
||||
* special value 0 indicates that the read should start from the first entries. The first
|
||||
* two entries returned by ReadDirectory should always be the "." and ".." entries,
|
||||
* except for the root directory which does not have these entries.
|
||||
*
|
||||
* This parameter is used by the WinFsp FSD to break directory listings into chunks.
|
||||
* In this case all 64-bits of the Offset are valid. In some cases the Windows kernel
|
||||
* (NTOS) may also use this parameter. In this case only the lower 32-bits of this
|
||||
* parameter will be valid. This is an unfortunate limitation of Windows (for more
|
||||
* information see the documentation for IRP_MJ_DIRECTORY_CONTROL and the flag
|
||||
* SL_INDEX_SPECIFIED).
|
||||
*
|
||||
* In practice this means that you should only rely on the lower 32-bits of this value
|
||||
* to be valid.
|
||||
* @param Length
|
||||
* Length of data to read.
|
||||
* @param Pattern
|
||||
* The pattern to match against files in this directory. Can be NULL. The file system
|
||||
* can choose to ignore this parameter as the FSD will always perform its own pattern
|
||||
* matching on the returned results.
|
||||
* @param Marker
|
||||
* A file name that marks where in the directory to start reading. Files with names
|
||||
* that are greater than (not equal to) this marker (in the directory order determined
|
||||
* by the file system) should be returned. Can be NULL.
|
||||
* @param Buffer
|
||||
* Pointer to a buffer that will receive the results of the read operation.
|
||||
* @param Length
|
||||
* Length of data to read.
|
||||
* @param PBytesTransferred [out]
|
||||
* Pointer to a memory location that will receive the actual number of bytes read.
|
||||
* @return
|
||||
@ -680,9 +671,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
||||
* FspFileSystemAddDirInfo
|
||||
*/
|
||||
NTSTATUS (*ReadDirectory)(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length,
|
||||
PWSTR Pattern,
|
||||
PULONG PBytesTransferred);
|
||||
PVOID FileContext, PWSTR Pattern, PWSTR Marker,
|
||||
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
|
||||
/**
|
||||
* Resolve reparse points.
|
||||
*
|
||||
@ -812,12 +802,32 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
||||
NTSTATUS (*GetStreamInfo)(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileContext, PVOID Buffer, ULONG Length,
|
||||
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.
|
||||
* Please update when changing the interface as it is important for future compatibility.
|
||||
*/
|
||||
NTSTATUS (*Reserved[40])();
|
||||
NTSTATUS (*Reserved[39])();
|
||||
} FSP_FILE_SYSTEM_INTERFACE;
|
||||
FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
|
||||
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
|
||||
@ -845,6 +855,20 @@ typedef struct _FSP_FILE_SYSTEM_OPERATION_CONTEXT
|
||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||
FSP_FSCTL_TRANSACT_RSP *Response;
|
||||
} FSP_FILE_SYSTEM_OPERATION_CONTEXT;
|
||||
/**
|
||||
* Check whether creating a file system object is possible.
|
||||
*
|
||||
* @param DevicePath
|
||||
* The name of the control device for this file system. This must be either
|
||||
* FSP_FSCTL_DISK_DEVICE_NAME or FSP_FSCTL_NET_DEVICE_NAME.
|
||||
* @param MountPoint
|
||||
* The mount point for the new file system. A value of NULL means that the file system should
|
||||
* use the next available drive letter counting downwards from Z: as its mount point.
|
||||
* @return
|
||||
* STATUS_SUCCESS or error code.
|
||||
*/
|
||||
FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath,
|
||||
PWSTR MountPoint);
|
||||
/**
|
||||
* Create a file system object.
|
||||
*
|
||||
@ -892,6 +916,8 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem);
|
||||
* STATUS_SUCCESS or error code.
|
||||
*/
|
||||
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint);
|
||||
FSP_API NTSTATUS FspFileSystemSetMountPointEx(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint,
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor);
|
||||
/**
|
||||
* Remove the mount point for a file system.
|
||||
*
|
||||
@ -960,6 +986,7 @@ PWSTR FspFileSystemMountPoint(FSP_FILE_SYSTEM *FileSystem)
|
||||
{
|
||||
return FileSystem->MountPoint;
|
||||
}
|
||||
FSP_API PWSTR FspFileSystemMountPointF(FSP_FILE_SYSTEM *FileSystem);
|
||||
static inline
|
||||
NTSTATUS FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
@ -969,6 +996,8 @@ NTSTATUS FspFileSystemEnterOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
||||
return FileSystem->EnterOperation(FileSystem, Request, Response);
|
||||
}
|
||||
FSP_API NTSTATUS FspFileSystemEnterOperationF(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
static inline
|
||||
NTSTATUS FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
@ -978,6 +1007,8 @@ NTSTATUS FspFileSystemLeaveOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
||||
return FileSystem->LeaveOperation(FileSystem, Request, Response);
|
||||
}
|
||||
FSP_API NTSTATUS FspFileSystemLeaveOperationF(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
static inline
|
||||
VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation,
|
||||
@ -986,6 +1017,9 @@ VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
|
||||
FileSystem->EnterOperation = EnterOperation;
|
||||
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.
|
||||
*
|
||||
@ -1002,6 +1036,8 @@ VOID FspFileSystemSetOperationGuardStrategy(FSP_FILE_SYSTEM *FileSystem,
|
||||
{
|
||||
FileSystem->OpGuardStrategy = GuardStrategy;
|
||||
}
|
||||
FSP_API VOID FspFileSystemSetOperationGuardStrategyF(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy);
|
||||
static inline
|
||||
VOID FspFileSystemSetOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
ULONG Index,
|
||||
@ -1009,6 +1045,9 @@ VOID FspFileSystemSetOperation(FSP_FILE_SYSTEM *FileSystem,
|
||||
{
|
||||
FileSystem->Operations[Index] = Operation;
|
||||
}
|
||||
FSP_API VOID FspFileSystemSetOperationF(FSP_FILE_SYSTEM *FileSystem,
|
||||
ULONG Index,
|
||||
FSP_FILE_SYSTEM_OPERATION *Operation);
|
||||
static inline
|
||||
VOID FspFileSystemGetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
|
||||
NTSTATUS *PDispatcherResult)
|
||||
@ -1017,6 +1056,8 @@ VOID FspFileSystemGetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
|
||||
*PDispatcherResult = FileSystem->DispatcherResult;
|
||||
MemoryBarrier();
|
||||
}
|
||||
FSP_API VOID FspFileSystemGetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem,
|
||||
NTSTATUS *PDispatcherResult);
|
||||
static inline
|
||||
VOID FspFileSystemSetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
|
||||
NTSTATUS DispatcherResult)
|
||||
@ -1025,12 +1066,16 @@ VOID FspFileSystemSetDispatcherResult(FSP_FILE_SYSTEM *FileSystem,
|
||||
return;
|
||||
InterlockedCompareExchange(&FileSystem->DispatcherResult, DispatcherResult, 0);
|
||||
}
|
||||
FSP_API VOID FspFileSystemSetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem,
|
||||
NTSTATUS DispatcherResult);
|
||||
static inline
|
||||
VOID FspFileSystemSetDebugLog(FSP_FILE_SYSTEM *FileSystem,
|
||||
UINT32 DebugLog)
|
||||
{
|
||||
FileSystem->DebugLog = DebugLog;
|
||||
}
|
||||
FSP_API VOID FspFileSystemSetDebugLogF(FSP_FILE_SYSTEM *FileSystem,
|
||||
UINT32 DebugLog);
|
||||
static inline
|
||||
BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID)
|
||||
{
|
||||
@ -1039,6 +1084,29 @@ BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID)
|
||||
FspFsctlTransactCreateKind == Request->Kind && Request->Req.Create.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
|
||||
@ -1292,6 +1360,19 @@ FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint(
|
||||
FSP_API BOOLEAN FspFileSystemAddStreamInfo(FSP_FSCTL_STREAM_INFO *StreamInfo,
|
||||
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
|
||||
|
||||
/*
|
||||
* Directory buffering
|
||||
*/
|
||||
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
|
||||
BOOLEAN Reset, PNTSTATUS PResult);
|
||||
FSP_API BOOLEAN FspFileSystemFillDirectoryBuffer(PVOID *PDirBuffer,
|
||||
FSP_FSCTL_DIR_INFO *DirInfo, PNTSTATUS PResult);
|
||||
FSP_API VOID FspFileSystemReleaseDirectoryBuffer(PVOID *PDirBuffer);
|
||||
FSP_API VOID FspFileSystemReadDirectoryBuffer(PVOID *PDirBuffer,
|
||||
PWSTR Marker,
|
||||
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
|
||||
FSP_API VOID FspFileSystemDeleteDirectoryBuffer(PVOID *PDirBuffer);
|
||||
|
||||
/*
|
||||
* Security
|
||||
*/
|
||||
@ -1389,6 +1470,23 @@ NTSTATUS FspPosixMapPosixToWindowsPath(const char *PosixPath, PWSTR *PWindowsPat
|
||||
return FspPosixMapPosixToWindowsPathEx(PosixPath, PWindowsPath, TRUE);
|
||||
}
|
||||
FSP_API VOID FspPosixDeletePath(void *Path);
|
||||
FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size);
|
||||
FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size);
|
||||
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
|
||||
@ -1609,6 +1707,71 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
|
||||
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
|
||||
PULONG PBytesTransferred, ULONG Timeout,
|
||||
PSID Sid);
|
||||
FSP_API NTSTATUS FspVersion(PUINT32 PVersion);
|
||||
|
||||
/*
|
||||
* Delay load
|
||||
*/
|
||||
static inline
|
||||
NTSTATUS FspLoad(PVOID *PModule)
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
#define FSP_DLLNAME "winfsp-x64.dll"
|
||||
#else
|
||||
#define FSP_DLLNAME "winfsp-x86.dll"
|
||||
#endif
|
||||
#define FSP_DLLPATH "bin\\" FSP_DLLNAME
|
||||
|
||||
WINADVAPI
|
||||
LSTATUS
|
||||
APIENTRY
|
||||
RegGetValueW(
|
||||
HKEY hkey,
|
||||
LPCWSTR lpSubKey,
|
||||
LPCWSTR lpValue,
|
||||
DWORD dwFlags,
|
||||
LPDWORD pdwType,
|
||||
PVOID pvData,
|
||||
LPDWORD pcbData);
|
||||
|
||||
WCHAR PathBuf[MAX_PATH];
|
||||
DWORD Size;
|
||||
HKEY RegKey;
|
||||
LONG Result;
|
||||
HMODULE Module;
|
||||
|
||||
if (0 != PModule)
|
||||
*PModule = 0;
|
||||
|
||||
Module = LoadLibraryW(L"" FSP_DLLNAME);
|
||||
if (0 == Module)
|
||||
{
|
||||
Result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\WinFsp",
|
||||
0, KEY_READ | KEY_WOW64_32KEY, &RegKey);
|
||||
if (ERROR_SUCCESS == Result)
|
||||
{
|
||||
Size = sizeof PathBuf - sizeof L"" FSP_DLLPATH + sizeof(WCHAR);
|
||||
Result = RegGetValueW(RegKey, 0, L"InstallDir",
|
||||
RRF_RT_REG_SZ, 0, PathBuf, &Size);
|
||||
RegCloseKey(RegKey);
|
||||
}
|
||||
if (ERROR_SUCCESS != Result)
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
|
||||
RtlCopyMemory(PathBuf + (Size / sizeof(WCHAR) - 1), L"" FSP_DLLPATH, sizeof L"" FSP_DLLPATH);
|
||||
Module = LoadLibraryW(PathBuf);
|
||||
if (0 == Module)
|
||||
return STATUS_DLL_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (0 != PModule)
|
||||
*PModule = Module;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
#undef FSP_DLLNAME
|
||||
#undef FSP_DLLPATH
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
1308
inc/winfsp/winfsp.hpp
Normal file
@ -18,3 +18,13 @@ cygport:
|
||||
> opt/cygfuse/winfsp-work.tar.gz\
|
||||
)
|
||||
CYGPORT_SRC_URI=winfsp-work.tar.gz CYGPORT_SRC_DIR=winfsp-work cygport fuse.cygport download prep compile install package
|
||||
|
||||
dist: cygport
|
||||
case $(shell uname -m) in \
|
||||
x86_64)\
|
||||
mkdir -p 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 ;;\
|
||||
esac
|
||||
|
@ -17,22 +17,39 @@
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/cygwin.h>
|
||||
|
||||
static void *cygfuse_init_slow(int force);
|
||||
static void *cygfuse_init_winfsp();
|
||||
static void *cygfuse_init_fail();
|
||||
|
||||
static pthread_mutex_t cygfuse_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static void *cygfuse_handle = 0;
|
||||
|
||||
static inline void cygfuse_init(int force)
|
||||
static inline void *cygfuse_init_fast(void)
|
||||
{
|
||||
void *handle = cygfuse_handle;
|
||||
__sync_synchronize(); /* memory barrier */
|
||||
if (0 == handle)
|
||||
handle = cygfuse_init_slow(0);
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void *cygfuse_init_slow(int force)
|
||||
{
|
||||
void *handle;
|
||||
pthread_mutex_lock(&cygfuse_mutex);
|
||||
if (force || 0 == cygfuse_handle)
|
||||
cygfuse_handle = cygfuse_init_winfsp();
|
||||
handle = cygfuse_handle;
|
||||
if (force || 0 == handle)
|
||||
{
|
||||
handle = cygfuse_init_winfsp();
|
||||
__sync_synchronize(); /* memory barrier */
|
||||
cygfuse_handle = handle;
|
||||
}
|
||||
pthread_mutex_unlock(&cygfuse_mutex);
|
||||
return handle;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -50,7 +67,7 @@ static inline int cygfuse_daemon(int nochdir, int noclose)
|
||||
return -1;
|
||||
|
||||
/* force reload of WinFsp DLL to workaround fork() problems */
|
||||
cygfuse_init(1);
|
||||
cygfuse_init_slow(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -58,7 +75,7 @@ static inline int cygfuse_daemon(int nochdir, int noclose)
|
||||
|
||||
#define FSP_FUSE_API static
|
||||
#define FSP_FUSE_API_NAME(api) (* pfn_ ## api)
|
||||
#define FSP_FUSE_API_CALL(api) (cygfuse_init(0), pfn_ ## api)
|
||||
#define FSP_FUSE_API_CALL(api) (cygfuse_init_fast(), pfn_ ## api)
|
||||
#define FSP_FUSE_SYM(proto, ...) __attribute__ ((visibility("default"))) proto { __VA_ARGS__ }
|
||||
#include <fuse_common.h>
|
||||
#include <fuse.h>
|
||||
@ -74,6 +91,7 @@ static inline int cygfuse_daemon(int nochdir, int noclose)
|
||||
if (0 == (*(void **)&(pfn_ ## n) = dlsym(h, #n)))\
|
||||
return cygfuse_init_fail();
|
||||
|
||||
static void *cygfuse_init_fail();
|
||||
static void *cygfuse_init_winfsp()
|
||||
{
|
||||
void *h;
|
||||
@ -125,6 +143,7 @@ static void *cygfuse_init_winfsp()
|
||||
CYGFUSE_GET_API(h, fsp_fuse_loop);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_loop_mt);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_exit);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_exited);
|
||||
CYGFUSE_GET_API(h, fsp_fuse_get_context);
|
||||
|
||||
/* fuse_opt.h */
|
||||
@ -141,6 +160,7 @@ static void *cygfuse_init_winfsp()
|
||||
|
||||
static void *cygfuse_init_fail()
|
||||
{
|
||||
abort();
|
||||
fprintf(stderr, "cygfuse: initialization failed: " CYGFUSE_WINFSP_NAME " not found\n");
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
|
8
opt/cygfuse/dist/install.sh
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
cd "$(dirname "$0")"
|
||||
case $(uname -m) in
|
||||
x86_64)
|
||||
tar -C/ -xaf x64/fuse-2.8-*.tar.xz ;;
|
||||
*)
|
||||
tar -C/ -xaf x86/fuse-2.8-*.tar.xz ;;
|
||||
esac
|
||||
echo FUSE for Cygwin installed.
|
8
opt/cygfuse/dist/uninstall.sh
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
cd "$(dirname "$0")"
|
||||
case $(uname -m) in
|
||||
x86_64)
|
||||
tar -taf x64/fuse-2.8-*.tar.xz | sed -e '/\/$/d' -e 's/.*/\/&/' | xargs rm -f ;;
|
||||
*)
|
||||
tar -taf x86/fuse-2.8-*.tar.xz | sed -e '/\/$/d' -e 's/.*/\/&/' | xargs rm -f ;;
|
||||
esac
|
||||
echo FUSE for Cygwin uninstalled.
|
BIN
opt/cygfuse/dist/x64/fuse-2.8-7.tar.xz
vendored
Normal file
BIN
opt/cygfuse/dist/x86/fuse-2.8-7.tar.xz
vendored
Normal file
@ -1,6 +1,6 @@
|
||||
NAME="fuse"
|
||||
VERSION=2.8
|
||||
RELEASE=3
|
||||
RELEASE=7
|
||||
CATEGORY="Utils"
|
||||
SUMMARY="WinFsp-FUSE compatibility layer"
|
||||
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."
|
||||
|
101
src/dll/debug.c
@ -106,7 +106,7 @@ static const char *FspDebugLogDispositionString(UINT32 CreateOptions)
|
||||
|
||||
static const char *FspDebugLogUserContextString(UINT64 UserContext, UINT64 UserContext2, char *Buf)
|
||||
{
|
||||
wsprintfA(Buf, 0 == UserContext2 ? "%p" : "%p:%p", UserContext, UserContext2);
|
||||
wsprintfA(Buf, 0 == UserContext2 ? "%p" : "%p:%p", (PVOID)UserContext, (PVOID)UserContext2);
|
||||
|
||||
return Buf;
|
||||
}
|
||||
@ -269,13 +269,13 @@ static const char *FspDebugLogReparseDataString(PVOID ReparseData0, char *Buf)
|
||||
static VOID FspDebugLogRequestVoid(FSP_FSCTL_TRANSACT_REQ *Request, const char *Name)
|
||||
{
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint, Name);
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint, Name);
|
||||
}
|
||||
|
||||
static VOID FspDebugLogResponseStatus(FSP_FSCTL_TRANSACT_RSP *Response, const char *Name)
|
||||
{
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<%s IoStatus=%lx[%ld]\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint, Name,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint, Name,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information);
|
||||
}
|
||||
|
||||
@ -302,9 +302,9 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c%c%c] \"%S\", "
|
||||
"%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, "
|
||||
"AllocationSize=%lx:%lx, "
|
||||
"AccessToken=%p, DesiredAccess=%lx, GrantedAccess=%lx, "
|
||||
"AccessToken=%p[PID=%lx], DesiredAccess=%lx, GrantedAccess=%lx, "
|
||||
"ShareAccess=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->Req.Create.UserMode ? 'U' : 'K',
|
||||
Request->Req.Create.HasTraversePrivilege ? 'T' : '-',
|
||||
Request->Req.Create.HasBackupPrivilege ? 'B' : '-',
|
||||
@ -319,7 +319,8 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "",
|
||||
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.GrantedAccess,
|
||||
Request->Req.Create.ShareAccess);
|
||||
@ -328,7 +329,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
case FspFsctlTransactOverwriteKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Overwrite%s %s%S%s%s, "
|
||||
"FileAttributes=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->Req.Overwrite.Supersede ? " [Supersede]" : "",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
@ -340,7 +341,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
break;
|
||||
case FspFsctlTransactCleanupKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Cleanup%s %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->Req.Cleanup.Delete ? " [Delete]" : "",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
@ -351,7 +352,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
break;
|
||||
case FspFsctlTransactCloseKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Close %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -362,14 +363,14 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
case FspFsctlTransactReadKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Read %s%S%s%s, "
|
||||
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Read.UserContext, Request->Req.Read.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.Read.Address,
|
||||
(PVOID)Request->Req.Read.Address,
|
||||
MAKE_UINT32_PAIR(Request->Req.Read.Offset),
|
||||
Request->Req.Read.Length,
|
||||
Request->Req.Read.Key);
|
||||
@ -377,7 +378,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
case FspFsctlTransactWriteKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Write%s %s%S%s%s, "
|
||||
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->Req.Write.ConstrainedIo ? " [C]" : "",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
@ -385,14 +386,14 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Write.UserContext, Request->Req.Write.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.Write.Address,
|
||||
(PVOID)Request->Req.Write.Address,
|
||||
MAKE_UINT32_PAIR(Request->Req.Write.Offset),
|
||||
Request->Req.Write.Length,
|
||||
Request->Req.Write.Key);
|
||||
break;
|
||||
case FspFsctlTransactQueryInformationKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QueryInformation %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -406,7 +407,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
case 4/*FileBasicInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Basic] %s%S%s%s, "
|
||||
"FileAttributes=%lx, CreationTime=%s, LastAccessTime=%s, LastWriteTime=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -424,7 +425,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
case 19/*FileAllocationInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Allocation] %s%S%s%s, "
|
||||
"AllocationSize=%lx:%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -436,7 +437,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
case 20/*FileEndOfFileInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [EndOfFile] %s%S%s%s, "
|
||||
"FileSize = %lx:%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -448,7 +449,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
case 13/*FileDispositionInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Disposition] %s%S%s%s, "
|
||||
"%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -459,8 +460,8 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
break;
|
||||
case 10/*FileRenameInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Rename] %s%S%s%s, "
|
||||
"NewFileName=\"%S\", AccessToken=%p\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
"NewFileName=\"%S\", AccessToken=%p[PID=%lx]\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -468,11 +469,12 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
|
||||
(PVOID)Request->Req.SetInformation.Info.Rename.AccessToken);
|
||||
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;
|
||||
default:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [INVALID] %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -490,7 +492,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
break;
|
||||
case FspFsctlTransactFlushBuffersKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FlushBuffers %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -507,39 +509,42 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
case 2/*FileFsLabelInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [FsLabel] "
|
||||
"Label=\"%S\"\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
(PWSTR)Request->Buffer);
|
||||
break;
|
||||
default:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [INVALID]\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint);
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactQueryDirectoryKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QueryDirectory %s%S%s%s, "
|
||||
"Address=%p, Offset=%lx:%lx, Length=%ld, Pattern=%s%S%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
"Address=%p, Length=%ld, Pattern=%s%S%s, Marker=%s%S%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.QueryDirectory.UserContext, Request->Req.QueryDirectory.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.QueryDirectory.Address,
|
||||
MAKE_UINT32_PAIR(Request->Req.QueryDirectory.Offset),
|
||||
(PVOID)Request->Req.QueryDirectory.Address,
|
||||
Request->Req.QueryDirectory.Length,
|
||||
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "",
|
||||
Request->Req.QueryDirectory.Pattern.Size ?
|
||||
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : L"NULL",
|
||||
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "");
|
||||
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "",
|
||||
Request->Req.QueryDirectory.Marker.Size ? "\"" : "",
|
||||
Request->Req.QueryDirectory.Marker.Size ?
|
||||
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset) : L"NULL",
|
||||
Request->Req.QueryDirectory.Marker.Size ? "\"" : "");
|
||||
break;
|
||||
case FspFsctlTransactFileSystemControlKind:
|
||||
switch (Request->Req.FileSystemControl.FsControlCode)
|
||||
{
|
||||
case FSCTL_GET_REPARSE_POINT:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [FSCTL_GET_REPARSE_POINT] %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -551,7 +556,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
case FSCTL_DELETE_REPARSE_POINT:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [%s] %s%S%s%s "
|
||||
"ReparseData=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
FSCTL_SET_REPARSE_POINT == Request->Req.FileSystemControl.FsControlCode ?
|
||||
"FSCTL_SET_REPARSE_POINT" : "FSCTL_DELETE_REPARSE_POINT",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
@ -565,7 +570,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
break;
|
||||
default:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [INVALID] %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -586,7 +591,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
break;
|
||||
case FspFsctlTransactQuerySecurityKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QuerySecurity %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -604,7 +609,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetSecurity %s%S%s%s, "
|
||||
"SecurityInformation=%lx, Security=%s%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -619,7 +624,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
break;
|
||||
case FspFsctlTransactQueryStreamInformationKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QueryStreamInformation %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
@ -655,7 +660,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
if (0/*IO_REPARSE*/ == Response->IoStatus.Information)
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||
"Reparse.FileName=\"%s\"\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogWideCharBufferString(
|
||||
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
|
||||
@ -666,7 +671,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||
"Reparse.Data=\"%s\"\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogReparseDataString(
|
||||
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
|
||||
@ -675,7 +680,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||
"UserContext=%s, GrantedAccess=%lx, FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogUserContextString(
|
||||
Response->Rsp.Create.Opened.UserContext, Response->Rsp.Create.Opened.UserContext2,
|
||||
@ -689,7 +694,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Overwrite IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.Overwrite.FileInfo, InfoBuf));
|
||||
break;
|
||||
@ -708,7 +713,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Write IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.Write.FileInfo, InfoBuf));
|
||||
break;
|
||||
@ -718,7 +723,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<QueryInformation IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.QueryInformation.FileInfo, InfoBuf));
|
||||
break;
|
||||
@ -728,7 +733,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<SetInformation IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.SetInformation.FileInfo, InfoBuf));
|
||||
break;
|
||||
@ -747,7 +752,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<QueryVolumeInformation IoStatus=%lx[%ld] "
|
||||
"VolumeInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogVolumeInfoString(&Response->Rsp.QueryVolumeInformation.VolumeInfo, InfoBuf));
|
||||
break;
|
||||
@ -757,7 +762,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<SetVolumeInformation IoStatus=%lx[%ld] "
|
||||
"VolumeInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogVolumeInfoString(&Response->Rsp.SetVolumeInformation.VolumeInfo, InfoBuf));
|
||||
break;
|
||||
@ -771,7 +776,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<FileSystemControl IoStatus=%lx[%ld] "
|
||||
"ReparseData=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogReparseDataString(Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset,
|
||||
InfoBuf));
|
||||
@ -799,7 +804,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<QuerySecurity IoStatus=%lx[%ld] "
|
||||
"Security=%s%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
@ -821,7 +826,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<SetSecurity IoStatus=%lx[%ld] "
|
||||
"Security=%s%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
|
404
src/dll/dirbuf.c
Normal file
@ -0,0 +1,404 @@
|
||||
/**
|
||||
* @file dll/dirbuf.c
|
||||
*
|
||||
* @copyright 2015-2017 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this file in
|
||||
* accordance with the commercial license agreement provided with the
|
||||
* software.
|
||||
*/
|
||||
|
||||
#include <dll/library.h>
|
||||
|
||||
#define RETURN(R, B) \
|
||||
do \
|
||||
{ \
|
||||
if (0 != PResult) \
|
||||
*PResult = R; \
|
||||
return B; \
|
||||
} while (0,0)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRWLOCK Lock;
|
||||
ULONG Capacity, LoMark, HiMark;
|
||||
PUINT8 Buffer;
|
||||
} FSP_FILE_SYSTEM_DIRECTORY_BUFFER;
|
||||
|
||||
static int FspFileSystemDirectoryBufferFileNameCmp(PWSTR a, int alen, PWSTR b, int blen)
|
||||
{
|
||||
int len, res;
|
||||
|
||||
if (-1 == alen)
|
||||
alen = (int)lstrlenW(a);
|
||||
if (-1 == blen)
|
||||
blen = (int)lstrlenW(b);
|
||||
|
||||
len = alen < blen ? alen : blen;
|
||||
|
||||
/* order "." and ".." first */
|
||||
switch (alen)
|
||||
{
|
||||
case 1:
|
||||
if (L'.' == a[0])
|
||||
a = L"\1";
|
||||
break;
|
||||
case 2:
|
||||
if (L'.' == a[0] && L'.' == a[1])
|
||||
a = L"\1\1";
|
||||
break;
|
||||
}
|
||||
|
||||
/* order "." and ".." first */
|
||||
switch (blen)
|
||||
{
|
||||
case 1:
|
||||
if (L'.' == b[0])
|
||||
b = L"\1";
|
||||
break;
|
||||
case 2:
|
||||
if (L'.' == b[0] && L'.' == b[1])
|
||||
b = L"\1\1";
|
||||
break;
|
||||
}
|
||||
|
||||
res = invariant_wcsncmp(a, b, len);
|
||||
|
||||
if (0 == res)
|
||||
res = alen - blen;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Binary search
|
||||
* "I wish I had the standard library!"
|
||||
*/
|
||||
static BOOLEAN FspFileSystemSearchDirectoryBuffer(FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer,
|
||||
PWSTR Marker, int MarkerLen, PULONG PIndexNum)
|
||||
{
|
||||
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
|
||||
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
|
||||
FSP_FSCTL_DIR_INFO *DirInfo;
|
||||
int Lo = 0, Hi = Count - 1, Mi;
|
||||
int CmpResult;
|
||||
|
||||
while (Lo <= Hi)
|
||||
{
|
||||
Mi = (unsigned)(Lo + Hi) >> 1;
|
||||
|
||||
DirInfo = (PVOID)(DirBuffer->Buffer + Index[Mi]);
|
||||
CmpResult = FspFileSystemDirectoryBufferFileNameCmp(
|
||||
DirInfo->FileNameBuf, (DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR),
|
||||
Marker, MarkerLen);
|
||||
|
||||
if (0 > CmpResult)
|
||||
Lo = Mi + 1;
|
||||
else if (0 < CmpResult)
|
||||
Hi = Mi - 1;
|
||||
else
|
||||
{
|
||||
*PIndexNum = Mi;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*PIndexNum = Lo;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Quick sort
|
||||
* "I wish I had the standard library!"
|
||||
*
|
||||
* Based on Sedgewick's Algorithms in C++; multiple editions.
|
||||
*
|
||||
* Implements a non-recursive quicksort with tail-end recursion eliminated
|
||||
* and median-of-three partitioning.
|
||||
*/
|
||||
|
||||
#define less(a, b) FspFileSystemDirectoryBufferLess(Buffer, a, b)
|
||||
#define exch(a, b) { ULONG t = a; a = b; b = t; }
|
||||
#define compexch(a, b) if (less(b, a)) exch(a, b)
|
||||
#define push(i) (stack[stackpos++] = (i))
|
||||
#define pop() (stack[--stackpos])
|
||||
|
||||
static __forceinline
|
||||
int FspFileSystemDirectoryBufferLess(PUINT8 Buffer, int a, int b)
|
||||
{
|
||||
FSP_FSCTL_DIR_INFO *DirInfoA = (FSP_FSCTL_DIR_INFO *)(Buffer + a);
|
||||
FSP_FSCTL_DIR_INFO *DirInfoB = (FSP_FSCTL_DIR_INFO *)(Buffer + b);
|
||||
return 0 > FspFileSystemDirectoryBufferFileNameCmp(
|
||||
DirInfoA->FileNameBuf, (DirInfoA->Size - sizeof *DirInfoA) / sizeof(WCHAR),
|
||||
DirInfoB->FileNameBuf, (DirInfoB->Size - sizeof *DirInfoB) / sizeof(WCHAR));
|
||||
}
|
||||
|
||||
static __forceinline
|
||||
int FspFileSystemPartitionDirectoryBuffer(PUINT8 Buffer, PULONG Index, int l, int r)
|
||||
{
|
||||
int i = l - 1, j = r;
|
||||
ULONG v = Index[r];
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (less(Index[++i], v))
|
||||
;
|
||||
|
||||
while (less(v, Index[--j]))
|
||||
if (j == l)
|
||||
break;
|
||||
|
||||
if (i >= j)
|
||||
break;
|
||||
|
||||
exch(Index[i], Index[j]);
|
||||
}
|
||||
|
||||
exch(Index[i], Index[r]);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static VOID FspFileSystemQSortDirectoryBuffer(PUINT8 Buffer, PULONG Index, int l, int r)
|
||||
{
|
||||
int stack[64], stackpos = 0;
|
||||
int i;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (r > l)
|
||||
{
|
||||
#if 0
|
||||
exch(Index[(l + r) / 2], Index[r - 1]);
|
||||
compexch(Index[l], Index[r - 1]);
|
||||
compexch(Index[l], Index[r]);
|
||||
compexch(Index[r - 1], Index[r]);
|
||||
|
||||
i = FspFileSystemPartitionDirectoryBuffer(Buffer, Index, l + 1, r - 1);
|
||||
#else
|
||||
i = FspFileSystemPartitionDirectoryBuffer(Buffer, Index, l, r);
|
||||
#endif
|
||||
|
||||
if (i - l > r - i)
|
||||
{
|
||||
push(l); push(i - 1);
|
||||
l = i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
push(i + 1); push(r);
|
||||
r = i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == stackpos)
|
||||
break;
|
||||
|
||||
r = pop(); l = pop();
|
||||
}
|
||||
}
|
||||
|
||||
#undef push
|
||||
#undef pop
|
||||
#undef less
|
||||
#undef compexch
|
||||
#undef exch
|
||||
|
||||
static inline VOID FspFileSystemSortDirectoryBuffer(FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer)
|
||||
{
|
||||
PUINT8 Buffer = DirBuffer->Buffer;
|
||||
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
|
||||
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
|
||||
|
||||
FspFileSystemQSortDirectoryBuffer(Buffer, Index, 0, Count - 1);
|
||||
}
|
||||
|
||||
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
|
||||
BOOLEAN Reset, PNTSTATUS PResult)
|
||||
{
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
|
||||
MemoryBarrier();
|
||||
|
||||
if (0 == DirBuffer)
|
||||
{
|
||||
static SRWLOCK CreateLock = SRWLOCK_INIT;
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *NewDirBuffer;
|
||||
|
||||
NewDirBuffer = MemAlloc(sizeof *NewDirBuffer);
|
||||
if (0 == NewDirBuffer)
|
||||
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
|
||||
memset(NewDirBuffer, 0, sizeof *NewDirBuffer);
|
||||
InitializeSRWLock(&NewDirBuffer->Lock);
|
||||
AcquireSRWLockExclusive(&NewDirBuffer->Lock);
|
||||
|
||||
AcquireSRWLockExclusive(&CreateLock);
|
||||
DirBuffer = *PDirBuffer;
|
||||
MemoryBarrier();
|
||||
if (0 == DirBuffer)
|
||||
*PDirBuffer = DirBuffer = NewDirBuffer;
|
||||
ReleaseSRWLockExclusive(&CreateLock);
|
||||
|
||||
if (DirBuffer == NewDirBuffer)
|
||||
RETURN(STATUS_SUCCESS, TRUE);
|
||||
|
||||
ReleaseSRWLockExclusive(&NewDirBuffer->Lock);
|
||||
MemFree(NewDirBuffer);
|
||||
}
|
||||
|
||||
if (Reset)
|
||||
{
|
||||
AcquireSRWLockExclusive(&DirBuffer->Lock);
|
||||
|
||||
DirBuffer->LoMark = 0;
|
||||
DirBuffer->HiMark = DirBuffer->Capacity;
|
||||
|
||||
RETURN(STATUS_SUCCESS, TRUE);
|
||||
}
|
||||
|
||||
RETURN(STATUS_SUCCESS, FALSE);
|
||||
}
|
||||
|
||||
FSP_API BOOLEAN FspFileSystemFillDirectoryBuffer(PVOID *PDirBuffer,
|
||||
FSP_FSCTL_DIR_INFO *DirInfo, PNTSTATUS PResult)
|
||||
{
|
||||
/* assume that FspFileSystemAcquireDirectoryBuffer has been called */
|
||||
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
|
||||
ULONG Capacity, LoMark, HiMark;
|
||||
PUINT8 Buffer;
|
||||
|
||||
if (0 == DirInfo)
|
||||
RETURN(STATUS_INVALID_PARAMETER, FALSE);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
LoMark = DirBuffer->LoMark;
|
||||
HiMark = DirBuffer->HiMark;
|
||||
Buffer = DirBuffer->Buffer;
|
||||
|
||||
if (FspFileSystemAddDirInfo(DirInfo,
|
||||
Buffer,
|
||||
HiMark > sizeof(ULONG) ? HiMark - sizeof(ULONG)/*space for new index entry*/ : HiMark,
|
||||
&LoMark))
|
||||
{
|
||||
HiMark -= sizeof(ULONG);
|
||||
*(PULONG)(Buffer + HiMark) = DirBuffer->LoMark;
|
||||
|
||||
DirBuffer->LoMark = LoMark;
|
||||
DirBuffer->HiMark = HiMark;
|
||||
|
||||
RETURN (STATUS_SUCCESS, TRUE);
|
||||
}
|
||||
|
||||
if (0 == Buffer)
|
||||
{
|
||||
Buffer = MemAlloc(Capacity = 512);
|
||||
if (0 == Buffer)
|
||||
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
|
||||
|
||||
HiMark = Capacity;
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer = MemRealloc(Buffer, Capacity = DirBuffer->Capacity * 2);
|
||||
if (0 == Buffer)
|
||||
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
|
||||
|
||||
ULONG IndexSize = DirBuffer->Capacity - HiMark;
|
||||
ULONG NewHiMark = Capacity - IndexSize;
|
||||
|
||||
memmove(Buffer + NewHiMark, Buffer + HiMark, IndexSize);
|
||||
HiMark = NewHiMark;
|
||||
}
|
||||
|
||||
DirBuffer->Capacity = Capacity;
|
||||
DirBuffer->LoMark = LoMark;
|
||||
DirBuffer->HiMark = HiMark;
|
||||
DirBuffer->Buffer = Buffer;
|
||||
}
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemReleaseDirectoryBuffer(PVOID *PDirBuffer)
|
||||
{
|
||||
/* assume that FspFileSystemAcquireDirectoryBuffer has been called */
|
||||
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
|
||||
|
||||
FspFileSystemSortDirectoryBuffer(DirBuffer);
|
||||
|
||||
ReleaseSRWLockExclusive(&DirBuffer->Lock);
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemReadDirectoryBuffer(PVOID *PDirBuffer,
|
||||
PWSTR Marker,
|
||||
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
|
||||
{
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
|
||||
MemoryBarrier();
|
||||
|
||||
if (0 != DirBuffer)
|
||||
{
|
||||
AcquireSRWLockShared(&DirBuffer->Lock);
|
||||
|
||||
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
|
||||
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
|
||||
ULONG IndexNum;
|
||||
FSP_FSCTL_DIR_INFO *DirInfo;
|
||||
|
||||
if (0 == Marker)
|
||||
IndexNum = 0;
|
||||
else
|
||||
{
|
||||
FspFileSystemSearchDirectoryBuffer(DirBuffer,
|
||||
Marker, lstrlenW(Marker),
|
||||
&IndexNum);
|
||||
IndexNum++;
|
||||
}
|
||||
|
||||
for (; IndexNum < Count; IndexNum++)
|
||||
{
|
||||
DirInfo = (PVOID)(DirBuffer->Buffer + Index[IndexNum]);
|
||||
if (!FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred))
|
||||
{
|
||||
ReleaseSRWLockShared(&DirBuffer->Lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSRWLockShared(&DirBuffer->Lock);
|
||||
}
|
||||
|
||||
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemDeleteDirectoryBuffer(PVOID *PDirBuffer)
|
||||
{
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
|
||||
MemoryBarrier();
|
||||
|
||||
if (0 != DirBuffer)
|
||||
{
|
||||
MemFree(DirBuffer->Buffer);
|
||||
MemFree(DirBuffer);
|
||||
*PDirBuffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
|
||||
PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount)
|
||||
{
|
||||
/* assume that FspFileSystemAcquireDirectoryBuffer has been called */
|
||||
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
|
||||
|
||||
*PBuffer = DirBuffer->Buffer;
|
||||
*PIndex = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
|
||||
*PCount = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
|
||||
}
|
329
src/dll/fs.c
@ -72,6 +72,48 @@ VOID FspFileSystemFinalize(BOOLEAN Dynamic)
|
||||
TlsFree(FspFileSystemTlsKey);
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath,
|
||||
PWSTR MountPoint)
|
||||
{
|
||||
NTSTATUS Result;
|
||||
WCHAR TargetPath[MAX_PATH];
|
||||
HANDLE DirHandle;
|
||||
|
||||
Result = FspFsctlPreflight(DevicePath);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
if (0 == MountPoint)
|
||||
Result = STATUS_SUCCESS;
|
||||
else
|
||||
{
|
||||
if (FspPathIsDrive(MountPoint))
|
||||
Result = QueryDosDeviceW(MountPoint, TargetPath, MAX_PATH) ?
|
||||
STATUS_OBJECT_NAME_COLLISION : STATUS_SUCCESS;
|
||||
else
|
||||
{
|
||||
DirHandle = CreateFileW(MountPoint,
|
||||
FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
|
||||
0);
|
||||
if (INVALID_HANDLE_VALUE != DirHandle)
|
||||
{
|
||||
CloseHandle(DirHandle);
|
||||
Result = STATUS_OBJECT_NAME_COLLISION;
|
||||
}
|
||||
else if (ERROR_FILE_NOT_FOUND != GetLastError())
|
||||
Result = STATUS_OBJECT_NAME_INVALID;
|
||||
else
|
||||
Result = STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
||||
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
|
||||
const FSP_FILE_SYSTEM_INTERFACE *Interface,
|
||||
@ -145,20 +187,63 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem)
|
||||
MemFree(FileSystem);
|
||||
}
|
||||
|
||||
static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWSTR VolumeName)
|
||||
static NTSTATUS FspFileSystemSetMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName,
|
||||
PHANDLE PMountHandle)
|
||||
{
|
||||
*PMountHandle = 0;
|
||||
|
||||
if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, VolumeName))
|
||||
return FspNtStatusFromWin32(GetLastError());
|
||||
|
||||
if (0 != FspNtOpenSymbolicLinkObject)
|
||||
{
|
||||
NTSTATUS Result;
|
||||
WCHAR SymlinkBuf[6];
|
||||
UNICODE_STRING Symlink;
|
||||
OBJECT_ATTRIBUTES Obja;
|
||||
|
||||
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
|
||||
SymlinkBuf[4] = MountPoint[0];
|
||||
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
|
||||
Symlink.Buffer = SymlinkBuf;
|
||||
|
||||
memset(&Obja, 0, sizeof Obja);
|
||||
Obja.Length = sizeof Obja;
|
||||
Obja.ObjectName = &Symlink;
|
||||
Obja.Attributes = OBJ_CASE_INSENSITIVE;
|
||||
|
||||
Result = FspNtOpenSymbolicLinkObject(PMountHandle, DELETE, &Obja);
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
Result = FspNtMakeTemporaryObject(*PMountHandle);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspNtClose(*PMountHandle);
|
||||
*PMountHandle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFileSystemSetMountPoint_Directory(PWSTR MountPoint, PWSTR VolumeName,
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor, PHANDLE PMountHandle)
|
||||
{
|
||||
NTSTATUS Result;
|
||||
HANDLE DirHandle;
|
||||
BOOL Success;
|
||||
SECURITY_ATTRIBUTES SecurityAttributes;
|
||||
HANDLE MountHandle = INVALID_HANDLE_VALUE;
|
||||
DWORD Backslashes, Bytes;
|
||||
USHORT VolumeNameLength, BackslashLength, ReparseDataLength;
|
||||
PREPARSE_DATA_BUFFER ReparseData = 0;
|
||||
PWSTR P, PathBuffer;
|
||||
|
||||
*PMountHandle = 0;
|
||||
|
||||
/*
|
||||
* Windows does not allow mount points (junctions) to point to network file systems.
|
||||
*
|
||||
* Count how many backslashes our VolumeName. If it is 3 or more this is a network
|
||||
* Count how many backslashes our VolumeName has. If it is 3 or more this is a network
|
||||
* file system. Preemptively return STATUS_NETWORK_ACCESS_DENIED.
|
||||
*/
|
||||
for (P = VolumeName, Backslashes = 0; *P; P++)
|
||||
@ -169,25 +254,24 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!CreateDirectoryW(MountPoint, 0))
|
||||
memset(&SecurityAttributes, 0, sizeof SecurityAttributes);
|
||||
SecurityAttributes.nLength = sizeof SecurityAttributes;
|
||||
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
|
||||
|
||||
MountHandle = CreateFileW(MountPoint,
|
||||
FILE_WRITE_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
&SecurityAttributes,
|
||||
CREATE_NEW,
|
||||
FILE_ATTRIBUTE_DIRECTORY |
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE,
|
||||
0);
|
||||
if (INVALID_HANDLE_VALUE == MountHandle)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DirHandle = CreateFileW(MountPoint,
|
||||
FILE_WRITE_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
|
||||
0);
|
||||
if (INVALID_HANDLE_VALUE == DirHandle)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto rmdir_and_exit;
|
||||
}
|
||||
|
||||
VolumeNameLength = (USHORT)lstrlenW(VolumeName);
|
||||
BackslashLength = 0 == VolumeNameLength || L'\\' != VolumeName[VolumeNameLength - 1];
|
||||
VolumeNameLength *= sizeof(WCHAR);
|
||||
@ -201,7 +285,7 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
|
||||
if (0 == ReparseData)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto rmdir_and_exit;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ReparseData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
||||
@ -228,86 +312,35 @@ static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWS
|
||||
PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\';
|
||||
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
|
||||
|
||||
Success = DeviceIoControl(DirHandle, FSCTL_SET_REPARSE_POINT,
|
||||
if (!DeviceIoControl(MountHandle, FSCTL_SET_REPARSE_POINT,
|
||||
ReparseData, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseData->ReparseDataLength,
|
||||
0, 0,
|
||||
&Bytes, 0);
|
||||
CloseHandle(DirHandle);
|
||||
if (!Success)
|
||||
&Bytes, 0))
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto rmdir_and_exit;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*PMountHandle = MountHandle;
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
if (!NT_SUCCESS(Result) && INVALID_HANDLE_VALUE != MountHandle)
|
||||
CloseHandle(MountHandle);
|
||||
|
||||
MemFree(ReparseData);
|
||||
return Result;
|
||||
|
||||
rmdir_and_exit:
|
||||
RemoveDirectoryW(MountPoint);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFileSystemSetMountPoint_MakeTemporary(PWSTR MountPoint, PHANDLE PMountHandle)
|
||||
{
|
||||
NTSTATUS Result = STATUS_SUCCESS;
|
||||
HANDLE MountHandle = 0;
|
||||
|
||||
if (FspPathIsDrive(MountPoint))
|
||||
{
|
||||
if (0 != FspNtOpenSymbolicLinkObject)
|
||||
{
|
||||
WCHAR SymlinkBuf[6];
|
||||
UNICODE_STRING Symlink;
|
||||
OBJECT_ATTRIBUTES Obja;
|
||||
|
||||
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
|
||||
SymlinkBuf[4] = MountPoint[0];
|
||||
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
|
||||
Symlink.Buffer = SymlinkBuf;
|
||||
|
||||
memset(&Obja, 0, sizeof Obja);
|
||||
Obja.Length = sizeof Obja;
|
||||
Obja.ObjectName = &Symlink;
|
||||
Obja.Attributes = OBJ_CASE_INSENSITIVE;
|
||||
|
||||
Result = FspNtOpenSymbolicLinkObject(&MountHandle, DELETE, &Obja);
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
Result = FspNtMakeTemporaryObject(MountHandle);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspNtClose(MountHandle);
|
||||
MountHandle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* open the directory for DELETE_ON_CLOSE; closing it will remove the directory */
|
||||
MountHandle = CreateFileW(MountPoint,
|
||||
FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_DELETE_ON_CLOSE,
|
||||
0);
|
||||
if (INVALID_HANDLE_VALUE == MountHandle)
|
||||
{
|
||||
MountHandle = 0;
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
*PMountHandle = MountHandle;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint)
|
||||
{
|
||||
return FspFileSystemSetMountPointEx(FileSystem, MountPoint, 0);
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemSetMountPointEx(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint,
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor)
|
||||
{
|
||||
if (0 != FileSystem->MountPoint)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
@ -333,11 +366,10 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
|
||||
if (0 == (Drives & (1 << (Drive - 'A'))))
|
||||
{
|
||||
MountPoint[0] = Drive;
|
||||
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName))
|
||||
{
|
||||
Result = STATUS_SUCCESS;
|
||||
Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
|
||||
&MountHandle);
|
||||
if (NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
Result = STATUS_NO_SUCH_DEVICE;
|
||||
}
|
||||
@ -358,22 +390,16 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
|
||||
MountPoint = P;
|
||||
|
||||
if (FspPathIsDrive(MountPoint))
|
||||
{
|
||||
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName))
|
||||
Result = STATUS_SUCCESS;
|
||||
else
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
}
|
||||
Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
|
||||
&MountHandle);
|
||||
else
|
||||
Result = FspFileSystemSetMountPoint_CreateDirectory(MountPoint, FileSystem->VolumeName);
|
||||
Result = FspFileSystemSetMountPoint_Directory(MountPoint, FileSystem->VolumeName,
|
||||
SecurityDescriptor, &MountHandle);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
FspFileSystemSetMountPoint_MakeTemporary(MountPoint, &MountHandle);
|
||||
/* ignore result; this path always considered successful */
|
||||
|
||||
FileSystem->MountPoint = MountPoint;
|
||||
FileSystem->MountHandle = MountHandle;
|
||||
}
|
||||
@ -383,33 +409,35 @@ exit:
|
||||
return Result;
|
||||
}
|
||||
|
||||
static VOID FspFileSystemRemoveMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName, HANDLE MountHandle)
|
||||
{
|
||||
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
|
||||
MountPoint, VolumeName);
|
||||
|
||||
if (0 != MountHandle)
|
||||
FspNtClose(MountHandle);
|
||||
}
|
||||
|
||||
static VOID FspFileSystemRemoveMountPoint_Directory(HANDLE MountHandle)
|
||||
{
|
||||
/* directory is marked DELETE_ON_CLOSE */
|
||||
CloseHandle(MountHandle);
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
|
||||
{
|
||||
BOOLEAN IsDrive;
|
||||
|
||||
if (0 == FileSystem->MountPoint)
|
||||
return;
|
||||
|
||||
IsDrive = FspPathIsDrive(FileSystem->MountPoint);
|
||||
if (IsDrive)
|
||||
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
|
||||
FileSystem->MountPoint, FileSystem->VolumeName);
|
||||
if (FspPathIsDrive(FileSystem->MountPoint))
|
||||
FspFileSystemRemoveMountPoint_Drive(FileSystem->MountPoint, FileSystem->VolumeName,
|
||||
FileSystem->MountHandle);
|
||||
else
|
||||
/* nothing to do! directory will be deleted when the MountHandle is closed */;
|
||||
FspFileSystemRemoveMountPoint_Directory(FileSystem->MountHandle);
|
||||
|
||||
MemFree(FileSystem->MountPoint);
|
||||
FileSystem->MountPoint = 0;
|
||||
|
||||
if (0 != FileSystem->MountHandle)
|
||||
{
|
||||
if (IsDrive)
|
||||
FspNtClose(FileSystem->MountHandle);
|
||||
else
|
||||
/* CloseHandle really calls NtClose, but I like being defensive when programming */
|
||||
CloseHandle(FileSystem->MountHandle);
|
||||
|
||||
FileSystem->MountHandle = 0;
|
||||
}
|
||||
FileSystem->MountHandle = 0;
|
||||
}
|
||||
|
||||
static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
|
||||
@ -591,3 +619,72 @@ FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID
|
||||
{
|
||||
return (FSP_FILE_SYSTEM_OPERATION_CONTEXT *)TlsGetValue(FspFileSystemTlsKey);
|
||||
}
|
||||
|
||||
/*
|
||||
* Out-of-Line
|
||||
*/
|
||||
|
||||
FSP_API PWSTR FspFileSystemMountPointF(FSP_FILE_SYSTEM *FileSystem)
|
||||
{
|
||||
return FspFileSystemMountPoint(FileSystem);
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemEnterOperationF(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
return FspFileSystemEnterOperation(FileSystem, Request, Response);
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemLeaveOperationF(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
return FspFileSystemLeaveOperation(FileSystem, Request, Response);
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemSetOperationGuardF(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation,
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD *LeaveOperation)
|
||||
{
|
||||
FspFileSystemSetOperationGuard(FileSystem, EnterOperation, LeaveOperation);
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemSetOperationGuardStrategyF(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy)
|
||||
{
|
||||
FspFileSystemSetOperationGuardStrategy(FileSystem, GuardStrategy);
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemSetOperationF(FSP_FILE_SYSTEM *FileSystem,
|
||||
ULONG Index,
|
||||
FSP_FILE_SYSTEM_OPERATION *Operation)
|
||||
{
|
||||
FspFileSystemSetOperation(FileSystem, Index, Operation);
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemGetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem,
|
||||
NTSTATUS *PDispatcherResult)
|
||||
{
|
||||
FspFileSystemGetDispatcherResult(FileSystem, PDispatcherResult);
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemSetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem,
|
||||
NTSTATUS DispatcherResult)
|
||||
{
|
||||
FspFileSystemSetDispatcherResult(FileSystem, DispatcherResult);
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemSetDebugLogF(FSP_FILE_SYSTEM *FileSystem,
|
||||
UINT32 DebugLog)
|
||||
{
|
||||
FspFileSystemSetDebugLog(FileSystem, DebugLog);
|
||||
}
|
||||
|
||||
FSP_API BOOLEAN FspFileSystemIsOperationCaseSensitiveF(VOID)
|
||||
{
|
||||
return FspFileSystemIsOperationCaseSensitive();
|
||||
}
|
||||
|
||||
FSP_API UINT32 FspFileSystemOperationProcessIdF(VOID)
|
||||
{
|
||||
return FspFileSystemOperationProcessId();
|
||||
}
|
||||
|
@ -355,10 +355,18 @@ static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
|
||||
{
|
||||
LastError = GetEffectiveRightsFromAclW(Dacl, &AccessEntry.Trustee, &AccessRights);
|
||||
if (0 != LastError)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(LastError);
|
||||
goto exit;
|
||||
}
|
||||
/*
|
||||
* Apparently GetEffectiveRightsFromAclW can fail with ERROR_CIRCULAR_DEPENDENCY
|
||||
* in some rare circumstances. Calling GetEffectiveRightsFromAclW is not essential
|
||||
* in this instance. It is only done to check whether the "Everyone/World" SID
|
||||
* already has the access required to start the FSD; if it does not have those
|
||||
* rights already they are added. It is probably safe to just assume that the
|
||||
* required rights are not there if GetEffectiveRightsFromAclW fails; the worst
|
||||
* that can happen is that the rights get added twice (which is benign).
|
||||
*
|
||||
* See https://github.com/billziss-gh/winfsp/issues/62
|
||||
*/
|
||||
AccessRights = 0;
|
||||
}
|
||||
|
||||
/* do we have the required access rights? */
|
||||
|
@ -1121,6 +1121,36 @@ FSP_API NTSTATUS FspFileSystemOpSetVolumeInformation(FSP_FILE_SYSTEM *FileSystem
|
||||
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_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
@ -1131,14 +1161,24 @@ FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
BytesTransferred = 0;
|
||||
Result = FileSystem->Interface->ReadDirectory(FileSystem,
|
||||
(PVOID)ValOfFileContext(Request->Req.QueryDirectory),
|
||||
(PVOID)Request->Req.QueryDirectory.Address,
|
||||
Request->Req.QueryDirectory.Offset,
|
||||
Request->Req.QueryDirectory.Length,
|
||||
0 != Request->Req.QueryDirectory.Pattern.Size ?
|
||||
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : 0,
|
||||
&BytesTransferred);
|
||||
if (0 != FileSystem->Interface->GetDirInfoByName &&
|
||||
0 != Request->Req.QueryDirectory.Pattern.Size && Request->Req.QueryDirectory.PatternIsFileName)
|
||||
Result = FspFileSystemOpQueryDirectory_GetDirInfoByName(FileSystem,
|
||||
(PVOID)ValOfFileContext(Request->Req.QueryDirectory),
|
||||
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset),
|
||||
(PVOID)Request->Req.QueryDirectory.Address,
|
||||
Request->Req.QueryDirectory.Length,
|
||||
&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))
|
||||
return Result;
|
||||
|
||||
@ -1353,7 +1393,7 @@ FSP_API BOOLEAN FspFileSystemFindReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemResolveReparsePointsInternal(FSP_FILE_SYSTEM *FileSystem,
|
||||
static NTSTATUS FspFileSystemResolveReparsePointsInternal(FSP_FILE_SYSTEM *FileSystem,
|
||||
NTSTATUS (*GetReparsePointByName)(
|
||||
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize),
|
||||
|
@ -32,18 +32,20 @@ struct fsp_fuse_core_opt_data
|
||||
{
|
||||
struct fsp_fuse_env *env;
|
||||
int help, debug;
|
||||
int hard_remove,
|
||||
use_ino, readdir_ino,
|
||||
set_umask, umask,
|
||||
HANDLE DebugLogHandle;
|
||||
int set_umask, umask,
|
||||
set_uid, uid,
|
||||
set_gid, gid,
|
||||
set_attr_timeout, attr_timeout,
|
||||
rellinks;
|
||||
int set_FileInfoTimeout;
|
||||
int CaseInsensitiveSearch,
|
||||
ReadOnlyVolume;
|
||||
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
||||
UINT16 VolumeLabelLength;
|
||||
WCHAR VolumeLabel[sizeof ((FSP_FSCTL_VOLUME_INFO *)0)->VolumeLabel / sizeof(WCHAR)];
|
||||
};
|
||||
FSP_FSCTL_STATIC_ASSERT(
|
||||
sizeof ((struct fuse *)0)->VolumeLabel == sizeof ((struct fsp_fuse_core_opt_data *)0)->VolumeLabel,
|
||||
"fuse::VolumeLabel and fsp_fuse_core_opt_data::VolumeLabel: sizeof must be same.");
|
||||
|
||||
static struct fuse_opt fsp_fuse_core_opts[] =
|
||||
{
|
||||
@ -56,9 +58,11 @@ static struct fuse_opt fsp_fuse_core_opts[] =
|
||||
FSP_FUSE_CORE_OPT("-d", debug, 1),
|
||||
FSP_FUSE_CORE_OPT("debug", debug, 1),
|
||||
|
||||
FSP_FUSE_CORE_OPT("hard_remove", hard_remove, 1),
|
||||
FSP_FUSE_CORE_OPT("use_ino", use_ino, 1),
|
||||
FSP_FUSE_CORE_OPT("readdir_ino", readdir_ino, 1),
|
||||
FUSE_OPT_KEY("DebugLog=", 'D'),
|
||||
|
||||
FUSE_OPT_KEY("hard_remove", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("use_ino", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("readdir_ino", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("direct_io", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("kernel_cache", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("auto_cache", FUSE_OPT_KEY_DISCARD),
|
||||
@ -83,25 +87,20 @@ static struct fuse_opt fsp_fuse_core_opts[] =
|
||||
FSP_FUSE_CORE_OPT("norellinks", rellinks, 0),
|
||||
|
||||
FUSE_OPT_KEY("fstypename=", 'F'),
|
||||
FUSE_OPT_KEY("volname=", 'v'),
|
||||
|
||||
FSP_FUSE_CORE_OPT("SectorSize=%hu", VolumeParams.SectorSize, 4096),
|
||||
FSP_FUSE_CORE_OPT("SectorsPerAllocationUnit=%hu", VolumeParams.SectorsPerAllocationUnit, 1),
|
||||
FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
|
||||
FSP_FUSE_CORE_OPT("VolumeCreationTime=%lli", VolumeParams.VolumeCreationTime, 0),
|
||||
FSP_FUSE_CORE_OPT("VolumeSerialNumber=%lx", VolumeParams.VolumeSerialNumber, 0),
|
||||
FSP_FUSE_CORE_OPT("TransactTimeout=%u", VolumeParams.TransactTimeout, 0),
|
||||
FSP_FUSE_CORE_OPT("IrpTimeout=%u", VolumeParams.IrpTimeout, 0),
|
||||
FSP_FUSE_CORE_OPT("IrpCapacity=%u", VolumeParams.IrpCapacity, 0),
|
||||
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
|
||||
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
|
||||
FSP_FUSE_CORE_OPT("CaseInsensitiveSearch", CaseInsensitiveSearch, 1),
|
||||
FSP_FUSE_CORE_OPT("ReadOnlyVolume", ReadOnlyVolume, 1),
|
||||
FUSE_OPT_KEY("ReparsePoints", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("NamedStreams", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("HardLinks", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("ExtendedAttributes", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("UNC=", 'U'),
|
||||
FUSE_OPT_KEY("--UNC=", 'U'),
|
||||
FUSE_OPT_KEY("VolumePrefix=", 'U'),
|
||||
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
|
||||
FUSE_OPT_KEY("FileSystemName=", 'F'),
|
||||
FUSE_OPT_KEY("--FileSystemName=", 'F'),
|
||||
|
||||
FUSE_OPT_END,
|
||||
@ -131,6 +130,9 @@ static inline void *fsp_fuse_obj_alloc(struct fsp_fuse_env *env, size_t size)
|
||||
|
||||
static inline void fsp_fuse_obj_free(void *obj)
|
||||
{
|
||||
if (0 == obj)
|
||||
return;
|
||||
|
||||
struct fsp_fuse_obj_hdr *hdr = (PVOID)((PUINT8)obj - sizeof(struct fsp_fuse_obj_hdr));
|
||||
|
||||
hdr->dtor(hdr);
|
||||
@ -190,23 +192,55 @@ FSP_FUSE_API struct fuse_chan *fsp_fuse_mount(struct fsp_fuse_env *env,
|
||||
const char *mountpoint, struct fuse_args *args)
|
||||
{
|
||||
struct fuse_chan *ch = 0;
|
||||
WCHAR TempMountPointBuf[MAX_PATH], MountPointBuf[MAX_PATH];
|
||||
int Size;
|
||||
|
||||
if (0 == mountpoint)
|
||||
mountpoint = "";
|
||||
if (0 == mountpoint || '\0' == mountpoint[0] ||
|
||||
('*' == mountpoint[0] && '\0' == mountpoint[1]))
|
||||
{
|
||||
MountPointBuf[0] = L'*';
|
||||
MountPointBuf[1] = L'\0';
|
||||
Size = 2 * sizeof(WCHAR);
|
||||
}
|
||||
else if (
|
||||
(
|
||||
('A' <= mountpoint[0] && mountpoint[0] <= 'Z') ||
|
||||
('a' <= mountpoint[0] && mountpoint[0] <= 'z')
|
||||
) &&
|
||||
':' == mountpoint[1] && '\0' == mountpoint[2])
|
||||
{
|
||||
MountPointBuf[0] = mountpoint[0];
|
||||
MountPointBuf[1] = ':';
|
||||
MountPointBuf[2] = '\0';
|
||||
Size = 3 * sizeof(WCHAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *win_mountpoint = 0;
|
||||
|
||||
Size = MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, 0, 0);
|
||||
if (0 == Size)
|
||||
goto fail;
|
||||
if (0 != env->conv_to_win_path)
|
||||
mountpoint = win_mountpoint = env->conv_to_win_path(mountpoint);
|
||||
|
||||
ch = fsp_fuse_obj_alloc(env, sizeof *ch + Size * sizeof(WCHAR));
|
||||
Size = 0;
|
||||
if (0 != mountpoint &&
|
||||
0 != MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, TempMountPointBuf, MAX_PATH))
|
||||
Size = GetFullPathNameW(TempMountPointBuf, MAX_PATH, MountPointBuf, 0);
|
||||
|
||||
env->memfree(win_mountpoint);
|
||||
|
||||
if (0 == Size || MAX_PATH <= Size)
|
||||
goto fail;
|
||||
|
||||
mountpoint = 0;
|
||||
Size = (Size + 1) * sizeof(WCHAR);
|
||||
}
|
||||
|
||||
ch = fsp_fuse_obj_alloc(env, sizeof *ch + Size);
|
||||
if (0 == ch)
|
||||
goto fail;
|
||||
|
||||
ch->MountPoint = (PVOID)ch->Buffer;
|
||||
Size = MultiByteToWideChar(CP_UTF8, 0, mountpoint, -1, ch->MountPoint, Size);
|
||||
if (0 == Size)
|
||||
goto fail;
|
||||
memcpy(ch->MountPoint, MountPointBuf, Size);
|
||||
|
||||
return ch;
|
||||
|
||||
@ -230,36 +264,6 @@ FSP_FUSE_API int fsp_fuse_is_lib_option(struct fsp_fuse_env *env,
|
||||
|
||||
static void fsp_fuse_cleanup(struct fuse *f);
|
||||
|
||||
static NTSTATUS fsp_fuse_preflight(struct fuse *f)
|
||||
{
|
||||
NTSTATUS Result;
|
||||
|
||||
Result = FspFsctlPreflight(f->VolumeParams.Prefix[0] ?
|
||||
L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
if (L'\0' != f->MountPoint)
|
||||
{
|
||||
if ((
|
||||
(L'A' <= f->MountPoint[0] && f->MountPoint[0] <= L'Z') ||
|
||||
(L'a' <= f->MountPoint[0] && f->MountPoint[0] <= L'z')
|
||||
) &&
|
||||
L':' == f->MountPoint[1] || L'\0' == f->MountPoint[2])
|
||||
{
|
||||
if (GetLogicalDrives() & (1 << ((f->MountPoint[0] & ~0x20) - 'a')))
|
||||
return STATUS_OBJECT_NAME_COLLISION;
|
||||
}
|
||||
else
|
||||
if (L'*' == f->MountPoint[0] && L'\0' == f->MountPoint[1])
|
||||
;
|
||||
else
|
||||
return STATUS_OBJECT_NAME_INVALID;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
{
|
||||
struct fuse *f = Service->UserContext;
|
||||
@ -279,6 +283,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
context->private_data = f->data;
|
||||
context->uid = -1;
|
||||
context->gid = -1;
|
||||
context->pid = -1;
|
||||
|
||||
memset(&conn, 0, sizeof conn);
|
||||
conn.proto_major = 7; /* pretend that we are FUSE kernel protocol 7.12 */
|
||||
@ -291,9 +296,26 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
//FUSE_CAP_ATOMIC_O_TRUNC | /* due to Windows/WinFsp design, no support */
|
||||
//FUSE_CAP_EXPORT_SUPPORT | /* not needed in Windows/WinFsp */
|
||||
FUSE_CAP_BIG_WRITES |
|
||||
FUSE_CAP_DONT_MASK;
|
||||
FUSE_CAP_DONT_MASK |
|
||||
FSP_FUSE_CAP_READDIR_PLUS |
|
||||
FSP_FUSE_CAP_READ_ONLY |
|
||||
FSP_FUSE_CAP_STAT_EX |
|
||||
FSP_FUSE_CAP_CASE_INSENSITIVE;
|
||||
if (0 != f->ops.init)
|
||||
{
|
||||
context->private_data = f->data = f->ops.init(&conn);
|
||||
f->VolumeParams.ReadOnlyVolume = 0 != (conn.want & FSP_FUSE_CAP_READ_ONLY);
|
||||
f->VolumeParams.CaseSensitiveSearch = 0 == (conn.want & FSP_FUSE_CAP_CASE_INSENSITIVE);
|
||||
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->fsinit = TRUE;
|
||||
if (0 != f->ops.statfs)
|
||||
{
|
||||
@ -308,16 +330,18 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (stbuf.f_frsize > FSP_FUSE_SECTORSIZE_MAX)
|
||||
stbuf.f_frsize = FSP_FUSE_SECTORSIZE_MAX;
|
||||
if (0 == f->VolumeParams.SectorSize)
|
||||
if (0 == f->VolumeParams.SectorSize && 0 != stbuf.f_frsize)
|
||||
f->VolumeParams.SectorSize = (UINT16)stbuf.f_frsize;
|
||||
#if 0
|
||||
if (0 == f->VolumeParams.SectorsPerAllocationUnit && 0 != stbuf.f_frsize)
|
||||
f->VolumeParams.SectorsPerAllocationUnit = (UINT16)(stbuf.f_bsize / stbuf.f_frsize);
|
||||
#endif
|
||||
if (0 == f->VolumeParams.MaxComponentLength)
|
||||
f->VolumeParams.MaxComponentLength = (UINT16)stbuf.f_namemax;
|
||||
}
|
||||
if (0 != f->ops.getattr)
|
||||
{
|
||||
struct fuse_stat stbuf;
|
||||
struct fuse_stat_ex stbuf;
|
||||
int err;
|
||||
|
||||
memset(&stbuf, 0, sizeof stbuf);
|
||||
@ -331,21 +355,18 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
if (0 == f->VolumeParams.VolumeCreationTime)
|
||||
{
|
||||
if (0 != stbuf.st_birthtim.tv_sec)
|
||||
f->VolumeParams.VolumeCreationTime =
|
||||
Int32x32To64(stbuf.st_birthtim.tv_sec, 10000000) + 116444736000000000 +
|
||||
stbuf.st_birthtim.tv_nsec / 100;
|
||||
FspPosixUnixTimeToFileTime((void *)&stbuf.st_birthtim,
|
||||
&f->VolumeParams.VolumeCreationTime);
|
||||
else
|
||||
if (0 != stbuf.st_ctim.tv_sec)
|
||||
f->VolumeParams.VolumeCreationTime =
|
||||
Int32x32To64(stbuf.st_ctim.tv_sec, 10000000) + 116444736000000000 +
|
||||
stbuf.st_ctim.tv_nsec / 100;
|
||||
FspPosixUnixTimeToFileTime((void *)&stbuf.st_ctim,
|
||||
&f->VolumeParams.VolumeCreationTime);
|
||||
}
|
||||
}
|
||||
|
||||
/* the FSD does not currently limit these VolumeParams fields; do so here! */
|
||||
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN)
|
||||
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MIN;
|
||||
if (f->VolumeParams.SectorSize > FSP_FUSE_SECTORSIZE_MAX)
|
||||
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN ||
|
||||
f->VolumeParams.SectorSize > FSP_FUSE_SECTORSIZE_MAX)
|
||||
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MAX;
|
||||
if (f->VolumeParams.SectorsPerAllocationUnit == 0)
|
||||
f->VolumeParams.SectorsPerAllocationUnit = 1;
|
||||
@ -380,7 +401,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
FspFileSystemSetOperationGuardStrategy(f->FileSystem, f->OpGuardStrategy);
|
||||
FspFileSystemSetDebugLog(f->FileSystem, f->DebugLog);
|
||||
|
||||
if (L'\0' != f->MountPoint)
|
||||
if (0 != f->MountPoint)
|
||||
{
|
||||
Result = FspFileSystemSetMountPoint(f->FileSystem,
|
||||
L'*' == f->MountPoint[0] && L'\0' == f->MountPoint[1] ? 0 : f->MountPoint);
|
||||
@ -447,18 +468,27 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
|
||||
default:
|
||||
return 1;
|
||||
case 'h':
|
||||
/* Note: The limit on FspServiceLog messages is 1024 bytes. This is getting close. */
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
|
||||
FSP_FUSE_LIBRARY_NAME " options:\n"
|
||||
" -o SectorSize=N sector size for Windows (512-4096, deflt: 512)\n"
|
||||
" -o SectorsPerAllocationUnit=N allocation unit size (deflt: 1*SectorSize)\n"
|
||||
" -o MaxComponentLength=N max file name component length (deflt: 255)\n"
|
||||
" -o VolumeCreationTime=T volume creation time (FILETIME hex format)\n"
|
||||
" -o VolumeSerialNumber=N 32-bit wide\n"
|
||||
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n"
|
||||
" -o CaseInsensitiveSearch file system supports case-insensitive file names\n"
|
||||
//" -o ReadOnlyVolume file system is read only\n"
|
||||
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n"
|
||||
" --FileSystemName=FSN Name of user mode file system\n");
|
||||
" -o umask=MASK set file permissions (octal)\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 rellinks interpret absolute symlinks as volume relative\n"
|
||||
" -o volname=NAME set volume label\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 DebugLog=FILE debug log file (requires -d)\n"
|
||||
"\n"
|
||||
FSP_FUSE_LIBRARY_NAME " advanced options:\n"
|
||||
" -o FileInfoTimeout=N metadata timeout (millis, -1 for data caching)\n"
|
||||
" -o SectorSize=N (512-4096, deflt: 4096)\n"
|
||||
" -o SectorsPerAllocationUnit=N (deflt: 1)\n"
|
||||
" -o MaxComponentLength=N (deflt: 255)\n"
|
||||
" -o VolumeCreationTime=T (FILETIME hex format)\n"
|
||||
" -o VolumeSerialNumber=N (32-bit wide)\n"
|
||||
);
|
||||
opt_data->help = 1;
|
||||
return 1;
|
||||
case 'V':
|
||||
@ -467,9 +497,24 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
|
||||
FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION);
|
||||
opt_data->help = 1;
|
||||
return 1;
|
||||
case 'D':
|
||||
arg += sizeof "DebugLog=" - 1;
|
||||
opt_data->DebugLogHandle = CreateFileA(
|
||||
arg,
|
||||
FILE_APPEND_DATA,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
0,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0);
|
||||
return 0;
|
||||
case 'U':
|
||||
if ('U' == arg[2])
|
||||
if ('U' == arg[0])
|
||||
arg += sizeof "UNC=" - 1;
|
||||
else if ('U' == arg[2])
|
||||
arg += sizeof "--UNC=" - 1;
|
||||
else if ('V' == arg[0])
|
||||
arg += sizeof "VolumePrefix=" - 1;
|
||||
else if ('V' == arg[2])
|
||||
arg += sizeof "--VolumePrefix=" - 1;
|
||||
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
|
||||
@ -477,20 +522,33 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
|
||||
return -1;
|
||||
opt_data->VolumeParams.Prefix
|
||||
[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;
|
||||
case 'F':
|
||||
if ('f' == arg[0])
|
||||
arg += sizeof "fstypename=" - 1;
|
||||
else if ('F' == arg[0])
|
||||
arg += sizeof "FileSystemName=" - 1;
|
||||
else if ('F' == arg[2])
|
||||
arg += sizeof "--FileSystemName=" - 1;
|
||||
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
|
||||
opt_data->VolumeParams.FileSystemName + 5,
|
||||
sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR)) - 5)
|
||||
sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR) - 5))
|
||||
return -1;
|
||||
opt_data->VolumeParams.FileSystemName
|
||||
[sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0';
|
||||
memcpy(opt_data->VolumeParams.FileSystemName, L"FUSE-", 5 * sizeof(WCHAR));
|
||||
return 0;
|
||||
case 'v':
|
||||
arg += sizeof "volname=" - 1;
|
||||
opt_data->VolumeLabelLength = (UINT16)(sizeof(WCHAR) *
|
||||
MultiByteToWideChar(CP_UTF8, 0, arg, lstrlenA(arg),
|
||||
opt_data->VolumeLabel, sizeof opt_data->VolumeLabel / sizeof(WCHAR)));
|
||||
if (0 == opt_data->VolumeLabelLength)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -509,21 +567,57 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
||||
|
||||
memset(&opt_data, 0, sizeof opt_data);
|
||||
opt_data.env = env;
|
||||
opt_data.DebugLogHandle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
opt_data.VolumeParams.FileInfoTimeout = 1000; /* default FileInfoTimeout for FUSE file systems */
|
||||
|
||||
if (-1 == fsp_fuse_opt_parse(env, args, &opt_data, fsp_fuse_core_opts, fsp_fuse_core_opt_proc))
|
||||
return 0;
|
||||
if (opt_data.help)
|
||||
return 0;
|
||||
|
||||
if (opt_data.debug)
|
||||
{
|
||||
if (INVALID_HANDLE_VALUE == opt_data.DebugLogHandle)
|
||||
{
|
||||
ErrorMessage = L": cannot open debug log file.";
|
||||
goto fail;
|
||||
}
|
||||
FspDebugLogSetHandle(opt_data.DebugLogHandle);
|
||||
}
|
||||
|
||||
if ((opt_data.set_uid && -1 == opt_data.uid) ||
|
||||
(opt_data.set_gid && -1 == opt_data.gid))
|
||||
{
|
||||
HANDLE Token;
|
||||
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token))
|
||||
{
|
||||
fsp_fuse_get_token_uidgid(Token, TokenUser,
|
||||
opt_data.set_uid && -1 == opt_data.uid ? &opt_data.uid : 0,
|
||||
opt_data.set_gid && -1 == opt_data.gid ? &opt_data.gid : 0);
|
||||
|
||||
CloseHandle(Token);
|
||||
}
|
||||
|
||||
if ((opt_data.set_uid && -1 == opt_data.uid) ||
|
||||
(opt_data.set_gid && -1 == opt_data.gid))
|
||||
{
|
||||
ErrorMessage = L": unknown user/group.";
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout)
|
||||
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
|
||||
opt_data.VolumeParams.CaseSensitiveSearch = !opt_data.CaseInsensitiveSearch;
|
||||
opt_data.VolumeParams.CaseSensitiveSearch = TRUE;
|
||||
opt_data.VolumeParams.CasePreservedNames = TRUE;
|
||||
opt_data.VolumeParams.PersistentAcls = TRUE;
|
||||
opt_data.VolumeParams.ReparsePoints = TRUE;
|
||||
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
|
||||
opt_data.VolumeParams.NamedStreams = FALSE;
|
||||
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
|
||||
opt_data.VolumeParams.ReadOnlyVolume = FALSE;
|
||||
opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
|
||||
opt_data.VolumeParams.PassQueryDirectoryFileName = TRUE;
|
||||
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
|
||||
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
|
||||
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
|
||||
@ -541,6 +635,8 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
||||
f->data = data;
|
||||
f->DebugLog = opt_data.debug ? -1 : 0;
|
||||
memcpy(&f->VolumeParams, &opt_data.VolumeParams, sizeof opt_data.VolumeParams);
|
||||
f->VolumeLabelLength = opt_data.VolumeLabelLength;
|
||||
memcpy(&f->VolumeLabel, &opt_data.VolumeLabel, opt_data.VolumeLabelLength);
|
||||
|
||||
Size = (lstrlenW(ch->MountPoint) + 1) * sizeof(WCHAR);
|
||||
f->MountPoint = fsp_fuse_obj_alloc(env, Size);
|
||||
@ -548,7 +644,9 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
||||
goto fail;
|
||||
memcpy(f->MountPoint, ch->MountPoint, Size);
|
||||
|
||||
Result = fsp_fuse_preflight(f);
|
||||
Result = FspFileSystemPreflight(
|
||||
f->VolumeParams.Prefix[0] ? L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME,
|
||||
'*' != f->MountPoint[0] || '\0' != f->MountPoint[1] ? f->MountPoint : 0);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
switch (Result)
|
||||
@ -621,6 +719,13 @@ FSP_FUSE_API void fsp_fuse_exit(struct fsp_fuse_env *env,
|
||||
{
|
||||
if (0 != f->Service)
|
||||
FspServiceStop(f->Service);
|
||||
f->exited = 1;
|
||||
}
|
||||
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_exited)(struct fsp_fuse_env *env,
|
||||
struct fuse *f)
|
||||
{
|
||||
return f->exited;
|
||||
}
|
||||
|
||||
FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env)
|
||||
@ -642,7 +747,6 @@ FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env)
|
||||
return 0;
|
||||
|
||||
context = FSP_FUSE_CONTEXT_FROM_HDR(contexthdr);
|
||||
context->pid = -1;
|
||||
|
||||
TlsSetValue(fsp_fuse_tlskey, context);
|
||||
}
|
||||
|
35
src/dll/fuse/fuse_compat.c
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @file dll/fuse/fuse_compat.c
|
||||
*
|
||||
* @copyright 2015-2017 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this file in
|
||||
* accordance with the commercial license agreement provided with the
|
||||
* software.
|
||||
*/
|
||||
|
||||
#include <dll/library.h>
|
||||
|
||||
/*
|
||||
* This file provides an implementation of the `fuse_*` symbols. This
|
||||
* implementation is a simple shim that forwards `fuse_*` calls to the
|
||||
* equivalent `fsp_fuse_*` ones using a default `fsp_fuse_env`.
|
||||
*
|
||||
* These symbols should *not* be used by C/C++ programs. For this reason
|
||||
* the `fuse.h` headers only expose the `fsp_fuse_*` symbols, wrapped
|
||||
* with macros. These symbols are for use only from programs using FFI
|
||||
* technology to access FUSE symbols (e.g. fusepy, jnr-fuse).
|
||||
*/
|
||||
|
||||
#define FSP_FUSE_API
|
||||
#define FSP_FUSE_SYM(proto, ...) __declspec(dllexport) proto { __VA_ARGS__ }
|
||||
#include <fuse/fuse_common.h>
|
||||
#include <fuse/fuse.h>
|
||||
#include <fuse/fuse_opt.h>
|
@ -40,13 +40,17 @@ struct fuse
|
||||
int rellinks;
|
||||
struct fuse_operations ops;
|
||||
void *data;
|
||||
unsigned conn_want;
|
||||
BOOLEAN fsinit;
|
||||
UINT32 DebugLog;
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
|
||||
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
||||
UINT16 VolumeLabelLength;
|
||||
WCHAR VolumeLabel[sizeof ((FSP_FSCTL_VOLUME_INFO *)0)->VolumeLabel / sizeof(WCHAR)];
|
||||
PWSTR MountPoint;
|
||||
FSP_FILE_SYSTEM *FileSystem;
|
||||
BOOLEAN fsinit;
|
||||
FSP_SERVICE *Service; /* weak */
|
||||
volatile int exited;
|
||||
};
|
||||
|
||||
struct fsp_fuse_context_header
|
||||
@ -62,27 +66,19 @@ struct fsp_fuse_file_desc
|
||||
int OpenFlags;
|
||||
UINT64 FileHandle;
|
||||
PVOID DirBuffer;
|
||||
ULONG DirBufferSize;
|
||||
};
|
||||
|
||||
struct fuse_dirhandle
|
||||
{
|
||||
PVOID Buffer;
|
||||
ULONG Length;
|
||||
ULONG BytesTransferred;
|
||||
BOOLEAN NonZeroOffset;
|
||||
/* ReadDirectory */
|
||||
struct fsp_fuse_file_desc *filedesc;
|
||||
FSP_FILE_SYSTEM *FileSystem;
|
||||
BOOLEAN ReaddirPlus;
|
||||
NTSTATUS Result;
|
||||
/* CanDelete */
|
||||
BOOLEAN DotFiles, HasChild;
|
||||
};
|
||||
|
||||
struct fsp_fuse_dirinfo
|
||||
{
|
||||
UINT16 Size;
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
BOOLEAN FileInfoValid;
|
||||
UINT64 NextOffset;
|
||||
char PosixNameBuf[]; /* includes term-0 (unlike FSP_FSCTL_DIR_INFO) */
|
||||
};
|
||||
|
||||
NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem,
|
||||
@ -90,6 +86,11 @@ NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
||||
extern FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf;
|
||||
|
||||
NTSTATUS fsp_fuse_get_token_uidgid(
|
||||
HANDLE Token,
|
||||
TOKEN_INFORMATION_CLASS UserOrOwnerClass, /* TokenUser|TokenOwner */
|
||||
PUINT32 PUid, PUINT32 PGid);
|
||||
|
||||
/* NFS reparse points */
|
||||
|
||||
#define NFS_SPECFILE_FIFO 0x000000004F464946
|
||||
|
@ -51,6 +51,9 @@ NTSTATUS FspEventLogUnregister(VOID);
|
||||
|
||||
PWSTR FspDiagIdent(VOID);
|
||||
|
||||
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
|
||||
PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount);
|
||||
|
||||
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
|
||||
|
||||
static inline ULONG FspPathSuffixIndex(PWSTR FileName)
|
||||
@ -73,7 +76,7 @@ static inline BOOLEAN FspPathIsDrive(PWSTR FileName)
|
||||
(L'A' <= FileName[0] && FileName[0] <= L'Z') ||
|
||||
(L'a' <= FileName[0] && FileName[0] <= L'z')
|
||||
) &&
|
||||
L':' == FileName[1] || L'\0' == FileName[2];
|
||||
L':' == FileName[1] && L'\0' == FileName[2];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
65
src/dll/np.c
@ -22,6 +22,7 @@
|
||||
|
||||
#define FSP_NP_NAME LIBRARY_NAME ".Np"
|
||||
#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */
|
||||
#define FSP_NP_ADDCONNECTION_TIMEOUT 15000
|
||||
|
||||
/*
|
||||
* Define the following macro to use CredUIPromptForWindowsCredentials.
|
||||
@ -146,7 +147,7 @@ static inline BOOLEAN FspNpParseRemoteName(PWSTR RemoteName,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline BOOLEAN FspNpParseUserName(PWSTR RemoteName,
|
||||
static inline BOOLEAN FspNpParseRemoteUserName(PWSTR RemoteName,
|
||||
PWSTR UserName, ULONG UserNameSize/* in chars */)
|
||||
{
|
||||
PWSTR ClassName, InstanceName, P;
|
||||
@ -283,7 +284,8 @@ static DWORD FspNpGetCredentialsKind(PWSTR RemoteName, PDWORD PCredentialsKind)
|
||||
memcpy(ClassNameBuf, ClassName, ClassNameLen * sizeof(WCHAR));
|
||||
ClassNameBuf[ClassNameLen] = '\0';
|
||||
|
||||
NpResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY, 0, KEY_READ, &RegKey);
|
||||
NpResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY,
|
||||
0, LAUNCHER_REGKEY_WOW64 | KEY_READ, &RegKey);
|
||||
if (ERROR_SUCCESS != NpResult)
|
||||
goto exit;
|
||||
|
||||
@ -583,6 +585,63 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
|
||||
switch (NpResult)
|
||||
{
|
||||
case WN_SUCCESS:
|
||||
/*
|
||||
* The Launcher is reporting success. Wait until we can access the new volume
|
||||
* root directory. If we see it report success, otherwise report error.
|
||||
*/
|
||||
{
|
||||
WCHAR RemoteNameBuf[9 + sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
|
||||
HANDLE Handle;
|
||||
|
||||
if (L'\0' != LocalNameBuf[0])
|
||||
{
|
||||
P = RemoteNameBuf;
|
||||
*P++ = L'\\'; *P++ = L'\\'; *P++ = L'?'; *P++ = L'\\';
|
||||
*P++ = LocalNameBuf[0]; *P++ = L':'; *P++ = L'\\';
|
||||
*P++ = L'\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
P = RemoteNameBuf;
|
||||
*P++ = L'\\'; *P++ = L'\\'; *P++ = L'?'; *P++ = L'\\';
|
||||
*P++ = L'U'; *P++ = L'N'; *P++ = L'C'; *P++ = L'\\';
|
||||
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\\';
|
||||
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\\';
|
||||
*P++ = L'\0';
|
||||
}
|
||||
|
||||
NpResult = WN_NO_NETWORK; /* timeout error */
|
||||
|
||||
for (ULONG I = 0, N = 1 + FSP_NP_ADDCONNECTION_TIMEOUT / 500; N > I; I++)
|
||||
{
|
||||
if (0 != I)
|
||||
Sleep(500);
|
||||
|
||||
Handle = CreateFileW(RemoteNameBuf,
|
||||
FILE_READ_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
if (INVALID_HANDLE_VALUE != Handle)
|
||||
{
|
||||
/* the file system is up and running */
|
||||
CloseHandle(Handle);
|
||||
NpResult = WN_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
P = PipeBuf;
|
||||
*P++ = LauncherSvcInstanceInfo;
|
||||
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
|
||||
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
|
||||
|
||||
if (WN_SUCCESS != FspNpCallLauncherPipe(
|
||||
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE))
|
||||
{
|
||||
/* looks like the file system is gone! */
|
||||
NpResult = WN_NO_NETWORK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WN_ACCESS_DENIED:
|
||||
break;
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
@ -662,7 +721,7 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
|
||||
lstrcpyW(UserName, L"UNSPECIFIED");
|
||||
Password[0] = L'\0';
|
||||
if (FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind)
|
||||
FspNpParseUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]);
|
||||
FspNpParseRemoteUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]);
|
||||
do
|
||||
{
|
||||
NpResult = FspNpGetCredentials(
|
||||
|
@ -923,3 +923,30 @@ FSP_API VOID FspPosixDeletePath(void *Path)
|
||||
{
|
||||
MemFree(Path);
|
||||
}
|
||||
|
||||
FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size)
|
||||
{
|
||||
for (PWSTR p = WindowsPath, endp = p + Size; endp > p; p++)
|
||||
{
|
||||
WCHAR c = *p;
|
||||
|
||||
if (L'\\' == c)
|
||||
*p = L'/';
|
||||
/* encode characters in the Unicode private use area: U+F0XX -> XX */
|
||||
else if (0xf000 <= c && c <= 0xf0ff)
|
||||
*p &= ~0xf000;
|
||||
}
|
||||
}
|
||||
|
||||
FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size)
|
||||
{
|
||||
for (PWSTR p = WindowsPath, endp = p + Size; endp > p; p++)
|
||||
{
|
||||
WCHAR c = *p;
|
||||
|
||||
if (L'/' == c)
|
||||
*p = L'\\';
|
||||
else if (128 > c && (FspPosixInvalidPathChars[c >> 5] & (0x80000000 >> (c & 0x1f))))
|
||||
*p |= 0xf000;
|
||||
}
|
||||
}
|
||||
|
@ -172,8 +172,12 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
||||
if (0 < SecurityDescriptorSize)
|
||||
{
|
||||
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, FILE_TRAVERSE,
|
||||
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, &TraverseAccess, &AccessStatus))
|
||||
if (AccessCheck(SecurityDescriptor,
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
|
||||
FILE_TRAVERSE,
|
||||
&FspFileGenericMapping,
|
||||
PrivilegeSet, &PrivilegeSetLength,
|
||||
&TraverseAccess, &AccessStatus))
|
||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||
else
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
@ -202,8 +206,12 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
{
|
||||
if (0 == DesiredAccess)
|
||||
Result = STATUS_SUCCESS;
|
||||
else if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess,
|
||||
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
||||
else if (AccessCheck(SecurityDescriptor,
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
|
||||
DesiredAccess,
|
||||
&FspFileGenericMapping,
|
||||
PrivilegeSet, &PrivilegeSetLength,
|
||||
PGrantedAccess, &AccessStatus))
|
||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||
else
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
@ -244,8 +252,12 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
((FILE_LIST_DIRECTORY & ParentAccess) ? FILE_READ_ATTRIBUTES : 0));
|
||||
if (0 != DesiredAccess2)
|
||||
{
|
||||
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess2,
|
||||
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
||||
if (AccessCheck(SecurityDescriptor,
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
|
||||
DesiredAccess2,
|
||||
&FspFileGenericMapping,
|
||||
PrivilegeSet, &PrivilegeSetLength,
|
||||
PGrantedAccess, &AccessStatus))
|
||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||
else
|
||||
/* any failure just becomes ACCESS DENIED at this point */
|
||||
@ -396,7 +408,7 @@ FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
|
||||
(PSECURITY_DESCRIPTOR)(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset) : 0,
|
||||
PSecurityDescriptor,
|
||||
0 != (Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE),
|
||||
(HANDLE)Request->Req.Create.AccessToken,
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
|
||||
&FspFileGenericMapping))
|
||||
return FspNtStatusFromWin32(GetLastError());
|
||||
|
||||
|
@ -79,7 +79,7 @@ FSP_API ULONG FspServiceRunEx(PWSTR ServiceName,
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE,
|
||||
L"The service %s cannot be created (Status=%lx).", Service->ServiceName, Result);
|
||||
L"The service %s cannot be created (Status=%lx).", ServiceName, Result);
|
||||
return FspWin32FromNtStatus(Result);
|
||||
}
|
||||
Service->UserContext = UserContext;
|
||||
@ -92,7 +92,7 @@ FSP_API ULONG FspServiceRunEx(PWSTR ServiceName,
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE,
|
||||
L"The service %s has failed to run (Status=%lx).", Service->ServiceName, Result);
|
||||
L"The service %s has failed to run (Status=%lx).", ServiceName, Result);
|
||||
return FspWin32FromNtStatus(Result);
|
||||
}
|
||||
|
||||
|
@ -163,3 +163,49 @@ exit:
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspVersion(PUINT32 PVersion)
|
||||
{
|
||||
static UINT32 Version;
|
||||
|
||||
if (0 == Version)
|
||||
{
|
||||
/*
|
||||
* This check is not thread-safe, but that should be ok.
|
||||
* Two threads competing to read the version will read
|
||||
* the same value from the Version resource.
|
||||
*/
|
||||
*PVersion = 0;
|
||||
|
||||
extern HINSTANCE DllInstance;
|
||||
WCHAR ModuleFileName[MAX_PATH];
|
||||
PVOID VersionInfo;
|
||||
DWORD Size;
|
||||
VS_FIXEDFILEINFO *FixedFileInfo = 0;
|
||||
|
||||
if (0 != GetModuleFileNameW(DllInstance, ModuleFileName, MAX_PATH))
|
||||
{
|
||||
Size = GetFileVersionInfoSizeW(ModuleFileName, &Size/*dummy*/);
|
||||
if (0 < Size)
|
||||
{
|
||||
VersionInfo = MemAlloc(Size);
|
||||
if (0 != VersionInfo &&
|
||||
GetFileVersionInfoW(ModuleFileName, 0, Size, VersionInfo) &&
|
||||
VerQueryValueW(VersionInfo, L"\\", &FixedFileInfo, &Size))
|
||||
{
|
||||
/* 32-bit store should be atomic! */
|
||||
Version = FixedFileInfo->dwFileVersionMS;
|
||||
}
|
||||
|
||||
MemFree(VersionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == FixedFileInfo)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
*PVersion = Version;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
2364
src/dotnet/FileSystemBase+Const.cs
Normal file
1194
src/dotnet/FileSystemBase.cs
Normal file
1063
src/dotnet/FileSystemHost.cs
Normal file
1093
src/dotnet/Interop.cs
Normal file
187
src/dotnet/Service.cs
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* dotnet/Service.cs
|
||||
*
|
||||
* Copyright 2015-2017 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this file in
|
||||
* accordance with the commercial license agreement provided with the
|
||||
* software.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
using Fsp.Interop;
|
||||
|
||||
namespace Fsp
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Provides the base class for a process that can be run as a service,
|
||||
/// command line application or under the control of the WinFsp launcher.
|
||||
/// </summary>
|
||||
public class Service
|
||||
{
|
||||
/* const */
|
||||
public const UInt32 EVENTLOG_ERROR_TYPE = 0x0001;
|
||||
public const UInt32 EVENTLOG_WARNING_TYPE = 0x0002;
|
||||
public const UInt32 EVENTLOG_INFORMATION_TYPE = 0x0004;
|
||||
|
||||
/* ctor/dtor */
|
||||
/// <summary>
|
||||
/// Creates an instance of the Service class.
|
||||
/// </summary>
|
||||
/// <param name="ServiceName">The name of the service.</param>
|
||||
public Service(String ServiceName)
|
||||
{
|
||||
Api.FspServiceCreate(ServiceName, _OnStart, _OnStop, null, out _ServicePtr);
|
||||
if (IntPtr.Zero != _ServicePtr)
|
||||
Api.SetUserContext(_ServicePtr, this);
|
||||
}
|
||||
~Service()
|
||||
{
|
||||
if (IntPtr.Zero != _ServicePtr)
|
||||
{
|
||||
Api.DisposeUserContext(_ServicePtr);
|
||||
Api.FspServiceDelete(_ServicePtr);
|
||||
}
|
||||
}
|
||||
|
||||
/* control */
|
||||
/// <summary>
|
||||
/// Runs a service.
|
||||
/// </summary>
|
||||
/// <returns>Service process exit code.</returns>
|
||||
public int Run()
|
||||
{
|
||||
if (IntPtr.Zero == _ServicePtr)
|
||||
{
|
||||
const Int32 STATUS_INSUFFICIENT_RESOURCES = unchecked((Int32)0xc000009a);
|
||||
Log(EVENTLOG_ERROR_TYPE,
|
||||
String.Format("The service {0} cannot be created (Status={1:X}).",
|
||||
GetType().FullName, STATUS_INSUFFICIENT_RESOURCES));
|
||||
return (int)Api.FspWin32FromNtStatus(STATUS_INSUFFICIENT_RESOURCES);
|
||||
}
|
||||
Api.FspServiceAllowConsoleMode(_ServicePtr);
|
||||
Int32 Result = Api.FspServiceLoop(_ServicePtr);
|
||||
int ExitCode = (int)Api.FspServiceGetExitCode(_ServicePtr);
|
||||
if (0 > Result)
|
||||
{
|
||||
Log(EVENTLOG_ERROR_TYPE,
|
||||
String.Format("The service {0} has failed to run (Status={1:X}).",
|
||||
GetType().FullName, Result));
|
||||
return (int)Api.FspWin32FromNtStatus(Result);
|
||||
}
|
||||
return ExitCode;
|
||||
}
|
||||
/// <summary>
|
||||
/// Stops a running service.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (IntPtr.Zero == _ServicePtr)
|
||||
throw new InvalidOperationException();
|
||||
Api.FspServiceStop(_ServicePtr);
|
||||
}
|
||||
public void RequestTime(UInt32 Time)
|
||||
{
|
||||
if (IntPtr.Zero == _ServicePtr)
|
||||
throw new InvalidOperationException();
|
||||
Api.FspServiceRequestTime(_ServicePtr, Time);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the service process exit code.
|
||||
/// </summary>
|
||||
public int ExitCode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IntPtr.Zero == _ServicePtr)
|
||||
throw new InvalidOperationException();
|
||||
return (int)Api.FspServiceGetExitCode(_ServicePtr);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (IntPtr.Zero == _ServicePtr)
|
||||
throw new InvalidOperationException();
|
||||
Api.FspServiceSetExitCode(_ServicePtr, (UInt32)value);
|
||||
}
|
||||
}
|
||||
public IntPtr ServiceHandle
|
||||
{
|
||||
get { return _ServicePtr; }
|
||||
}
|
||||
public static void Log(UInt32 Type, String Message)
|
||||
{
|
||||
Api.FspServiceLog(Type, "%s", Message);
|
||||
}
|
||||
|
||||
/* start/stop */
|
||||
/// <summary>
|
||||
/// Provides a means to customize the returned status code when an exception happens.
|
||||
/// </summary>
|
||||
/// <param name="ex"></param>
|
||||
/// <returns>STATUS_SUCCESS or error code.</returns>
|
||||
protected virtual Int32 ExceptionHandler(Exception ex)
|
||||
{
|
||||
return unchecked((Int32)0xE0434f4D)/*STATUS_CLR_EXCEPTION*/;
|
||||
}
|
||||
/// <summary>
|
||||
/// Occurs when the service starts.
|
||||
/// </summary>
|
||||
/// <param name="Args">Command line arguments passed to the service.</param>
|
||||
protected virtual void OnStart(String[] Args)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Occurs when the service stops.
|
||||
/// </summary>
|
||||
protected virtual void OnStop()
|
||||
{
|
||||
}
|
||||
|
||||
/* callbacks */
|
||||
private static Int32 OnStart(
|
||||
IntPtr Service,
|
||||
UInt32 Argc,
|
||||
String[] Argv)
|
||||
{
|
||||
Service self = (Service)Api.GetUserContext(Service);
|
||||
try
|
||||
{
|
||||
self.OnStart(
|
||||
Argv);
|
||||
return 0/*STATUS_SUCCESS*/;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return self.ExceptionHandler(ex);
|
||||
}
|
||||
}
|
||||
private static Int32 OnStop(
|
||||
IntPtr Service)
|
||||
{
|
||||
Service self = (Service)Api.GetUserContext(Service);
|
||||
try
|
||||
{
|
||||
self.OnStop();
|
||||
return 0/*STATUS_SUCCESS*/;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return self.ExceptionHandler(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static Api.Proto.ServiceStart _OnStart = OnStart;
|
||||
private static Api.Proto.ServiceStop _OnStop = OnStop;
|
||||
private IntPtr _ServicePtr;
|
||||
}
|
||||
|
||||
}
|
37
src/fsptool/fsptool-version.rc
Normal 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
@ -0,0 +1,602 @@
|
||||
/**
|
||||
* @file fsptool/fsptool.c
|
||||
*
|
||||
* @copyright 2015-2017 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this file in
|
||||
* accordance with the commercial license agreement provided with the
|
||||
* software.
|
||||
*/
|
||||
|
||||
#include <winfsp/winfsp.h>
|
||||
#include <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));
|
||||
}
|
@ -19,7 +19,6 @@
|
||||
#include <sddl.h>
|
||||
|
||||
#define PROGNAME "WinFsp.Launcher"
|
||||
#define REGKEY LAUNCHER_REGKEY
|
||||
|
||||
BOOL CreateOverlappedPipe(
|
||||
PHANDLE PReadPipe, PHANDLE PWritePipe, PSECURITY_ATTRIBUTES SecurityAttributes, DWORD Size,
|
||||
@ -68,6 +67,76 @@ BOOL CreateOverlappedPipe(
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static NTSTATUS GetTokenUserName(HANDLE Token, PWSTR *PUserName)
|
||||
{
|
||||
TOKEN_USER *User = 0;
|
||||
WCHAR Name[256], Domn[256];
|
||||
DWORD UserSize, NameSize, DomnSize;
|
||||
SID_NAME_USE Use;
|
||||
PWSTR P;
|
||||
NTSTATUS Result;
|
||||
|
||||
*PUserName = 0;
|
||||
|
||||
if (GetTokenInformation(Token, TokenUser, 0, 0, &UserSize))
|
||||
{
|
||||
Result = STATUS_INVALID_PARAMETER;
|
||||
goto exit;
|
||||
}
|
||||
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
User = MemAlloc(UserSize);
|
||||
if (0 == User)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!GetTokenInformation(Token, TokenUser, User, UserSize, &UserSize))
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
NameSize = sizeof Name / sizeof Name[0];
|
||||
DomnSize = sizeof Domn / sizeof Domn[0];
|
||||
if (!LookupAccountSidW(0, User->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:
|
||||
MemFree(User);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE Process;
|
||||
@ -143,6 +212,17 @@ typedef struct
|
||||
static CRITICAL_SECTION SvcInstanceLock;
|
||||
static HANDLE SvcInstanceEvent;
|
||||
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);
|
||||
|
||||
@ -211,6 +291,14 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
|
||||
else
|
||||
Length += SvcInstanceArgumentLength(EmptyArg);
|
||||
}
|
||||
else
|
||||
if (L'U' == *P)
|
||||
{
|
||||
if (0 != SvcInstanceUserName())
|
||||
Length += SvcInstanceArgumentLength(SvcInstanceUserName());
|
||||
else
|
||||
Length += SvcInstanceArgumentLength(EmptyArg);
|
||||
}
|
||||
else
|
||||
Length++;
|
||||
break;
|
||||
@ -237,6 +325,14 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
|
||||
else
|
||||
Q = SvcInstanceArgumentCopy(Q, EmptyArg);
|
||||
}
|
||||
else
|
||||
if (L'U' == *P)
|
||||
{
|
||||
if (0 != SvcInstanceUserName())
|
||||
Q = SvcInstanceArgumentCopy(Q, SvcInstanceUserName());
|
||||
else
|
||||
Q = SvcInstanceArgumentCopy(Q, EmptyArg);
|
||||
}
|
||||
else
|
||||
*Q++ = *P;
|
||||
break;
|
||||
@ -441,7 +537,8 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" REGKEY, 0, KEY_READ, &RegKey);
|
||||
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY,
|
||||
0, LAUNCHER_REGKEY_WOW64 | KEY_READ, &RegKey);
|
||||
if (ERROR_SUCCESS != RegResult)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(RegResult);
|
||||
@ -918,6 +1015,10 @@ static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
if (0 == SvcInstanceEvent)
|
||||
goto fail;
|
||||
|
||||
SvcInstanceTlsKey = TlsAlloc();
|
||||
if (TLS_OUT_OF_INDEXES == SvcInstanceTlsKey)
|
||||
goto fail;
|
||||
|
||||
SvcJob = CreateJobObjectW(0, 0);
|
||||
if (0 != SvcJob)
|
||||
{
|
||||
@ -980,6 +1081,9 @@ fail:
|
||||
if (0 != SvcJob)
|
||||
CloseHandle(SvcJob);
|
||||
|
||||
if (TLS_OUT_OF_INDEXES != SvcInstanceTlsKey)
|
||||
TlsFree(SvcInstanceTlsKey);
|
||||
|
||||
if (0 != SvcInstanceEvent)
|
||||
CloseHandle(SvcInstanceEvent);
|
||||
|
||||
@ -1023,6 +1127,9 @@ static NTSTATUS SvcStop(FSP_SERVICE *Service)
|
||||
if (0 != SvcJob)
|
||||
CloseHandle(SvcJob);
|
||||
|
||||
if (TLS_OUT_OF_INDEXES != SvcInstanceTlsKey)
|
||||
TlsFree(SvcInstanceTlsKey);
|
||||
|
||||
if (0 != SvcInstanceEvent)
|
||||
CloseHandle(SvcInstanceEvent);
|
||||
|
||||
@ -1194,13 +1301,16 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
||||
return;
|
||||
|
||||
PWSTR P = PipeBuf, PipeBufEnd = PipeBuf + *PSize / sizeof(WCHAR);
|
||||
PWSTR ClassName, InstanceName;
|
||||
PWSTR ClassName, InstanceName, UserName;
|
||||
ULONG Argc; PWSTR Argv[9];
|
||||
BOOLEAN HasSecret = FALSE;
|
||||
NTSTATUS Result;
|
||||
|
||||
*PSize = 0;
|
||||
|
||||
GetTokenUserName(ClientToken, &UserName);
|
||||
SvcInstanceSetUserName(UserName);
|
||||
|
||||
switch (*P++)
|
||||
{
|
||||
case LauncherSvcInstanceStartWithSecret:
|
||||
@ -1264,6 +1374,9 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
||||
SvcPipeTransactResult(STATUS_INVALID_PARAMETER, PipeBuf, PSize);
|
||||
break;
|
||||
}
|
||||
|
||||
SvcInstanceSetUserName(0);
|
||||
MemFree(UserName);
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t **argv)
|
||||
|
@ -21,7 +21,8 @@
|
||||
#include <winfsp/winfsp.h>
|
||||
#include <shared/minimal.h>
|
||||
|
||||
#define LAUNCHER_REGKEY "SYSTEM\\CurrentControlSet\\Services\\WinFsp.Launcher\\Services"
|
||||
#define LAUNCHER_REGKEY "Software\\WinFsp\\Services"
|
||||
#define LAUNCHER_REGKEY_WOW64 KEY_WOW64_32KEY
|
||||
|
||||
#define LAUNCHER_STOP_TIMEOUT 5500
|
||||
#define LAUNCHER_KILL_TIMEOUT 5000
|
||||
|
@ -126,6 +126,10 @@ static inline void *MemAlloc(size_t Size)
|
||||
{
|
||||
return HeapAlloc(GetProcessHeap(), 0, Size);
|
||||
}
|
||||
static inline void *MemRealloc(void *Pointer, size_t Size)
|
||||
{
|
||||
return HeapReAlloc(GetProcessHeap(), 0, Pointer, Size);
|
||||
}
|
||||
static inline void MemFree(void *Pointer)
|
||||
{
|
||||
if (0 != Pointer)
|
||||
|
@ -80,8 +80,18 @@ static NTSTATUS FspFsvolClose(
|
||||
FspFileDescDelete(FileDesc); /* this will also close the MainFileObject if any */
|
||||
FspFileNodeDereference(FileNode);
|
||||
|
||||
/* if we are closing files in the context of a rename make it synchronous */
|
||||
if (FspFsvolDeviceFileRenameIsAcquiredExclusive(FsvolDeviceObject))
|
||||
{
|
||||
/* acquire ownership of the Request */
|
||||
Request->Hint = (UINT_PTR)Irp;
|
||||
FspIrpSetRequest(Irp, Request);
|
||||
|
||||
return FSP_STATUS_IOQ_POST_BEST_EFFORT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Post as a BestEffort work request. This allows us to complete our own IRP
|
||||
* Post as a BestEffort WORK request. This allows us to complete our own IRP
|
||||
* and return immediately.
|
||||
*/
|
||||
FspIopPostWorkRequestBestEffort(FsvolDeviceObject, Request);
|
||||
|
@ -545,6 +545,7 @@ NTSTATUS FspFsvolCreatePrepare(
|
||||
SECURITY_CLIENT_CONTEXT SecurityClientContext;
|
||||
HANDLE UserModeAccessToken;
|
||||
PEPROCESS Process;
|
||||
ULONG OriginatingProcessId;
|
||||
FSP_FILE_NODE *FileNode;
|
||||
FSP_FILE_DESC *FileDesc;
|
||||
PFILE_OBJECT FileObject;
|
||||
@ -579,10 +580,16 @@ NTSTATUS FspFsvolCreatePrepare(
|
||||
Process = PsGetCurrentProcess();
|
||||
ObReferenceObject(Process);
|
||||
|
||||
/* get the originating process ID stored in the IRP */
|
||||
OriginatingProcessId = IoGetRequestorProcessId(Irp);
|
||||
|
||||
/* send the user-mode handle to the user-mode file system */
|
||||
FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken;
|
||||
FspIopRequestContext(Request, RequestProcess) = Process;
|
||||
Request->Req.Create.AccessToken = (UINT_PTR)UserModeAccessToken;
|
||||
ASSERT((UINT64)(UINT_PTR)UserModeAccessToken <= 0xffffffffULL);
|
||||
ASSERT((UINT64)(UINT_PTR)OriginatingProcessId <= 0xffffffffULL);
|
||||
Request->Req.Create.AccessToken =
|
||||
((UINT64)(UINT_PTR)OriginatingProcessId << 32) | (UINT64)(UINT_PTR)UserModeAccessToken;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@ -808,6 +815,16 @@ NTSTATUS FspFsvolCreateComplete(
|
||||
}
|
||||
|
||||
/* populate the FileNode/FileDesc fields from the Response */
|
||||
FileNode->UserContext = Response->Rsp.Create.Opened.UserContext;
|
||||
FileNode->IndexNumber = Response->Rsp.Create.Opened.FileInfo.IndexNumber;
|
||||
FileNode->IsDirectory = BooleanFlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes,
|
||||
FILE_ATTRIBUTE_DIRECTORY);
|
||||
FileNode->IsRootDirectory = FileNode->IsDirectory &&
|
||||
sizeof(WCHAR) == FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0];
|
||||
FileDesc->UserContext2 = Response->Rsp.Create.Opened.UserContext2;
|
||||
FileDesc->DeleteOnClose = BooleanFlagOn(IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE);
|
||||
|
||||
/* handle normalized names */
|
||||
if (!FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch)
|
||||
{
|
||||
/* is there a normalized file name as part of the response? */
|
||||
@ -843,14 +860,6 @@ NTSTATUS FspFsvolCreateComplete(
|
||||
RtlCopyMemory(FileNode->FileName.Buffer, NormalizedName.Buffer, NormalizedName.Length);
|
||||
}
|
||||
}
|
||||
FileNode->UserContext = Response->Rsp.Create.Opened.UserContext;
|
||||
FileNode->IndexNumber = Response->Rsp.Create.Opened.FileInfo.IndexNumber;
|
||||
FileNode->IsDirectory = BooleanFlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes,
|
||||
FILE_ATTRIBUTE_DIRECTORY);
|
||||
FileNode->IsRootDirectory = FileNode->IsDirectory &&
|
||||
sizeof(WCHAR) == FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0];
|
||||
FileDesc->UserContext2 = Response->Rsp.Create.Opened.UserContext2;
|
||||
FileDesc->DeleteOnClose = BooleanFlagOn(IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE);
|
||||
|
||||
/* open the FileNode */
|
||||
Result = FspFileNodeOpen(FileNode, FileObject,
|
||||
@ -876,8 +885,7 @@ NTSTATUS FspFsvolCreateComplete(
|
||||
|
||||
Result = FspFsvolCreateSharingViolationOplock(
|
||||
FsvolDeviceObject, Irp, IrpSp, FALSE);
|
||||
if (STATUS_PENDING == Result)
|
||||
FSP_RETURN();
|
||||
FSP_RETURN();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1097,7 +1105,44 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
|
||||
return Result;
|
||||
}
|
||||
|
||||
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Create.Opened.FileInfo,
|
||||
/*
|
||||
* FspFileNodeTrySetFileInfoOnOpen sets the FileNode's metadata to values reported
|
||||
* by the user mode file system. It does so only if the file is not already open; the
|
||||
* reason is that there is a subtle race condition otherwise.
|
||||
*
|
||||
* Consider that a file is already open and (for example) being appended to. The appends
|
||||
* appear as WRITE IRP's and they are all synchronized by acquiring the FileNode resources
|
||||
* exclusive. Part of the WRITE protocol involves returning an updated FileInfo for the
|
||||
* written FileNode, which the FSD uses to update its view of the file metadata.
|
||||
*
|
||||
* Now consider that a file OPEN comes in. Because the FSD does not know yet which FileNode
|
||||
* will be opened it does not acquire any FileNode. [Note that while it is possible to
|
||||
* uniquely identify a FileNode by FileName currently, this would no longer be the case
|
||||
* when we implement hard links.] The FSD posts the OPEN request to the user mode file system.
|
||||
* The user mode file system processes the OPEN request successfully and responds with the
|
||||
* opened file and its FileInfo.
|
||||
*
|
||||
* Prior to the FSD processing the OPEN response additional WRITE IRP's come through the
|
||||
* original file handle. These WRITE's update the FileSize as understood by the user mode
|
||||
* file system and the corresponding FileInfo gets reported back to the FSD. Eventually the
|
||||
* delayed OPEN response gets processed, which now clobbers the FileInfo as understood by
|
||||
* the FSD.
|
||||
*
|
||||
* The problem here is that OPEN requests have no way of locking the FileNode while the OPEN
|
||||
* request is in transit to the user mode file system. In all other cases the user mode file
|
||||
* system and the FSD update their view of the file's metadata in an atomic fashion. Not so
|
||||
* in the case of OPEN.
|
||||
*
|
||||
* While this is a subtle race condition it can nevertheless creates a real problem. For
|
||||
* example, Explorer often opens files to get information about them and may inappropriately
|
||||
* update the FSD view of the file size during WRITE's.
|
||||
*
|
||||
* FspFileNodeTrySetFileInfoOnOpen attempts to mitigate this problem by only updating the
|
||||
* FileInfo if the file is not already open. This avoids placing stale information in the
|
||||
* FileNode.
|
||||
*/
|
||||
|
||||
FspFileNodeTrySetFileInfoOnOpen(FileNode, FileObject, &Response->Rsp.Create.Opened.FileInfo,
|
||||
FILE_CREATED == Response->IoStatus.Information);
|
||||
|
||||
if (FlushImage)
|
||||
@ -1315,6 +1360,7 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock(
|
||||
|
||||
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||
FSP_FSCTL_TRANSACT_RSP *Response;
|
||||
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
|
||||
FSP_FILE_NODE *ExtraFileNode = FspIopRequestContext(Request, FspIopRequestExtraContext);
|
||||
ULONG SharingViolationReason = (ULONG)Irp->IoStatus.Information;
|
||||
NTSTATUS Result;
|
||||
@ -1351,6 +1397,12 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock(
|
||||
return FspWqRepostIrpWorkItem(Irp,
|
||||
FspFsvolCreateSharingViolationOplock, FspFsvolCreateRequestFini);
|
||||
|
||||
FspFileNodeClose(ExtraFileNode, 0, TRUE);
|
||||
FspFileNodeDereference(ExtraFileNode);
|
||||
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
|
||||
|
||||
FspFsvolCreatePostClose(FileDesc);
|
||||
|
||||
Irp->IoStatus.Information = 0;
|
||||
return STATUS_SHARING_VIOLATION;
|
||||
}
|
||||
@ -1369,7 +1421,6 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock(
|
||||
* stream.
|
||||
*/
|
||||
|
||||
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
|
||||
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
|
||||
|
||||
/* break Batch oplocks on the main file and this stream */
|
||||
@ -1425,14 +1476,14 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock(
|
||||
|
||||
Response = FspIopIrpResponse(Irp);
|
||||
|
||||
if (STATUS_SUCCESS == Result)
|
||||
{
|
||||
FspFileNodeClose(ExtraFileNode, 0, TRUE);
|
||||
FspFileNodeDereference(ExtraFileNode);
|
||||
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
|
||||
}
|
||||
else
|
||||
FspFileNodeClose(ExtraFileNode, 0, TRUE);
|
||||
FspFileNodeDereference(ExtraFileNode);
|
||||
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
|
||||
|
||||
if (STATUS_SUCCESS != Result)
|
||||
{
|
||||
FspFsvolCreatePostClose(FileDesc);
|
||||
|
||||
Response->IoStatus.Status = (UINT32)Result;
|
||||
Response->IoStatus.Information = (UINT32)Irp->IoStatus.Information;
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject);
|
||||
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
|
||||
VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
|
||||
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
|
||||
BOOLEAN FspFsvolDeviceFileRenameIsAcquiredExclusive(PDEVICE_OBJECT DeviceObject);
|
||||
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject);
|
||||
VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject);
|
||||
NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject,
|
||||
@ -80,6 +81,7 @@ VOID FspDeviceDeleteAll(VOID);
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameSetOwner)
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameRelease)
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameReleaseOwner)
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameIsAcquiredExclusive)
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceLockContextTable)
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceUnlockContextTable)
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceCopyContextList)
|
||||
@ -574,6 +576,15 @@ VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Own
|
||||
ExReleaseResourceForThreadLite(&FsvolDeviceExtension->FileRenameResource, (ERESOURCE_THREAD)Owner);
|
||||
}
|
||||
|
||||
BOOLEAN FspFsvolDeviceFileRenameIsAcquiredExclusive(PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
|
||||
|
||||
return ExIsResourceAcquiredExclusiveLite(&FsvolDeviceExtension->FileRenameResource);
|
||||
}
|
||||
|
||||
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
635
src/sys/dirctl.c
@ -17,18 +17,9 @@
|
||||
|
||||
#include <sys/driver.h>
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
*
|
||||
* FspIopCompleteIrpEx does some special processing for IRP_MJ_DIRECTORY_CONTROL /
|
||||
* IRP_MN_QUERY_DIRECTORY IRP's that come from SRV2. If the processing of this IRP
|
||||
* changes substantially (in particular if we eliminate our use of
|
||||
* Irp->AssociatedIrp.SystemBuffer) we should also revisit FspIopCompleteIrpEx.
|
||||
*/
|
||||
|
||||
static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
|
||||
UINT64 DirectoryOffset, PUINT64 PDirectoryOffset,
|
||||
PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut,
|
||||
FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry,
|
||||
FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize,
|
||||
PVOID DestBuf, PULONG PDestLen);
|
||||
@ -74,27 +65,24 @@ FSP_DRIVER_DISPATCH FspDirectoryControl;
|
||||
#pragma alloc_text(PAGE, FspDirectoryControl)
|
||||
#endif
|
||||
|
||||
#define FILE_INDEX_FROM_OFFSET(v) ((ULONG)(v))
|
||||
#define OFFSET_FROM_FILE_INDEX(v) ((UINT64)(v))
|
||||
|
||||
enum
|
||||
{
|
||||
/* QueryDirectory */
|
||||
RequestIrp = 0,
|
||||
RequestMdl = 1,
|
||||
RequestFileNode = 0,
|
||||
RequestCookie = 1,
|
||||
RequestAddress = 2,
|
||||
RequestProcess = 3,
|
||||
};
|
||||
|
||||
/* QueryDirectoryRetry */
|
||||
RequestSystemBufferLength = 0,
|
||||
|
||||
/* DirectoryControlComplete retry */
|
||||
RequestDirInfoChangeNumber = 0,
|
||||
enum
|
||||
{
|
||||
FspFsvolQueryDirectoryLengthMax =
|
||||
FspFsvolDeviceDirInfoCacheItemSizeMax - FspMetaCacheItemHeaderSize,
|
||||
};
|
||||
|
||||
static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
|
||||
UINT64 DirectoryOffset, PUINT64 PDirectoryOffset,
|
||||
PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut,
|
||||
FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry,
|
||||
FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize,
|
||||
PVOID DestBuf, PULONG PDestLen)
|
||||
@ -104,7 +92,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||
{\
|
||||
TYPE InfoStruct = { 0 }, *Info = &InfoStruct;\
|
||||
Info->NextEntryOffset = 0;\
|
||||
Info->FileIndex = FILE_INDEX_FROM_OFFSET(DirInfo->NextOffset);\
|
||||
Info->FileIndex = 0;\
|
||||
Info->FileNameLength = FileName.Length;\
|
||||
__VA_ARGS__\
|
||||
Info = DestBuf;\
|
||||
@ -128,7 +116,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||
|
||||
NTSTATUS Result = STATUS_SUCCESS;
|
||||
BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer, Match;
|
||||
BOOLEAN Loop = TRUE, DirectoryOffsetFound = FALSE;
|
||||
BOOLEAN Loop = TRUE, DirectoryMarkerFound = FALSE;
|
||||
FSP_FSCTL_DIR_INFO *DirInfo = *PDirInfo;
|
||||
PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize;
|
||||
PUINT8 DestBufBgn = (PUINT8)DestBuf;
|
||||
@ -178,16 +166,18 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||
break;
|
||||
}
|
||||
|
||||
if (0 != DirectoryOffset && !DirectoryOffsetFound)
|
||||
{
|
||||
DirectoryOffsetFound = DirInfo->NextOffset == DirectoryOffset;
|
||||
continue;
|
||||
}
|
||||
|
||||
FileName.Length =
|
||||
FileName.MaximumLength = (USHORT)(DirInfoSize - sizeof(FSP_FSCTL_DIR_INFO));
|
||||
FileName.Buffer = DirInfo->FileNameBuf;
|
||||
|
||||
if (0 != DirectoryMarker && 0 != DirectoryMarker->Buffer &&
|
||||
!DirectoryMarkerFound)
|
||||
{
|
||||
DirectoryMarkerFound = 0 == FspFileNameCompare(
|
||||
&FileName, DirectoryMarker, CaseInsensitive, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
|
||||
CopyLength = FileName.Length;
|
||||
|
||||
@ -223,7 +213,6 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||
*(PULONG)PrevDestBuf = (ULONG)((PUINT8)DestBuf - (PUINT8)PrevDestBuf);
|
||||
PrevDestBuf = DestBuf;
|
||||
|
||||
*PDirectoryOffset = DirInfo->NextOffset;
|
||||
*PDestLen = (ULONG)((PUINT8)DestBuf + BaseInfoLen + CopyLength - DestBufBgn);
|
||||
|
||||
switch (FileInformationClass)
|
||||
@ -265,6 +254,9 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||
break;
|
||||
}
|
||||
|
||||
DirectoryMarkerOut->Length = DirectoryMarkerOut->MaximumLength = FileName.Length;
|
||||
DirectoryMarkerOut->Buffer = (PVOID)((PUINT8)DestBuf + BaseInfoLen);
|
||||
|
||||
DestBuf = (PVOID)((PUINT8)DestBuf +
|
||||
FSP_FSCTL_ALIGN_UP(BaseInfoLen + CopyLength, sizeof(LONGLONG)));
|
||||
|
||||
@ -273,7 +265,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||
Loop = FALSE;
|
||||
}
|
||||
else
|
||||
*PDirectoryOffset = DirInfo->NextOffset;
|
||||
*DirectoryMarkerOut = FileName;
|
||||
}
|
||||
}
|
||||
except (EXCEPTION_EXECUTE_HANDLER)
|
||||
@ -315,7 +307,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopyCache(
|
||||
NTSTATUS Result;
|
||||
BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive;
|
||||
PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern;
|
||||
UINT64 DirectoryOffset = FileDesc->DirectoryOffset;
|
||||
UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker;
|
||||
PUINT8 DirInfoBgn = (PUINT8)DirInfo;
|
||||
PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize;
|
||||
|
||||
@ -323,17 +315,20 @@ static NTSTATUS FspFsvolQueryDirectoryCopyCache(
|
||||
DirInfoSize = (ULONG)(DirInfoEnd - (PUINT8)DirInfo);
|
||||
|
||||
Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive,
|
||||
0 != FileDesc->DirInfoCacheHint ? 0 : DirectoryOffset, &DirectoryOffset,
|
||||
0 != FileDesc->DirInfoCacheHint ? 0 : &FileDesc->DirectoryMarker, &DirectoryMarker,
|
||||
FileInformationClass, ReturnSingleEntry,
|
||||
&DirInfo, DirInfoSize,
|
||||
DestBuf, PDestLen);
|
||||
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
if (0 != *PDestLen)
|
||||
FileDesc->DirectoryHasSuchFile = TRUE;
|
||||
FileDesc->DirectoryOffset = DirectoryOffset;
|
||||
FileDesc->DirInfoCacheHint = (ULONG)((PUINT8)DirInfo - DirInfoBgn);
|
||||
Result = FspFileDescSetDirectoryMarker(FileDesc, &DirectoryMarker);
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
if (0 != *PDestLen)
|
||||
FileDesc->DirectoryHasSuchFile = TRUE;
|
||||
FileDesc->DirInfoCacheHint = (ULONG)((PUINT8)DirInfo - DirInfoBgn);
|
||||
}
|
||||
}
|
||||
else if (STATUS_NO_MORE_FILES == Result && !FileDesc->DirectoryHasSuchFile)
|
||||
Result = STATUS_NO_SUCH_FILE;
|
||||
@ -354,25 +349,27 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
|
||||
NTSTATUS Result;
|
||||
BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive;
|
||||
PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern;
|
||||
UINT64 DirectoryOffset = FileDesc->DirectoryOffset;
|
||||
UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker;
|
||||
|
||||
ASSERT(DirInfo == DestBuf);
|
||||
FSP_FSCTL_STATIC_ASSERT(
|
||||
FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) >=
|
||||
FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName),
|
||||
"FSP_FSCTL_DIR_INFO must be bigger than FILE_ID_BOTH_DIR_INFORMATION");
|
||||
|
||||
Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive,
|
||||
0, &DirectoryOffset,
|
||||
0, &DirectoryMarker,
|
||||
FileInformationClass, ReturnSingleEntry,
|
||||
&DirInfo, DirInfoSize,
|
||||
DestBuf, PDestLen);
|
||||
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
if (0 != *PDestLen)
|
||||
FileDesc->DirectoryHasSuchFile = TRUE;
|
||||
FileDesc->DirectoryOffset = DirectoryOffset;
|
||||
Result = FspFileDescSetDirectoryMarker(FileDesc, &DirectoryMarker);
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
if (0 != *PDestLen)
|
||||
FileDesc->DirectoryHasSuchFile = TRUE;
|
||||
}
|
||||
}
|
||||
else if (STATUS_NO_MORE_FILES == Result && !FileDesc->DirectoryHasSuchFile)
|
||||
Result = STATUS_NO_SUCH_FILE;
|
||||
@ -380,77 +377,10 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
|
||||
return Result;
|
||||
}
|
||||
|
||||
static inline NTSTATUS FspFsvolQueryDirectoryBufferUserBuffer(
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension, PIRP Irp, PULONG PLength)
|
||||
{
|
||||
if (0 != Irp->AssociatedIrp.SystemBuffer)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
NTSTATUS Result;
|
||||
ULONG Length = *PLength;
|
||||
|
||||
if (Length > FspFsvolDeviceDirInfoCacheItemSizeMax)
|
||||
Length = FspFsvolDeviceDirInfoCacheItemSizeMax;
|
||||
else if (Length < sizeof(FSP_FSCTL_DIR_INFO) +
|
||||
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR))
|
||||
Length = sizeof(FSP_FSCTL_DIR_INFO) +
|
||||
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR);
|
||||
|
||||
Result = FspBufferUserBuffer(Irp, FSP_FSCTL_ALIGN_UP(Length, PAGE_SIZE), IoWriteAccess);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
*PLength = Length;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolQueryDirectoryRetry(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||
BOOLEAN CanWait)
|
||||
{
|
||||
/*
|
||||
* The SystemBufferLength contains the length of the SystemBuffer that we
|
||||
* are going to allocate (in FspFsvolQueryDirectoryBufferUserBuffer). This
|
||||
* buffer is going to be used as the IRP SystemBuffer and it will also be
|
||||
* mapped into the user mode file system process (in
|
||||
* FspFsvolDirectoryControlPrepare) so that the file system can fill in the
|
||||
* buffer.
|
||||
*
|
||||
* The SystemBufferLength is not the actual length that we are going to use
|
||||
* when completing the IRP. This will be computed at IRP completion time
|
||||
* (using FspFsvolQueryDirectoryCopy). Instead the SystemBufferLength is
|
||||
* the size that we want the user mode file system to see and it may be
|
||||
* different from the requested length for the following reasons:
|
||||
*
|
||||
* - If the FileInfoTimeout is non-zero, then the directory maintains a
|
||||
* DirInfo meta cache that can be used to fulfill IRP requests without
|
||||
* reaching out to user mode. In this case we want the SystemBufferLength
|
||||
* to be FspFsvolDeviceDirInfoCacheItemSizeMax so that we read up to the
|
||||
* cache size maximum.
|
||||
*
|
||||
* - If the requested DirectoryPattern (stored in FileDesc) is not the "*"
|
||||
* (MatchAll) pattern, then we want to read as many entries as possible
|
||||
* from the user mode file system to avoid multiple roundtrips to user
|
||||
* mode when doing file name matching. In this case we set again the
|
||||
* SystemBufferLength to be FspFsvolDeviceDirInfoCacheItemSizeMax. This
|
||||
* is an important optimization and without it QueryDirectory is *very*
|
||||
* slow without the DirInfo meta cache (i.e. when FileInfoTimeout is 0).
|
||||
*
|
||||
* - If the requsted DirectoryPattern is the MatchAll pattern then we set
|
||||
* the SystemBufferLength to the requested (IRP) length as it is actually
|
||||
* counter-productive to try to read more than we need.
|
||||
*/
|
||||
#define GetSystemBufferLengthMaybeCached()\
|
||||
(0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout && 0 == FileDesc->DirectoryOffset) ||\
|
||||
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ?\
|
||||
FspFsvolDeviceDirInfoCacheItemSizeMax : Length
|
||||
#define GetSystemBufferLengthNonCached()\
|
||||
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ?\
|
||||
FspFsvolDeviceDirInfoCacheItemSizeMax : Length
|
||||
#define GetSystemBufferLengthBestGuess()\
|
||||
FspFsvolDeviceDirInfoCacheItemSizeMax
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
NTSTATUS Result;
|
||||
@ -462,185 +392,23 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
||||
BOOLEAN IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);
|
||||
BOOLEAN ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
|
||||
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
|
||||
ULONG BaseInfoLen;
|
||||
PUNICODE_STRING FileName = IrpSp->Parameters.QueryDirectory.FileName;
|
||||
ULONG FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;
|
||||
PVOID Buffer = 0 != Irp->AssociatedIrp.SystemBuffer ?
|
||||
Irp->AssociatedIrp.SystemBuffer : Irp->UserBuffer;
|
||||
//ULONG FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;
|
||||
PVOID Buffer = 0 == Irp->MdlAddress ?
|
||||
Irp->UserBuffer : MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
|
||||
ULONG Length = IrpSp->Parameters.QueryDirectory.Length;
|
||||
ULONG SystemBufferLength;
|
||||
ULONG QueryDirectoryLength, QueryDirectoryLengthMin;
|
||||
PVOID DirInfoBuffer;
|
||||
ULONG DirInfoSize;
|
||||
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||
BOOLEAN PassQueryDirectoryPattern, PatternIsFileName;
|
||||
BOOLEAN Success;
|
||||
|
||||
ASSERT(FileNode == FileDesc->FileNode);
|
||||
|
||||
SystemBufferLength = 0 != Request ?
|
||||
(ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestSystemBufferLength) : 0;
|
||||
|
||||
/* try to acquire the FileNode exclusive; Full because we may need to send a Request */
|
||||
Success = DEBUGTEST(90) &&
|
||||
FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, CanWait);
|
||||
if (!Success)
|
||||
{
|
||||
if (0 == SystemBufferLength)
|
||||
SystemBufferLength = GetSystemBufferLengthBestGuess();
|
||||
|
||||
Result = FspFsvolQueryDirectoryBufferUserBuffer(
|
||||
FsvolDeviceExtension, Irp, &SystemBufferLength);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
Result = FspWqCreateIrpWorkItem(Irp, FspFsvolQueryDirectoryRetry, 0);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
Request = FspIrpRequest(Irp);
|
||||
FspIopRequestContext(Request, RequestSystemBufferLength) =
|
||||
(PVOID)(UINT_PTR)SystemBufferLength;
|
||||
|
||||
FspWqPostIrpWorkItem(Irp);
|
||||
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
/* if we have been retried reset our work item now! */
|
||||
if (0 != Request)
|
||||
{
|
||||
FspIrpDeleteRequest(Irp);
|
||||
Request = 0;
|
||||
}
|
||||
|
||||
/* set the DirectoryPattern in the FileDesc */
|
||||
Result = FspFileDescResetDirectoryPattern(FileDesc, FileName,
|
||||
RestartScan && 0 != FileName && 0 != FileName->Length);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/* determine where to (re)start */
|
||||
if (IndexSpecified)
|
||||
{
|
||||
FileDesc->DirectoryHasSuchFile = FALSE;
|
||||
FileDesc->DirectoryOffset = OFFSET_FROM_FILE_INDEX(FileIndex);
|
||||
}
|
||||
else if (RestartScan)
|
||||
{
|
||||
FileDesc->DirectoryHasSuchFile = FALSE;
|
||||
FileDesc->DirectoryOffset = 0;
|
||||
}
|
||||
|
||||
/* see if the required information is still in the cache and valid! */
|
||||
if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize))
|
||||
{
|
||||
if (0 == SystemBufferLength)
|
||||
SystemBufferLength = GetSystemBufferLengthNonCached();
|
||||
|
||||
Result = FspFsvolQueryDirectoryCopyCache(FileDesc,
|
||||
IndexSpecified || RestartScan,
|
||||
FileInformationClass, ReturnSingleEntry,
|
||||
DirInfoBuffer, DirInfoSize, Buffer, &Length);
|
||||
|
||||
FspFileNodeDereferenceDirInfo(DirInfoBuffer);
|
||||
|
||||
if (!NT_SUCCESS(Result) || 0 != Length)
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
Irp->IoStatus.Information = Length;
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 == SystemBufferLength)
|
||||
SystemBufferLength = GetSystemBufferLengthMaybeCached();
|
||||
}
|
||||
|
||||
FspFileNodeConvertExclusiveToShared(FileNode, Full);
|
||||
|
||||
/* buffer the user buffer! */
|
||||
Result = FspFsvolQueryDirectoryBufferUserBuffer(
|
||||
FsvolDeviceExtension, Irp, &SystemBufferLength);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/* create request */
|
||||
Result = FspIopCreateRequestEx(Irp, 0,
|
||||
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ?
|
||||
FileDesc->DirectoryPattern.Length + sizeof(WCHAR) : 0,
|
||||
FspFsvolQueryDirectoryRequestFini, &Request);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
return Result;
|
||||
}
|
||||
|
||||
Request->Kind = FspFsctlTransactQueryDirectoryKind;
|
||||
Request->Req.QueryDirectory.UserContext = FileNode->UserContext;
|
||||
Request->Req.QueryDirectory.UserContext2 = FileDesc->UserContext2;
|
||||
Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset;
|
||||
Request->Req.QueryDirectory.Length = SystemBufferLength;
|
||||
Request->Req.QueryDirectory.CaseSensitive = FileDesc->CaseSensitive;
|
||||
|
||||
if (FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer)
|
||||
{
|
||||
Request->Req.QueryDirectory.Pattern.Offset = Request->FileName.Size;
|
||||
Request->Req.QueryDirectory.Pattern.Size =
|
||||
FileDesc->DirectoryPattern.Length + sizeof(WCHAR);
|
||||
RtlCopyMemory(Request->Buffer + Request->FileName.Size,
|
||||
FileDesc->DirectoryPattern.Buffer, FileDesc->DirectoryPattern.Length);
|
||||
*(PWSTR)(Request->Buffer + Request->FileName.Size + FileDesc->DirectoryPattern.Length) =
|
||||
L'\0';
|
||||
}
|
||||
|
||||
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||
FspIopRequestContext(Request, RequestIrp) = Irp;
|
||||
|
||||
return FSP_STATUS_IOQ_POST;
|
||||
|
||||
#undef GetSystemBufferLengthBestGuess
|
||||
#undef GetSystemBufferLengthNonCached
|
||||
#undef GetSystemBufferLengthMaybeCached
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolQueryDirectory(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
/* is this a valid FileObject? */
|
||||
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
NTSTATUS Result;
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
|
||||
PUNICODE_STRING FileName = IrpSp->Parameters.QueryDirectory.FileName;
|
||||
ULONG Length = IrpSp->Parameters.QueryDirectory.Length;
|
||||
ULONG BaseInfoLen;
|
||||
|
||||
/* SystemBuffer must be NULL as we are going to be using it! */
|
||||
if (0 != Irp->AssociatedIrp.SystemBuffer)
|
||||
{
|
||||
ASSERT(0);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* only directory files can be queried */
|
||||
if (!FileNode->IsDirectory)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
/* check that FileName is valid (if supplied) */
|
||||
if (0 != FileName &&
|
||||
!FspFileNameIsValidPattern(FileName, FsvolDeviceExtension->VolumeParams.MaxComponentLength))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (0 == Buffer)
|
||||
return 0 == Irp->MdlAddress ? STATUS_INVALID_PARAMETER : STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
/* is this an allowed file information class? */
|
||||
switch (FileInformationClass)
|
||||
@ -666,12 +434,227 @@ static NTSTATUS FspFsvolQueryDirectory(
|
||||
default:
|
||||
return STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
|
||||
if (BaseInfoLen >= Length)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
Result = FspFsvolQueryDirectoryRetry(FsvolDeviceObject, Irp, IrpSp, IoIsOperationSynchronous(Irp));
|
||||
/* try to acquire the FileNode exclusive; Full because we may need to send a Request */
|
||||
Success = DEBUGTEST(90) &&
|
||||
FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, CanWait);
|
||||
if (!Success)
|
||||
return FspWqRepostIrpWorkItem(Irp, FspFsvolQueryDirectoryRetry, 0);
|
||||
|
||||
return Result;
|
||||
/* if we have been retried reset our work item now! */
|
||||
if (0 != Request)
|
||||
{
|
||||
FspIrpDeleteRequest(Irp);
|
||||
Request = 0;
|
||||
}
|
||||
|
||||
/* reset the FileDesc */
|
||||
Result = FspFileDescResetDirectory(FileDesc, FileName, RestartScan, IndexSpecified);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/* see if the required information is still in the cache and valid! */
|
||||
if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize))
|
||||
{
|
||||
Result = FspFsvolQueryDirectoryCopyCache(FileDesc,
|
||||
IndexSpecified || RestartScan,
|
||||
FileInformationClass, ReturnSingleEntry,
|
||||
DirInfoBuffer, DirInfoSize, Buffer, &Length);
|
||||
|
||||
FspFileNodeDereferenceDirInfo(DirInfoBuffer);
|
||||
|
||||
if (!NT_SUCCESS(Result) || 0 != Length)
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
Irp->IoStatus.Information = Length;
|
||||
return Result;
|
||||
}
|
||||
|
||||
/* reset Length! */
|
||||
Length = IrpSp->Parameters.QueryDirectory.Length;
|
||||
}
|
||||
|
||||
FspFileNodeConvertExclusiveToShared(FileNode, Full);
|
||||
|
||||
/* special handling when pattern is filename */
|
||||
PatternIsFileName = FsvolDeviceExtension->VolumeParams.PassQueryDirectoryFileName &&
|
||||
!FsRtlDoesNameContainWildCards(&FileDesc->DirectoryPattern);
|
||||
PassQueryDirectoryPattern = PatternIsFileName ||
|
||||
(FsvolDeviceExtension->VolumeParams.PassQueryDirectoryPattern &&
|
||||
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer);
|
||||
if (PatternIsFileName &&
|
||||
0 != FileDesc->DirectoryMarker.Buffer &&
|
||||
0 == FspFileNameCompare(&FileDesc->DirectoryPattern, &FileDesc->DirectoryMarker,
|
||||
!FileDesc->CaseSensitive, 0))
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
return !FileDesc->DirectoryHasSuchFile ?
|
||||
STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
|
||||
}
|
||||
|
||||
/* probe and lock the user buffer */
|
||||
Result = FspLockUserBuffer(Irp, Length, IoWriteAccess);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/* create request */
|
||||
Result = FspIopCreateRequestEx(Irp, 0,
|
||||
(PassQueryDirectoryPattern ? FileDesc->DirectoryPattern.Length + sizeof(WCHAR) : 0) +
|
||||
(FsvolDeviceExtension->VolumeParams.MaxComponentLength + 1) * sizeof(WCHAR),
|
||||
FspFsvolQueryDirectoryRequestFini, &Request);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute QueryDirectoryLength
|
||||
*
|
||||
* How much data to request from the file system varies according to the following matrix:
|
||||
*
|
||||
* Pattern | NoCache | Cache+1st | Cache+2nd
|
||||
* -------------------------+---------+-----------+----------
|
||||
* Full Wild | Ratio | Maximum | Ratio
|
||||
* Partial Wild w/o PassQDP | Maximum | Maximum | Maximum
|
||||
* Partial Wild w/ PassQDP | Ratio | Ratio | Ratio
|
||||
* File Name w/o PassQDF | Maximum | Maximum | Maximum
|
||||
* File Name w/ PassQDF | Minimum | Minimum | Minimum
|
||||
*
|
||||
* NoCache means DirInfo caching disabled. Cache+1st means DirInfo caching enabled, but
|
||||
* cache not primed. Cache+2nd means DirInfo caching enabled, cache is primed, but missed.
|
||||
* [If there is no cache miss, there is no need to send the request to the file system.]
|
||||
*
|
||||
* Maximum means to request the maximum size allowed by the FSD. Minimum means the size that
|
||||
* is guaranteed to contain at least one entry. Ratio means to compute how many directory
|
||||
* entries to request from the file system based on an estimate of how many entries the FSD
|
||||
* is supposed to deliver.
|
||||
*
|
||||
* The Ratio computation is as follows: Assume that N is the size of the average file name,
|
||||
* taken to be 24 * sizeof(WCHAR). Let M be the number of entries that can fit in the passed
|
||||
* buffer:
|
||||
*
|
||||
* M := Length / (BaseInfoLen + N) = QueryDirectoryLength / (sizeof(FSP_FSCTL_DIR_INFO) + N)
|
||||
* => QueryDirectoryLength = Length * (sizeof(FSP_FSCTL_DIR_INFO) + N) / (BaseInfoLen + N)
|
||||
*/
|
||||
|
||||
QueryDirectoryLengthMin = sizeof(FSP_FSCTL_DIR_INFO) +
|
||||
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR);
|
||||
QueryDirectoryLengthMin = FSP_FSCTL_ALIGN_UP(QueryDirectoryLengthMin, 8);
|
||||
ASSERT(QueryDirectoryLengthMin < FspFsvolQueryDirectoryLengthMax);
|
||||
if (0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout &&
|
||||
0 == FileDesc->DirectoryMarker.Buffer)
|
||||
{
|
||||
if (PatternIsFileName)
|
||||
QueryDirectoryLength = QueryDirectoryLengthMin;
|
||||
else if (PassQueryDirectoryPattern)
|
||||
{
|
||||
QueryDirectoryLength = Length *
|
||||
(sizeof(FSP_FSCTL_DIR_INFO) + 24 * sizeof(WCHAR)) / (BaseInfoLen + 24 * sizeof(WCHAR));
|
||||
QueryDirectoryLength = FSP_FSCTL_ALIGN_UP(QueryDirectoryLength, 8);
|
||||
if (QueryDirectoryLength < QueryDirectoryLengthMin)
|
||||
QueryDirectoryLength = QueryDirectoryLengthMin;
|
||||
else if (QueryDirectoryLength > FspFsvolQueryDirectoryLengthMax)
|
||||
QueryDirectoryLength = FspFsvolQueryDirectoryLengthMax;
|
||||
}
|
||||
else
|
||||
QueryDirectoryLength = FspFsvolQueryDirectoryLengthMax;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PatternIsFileName)
|
||||
QueryDirectoryLength = QueryDirectoryLengthMin;
|
||||
else if (PassQueryDirectoryPattern ||
|
||||
FspFileDescDirectoryPatternMatchAll == FileDesc->DirectoryPattern.Buffer)
|
||||
{
|
||||
QueryDirectoryLength = Length *
|
||||
(sizeof(FSP_FSCTL_DIR_INFO) + 24 * sizeof(WCHAR)) / (BaseInfoLen + 24 * sizeof(WCHAR));
|
||||
QueryDirectoryLength = FSP_FSCTL_ALIGN_UP(QueryDirectoryLength, 8);
|
||||
if (QueryDirectoryLength < QueryDirectoryLengthMin)
|
||||
QueryDirectoryLength = QueryDirectoryLengthMin;
|
||||
else if (QueryDirectoryLength > FspFsvolQueryDirectoryLengthMax)
|
||||
QueryDirectoryLength = FspFsvolQueryDirectoryLengthMax;
|
||||
}
|
||||
else
|
||||
QueryDirectoryLength = FspFsvolQueryDirectoryLengthMax;
|
||||
}
|
||||
|
||||
Request->Kind = FspFsctlTransactQueryDirectoryKind;
|
||||
Request->Req.QueryDirectory.UserContext = FileNode->UserContext;
|
||||
Request->Req.QueryDirectory.UserContext2 = FileDesc->UserContext2;
|
||||
Request->Req.QueryDirectory.Length = QueryDirectoryLength;
|
||||
Request->Req.QueryDirectory.CaseSensitive = FileDesc->CaseSensitive;
|
||||
|
||||
if (PassQueryDirectoryPattern)
|
||||
{
|
||||
Request->Req.QueryDirectory.PatternIsFileName = PatternIsFileName;
|
||||
Request->Req.QueryDirectory.Pattern.Offset =
|
||||
Request->FileName.Size;
|
||||
Request->Req.QueryDirectory.Pattern.Size =
|
||||
FileDesc->DirectoryPattern.Length + sizeof(WCHAR);
|
||||
RtlCopyMemory(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset,
|
||||
FileDesc->DirectoryPattern.Buffer, FileDesc->DirectoryPattern.Length);
|
||||
*(PWSTR)(Request->Buffer +
|
||||
Request->Req.QueryDirectory.Pattern.Offset +
|
||||
FileDesc->DirectoryPattern.Length) = L'\0';
|
||||
}
|
||||
|
||||
if (0 != FileDesc->DirectoryMarker.Buffer)
|
||||
{
|
||||
ASSERT(
|
||||
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR) >=
|
||||
FileDesc->DirectoryMarker.Length);
|
||||
|
||||
Request->Req.QueryDirectory.Marker.Offset =
|
||||
Request->FileName.Size + Request->Req.QueryDirectory.Pattern.Size;
|
||||
Request->Req.QueryDirectory.Marker.Size =
|
||||
FileDesc->DirectoryMarker.Length + sizeof(WCHAR);
|
||||
RtlCopyMemory(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset,
|
||||
FileDesc->DirectoryMarker.Buffer, FileDesc->DirectoryMarker.Length);
|
||||
*(PWSTR)(Request->Buffer +
|
||||
Request->Req.QueryDirectory.Marker.Offset +
|
||||
FileDesc->DirectoryMarker.Length) = L'\0';
|
||||
}
|
||||
|
||||
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
||||
|
||||
return FSP_STATUS_IOQ_POST;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolQueryDirectory(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
/* is this a valid FileObject? */
|
||||
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||
PUNICODE_STRING FileName = IrpSp->Parameters.QueryDirectory.FileName;
|
||||
|
||||
/* only directory files can be queried */
|
||||
if (!FileNode->IsDirectory)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
/* check that FileName is valid (if supplied) */
|
||||
if (0 != FileName &&
|
||||
!FspFileNameIsValidPattern(FileName, FsvolDeviceExtension->VolumeParams.MaxComponentLength))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
return FspFsvolQueryDirectoryRetry(FsvolDeviceObject, Irp, IrpSp, IoIsOperationSynchronous(Irp));
|
||||
}
|
||||
|
||||
typedef struct
|
||||
@ -819,36 +802,21 @@ NTSTATUS FspFsvolDirectoryControlPrepare(
|
||||
PAGED_CODE();
|
||||
|
||||
NTSTATUS Result;
|
||||
PMDL Mdl = 0;
|
||||
PVOID Cookie;
|
||||
PVOID Address;
|
||||
PEPROCESS Process;
|
||||
|
||||
Mdl = IoAllocateMdl(
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
Request->Req.QueryDirectory.Length,
|
||||
FALSE, FALSE, 0);
|
||||
if (0 == Mdl)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
MmBuildMdlForNonPagedPool(Mdl);
|
||||
|
||||
/* map the MDL into user-mode */
|
||||
Result = FspMapLockedPagesInUserMode(Mdl, &Address, 0);
|
||||
Result = FspProcessBufferAcquire(Request->Req.QueryDirectory.Length, &Cookie, &Address);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
if (0 != Mdl)
|
||||
IoFreeMdl(Mdl);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/* get a pointer to the current process so that we can unmap the address later */
|
||||
/* get a pointer to the current process so that we can release the buffer later */
|
||||
Process = PsGetCurrentProcess();
|
||||
ObReferenceObject(Process);
|
||||
|
||||
Request->Req.QueryDirectory.Address = (UINT64)(UINT_PTR)Address;
|
||||
|
||||
FspIopRequestContext(Request, RequestMdl) = Mdl;
|
||||
FspIopRequestContext(Request, RequestCookie) = (PVOID)((UINT_PTR)Cookie | 1);
|
||||
FspIopRequestContext(Request, RequestAddress) = Address;
|
||||
FspIopRequestContext(Request, RequestProcess) = Process;
|
||||
|
||||
@ -877,15 +845,13 @@ NTSTATUS FspFsvolDirectoryControlComplete(
|
||||
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||
BOOLEAN ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
|
||||
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
|
||||
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
PVOID Buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
|
||||
ULONG Length = IrpSp->Parameters.QueryDirectory.Length;
|
||||
ULONG DirInfoChangeNumber;
|
||||
PVOID DirInfoBuffer;
|
||||
ULONG DirInfoSize;
|
||||
BOOLEAN Success;
|
||||
|
||||
ASSERT(FileNode == FileDesc->FileNode);
|
||||
ASSERT(Request->Req.QueryDirectory.Offset == FileDesc->DirectoryOffset);
|
||||
|
||||
if (0 == Response->IoStatus.Information)
|
||||
{
|
||||
@ -894,16 +860,14 @@ NTSTATUS FspFsvolDirectoryControlComplete(
|
||||
FSP_RETURN();
|
||||
}
|
||||
|
||||
if (FspFsctlTransactQueryDirectoryKind == Request->Kind)
|
||||
if (0 != FspIopRequestContext(Request, RequestFileNode))
|
||||
{
|
||||
DirInfoChangeNumber = FspFileNodeDirInfoChangeNumber(FileNode);
|
||||
Request->Kind = FspFsctlTransactReservedKind;
|
||||
FspIopResetRequest(Request, 0);
|
||||
FspIopRequestContext(Request, RequestDirInfoChangeNumber) = (PVOID)DirInfoChangeNumber;
|
||||
FspIopRequestContext(Request, FspIopRequestExtraContext) = (PVOID)
|
||||
FspFileNodeDirInfoChangeNumber(FileNode);
|
||||
FspIopRequestContext(Request, RequestFileNode) = 0;
|
||||
|
||||
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||
}
|
||||
else
|
||||
DirInfoChangeNumber =
|
||||
(ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestDirInfoChangeNumber);
|
||||
|
||||
/* acquire FileNode exclusive Full (because we may need to go back to user-mode) */
|
||||
Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusive(FileNode, Full);
|
||||
@ -913,11 +877,12 @@ NTSTATUS FspFsvolDirectoryControlComplete(
|
||||
FSP_RETURN();
|
||||
}
|
||||
|
||||
if (0 == FileDesc->DirectoryOffset &&
|
||||
if (0 == Request->Req.QueryDirectory.Pattern.Size &&
|
||||
0 == Request->Req.QueryDirectory.Marker.Size &&
|
||||
FspFileNodeTrySetDirInfo(FileNode,
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
(PVOID)(UINT_PTR)Request->Req.QueryDirectory.Address,
|
||||
(ULONG)Response->IoStatus.Information,
|
||||
DirInfoChangeNumber) &&
|
||||
(ULONG)(UINT_PTR)FspIopRequestContext(Request, FspIopRequestExtraContext)) &&
|
||||
FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize))
|
||||
{
|
||||
Result = FspFsvolQueryDirectoryCopyCache(FileDesc,
|
||||
@ -929,7 +894,7 @@ NTSTATUS FspFsvolDirectoryControlComplete(
|
||||
}
|
||||
else
|
||||
{
|
||||
DirInfoBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
DirInfoBuffer = (PVOID)(UINT_PTR)Request->Req.QueryDirectory.Address;
|
||||
DirInfoSize = (ULONG)Response->IoStatus.Information;
|
||||
Result = FspFsvolQueryDirectoryCopyInPlace(FileDesc,
|
||||
FileInformationClass, ReturnSingleEntry,
|
||||
@ -948,14 +913,30 @@ NTSTATUS FspFsvolDirectoryControlComplete(
|
||||
|
||||
FspFileNodeConvertExclusiveToShared(FileNode, Full);
|
||||
|
||||
Request->Kind = FspFsctlTransactQueryDirectoryKind;
|
||||
FspIopResetRequest(Request, FspFsvolQueryDirectoryRequestFini);
|
||||
|
||||
Request->Req.QueryDirectory.Address = 0;
|
||||
Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset;
|
||||
Request->Req.QueryDirectory.Marker.Offset = 0;
|
||||
Request->Req.QueryDirectory.Marker.Size = 0;
|
||||
if (0 != FileDesc->DirectoryMarker.Buffer)
|
||||
{
|
||||
ASSERT(
|
||||
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR) >=
|
||||
FileDesc->DirectoryMarker.Length);
|
||||
|
||||
Request->Req.QueryDirectory.Marker.Offset =
|
||||
Request->FileName.Size + Request->Req.QueryDirectory.Pattern.Size;
|
||||
Request->Req.QueryDirectory.Marker.Size =
|
||||
FileDesc->DirectoryMarker.Length + sizeof(WCHAR);
|
||||
RtlCopyMemory(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset,
|
||||
FileDesc->DirectoryMarker.Buffer, FileDesc->DirectoryMarker.Length);
|
||||
*(PWSTR)(Request->Buffer +
|
||||
Request->Req.QueryDirectory.Marker.Offset +
|
||||
FileDesc->DirectoryMarker.Length) = L'\0';
|
||||
}
|
||||
|
||||
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||
FspIopRequestContext(Request, RequestIrp) = Irp;
|
||||
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
||||
|
||||
FspIoqPostIrp(FsvolDeviceExtension->Ioq, Irp, &Result);
|
||||
}
|
||||
@ -977,8 +958,8 @@ static VOID FspFsvolQueryDirectoryRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
PIRP Irp = Context[RequestIrp];
|
||||
PMDL Mdl = Context[RequestMdl];
|
||||
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
|
||||
PVOID Cookie = (PVOID)((UINT_PTR)Context[RequestCookie] & ~1);
|
||||
PVOID Address = Context[RequestAddress];
|
||||
PEPROCESS Process = Context[RequestProcess];
|
||||
|
||||
@ -992,23 +973,15 @@ static VOID FspFsvolQueryDirectoryRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
|
||||
|
||||
if (Attach)
|
||||
KeStackAttachProcess(Process, &ApcState);
|
||||
MmUnmapLockedPages(Address, Mdl);
|
||||
FspProcessBufferRelease(Cookie, Address);
|
||||
if (Attach)
|
||||
KeUnstackDetachProcess(&ApcState);
|
||||
|
||||
ObDereferenceObject(Process);
|
||||
}
|
||||
|
||||
if (0 != Mdl)
|
||||
IoFreeMdl(Mdl);
|
||||
|
||||
if (0 != Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
FSP_FILE_NODE *FileNode = IrpSp->FileObject->FsContext;
|
||||
|
||||
if (0 != FileNode)
|
||||
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS FspDirectoryControl(
|
||||
|
@ -46,6 +46,10 @@ NTSTATUS DriverEntry(
|
||||
|
||||
FspDriverMultiVersionInitialize();
|
||||
|
||||
Result = FspProcessBufferInitialize();
|
||||
if (!NT_SUCCESS(Result))
|
||||
FSP_RETURN();
|
||||
|
||||
FspDriverObject = DriverObject;
|
||||
ExInitializeResourceLite(&FspDeviceGlobalResource);
|
||||
|
||||
@ -59,14 +63,21 @@ NTSTATUS DriverEntry(
|
||||
&DeviceSddl, &FspFsctlDeviceClassGuid,
|
||||
&FspFsctlDiskDeviceObject);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspProcessBufferFinalize();
|
||||
FSP_RETURN();
|
||||
}
|
||||
RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
|
||||
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
|
||||
&DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
|
||||
&DeviceSddl, &FspFsctlDeviceClassGuid,
|
||||
&FspFsctlNetDeviceObject);
|
||||
if (!NT_SUCCESS(Result))
|
||||
FSP_RETURN(FspDeviceDelete(FspFsctlDiskDeviceObject));
|
||||
{
|
||||
FspDeviceDelete(FspFsctlDiskDeviceObject);
|
||||
FspProcessBufferFinalize();
|
||||
FSP_RETURN();
|
||||
}
|
||||
Result = FspDeviceInitialize(FspFsctlDiskDeviceObject);
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
Result = FspDeviceInitialize(FspFsctlNetDeviceObject);
|
||||
@ -178,6 +189,7 @@ static VOID FspDriverMultiVersionInitialize(VOID)
|
||||
{
|
||||
FspProcessorCount = KeQueryActiveProcessorCount(0);
|
||||
|
||||
#pragma prefast(suppress:30035, "FspDriverMultiVersionInitialize is called from DriverEntry")
|
||||
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
|
||||
|
||||
if (RtlIsNtDdiVersionAvailable(NTDDI_WIN7))
|
||||
@ -206,6 +218,8 @@ VOID FspUnload(
|
||||
ExDeleteResourceLite(&FspDeviceGlobalResource);
|
||||
FspDriverObject = 0;
|
||||
|
||||
FspProcessBufferFinalize();
|
||||
|
||||
#pragma prefast(suppress:28175, "We are in DriverUnload: ok to access DriverName")
|
||||
FSP_LEAVE_VOID("DriverName=\"%wZ\"",
|
||||
&DriverObject->DriverName);
|
||||
|
@ -601,6 +601,14 @@ VOID FspIrpHookReset(PIRP Irp);
|
||||
PVOID FspIrpHookContext(PVOID Context);
|
||||
NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
|
||||
|
||||
/* process buffers */
|
||||
#define FspProcessBufferSizeMax (64 * 1024)
|
||||
NTSTATUS FspProcessBufferInitialize(VOID);
|
||||
VOID FspProcessBufferFinalize(VOID);
|
||||
VOID FspProcessBufferCollect(HANDLE ProcessId);
|
||||
NTSTATUS FspProcessBufferAcquire(SIZE_T BufferSize, PVOID *PBufferCookie, PVOID *PBuffer);
|
||||
VOID FspProcessBufferRelease(PVOID BufferCookie, PVOID Buffer);
|
||||
|
||||
/* IRP context */
|
||||
#define FspIrpTimestampInfinity ((ULONG)-1L)
|
||||
#define FspIrpTimestamp(Irp) \
|
||||
@ -829,6 +837,10 @@ PIRP FspIoqNextCompleteIrp(FSP_IOQ *Ioq, PIRP BoundaryIrp);
|
||||
ULONG FspIoqRetriedIrpCount(FSP_IOQ *Ioq);
|
||||
|
||||
/* meta cache */
|
||||
enum
|
||||
{
|
||||
FspMetaCacheItemHeaderSize = MEMORY_ALLOCATION_ALIGNMENT,
|
||||
};
|
||||
typedef struct
|
||||
{
|
||||
KSPIN_LOCK SpinLock;
|
||||
@ -1064,6 +1076,7 @@ VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject);
|
||||
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
|
||||
VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
|
||||
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
|
||||
BOOLEAN FspFsvolDeviceFileRenameIsAcquiredExclusive(PDEVICE_OBJECT DeviceObject);
|
||||
VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject);
|
||||
VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject);
|
||||
NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject,
|
||||
@ -1112,6 +1125,37 @@ VOID FspDeviceGlobalUnlock(VOID)
|
||||
//(FILE_DEVICE_DISK_FILE_SYSTEM == (DeviceObject)->DeviceType ?\
|
||||
// STATUS_VOLUME_DISMOUNTED : STATUS_DEVICE_NOT_CONNECTED)
|
||||
|
||||
/* process buffers conditional usage */
|
||||
static inline
|
||||
BOOLEAN FspReadIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
|
||||
{
|
||||
ASSERT(0 != Irp);
|
||||
#if DBG
|
||||
return DEBUGTEST(50) ||
|
||||
#else
|
||||
return FspProcessBufferSizeMax >= BufferSize ||
|
||||
#endif
|
||||
FspFsvolDeviceExtension(IoGetCurrentIrpStackLocation(Irp)->DeviceObject)->
|
||||
VolumeParams.AlwaysUseDoubleBuffering;
|
||||
}
|
||||
static inline
|
||||
BOOLEAN FspWriteIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
|
||||
{
|
||||
ASSERT(0 != Irp);
|
||||
#if DBG
|
||||
return DEBUGTEST(50);
|
||||
#else
|
||||
return FspProcessBufferSizeMax >= BufferSize;
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
static inline
|
||||
BOOLEAN FspQueryDirectoryIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
|
||||
{
|
||||
return FspReadIrpShouldUseProcessBuffer(Irp, BufferSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* volume management */
|
||||
#define FspVolumeTransactEarlyTimeout (1 * 10000ULL)
|
||||
NTSTATUS FspVolumeCreate(
|
||||
@ -1231,7 +1275,7 @@ typedef struct
|
||||
DidSetCreationTime:1, DidSetLastAccessTime:1, DidSetLastWriteTime:1, DidSetChangeTime:1,
|
||||
DirectoryHasSuchFile:1;
|
||||
UNICODE_STRING DirectoryPattern;
|
||||
UINT64 DirectoryOffset;
|
||||
UNICODE_STRING DirectoryMarker;
|
||||
UINT64 DirInfo;
|
||||
ULONG DirInfoCacheHint;
|
||||
/* stream support */
|
||||
@ -1312,6 +1356,8 @@ VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileIn
|
||||
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
||||
BOOLEAN FspFileNodeTrySetFileInfoOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
||||
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
|
||||
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
|
||||
@ -1362,8 +1408,10 @@ VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action
|
||||
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
|
||||
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
|
||||
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
|
||||
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
|
||||
PUNICODE_STRING FileName, BOOLEAN Reset);
|
||||
NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
|
||||
PUNICODE_STRING FileName, BOOLEAN RestartScan, BOOLEAN IndexSpecified);
|
||||
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
|
||||
PUNICODE_STRING FileName);
|
||||
NTSTATUS FspMainFileOpen(
|
||||
PDEVICE_OBJECT FsvolDeviceObject,
|
||||
PDEVICE_OBJECT DeviceObjectHint,
|
||||
|
161
src/sys/file.c
@ -58,6 +58,8 @@ VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileIn
|
||||
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
||||
BOOLEAN FspFileNodeTrySetFileInfoOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
||||
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
|
||||
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
|
||||
@ -84,8 +86,10 @@ NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
|
||||
static NTSTATUS FspFileNodeCompleteLockIrp(PVOID Context, PIRP Irp);
|
||||
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
|
||||
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
|
||||
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
|
||||
PUNICODE_STRING FileName, BOOLEAN Reset);
|
||||
NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
|
||||
PUNICODE_STRING FileName, BOOLEAN RestartScan, BOOLEAN IndexSpecified);
|
||||
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
|
||||
PUNICODE_STRING FileName);
|
||||
NTSTATUS FspMainFileOpen(
|
||||
PDEVICE_OBJECT FsvolDeviceObject,
|
||||
PDEVICE_OBJECT DeviceObjectHint,
|
||||
@ -127,6 +131,7 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
|
||||
#pragma alloc_text(PAGE, FspFileNodeGetFileInfo)
|
||||
#pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo)
|
||||
#pragma alloc_text(PAGE, FspFileNodeSetFileInfo)
|
||||
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfoOnOpen)
|
||||
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfo)
|
||||
#pragma alloc_text(PAGE, FspFileNodeInvalidateFileInfo)
|
||||
#pragma alloc_text(PAGE, FspFileNodeReferenceSecurity)
|
||||
@ -147,7 +152,8 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
|
||||
#pragma alloc_text(PAGE, FspFileNodeCompleteLockIrp)
|
||||
#pragma alloc_text(PAGE, FspFileDescCreate)
|
||||
#pragma alloc_text(PAGE, FspFileDescDelete)
|
||||
#pragma alloc_text(PAGE, FspFileDescResetDirectoryPattern)
|
||||
#pragma alloc_text(PAGE, FspFileDescResetDirectory)
|
||||
#pragma alloc_text(PAGE, FspFileDescSetDirectoryMarker)
|
||||
#pragma alloc_text(PAGE, FspMainFileOpen)
|
||||
#pragma alloc_text(PAGE, FspMainFileClose)
|
||||
#pragma alloc_text(PAGE, FspFileNodeOplockPrepare)
|
||||
@ -1240,6 +1246,50 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp
|
||||
}
|
||||
}
|
||||
|
||||
/* flush and purge cleaned up but still open files affected by rename (github issue #45) */
|
||||
{
|
||||
PIRP TopLevelIrp;
|
||||
IO_STATUS_BLOCK IoStatus;
|
||||
|
||||
/* reset the top-level IRP to avoid deadlock on the FileNodes' resources */
|
||||
TopLevelIrp = IoGetTopLevelIrp();
|
||||
IoSetTopLevelIrp(0);
|
||||
|
||||
/* enumerate in reverse order so that files are flushed before containing directories */
|
||||
for (
|
||||
DescendantFileNodeIndex = DescendantFileNodeCount - 1;
|
||||
DescendantFileNodeCount > DescendantFileNodeIndex;
|
||||
DescendantFileNodeIndex--)
|
||||
{
|
||||
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
||||
HasHandles = (UINT_PTR)DescendantFileNode & 1;
|
||||
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
|
||||
|
||||
if (HasHandles)
|
||||
continue;
|
||||
if (CheckingOldName &&
|
||||
(DescendantFileNode->FileName.Length <= FileName->Length ||
|
||||
L'\\' != DescendantFileNode->FileName.Buffer[FileName->Length / sizeof(WCHAR)]))
|
||||
continue;
|
||||
if (MmDoesFileHaveUserWritableReferences(&DescendantFileNode->NonPaged->SectionObjectPointers))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* There are no handles and no writable user mappings. [Ideally we would want to know
|
||||
* that there are no handles and no user mappings, period. Is there an DDI/method to
|
||||
* do that?] There may be a read-only user mapping, but in this case CcFlushCache
|
||||
* should be a no-op and MmForceSectionClosed will fail (which is fine).
|
||||
*/
|
||||
|
||||
ASSERT(DescendantFileNode != FileNode && DescendantFileNode->MainFileNode != FileNode);
|
||||
|
||||
FspCcFlushCache(&DescendantFileNode->NonPaged->SectionObjectPointers, 0, 0, &IoStatus);
|
||||
MmForceSectionClosed(&DescendantFileNode->NonPaged->SectionObjectPointers, FALSE);
|
||||
}
|
||||
|
||||
IoSetTopLevelIrp(TopLevelIrp);
|
||||
}
|
||||
|
||||
/* break any Batch or Handle oplocks on descendants */
|
||||
Result = STATUS_SUCCESS;
|
||||
for (
|
||||
@ -1613,6 +1663,43 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN FspFileNodeTrySetFileInfoOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
BOOLEAN EarlyExit;
|
||||
|
||||
FspFsvolDeviceLockContextTable(FileNode->FsvolDeviceObject);
|
||||
EarlyExit = 1 < FileNode->OpenCount;
|
||||
FspFsvolDeviceUnlockContextTable(FileNode->FsvolDeviceObject);
|
||||
|
||||
if (EarlyExit)
|
||||
{
|
||||
if (TruncateOnClose)
|
||||
{
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
||||
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
||||
UINT64 AllocationSize = FileInfo->AllocationSize > FileInfo->FileSize ?
|
||||
FileInfo->AllocationSize : FileInfo->FileSize;
|
||||
UINT64 AllocationUnit;
|
||||
|
||||
AllocationUnit = FsvolDeviceExtension->VolumeParams.SectorSize *
|
||||
FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit;
|
||||
AllocationSize = (AllocationSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
||||
|
||||
if ((UINT64)FileNode->Header.AllocationSize.QuadPart != AllocationSize ||
|
||||
(UINT64)FileNode->Header.FileSize.QuadPart != FileInfo->FileSize)
|
||||
FileNode->TruncateOnClose = TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FspFileNodeSetFileInfo(FileNode, CcFileObject, FileInfo, TruncateOnClose);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber)
|
||||
{
|
||||
@ -1984,15 +2071,19 @@ VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc)
|
||||
RtlFreeUnicodeString(&FileDesc->DirectoryPattern);
|
||||
}
|
||||
|
||||
if (0 != FileDesc->DirectoryMarker.Buffer)
|
||||
FspFree(FileDesc->DirectoryMarker.Buffer);
|
||||
|
||||
FspFree(FileDesc);
|
||||
}
|
||||
|
||||
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
|
||||
PUNICODE_STRING FileName, BOOLEAN Reset)
|
||||
NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
|
||||
PUNICODE_STRING FileName, BOOLEAN RestartScan, BOOLEAN IndexSpecified)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (Reset || 0 == FileDesc->DirectoryPattern.Buffer)
|
||||
if (0 == FileDesc->DirectoryPattern.Buffer ||
|
||||
(RestartScan && 0 != FileName && 0 != FileName->Length))
|
||||
{
|
||||
UNICODE_STRING DirectoryPattern;
|
||||
|
||||
@ -2029,7 +2120,65 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
|
||||
}
|
||||
|
||||
FileDesc->DirectoryPattern = DirectoryPattern;
|
||||
FileDesc->DirectoryHasSuchFile = FALSE;
|
||||
|
||||
if (0 != FileDesc->DirectoryMarker.Buffer)
|
||||
{
|
||||
FspFree(FileDesc->DirectoryMarker.Buffer);
|
||||
FileDesc->DirectoryMarker.Buffer = 0;
|
||||
}
|
||||
}
|
||||
else if (RestartScan)
|
||||
{
|
||||
ASSERT(0 == FileName || 0 == FileName->Length);
|
||||
|
||||
FileDesc->DirectoryHasSuchFile = FALSE;
|
||||
|
||||
if (0 != FileDesc->DirectoryMarker.Buffer)
|
||||
{
|
||||
FspFree(FileDesc->DirectoryMarker.Buffer);
|
||||
FileDesc->DirectoryMarker.Buffer = 0;
|
||||
}
|
||||
}
|
||||
else if (IndexSpecified && 0 != FileName && 0 != FileName->Length)
|
||||
{
|
||||
NTSTATUS Result;
|
||||
|
||||
Result = FspFileDescSetDirectoryMarker(FileDesc, FileName);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
FileDesc->DirectoryHasSuchFile = FALSE;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
|
||||
PUNICODE_STRING FileName)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (&FileDesc->DirectoryMarker == FileName)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
||||
FspFsvolDeviceExtension(FileDesc->FileNode->FsvolDeviceObject);
|
||||
UNICODE_STRING DirectoryMarker;
|
||||
|
||||
if (FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR) < FileName->Length)
|
||||
return STATUS_OBJECT_NAME_INVALID;
|
||||
|
||||
DirectoryMarker.Length = DirectoryMarker.MaximumLength = FileName->Length;
|
||||
DirectoryMarker.Buffer = FspAlloc(FileName->Length);
|
||||
if (0 == DirectoryMarker.Buffer)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
RtlCopyMemory(DirectoryMarker.Buffer, FileName->Buffer, FileName->Length);
|
||||
|
||||
if (0 != FileDesc->DirectoryMarker.Buffer)
|
||||
FspFree(FileDesc->DirectoryMarker.Buffer);
|
||||
|
||||
FileDesc->DirectoryMarker = DirectoryMarker;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -1573,6 +1573,7 @@ NTSTATUS FspFsvolSetInformationPrepare(
|
||||
SECURITY_CLIENT_CONTEXT SecurityClientContext;
|
||||
HANDLE UserModeAccessToken;
|
||||
PEPROCESS Process;
|
||||
ULONG OriginatingProcessId;
|
||||
|
||||
SecuritySubjectContext = FspIopRequestContext(Request, RequestSubjectContextOrAccessToken);
|
||||
|
||||
@ -1605,10 +1606,16 @@ NTSTATUS FspFsvolSetInformationPrepare(
|
||||
Process = PsGetCurrentProcess();
|
||||
ObReferenceObject(Process);
|
||||
|
||||
/* get the originating process ID stored in the IRP */
|
||||
OriginatingProcessId = IoGetRequestorProcessId(Irp);
|
||||
|
||||
/* send the user-mode handle to the user-mode file system */
|
||||
FspIopRequestContext(Request, RequestSubjectContextOrAccessToken) = UserModeAccessToken;
|
||||
FspIopRequestContext(Request, RequestProcess) = Process;
|
||||
Request->Req.SetInformation.Info.Rename.AccessToken = (UINT_PTR)UserModeAccessToken;
|
||||
ASSERT((UINT64)(UINT_PTR)UserModeAccessToken <= 0xffffffffULL);
|
||||
ASSERT((UINT64)(UINT_PTR)OriginatingProcessId <= 0xffffffffULL);
|
||||
Request->Req.SetInformation.Info.Rename.AccessToken =
|
||||
((UINT64)(UINT_PTR)OriginatingProcessId << 32) | (UINT64)(UINT_PTR)UserModeAccessToken;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -306,47 +306,6 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceDereference)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
/*
|
||||
* HACK:
|
||||
*
|
||||
* Turns out that SRV2 sends an undocumented flavor of IRP_MJ_DIRECTORY_CONTROL /
|
||||
* IRP_MN_QUERY_DIRECTORY. These IRP's have a non-NULL Irp->MdlAddress. They expect
|
||||
* the FSD to fill the buffer pointed by Irp->MdlAddress and they cannot handle
|
||||
* completed IRP's with a non-NULL Irp->AssociatedIrp.SystemBuffer. So we have to
|
||||
* provide special support for these IRPs.
|
||||
*
|
||||
* While this processing is IRP_MJ_DIRECTORY_CONTROL specific, we do this here for
|
||||
* these reasons:
|
||||
*
|
||||
* 1. There may be other IRP's that have similar completion requirements under SRV2.
|
||||
* If/when such IRP's are discovered the completion processing can be centralized
|
||||
* here.
|
||||
* 2. IRP_MJ_DIRECTORY_CONTROL has a few different ways that it can complete IRP's.
|
||||
* It is far simpler to do this processing here, even if not academically correct.
|
||||
*
|
||||
* This will have to be revisited if IRP_MJ_DIRECTORY_CONTROL processing changes
|
||||
* substantially (e.g. to no longer use Irp->AssociatedIrp.SystemBuffer).
|
||||
*/
|
||||
if (IRP_MJ_DIRECTORY_CONTROL == IrpSp->MajorFunction &&
|
||||
IRP_MN_QUERY_DIRECTORY == IrpSp->MinorFunction &&
|
||||
0 != Irp->MdlAddress && /* SRV2 queries have this set */
|
||||
0 != Irp->AssociatedIrp.SystemBuffer &&
|
||||
FlagOn(Irp->Flags, IRP_BUFFERED_IO))
|
||||
{
|
||||
if (STATUS_SUCCESS == Result)
|
||||
{
|
||||
PVOID Address = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
|
||||
if (0 != Address)
|
||||
RtlCopyMemory(Address, Irp->AssociatedIrp.SystemBuffer, Irp->IoStatus.Information);
|
||||
else
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
FspFreeExternal(Irp->AssociatedIrp.SystemBuffer);
|
||||
Irp->AssociatedIrp.SystemBuffer = 0;
|
||||
ClearFlag(Irp->Flags, IRP_INPUT_OPERATION | IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
|
||||
}
|
||||
|
||||
if (STATUS_SUCCESS != Result &&
|
||||
STATUS_REPARSE != Result &&
|
||||
|
@ -33,6 +33,8 @@ typedef struct
|
||||
ULONG Size;
|
||||
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 Buffer[];
|
||||
} FSP_META_CACHE_ITEM_BUFFER;
|
||||
FSP_FSCTL_STATIC_ASSERT(FIELD_OFFSET(FSP_META_CACHE_ITEM_BUFFER, Buffer) == FspMetaCacheItemHeaderSize,
|
||||
"FspMetaCacheItemHeaderSize must match offset of FSP_META_CACHE_ITEM_BUFFER::Buffer");
|
||||
|
||||
static inline VOID FspMetaCacheDereferenceItem(FSP_META_CACHE_ITEM *Item)
|
||||
{
|
||||
@ -218,7 +220,16 @@ UINT64 FspMetaCacheAddItem(FSP_META_CACHE *MetaCache, PCVOID Buffer, ULONG Size)
|
||||
Item->RefCount = 1;
|
||||
ItemBuffer->Item = Item;
|
||||
ItemBuffer->Size = Size;
|
||||
RtlCopyMemory(ItemBuffer->Buffer, Buffer, Size);
|
||||
try
|
||||
{
|
||||
RtlCopyMemory(ItemBuffer->Buffer, Buffer, Size);
|
||||
}
|
||||
except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
FspFree(ItemBuffer);
|
||||
FspFree(Item);
|
||||
return 0;
|
||||
}
|
||||
KeAcquireSpinLock(&MetaCache->SpinLock, &Irql);
|
||||
if (MetaCache->ItemCount >= MetaCache->MetaCapacity)
|
||||
FspMetaCacheRemoveExpiredItemAtDpcLevel(MetaCache, (UINT64)-1LL);
|
||||
|
277
src/sys/psbuffer.c
Normal file
@ -0,0 +1,277 @@
|
||||
/**
|
||||
* @file sys/psbuffer.c
|
||||
*
|
||||
* @copyright 2015-2017 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this file in
|
||||
* accordance with the commercial license agreement provided with the
|
||||
* software.
|
||||
*/
|
||||
|
||||
#include <sys/driver.h>
|
||||
|
||||
#define SafeGetCurrentProcessId() (PsGetProcessId(PsGetCurrentProcess()))
|
||||
|
||||
#define FspProcessBufferCountMax (2 >= FspProcessorCount ? 2 : (8 <= FspProcessorCount ? 8 : FspProcessorCount))
|
||||
#define ProcessBufferBucketCount 61 /* are you going to have that many file systems? */
|
||||
|
||||
typedef struct _FSP_PROCESS_BUFFER_ITEM
|
||||
{
|
||||
struct _FSP_PROCESS_BUFFER_ITEM *DictNext;
|
||||
struct _FSP_PROCESS_BUFFER_LIST_ENTRY *BufferList;
|
||||
ULONG BufferCount;
|
||||
HANDLE ProcessId;
|
||||
} FSP_PROCESS_BUFFER_ITEM;
|
||||
|
||||
typedef struct _FSP_PROCESS_BUFFER_LIST_ENTRY
|
||||
{
|
||||
struct _FSP_PROCESS_BUFFER_LIST_ENTRY *Next;
|
||||
PVOID Buffer;
|
||||
} FSP_PROCESS_BUFFER_LIST_ENTRY;
|
||||
|
||||
static KSPIN_LOCK ProcessBufferLock;
|
||||
static FSP_PROCESS_BUFFER_ITEM *ProcessBufferBuckets[ProcessBufferBucketCount];
|
||||
|
||||
static VOID FspProcessBufferNotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create);
|
||||
|
||||
static inline FSP_PROCESS_BUFFER_ITEM *FspProcessBufferLookupItemAtDpcLevel(HANDLE ProcessId)
|
||||
{
|
||||
FSP_PROCESS_BUFFER_ITEM *Item = 0;
|
||||
ULONG HashIndex = FspHashMixPointer(ProcessId) % ProcessBufferBucketCount;
|
||||
for (FSP_PROCESS_BUFFER_ITEM *ItemX = ProcessBufferBuckets[HashIndex]; ItemX; ItemX = ItemX->DictNext)
|
||||
if (ItemX->ProcessId == ProcessId)
|
||||
{
|
||||
Item = ItemX;
|
||||
break;
|
||||
}
|
||||
return Item;
|
||||
}
|
||||
|
||||
static inline VOID FspProcessBufferAddItemAtDpcLevel(FSP_PROCESS_BUFFER_ITEM *Item)
|
||||
{
|
||||
ULONG HashIndex = FspHashMixPointer(Item->ProcessId) % ProcessBufferBucketCount;
|
||||
#if DBG
|
||||
for (FSP_PROCESS_BUFFER_ITEM *ItemX = ProcessBufferBuckets[HashIndex]; ItemX; ItemX = ItemX->DictNext)
|
||||
ASSERT(ItemX->ProcessId != Item->ProcessId);
|
||||
#endif
|
||||
Item->DictNext = ProcessBufferBuckets[HashIndex];
|
||||
ProcessBufferBuckets[HashIndex] = Item;
|
||||
}
|
||||
|
||||
static inline FSP_PROCESS_BUFFER_ITEM *FspProcessBufferRemoveItemAtDpcLevel(HANDLE ProcessId)
|
||||
{
|
||||
FSP_PROCESS_BUFFER_ITEM *Item = 0;
|
||||
ULONG HashIndex = FspHashMixPointer(ProcessId) % ProcessBufferBucketCount;
|
||||
for (FSP_PROCESS_BUFFER_ITEM **P = &ProcessBufferBuckets[HashIndex]; *P; P = &(*P)->DictNext)
|
||||
if ((*P)->ProcessId == ProcessId)
|
||||
{
|
||||
Item = *P;
|
||||
*P = (*P)->DictNext;
|
||||
break;
|
||||
}
|
||||
return Item;
|
||||
}
|
||||
|
||||
static inline VOID FspProcessBufferReuseEntry(HANDLE ProcessId,
|
||||
FSP_PROCESS_BUFFER_LIST_ENTRY *BufferEntry)
|
||||
{
|
||||
KIRQL Irql;
|
||||
FSP_PROCESS_BUFFER_ITEM *Item;
|
||||
|
||||
KeAcquireSpinLock(&ProcessBufferLock, &Irql);
|
||||
|
||||
Item = FspProcessBufferLookupItemAtDpcLevel(ProcessId);
|
||||
|
||||
if (0 != Item)
|
||||
{
|
||||
BufferEntry->Next = Item->BufferList;
|
||||
Item->BufferList = BufferEntry;
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&ProcessBufferLock, Irql);
|
||||
|
||||
if (0 == Item)
|
||||
{
|
||||
if (0 != BufferEntry->Buffer)
|
||||
{
|
||||
SIZE_T BufferSize = 0;
|
||||
ZwFreeVirtualMemory(ZwCurrentProcess(), &BufferEntry->Buffer, &BufferSize, MEM_RELEASE);
|
||||
}
|
||||
|
||||
FspFree(BufferEntry);
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS FspProcessBufferInitialize(VOID)
|
||||
{
|
||||
KeInitializeSpinLock(&ProcessBufferLock);
|
||||
|
||||
return PsSetCreateProcessNotifyRoutine(FspProcessBufferNotifyRoutine, FALSE);
|
||||
}
|
||||
|
||||
VOID FspProcessBufferFinalize(VOID)
|
||||
{
|
||||
PsSetCreateProcessNotifyRoutine(FspProcessBufferNotifyRoutine, TRUE);
|
||||
}
|
||||
|
||||
static VOID FspProcessBufferNotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)
|
||||
{
|
||||
if (!Create)
|
||||
FspProcessBufferCollect(ProcessId);
|
||||
}
|
||||
|
||||
VOID FspProcessBufferCollect(HANDLE ProcessId)
|
||||
{
|
||||
KIRQL Irql;
|
||||
FSP_PROCESS_BUFFER_ITEM *Item = 0;
|
||||
|
||||
KeAcquireSpinLock(&ProcessBufferLock, &Irql);
|
||||
|
||||
Item = FspProcessBufferRemoveItemAtDpcLevel(ProcessId);
|
||||
|
||||
KeReleaseSpinLock(&ProcessBufferLock, Irql);
|
||||
|
||||
if (0 != Item)
|
||||
{
|
||||
DEBUGLOG("pid=%ld", (ULONG)(UINT_PTR)ProcessId);
|
||||
|
||||
for (FSP_PROCESS_BUFFER_LIST_ENTRY *P = Item->BufferList, *Next; P; P = Next)
|
||||
{
|
||||
Next = P->Next;
|
||||
FspFree(P);
|
||||
}
|
||||
|
||||
FspFree(Item);
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS FspProcessBufferAcquire(SIZE_T BufferSize, PVOID *PBufferCookie, PVOID *PBuffer)
|
||||
{
|
||||
if (FspProcessBufferSizeMax >= BufferSize)
|
||||
{
|
||||
HANDLE ProcessId = SafeGetCurrentProcessId();
|
||||
KIRQL Irql;
|
||||
FSP_PROCESS_BUFFER_ITEM *Item, *NewItem;
|
||||
FSP_PROCESS_BUFFER_LIST_ENTRY *BufferEntry = 0;
|
||||
BOOLEAN AllocNoReuse;
|
||||
NTSTATUS Result;
|
||||
|
||||
KeAcquireSpinLock(&ProcessBufferLock, &Irql);
|
||||
|
||||
Item = FspProcessBufferLookupItemAtDpcLevel(ProcessId);
|
||||
|
||||
if (0 != Item)
|
||||
{
|
||||
BufferEntry = Item->BufferList;
|
||||
if (0 != BufferEntry)
|
||||
Item->BufferList = BufferEntry->Next;
|
||||
}
|
||||
|
||||
AllocNoReuse = 0 == BufferEntry &&
|
||||
(0 != Item && FspProcessBufferCountMax <= Item->BufferCount);
|
||||
|
||||
KeReleaseSpinLock(&ProcessBufferLock, Irql);
|
||||
|
||||
if (AllocNoReuse)
|
||||
goto alloc_no_reuse;
|
||||
|
||||
if (0 == BufferEntry)
|
||||
{
|
||||
*PBufferCookie = 0;
|
||||
*PBuffer = 0;
|
||||
|
||||
BufferEntry = FspAllocNonPaged(sizeof *BufferEntry);
|
||||
if (0 == BufferEntry)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
RtlZeroMemory(BufferEntry, sizeof *BufferEntry);
|
||||
|
||||
NewItem = FspAllocNonPaged(sizeof *NewItem);
|
||||
if (0 == NewItem)
|
||||
{
|
||||
FspFree(BufferEntry);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
RtlZeroMemory(NewItem, sizeof *NewItem);
|
||||
|
||||
KeAcquireSpinLock(&ProcessBufferLock, &Irql);
|
||||
|
||||
Item = FspProcessBufferLookupItemAtDpcLevel(ProcessId);
|
||||
|
||||
if (0 == Item)
|
||||
{
|
||||
Item = NewItem;
|
||||
NewItem = 0;
|
||||
Item->BufferCount = 1;
|
||||
Item->ProcessId = ProcessId;
|
||||
FspProcessBufferAddItemAtDpcLevel(Item);
|
||||
}
|
||||
else if (FspProcessBufferCountMax > Item->BufferCount)
|
||||
Item->BufferCount++;
|
||||
else
|
||||
AllocNoReuse = TRUE;
|
||||
|
||||
KeReleaseSpinLock(&ProcessBufferLock, Irql);
|
||||
|
||||
if (0 != NewItem)
|
||||
FspFree(NewItem);
|
||||
|
||||
if (AllocNoReuse)
|
||||
{
|
||||
FspFree(BufferEntry);
|
||||
goto alloc_no_reuse;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == BufferEntry->Buffer)
|
||||
{
|
||||
BufferSize = FspProcessBufferSizeMax;
|
||||
Result = ZwAllocateVirtualMemory(ZwCurrentProcess(),
|
||||
&BufferEntry->Buffer, 0, &BufferSize, MEM_COMMIT, PAGE_READWRITE);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
/* failed to allocate actual buffer; reuse BufferEntry */
|
||||
FspProcessBufferReuseEntry(ProcessId, BufferEntry);
|
||||
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
|
||||
*PBufferCookie = BufferEntry;
|
||||
*PBuffer = BufferEntry->Buffer;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
alloc_no_reuse:
|
||||
*PBufferCookie = 0;
|
||||
*PBuffer = 0;
|
||||
return ZwAllocateVirtualMemory(ZwCurrentProcess(),
|
||||
PBuffer, 0, &BufferSize, MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
}
|
||||
|
||||
VOID FspProcessBufferRelease(PVOID BufferCookie, PVOID Buffer)
|
||||
{
|
||||
if (0 != BufferCookie)
|
||||
{
|
||||
HANDLE ProcessId = SafeGetCurrentProcessId();
|
||||
FSP_PROCESS_BUFFER_LIST_ENTRY *BufferEntry = BufferCookie;
|
||||
|
||||
ASSERT(Buffer == BufferEntry->Buffer);
|
||||
|
||||
FspProcessBufferReuseEntry(ProcessId, BufferEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
SIZE_T BufferSize = 0;
|
||||
ZwFreeVirtualMemory(ZwCurrentProcess(), &Buffer, &BufferSize, MEM_RELEASE);
|
||||
}
|
||||
}
|