mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-03 09:22:57 -05:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
e33fda4d00 | |||
2151e193dc | |||
ccfaf04f76 | |||
7e8d9fb986 | |||
37b6936ad0 | |||
3683afe203 | |||
a3cfc84007 | |||
ee5c584614 | |||
b8b15e8035 | |||
3db09be764 | |||
f2a0eb544e | |||
8c1c407b34 | |||
8dc4225ea1 | |||
ed0b83c84d | |||
71c68d1e17 | |||
053a5f1e4b | |||
e5d7f4ee9a | |||
d6fb076cad | |||
698b711df4 | |||
842f649f06 | |||
b062df9c42 | |||
f0385e3c7d | |||
10ce221fcc | |||
3f3092bdae |
21
README.md
21
README.md
@ -20,14 +20,19 @@ WinFsp consists of a kernel mode FSD (File System Driver) and a user mode DLL (D
|
|||||||
|
|
||||||
The project source code is organized as follows:
|
The project source code is organized as follows:
|
||||||
|
|
||||||
* build/VStudio: contains the WinFsp solution and project files.
|
* build/VStudio: WinFsp solution and project files.
|
||||||
* doc: contains the WinFsp license, contributor agreement and additional documentation. The WinFsp design document can be found here.
|
* doc: WinFsp license, contributor agreement and additional documentation. The WinFsp design documents can be found here.
|
||||||
* ext/tlib: contains a small test library originally from the secfs (Secure Cloud File System) project.
|
* ext/tlib: A small test library originally from the secfs (Secure Cloud File System) project.
|
||||||
* inc/winfsp: contains public include files to be used when developing a user mode file system.
|
* ext/test: Submodule pointing to the secfs.test project, which contains a number of tools for testing Windows and POSIX file systems.
|
||||||
* src/dll: contains the source code to the WinFsp DLL.
|
* inc/winfsp: Public headers for the WinFsp API.
|
||||||
* src/sys: contains the source code to the WinFsp FSD.
|
* inc/fuse: Public headers for the FUSE compatibility layer.
|
||||||
* tst/memfs: contains the source code to an example file system written in C++ (memfs).
|
* src/dll: Source code to the WinFsp DLL.
|
||||||
* tst/winfsp-tests: contains the WinFsp test suite.
|
* src/dll/fuse: Source code to the FUSE compatibility layer.
|
||||||
|
* src/launcher: Source code to the launcher service and the launchctl utility.
|
||||||
|
* src/sys: Source code to the WinFsp FSD.
|
||||||
|
* opt/cygfuse: Source code for the Cygwin FUSE package.
|
||||||
|
* tst/memfs: Source code to an example file system written in C++ (memfs).
|
||||||
|
* tst/winfsp-tests: WinFsp test suite.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<MyCopyright>2015-2016 Bill Zissimopoulos</MyCopyright>
|
<MyCopyright>2015-2016 Bill Zissimopoulos</MyCopyright>
|
||||||
<!-- build number: concat 2-digit year with 3-digit day of the year (16-bits until 2066) -->
|
<!-- build number: concat 2-digit year with 3-digit day of the year (16-bits until 2066) -->
|
||||||
<MyBuildNumber>$([System.DateTime]::Now.ToString(`yy`))$([System.DateTime]::Now.DayOfYear.ToString(`000`))</MyBuildNumber>
|
<MyBuildNumber>$([System.DateTime]::Now.ToString(`yy`))$([System.DateTime]::Now.DayOfYear.ToString(`000`))</MyBuildNumber>
|
||||||
<MyVersion>0.12.$(MyBuildNumber)</MyVersion>
|
<MyVersion>0.13.$(MyBuildNumber)</MyVersion>
|
||||||
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
16
doc/Changelog.adoc
Normal file
16
doc/Changelog.adoc
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
= Changelog
|
||||||
|
|
||||||
|
|
||||||
|
v0.13::
|
||||||
|
|
||||||
|
This release includes a Cygwin package, an API change and some other minor changes:
|
||||||
|
|
||||||
|
- New Cygwin package includes `cygfuse-2.8.dll` and `libfuse-2.8.dll.a` for easy use in the Cygwin environment. This is currently offered as a separate download.
|
||||||
|
- Minor but breaking API change: `SetFileSize`/`SetAllocationSize` have been consolidated. Please refer to the documentation for a description of the changes.
|
||||||
|
- File system drive symbolic links (`DefineDosDeviceW`) now automatically cleaned up even if user mode file system crashes or is terminated forcefully.
|
||||||
|
- WinFsp-FUSE now maps unmapped UID's to the Anonymous SID (S-1-5-7). See: https://cygwin.com/ml/cygwin/2016-06/msg00359.html
|
||||||
|
|
||||||
|
|
||||||
|
v0.12::
|
||||||
|
|
||||||
|
Prior changes are not recorded in this Changelog.
|
@ -136,3 +136,82 @@ The mappings provided are not perfect, but they come pretty close. They are also
|
|||||||
=== WinFsp Implementation
|
=== WinFsp Implementation
|
||||||
|
|
||||||
A WinFsp implementation of the above mappings can be found in the file `src/dll/posix.c`.
|
A WinFsp implementation of the above mappings can be found in the file `src/dll/posix.c`.
|
||||||
|
|
||||||
|
== Step 4: Implementing FUSE Core
|
||||||
|
|
||||||
|
We are now finally ready to implement the `fuse_operations`. This actually proves to be a straightforward mapping of the WinFSP `FSP_FILE_SYSTEM_INTERACE` to `fuse_operations`:
|
||||||
|
|
||||||
|
GetVolumeInfo:: Mapped to `statfs`. Volume labels are not supported by FUSE (see below).
|
||||||
|
|
||||||
|
SetVolumeLabel:: No equivalent on FUSE, so simply return `STATUS_INVALID_PARAMETER`. One thought is to map this call into a `setxattr("sys.VolumeLabel")` (or similar) call on the root directory (`/`).
|
||||||
|
|
||||||
|
GetSecurityByName:: Mapped to `fgetattr`/`getattr`. The returned `stat` information is translated into a Windows security descriptor using `FspPosixMapPermissionsToSecurityDescriptor`.
|
||||||
|
|
||||||
|
Create:: This is used to create a new file or directory. If a file is created this is mapped to `create` or `mknod`;`open`. If a directory is created this is mapped to `mkdir`;`opendir` calls (the reason is that on Windows a directory remains open after being created). In some circumstances a `chown` may be issued as well. After the file or directory has been created a `fgetattr`/`getattr` is issued to get `stat` information to return to the FSD.
|
||||||
|
|
||||||
|
Open:: This is used to open a new file or directory. First a `fgetattr`/`getattr` is issued. If the file is not a directory it is followed by `open`. If the file is a directory it is followed by `opendir`.
|
||||||
|
|
||||||
|
Overwrite:: This is used to overwrite a file when one of the `FILE_OVERWRITE`, `FILE_SUPERSEDE` or `FILE_OVERWRITE_IF` flags has been set. Mapped to `ftruncate`/`truncate`.
|
||||||
|
|
||||||
|
Cleanup:: Mapped to `unlink` when deleting a file and `rmdir` when deleting a directory.
|
||||||
|
|
||||||
|
Close:: Mapped to `flush`;`release` when closing a file and `releasedir` when closing a directory.
|
||||||
|
|
||||||
|
Read:: Mapped to `read`.
|
||||||
|
|
||||||
|
Write:: Mapped to `fgetattr`/`getattr` and `write`.
|
||||||
|
|
||||||
|
Flush:: Mapped to `fsync` or `fsyncdir`.
|
||||||
|
|
||||||
|
GetFileInfo:: Mapped to `fgetattr`/`getattr`.
|
||||||
|
|
||||||
|
SetBasicInfo:: Mapped to `utimens`/`utime`.
|
||||||
|
|
||||||
|
SetAllocationSize:: Mapped to `fgetattr`/`getattr` followed by `ftruncate`/`truncate`. Note that this call and `SetFileSize` may be consolidated soon in the WinFsp API.
|
||||||
|
|
||||||
|
SetFileSize:: Mapped to `fgetattr`/`getattr` followed by `ftruncate`/`truncate`. Note that this call and `SetAllocationSize` may be consolidated soon in the WinFsp API.
|
||||||
|
|
||||||
|
CanDelete:: For directories only: mapped to a `getdir`/`readdir` call to determine if they are empty and can therefore be deleted.
|
||||||
|
|
||||||
|
Rename:: Mapped to `fgetattr`/`getattr` on the destination file name and `rename`.
|
||||||
|
|
||||||
|
GetSecurity:: Mapped to `fgetattr`/`getattr`. The returned `stat` information is translated into a Windows security descriptor using `FspPosixMapPermissionsToSecurityDescriptor`.
|
||||||
|
|
||||||
|
SetSecurity:: Mapped to `fgetattr`/`getattr` followed by `chmod` and/or `chown`.
|
||||||
|
|
||||||
|
ReadDirectory:: Mapped to `getdir`/`readdir`. Note that because of how the Windows directory enumeration API's work there is a further `fgetattr`/`getattr` per file returned!
|
||||||
|
|
||||||
|
=== Some Additional Challenges
|
||||||
|
|
||||||
|
Let us now discuss a couple of final challenges in getting a proper FUSE port working under Cygwin: the implementation of `fuse_set_signal_handlers`/`fuse_remove_signal_handlers` and `fuse_daemonize`.
|
||||||
|
|
||||||
|
Let us start with `fuse_set_signal_handlers`/`fuse_remove_signal_handlers`. Cygwin supports POSIX signals and we can simply set up signal handlers similar to what libfuse does. However this simple approach does not work within WinFsp, because it uses native API's that Cygwin cannot interrupt with its signal mechanism. For example, the `fuse_loop` FUSE call eventually results in a `WaitForSingleObject` API call that Cygwin cannot interrupt. Even trying with an alertable `WaitForSingleObjectEx` did not work as unfortunately Cygwin does not issue a `QueueUserAPC` when issuing a signal. So we need an alternative mechanism to support signals.
|
||||||
|
|
||||||
|
The alternative is to use `sigwait` in a separate thread. `Fsp_fuse_signal_handler` is a WinFsp API that knows how to interrupt that `WaitForSingleObject` (actually it just signals the waited event).
|
||||||
|
|
||||||
|
----
|
||||||
|
static inline void *fsp_fuse_signal_thread(void *psigmask)
|
||||||
|
{
|
||||||
|
int sig;
|
||||||
|
|
||||||
|
if (0 == sigwait(psigmask, &sig))
|
||||||
|
fsp_fuse_signal_handler(sig);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Let us now move to `fuse_daemonize`. This FUSE call allows a FUSE file system to become a (UNIX) daemon. This is achieved by using the POSIX fork call, which unfortunately has many limitations in Cygwin. One such limitation (and the one that bit us in WinFsp) is that it does not know how to clone Windows heaps (`HeapAlloc`/`HeapFree`).
|
||||||
|
|
||||||
|
Recall that WinFsp uses its own memory allocator (just a thin wrapper around `HeapAlloc`/`HeapFree`). This means that any allocations made prior to the fork() call are doomed after a fork(); with good luck the pointers will point to invalid memory and one will get an Access Violation; with bad luck the pointers will point to valid memory that contains bad data and the program may stumble for a while, just enough to hide the actual cause of the problem.
|
||||||
|
|
||||||
|
Luckily there is a rather straightforward work-around: "do not allocate any non-Cygwin resources prior to fork". This is actually possible within WinFsp, because we are already capturing the Cygwin environment and its `malloc`/`free` (see `fsp_fuse_env` in "Step 2"). It is also possible, because the typical FUSE program structure looks like this:
|
||||||
|
|
||||||
|
----
|
||||||
|
fuse_new
|
||||||
|
fuse_daemonize // do not allocate any non-Cygwin resources prior to this
|
||||||
|
fuse_loop/fuse_loop_mt // safe to allocate non-Cygwin resources
|
||||||
|
fuse_destroy
|
||||||
|
----
|
||||||
|
|
||||||
|
With this change `fuse_daemonize` works and allows me to declare the Cygwin portion of the SSHFS port complete!
|
||||||
|
111
inc/fuse/fuse.h
111
inc/fuse/fuse.h
@ -102,95 +102,116 @@ struct fuse_context
|
|||||||
#define fuse_main(argc, argv, ops, data)\
|
#define fuse_main(argc, argv, ops, data)\
|
||||||
fuse_main_real(argc, argv, ops, sizeof *(ops), data)
|
fuse_main_real(argc, argv, ops, sizeof *(ops), data)
|
||||||
|
|
||||||
FSP_FUSE_API int fsp_fuse_main_real(struct fsp_fuse_env *env,
|
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_main_real)(struct fsp_fuse_env *env,
|
||||||
int argc, char *argv[],
|
int argc, char *argv[],
|
||||||
const struct fuse_operations *ops, size_t opsize, void *data);
|
const struct fuse_operations *ops, size_t opsize, void *data);
|
||||||
FSP_FUSE_API int fsp_fuse_is_lib_option(struct fsp_fuse_env *env,
|
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_is_lib_option)(struct fsp_fuse_env *env,
|
||||||
const char *opt);
|
const char *opt);
|
||||||
FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
FSP_FUSE_API struct fuse *FSP_FUSE_API_NAME(fsp_fuse_new)(struct fsp_fuse_env *env,
|
||||||
struct fuse_chan *ch, struct fuse_args *args,
|
struct fuse_chan *ch, struct fuse_args *args,
|
||||||
const struct fuse_operations *ops, size_t opsize, void *data);
|
const struct fuse_operations *ops, size_t opsize, void *data);
|
||||||
FSP_FUSE_API void fsp_fuse_destroy(struct fsp_fuse_env *env,
|
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_destroy)(struct fsp_fuse_env *env,
|
||||||
struct fuse *f);
|
struct fuse *f);
|
||||||
FSP_FUSE_API int fsp_fuse_loop(struct fsp_fuse_env *env,
|
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_loop)(struct fsp_fuse_env *env,
|
||||||
struct fuse *f);
|
struct fuse *f);
|
||||||
FSP_FUSE_API int fsp_fuse_loop_mt(struct fsp_fuse_env *env,
|
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_loop_mt)(struct fsp_fuse_env *env,
|
||||||
struct fuse *f);
|
struct fuse *f);
|
||||||
FSP_FUSE_API void fsp_fuse_exit(struct fsp_fuse_env *env,
|
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_exit)(struct fsp_fuse_env *env,
|
||||||
struct fuse *f);
|
struct fuse *f);
|
||||||
FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env);
|
FSP_FUSE_API struct fuse_context *FSP_FUSE_API_NAME(fsp_fuse_get_context)(struct fsp_fuse_env *env);
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_main_real(int argc, char *argv[],
|
FSP_FUSE_SYM(
|
||||||
const struct fuse_operations *ops, size_t opsize, void *data)
|
int fuse_main_real(int argc, char *argv[],
|
||||||
|
const struct fuse_operations *ops, size_t opsize, void *data),
|
||||||
{
|
{
|
||||||
return fsp_fuse_main_real(fsp_fuse_env(), argc, argv, ops, opsize, data);
|
return FSP_FUSE_API_CALL(fsp_fuse_main_real)
|
||||||
}
|
(fsp_fuse_env(), argc, argv, ops, opsize, data);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_is_lib_option(const char *opt)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_is_lib_option(const char *opt),
|
||||||
{
|
{
|
||||||
return fsp_fuse_is_lib_option(fsp_fuse_env(), opt);
|
return FSP_FUSE_API_CALL(fsp_fuse_is_lib_option)
|
||||||
}
|
(fsp_fuse_env(), opt);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
|
FSP_FUSE_SYM(
|
||||||
const struct fuse_operations *ops, size_t opsize, void *data)
|
struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
|
||||||
|
const struct fuse_operations *ops, size_t opsize, void *data),
|
||||||
{
|
{
|
||||||
return fsp_fuse_new(fsp_fuse_env(), ch, args, ops, opsize, data);
|
return FSP_FUSE_API_CALL(fsp_fuse_new)
|
||||||
}
|
(fsp_fuse_env(), ch, args, ops, opsize, data);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM void fuse_destroy(struct fuse *f)
|
FSP_FUSE_SYM(
|
||||||
|
void fuse_destroy(struct fuse *f),
|
||||||
{
|
{
|
||||||
fsp_fuse_destroy(fsp_fuse_env(), f);
|
FSP_FUSE_API_CALL(fsp_fuse_destroy)
|
||||||
}
|
(fsp_fuse_env(), f);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_loop(struct fuse *f)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_loop(struct fuse *f),
|
||||||
{
|
{
|
||||||
return fsp_fuse_loop(fsp_fuse_env(), f);
|
return FSP_FUSE_API_CALL(fsp_fuse_loop)
|
||||||
}
|
(fsp_fuse_env(), f);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_loop_mt(struct fuse *f)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_loop_mt(struct fuse *f),
|
||||||
{
|
{
|
||||||
return fsp_fuse_loop_mt(fsp_fuse_env(), f);
|
return FSP_FUSE_API_CALL(fsp_fuse_loop_mt)
|
||||||
}
|
(fsp_fuse_env(), f);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM void fuse_exit(struct fuse *f)
|
FSP_FUSE_SYM(
|
||||||
|
void fuse_exit(struct fuse *f),
|
||||||
{
|
{
|
||||||
fsp_fuse_exit(fsp_fuse_env(), f);
|
FSP_FUSE_API_CALL(fsp_fuse_exit)
|
||||||
}
|
(fsp_fuse_env(), f);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM struct fuse_context *fuse_get_context(void)
|
FSP_FUSE_SYM(
|
||||||
|
struct fuse_context *fuse_get_context(void),
|
||||||
{
|
{
|
||||||
return fsp_fuse_get_context(fsp_fuse_env());
|
return FSP_FUSE_API_CALL(fsp_fuse_get_context)
|
||||||
}
|
(fsp_fuse_env());
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_getgroups(int size, fuse_gid_t list[])
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_getgroups(int size, fuse_gid_t list[]),
|
||||||
{
|
{
|
||||||
(void)size;
|
(void)size;
|
||||||
(void)list;
|
(void)list;
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_interrupted(void)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_interrupted(void),
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_invalidate(struct fuse *f, const char *path)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_invalidate(struct fuse *f, const char *path),
|
||||||
{
|
{
|
||||||
(void)f;
|
(void)f;
|
||||||
(void)path;
|
(void)path;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_notify_poll(struct fuse_pollhandle *ph)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_notify_poll(struct fuse_pollhandle *ph),
|
||||||
{
|
{
|
||||||
(void)ph;
|
(void)ph;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM struct fuse_session *fuse_get_session(struct fuse *f)
|
FSP_FUSE_SYM(
|
||||||
|
struct fuse_session *fuse_get_session(struct fuse *f),
|
||||||
{
|
{
|
||||||
return (void *)f;
|
return (struct fuse_session *)f;
|
||||||
}
|
})
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -77,58 +77,70 @@ struct fuse_session;
|
|||||||
struct fuse_chan;
|
struct fuse_chan;
|
||||||
struct fuse_pollhandle;
|
struct fuse_pollhandle;
|
||||||
|
|
||||||
FSP_FUSE_API int fsp_fuse_version(struct fsp_fuse_env *env);
|
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_version)(struct fsp_fuse_env *env);
|
||||||
FSP_FUSE_API struct fuse_chan *fsp_fuse_mount(struct fsp_fuse_env *env,
|
FSP_FUSE_API struct fuse_chan *FSP_FUSE_API_NAME(fsp_fuse_mount)(struct fsp_fuse_env *env,
|
||||||
const char *mountpoint, struct fuse_args *args);
|
const char *mountpoint, struct fuse_args *args);
|
||||||
FSP_FUSE_API void fsp_fuse_unmount(struct fsp_fuse_env *env,
|
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_unmount)(struct fsp_fuse_env *env,
|
||||||
const char *mountpoint, struct fuse_chan *ch);
|
const char *mountpoint, struct fuse_chan *ch);
|
||||||
FSP_FUSE_API int fsp_fuse_parse_cmdline(struct fsp_fuse_env *env,
|
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_parse_cmdline)(struct fsp_fuse_env *env,
|
||||||
struct fuse_args *args,
|
struct fuse_args *args,
|
||||||
char **mountpoint, int *multithreaded, int *foreground);
|
char **mountpoint, int *multithreaded, int *foreground);
|
||||||
FSP_FUSE_API int32_t fsp_fuse_ntstatus_from_errno(struct fsp_fuse_env *env,
|
FSP_FUSE_API int32_t FSP_FUSE_API_NAME(fsp_fuse_ntstatus_from_errno)(struct fsp_fuse_env *env,
|
||||||
int err);
|
int err);
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_version(void)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_version(void),
|
||||||
{
|
{
|
||||||
return fsp_fuse_version(fsp_fuse_env());
|
return FSP_FUSE_API_CALL(fsp_fuse_version)
|
||||||
}
|
(fsp_fuse_env());
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args)
|
FSP_FUSE_SYM(
|
||||||
|
struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args),
|
||||||
{
|
{
|
||||||
return fsp_fuse_mount(fsp_fuse_env(), mountpoint, args);
|
return FSP_FUSE_API_CALL(fsp_fuse_mount)
|
||||||
}
|
(fsp_fuse_env(), mountpoint, args);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
|
FSP_FUSE_SYM(
|
||||||
|
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch),
|
||||||
{
|
{
|
||||||
fsp_fuse_unmount(fsp_fuse_env(), mountpoint, ch);
|
FSP_FUSE_API_CALL(fsp_fuse_unmount)
|
||||||
}
|
(fsp_fuse_env(), mountpoint, ch);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_parse_cmdline(struct fuse_args *args,
|
FSP_FUSE_SYM(
|
||||||
char **mountpoint, int *multithreaded, int *foreground)
|
int fuse_parse_cmdline(struct fuse_args *args,
|
||||||
|
char **mountpoint, int *multithreaded, int *foreground),
|
||||||
{
|
{
|
||||||
return fsp_fuse_parse_cmdline(fsp_fuse_env(), args, mountpoint, multithreaded, foreground);
|
return FSP_FUSE_API_CALL(fsp_fuse_parse_cmdline)
|
||||||
}
|
(fsp_fuse_env(), args, mountpoint, multithreaded, foreground);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
|
FSP_FUSE_SYM(
|
||||||
|
void fuse_pollhandle_destroy(struct fuse_pollhandle *ph),
|
||||||
{
|
{
|
||||||
(void)ph;
|
(void)ph;
|
||||||
}
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_daemonize(int foreground)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_daemonize(int foreground),
|
||||||
{
|
{
|
||||||
return fsp_fuse_daemonize(foreground);
|
return fsp_fuse_daemonize(foreground);
|
||||||
}
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_set_signal_handlers(struct fuse_session *se)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_set_signal_handlers(struct fuse_session *se),
|
||||||
{
|
{
|
||||||
return fsp_fuse_set_signal_handlers(se);
|
return fsp_fuse_set_signal_handlers(se);
|
||||||
}
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM void fuse_remove_signal_handlers(struct fuse_session *se)
|
FSP_FUSE_SYM(
|
||||||
|
void fuse_remove_signal_handlers(struct fuse_session *se),
|
||||||
{
|
{
|
||||||
(void)se;
|
(void)se;
|
||||||
fsp_fuse_set_signal_handlers(0);
|
fsp_fuse_set_signal_handlers(0);
|
||||||
}
|
})
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -56,57 +56,71 @@ struct fuse_args
|
|||||||
typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
|
typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
|
||||||
struct fuse_args *outargs);
|
struct fuse_args *outargs);
|
||||||
|
|
||||||
FSP_FUSE_API int fsp_fuse_opt_parse(struct fsp_fuse_env *env,
|
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_parse)(struct fsp_fuse_env *env,
|
||||||
struct fuse_args *args, void *data,
|
struct fuse_args *args, void *data,
|
||||||
const struct fuse_opt opts[], fuse_opt_proc_t proc);
|
const struct fuse_opt opts[], fuse_opt_proc_t proc);
|
||||||
FSP_FUSE_API int fsp_fuse_opt_add_arg(struct fsp_fuse_env *env,
|
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_add_arg)(struct fsp_fuse_env *env,
|
||||||
struct fuse_args *args, const char *arg);
|
struct fuse_args *args, const char *arg);
|
||||||
FSP_FUSE_API int fsp_fuse_opt_insert_arg(struct fsp_fuse_env *env,
|
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_insert_arg)(struct fsp_fuse_env *env,
|
||||||
struct fuse_args *args, int pos, const char *arg);
|
struct fuse_args *args, int pos, const char *arg);
|
||||||
FSP_FUSE_API void fsp_fuse_opt_free_args(struct fsp_fuse_env *env,
|
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_opt_free_args)(struct fsp_fuse_env *env,
|
||||||
struct fuse_args *args);
|
struct fuse_args *args);
|
||||||
FSP_FUSE_API int fsp_fuse_opt_add_opt(struct fsp_fuse_env *env,
|
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_add_opt)(struct fsp_fuse_env *env,
|
||||||
char **opts, const char *opt);
|
char **opts, const char *opt);
|
||||||
FSP_FUSE_API int fsp_fuse_opt_add_opt_escaped(struct fsp_fuse_env *env,
|
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_add_opt_escaped)(struct fsp_fuse_env *env,
|
||||||
char **opts, const char *opt);
|
char **opts, const char *opt);
|
||||||
FSP_FUSE_API int fsp_fuse_opt_match(struct fsp_fuse_env *env,
|
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_match)(struct fsp_fuse_env *env,
|
||||||
const struct fuse_opt opts[], const char *opt);
|
const struct fuse_opt opts[], const char *opt);
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_opt_parse(struct fuse_args *args, void *data,
|
FSP_FUSE_SYM(
|
||||||
const struct fuse_opt opts[], fuse_opt_proc_t proc)
|
int fuse_opt_parse(struct fuse_args *args, void *data,
|
||||||
|
const struct fuse_opt opts[], fuse_opt_proc_t proc),
|
||||||
{
|
{
|
||||||
return fsp_fuse_opt_parse(fsp_fuse_env(), args, data, opts, proc);
|
return FSP_FUSE_API_CALL(fsp_fuse_opt_parse)
|
||||||
}
|
(fsp_fuse_env(), args, data, opts, proc);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_opt_add_arg(struct fuse_args *args, const char *arg),
|
||||||
{
|
{
|
||||||
return fsp_fuse_opt_add_arg(fsp_fuse_env(), args, arg);
|
return FSP_FUSE_API_CALL(fsp_fuse_opt_add_arg)
|
||||||
}
|
(fsp_fuse_env(), args, arg);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg),
|
||||||
{
|
{
|
||||||
return fsp_fuse_opt_insert_arg(fsp_fuse_env(), args, pos, arg);
|
return FSP_FUSE_API_CALL(fsp_fuse_opt_insert_arg)
|
||||||
}
|
(fsp_fuse_env(), args, pos, arg);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM void fuse_opt_free_args(struct fuse_args *args)
|
FSP_FUSE_SYM(
|
||||||
|
void fuse_opt_free_args(struct fuse_args *args),
|
||||||
{
|
{
|
||||||
fsp_fuse_opt_free_args(fsp_fuse_env(), args);
|
FSP_FUSE_API_CALL(fsp_fuse_opt_free_args)
|
||||||
}
|
(fsp_fuse_env(), args);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_opt_add_opt(char **opts, const char *opt)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_opt_add_opt(char **opts, const char *opt),
|
||||||
{
|
{
|
||||||
return fsp_fuse_opt_add_opt(fsp_fuse_env(), opts, opt);
|
return FSP_FUSE_API_CALL(fsp_fuse_opt_add_opt)
|
||||||
}
|
(fsp_fuse_env(), opts, opt);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_opt_add_opt_escaped(char **opts, const char *opt)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_opt_add_opt_escaped(char **opts, const char *opt),
|
||||||
{
|
{
|
||||||
return fsp_fuse_opt_add_opt_escaped(fsp_fuse_env(), opts, opt);
|
return FSP_FUSE_API_CALL(fsp_fuse_opt_add_opt_escaped)
|
||||||
}
|
(fsp_fuse_env(), opts, opt);
|
||||||
|
})
|
||||||
|
|
||||||
FSP_FUSE_SYM int fuse_opt_match(const struct fuse_opt opts[], const char *opt)
|
FSP_FUSE_SYM(
|
||||||
|
int fuse_opt_match(const struct fuse_opt opts[], const char *opt),
|
||||||
{
|
{
|
||||||
return fsp_fuse_opt_match(fsp_fuse_env(), opts, opt);
|
return FSP_FUSE_API_CALL(fsp_fuse_opt_match)
|
||||||
}
|
(fsp_fuse_env(), opts, opt);
|
||||||
|
})
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -29,14 +29,28 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(FSP_FUSE_API)
|
||||||
#if defined(WINFSP_DLL_INTERNAL)
|
#if defined(WINFSP_DLL_INTERNAL)
|
||||||
#define FSP_FUSE_API __declspec(dllexport)
|
#define FSP_FUSE_API __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
#define FSP_FUSE_API __declspec(dllimport)
|
#define FSP_FUSE_API __declspec(dllimport)
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(FSP_FUSE_API_NAME)
|
||||||
|
#define FSP_FUSE_API_NAME(n) (n)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(FSP_FUSE_API_CALL)
|
||||||
|
#define FSP_FUSE_API_CALL(n) (n)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(FSP_FUSE_SYM)
|
#if !defined(FSP_FUSE_SYM)
|
||||||
#define FSP_FUSE_SYM static inline
|
#if !defined(CYGFUSE)
|
||||||
|
#define FSP_FUSE_SYM(proto, ...) static inline proto { __VA_ARGS__ }
|
||||||
|
#else
|
||||||
|
#define FSP_FUSE_SYM(proto, ...) proto;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -232,7 +246,7 @@ struct fsp_fuse_env
|
|||||||
int (*set_signal_handlers)(void *);
|
int (*set_signal_handlers)(void *);
|
||||||
};
|
};
|
||||||
|
|
||||||
FSP_FUSE_API void fsp_fuse_signal_handler(int sig);
|
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_signal_handler)(int sig);
|
||||||
|
|
||||||
#if defined(_WIN64) || defined(_WIN32)
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
|
||||||
@ -270,8 +284,8 @@ static inline void *fsp_fuse_signal_thread(void *psigmask)
|
|||||||
{
|
{
|
||||||
int sig;
|
int sig;
|
||||||
|
|
||||||
if (0 == sigwait(psigmask, &sig))
|
if (0 == sigwait((sigset_t *)psigmask, &sig))
|
||||||
fsp_fuse_signal_handler(sig);
|
FSP_FUSE_API_CALL(fsp_fuse_signal_handler)(sig);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -402,41 +402,35 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
|
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo);
|
FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
/**
|
/**
|
||||||
* Set file allocation size.
|
* Set file/allocation size.
|
||||||
|
*
|
||||||
|
* This function is used to change a file's sizes. Windows file systems maintain two kinds
|
||||||
|
* of sizes: the file size is where the End Of File (EOF) is, and the allocation size is the
|
||||||
|
* actual size that a file takes up on the "disk".
|
||||||
|
*
|
||||||
|
* The rules regarding file/allocation size are:
|
||||||
|
* <ul>
|
||||||
|
* <li>Allocation size must always be aligned to the allocation unit boundary. The allocation
|
||||||
|
* unit is the product <code>(UINT64)SectorSize * (UINT64)SectorsPerAllocationUnit</code> from
|
||||||
|
* the FSP_FSCTL_VOLUME_PARAMS structure. The FSD will always send properly aligned allocation
|
||||||
|
* sizes when setting the allocation size.</li>
|
||||||
|
* <li>Allocation size is always greater or equal to the file size.</li>
|
||||||
|
* <li>A file size of more than the current allocation size will also extend the allocation
|
||||||
|
* size to the next allocation unit boundary.</li>
|
||||||
|
* <li>An allocation size of less than the current file size should also truncate the current
|
||||||
|
* file size.</li>
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param FileSystem
|
* @param FileSystem
|
||||||
* The file system on which this request is posted.
|
* The file system on which this request is posted.
|
||||||
* @param Request
|
* @param Request
|
||||||
* The request posted by the kernel mode FSD.
|
* The request posted by the kernel mode FSD.
|
||||||
* @param FileNode
|
* @param FileNode
|
||||||
* The file node of the file to set the allocation size for.
|
* The file node of the file to set the file/allocation size for.
|
||||||
* @param AllocationSize
|
* @param NewSize
|
||||||
* Allocation size to apply to the file. Allocation size is always greater than file size.
|
* New file/allocation size to apply to the file.
|
||||||
* An allocation size of less than the current file size should also truncate the current
|
* @param SetAllocationSize
|
||||||
* file size.
|
* If TRUE, then the allocation size is being set. if FALSE, then the file size is being set.
|
||||||
* @param FileInfo [out]
|
|
||||||
* Pointer to a structure that will receive the file information on successful return
|
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
|
||||||
* @return
|
|
||||||
* STATUS_SUCCESS on error code.
|
|
||||||
*/
|
|
||||||
NTSTATUS (*SetAllocationSize)(FSP_FILE_SYSTEM *FileSystem,
|
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode, UINT64 AllocationSize,
|
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo);
|
|
||||||
/**
|
|
||||||
* Set file size.
|
|
||||||
*
|
|
||||||
* @param FileSystem
|
|
||||||
* The file system on which this request is posted.
|
|
||||||
* @param Request
|
|
||||||
* The request posted by the kernel mode FSD.
|
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file to set the size for.
|
|
||||||
* @param FileSize
|
|
||||||
* FileSize size to apply to the file. Allocation size is always greater than file size.
|
|
||||||
* A file size of more than the current allocation size will also extend the allocation
|
|
||||||
* size to the next allocation unit boundary.
|
|
||||||
* @param FileInfo [out]
|
* @param FileInfo [out]
|
||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
@ -445,7 +439,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
*/
|
*/
|
||||||
NTSTATUS (*SetFileSize)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetFileSize)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
PVOID FileNode, UINT64 FileSize,
|
PVOID FileNode, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo);
|
FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
/**
|
/**
|
||||||
* Determine whether a file or directory can be deleted.
|
* Determine whether a file or directory can be deleted.
|
||||||
@ -454,6 +448,12 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* not need to perform access checks, but may performs tasks such as check for empty
|
* not need to perform access checks, but may performs tasks such as check for empty
|
||||||
* directories, etc.
|
* directories, etc.
|
||||||
*
|
*
|
||||||
|
* This function should <b>NEVER</b> delete the file or directory in question. Deletion should
|
||||||
|
* happen during Cleanup with Delete==TRUE.
|
||||||
|
*
|
||||||
|
* This function gets called when Win32 API's such as DeleteFile or RemoveDirectory are used.
|
||||||
|
* It does not get called when a file or directory is opened with FILE_DELETE_ON_CLOSE.
|
||||||
|
*
|
||||||
* @param FileSystem
|
* @param FileSystem
|
||||||
* The file system on which this request is posted.
|
* The file system on which this request is posted.
|
||||||
* @param Request
|
* @param Request
|
||||||
@ -576,7 +576,21 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
||||||
PWSTR Pattern,
|
PWSTR Pattern,
|
||||||
PULONG PBytesTransferred);
|
PULONG PBytesTransferred);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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[45])();
|
||||||
} FSP_FILE_SYSTEM_INTERFACE;
|
} FSP_FILE_SYSTEM_INTERFACE;
|
||||||
|
#if defined(WINFSP_DLL_INTERNAL)
|
||||||
|
/*
|
||||||
|
* Static_assert is a C++11 feature, but seems to work with C on MSVC 2015.
|
||||||
|
* Use it to verify that FSP_FILE_SYSTEM_INTERFACE has the right size.
|
||||||
|
*/
|
||||||
|
static_assert(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
|
||||||
|
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
|
||||||
|
#endif
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0,
|
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0,
|
||||||
@ -595,7 +609,7 @@ typedef struct _FSP_FILE_SYSTEM
|
|||||||
ULONG DispatcherThreadCount;
|
ULONG DispatcherThreadCount;
|
||||||
NTSTATUS DispatcherResult;
|
NTSTATUS DispatcherResult;
|
||||||
PWSTR MountPoint;
|
PWSTR MountPoint;
|
||||||
LIST_ENTRY MountEntry;
|
HANDLE MountHandle;
|
||||||
UINT32 DebugLog;
|
UINT32 DebugLog;
|
||||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
|
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
|
||||||
SRWLOCK OpGuardLock;
|
SRWLOCK OpGuardLock;
|
||||||
|
20
opt/cygfuse/Makefile
Normal file
20
opt/cygfuse/Makefile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Version = $(shell sed -n '/^VERSION=/s/VERSION=\(.*\)/\1/p' fuse.cygport)
|
||||||
|
#Debug = -g
|
||||||
|
|
||||||
|
cygfuse-$(Version).dll libfuse-$(Version).dll.a fuse.pc: cygfuse.c fuse.pc.in
|
||||||
|
gcc $(Debug) -shared -o cygfuse-$(Version).dll -Wl,--out-implib=libfuse-$(Version).dll.a -I../../inc/fuse cygfuse.c
|
||||||
|
[ -n "$(Debug)" ] || strip cygfuse-$(Version).dll
|
||||||
|
sed "s/@Version@/$(Version)/g" fuse.pc.in > fuse.pc
|
||||||
|
|
||||||
|
cygfuse-test.exe: cygfuse-test.c cygfuse-$(Version).dll libfuse-$(Version).dll.a
|
||||||
|
gcc $(Debug) -o cygfuse-test.exe -I../../inc/fuse -DCYGFUSE cygfuse-test.c -L$(PWD) -lfuse-$(Version)
|
||||||
|
|
||||||
|
cygport:
|
||||||
|
git clean -dfx
|
||||||
|
(\
|
||||||
|
cd `git rev-parse --show-toplevel` &&\
|
||||||
|
Stash=`git stash create` &&\
|
||||||
|
git archive --prefix=winfsp-work/ --format=tar.gz $${Stash:-HEAD}\
|
||||||
|
> opt/cygfuse/winfsp-work.tar.gz\
|
||||||
|
)
|
||||||
|
CYGPORT_SRC_URI=winfsp-work.tar.gz CYGPORT_SRC_DIR=winfsp-work cygport fuse.cygport download prep compile install package
|
6
opt/cygfuse/cygfuse-test.c
Normal file
6
opt/cygfuse/cygfuse-test.c
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include <fuse.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return !(FUSE_VERSION == fuse_version());
|
||||||
|
}
|
146
opt/cygfuse/cygfuse.c
Normal file
146
opt/cygfuse/cygfuse.c
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/**
|
||||||
|
* @file cygfuse/cygfuse.c
|
||||||
|
*
|
||||||
|
* @copyright 2015-2016 Bill Zissimopoulos
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* This file is part of WinFsp.
|
||||||
|
*
|
||||||
|
* You can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU Affero General Public License version 3 as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Licensees holding a valid commercial license may use this file in
|
||||||
|
* accordance with the commercial license agreement provided with the
|
||||||
|
* software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/cygwin.h>
|
||||||
|
|
||||||
|
static void *cygfuse_init_winfsp();
|
||||||
|
static void *cygfuse_init_fail();
|
||||||
|
|
||||||
|
static pthread_mutex_t cygfuse_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static void *cygfuse_handle = 0;
|
||||||
|
|
||||||
|
static inline void cygfuse_init(int force)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&cygfuse_mutex);
|
||||||
|
if (force || 0 == cygfuse_handle)
|
||||||
|
cygfuse_handle = cygfuse_init_winfsp();
|
||||||
|
pthread_mutex_unlock(&cygfuse_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unfortunately Cygwin fork is very fragile and cannot even correctly
|
||||||
|
* handle dlopen'ed DLL's if they are native (rather than Cygwin ones).
|
||||||
|
*
|
||||||
|
* So we have this very nasty hack where we reset the dlopen'ed handle
|
||||||
|
* immediately after daemonization. This will force cygfuse_init() to
|
||||||
|
* reload the WinFsp DLL and reset all API pointers in the daemonized
|
||||||
|
* process.
|
||||||
|
*/
|
||||||
|
static inline int cygfuse_daemon(int nochdir, int noclose)
|
||||||
|
{
|
||||||
|
if (-1 == daemon(nochdir, noclose))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* force reload of WinFsp DLL to workaround fork() problems */
|
||||||
|
cygfuse_init(1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#define daemon cygfuse_daemon
|
||||||
|
|
||||||
|
#define FSP_FUSE_API static
|
||||||
|
#define FSP_FUSE_API_NAME(api) (* pfn_ ## api)
|
||||||
|
#define FSP_FUSE_API_CALL(api) (cygfuse_init(0), pfn_ ## api)
|
||||||
|
#define FSP_FUSE_SYM(proto, ...) __attribute__ ((visibility("default"))) proto { __VA_ARGS__ }
|
||||||
|
#include <fuse_common.h>
|
||||||
|
#include <fuse.h>
|
||||||
|
#include <fuse_opt.h>
|
||||||
|
|
||||||
|
#if defined(__LP64__)
|
||||||
|
#define CYGFUSE_WINFSP_NAME "winfsp-x64.dll"
|
||||||
|
#else
|
||||||
|
#define CYGFUSE_WINFSP_NAME "winfsp-x86.dll"
|
||||||
|
#endif
|
||||||
|
#define CYGFUSE_WINFSP_PATH "bin\\" CYGFUSE_WINFSP_NAME
|
||||||
|
#define CYGFUSE_GET_API(h, n) \
|
||||||
|
if (0 == (*(void **)&(pfn_ ## n) = dlsym(h, #n)))\
|
||||||
|
return cygfuse_init_fail();
|
||||||
|
|
||||||
|
static void *cygfuse_init_winfsp()
|
||||||
|
{
|
||||||
|
void *h;
|
||||||
|
|
||||||
|
h = dlopen(CYGFUSE_WINFSP_NAME, RTLD_NOW);
|
||||||
|
if (0 == h)
|
||||||
|
{
|
||||||
|
char winpath[260], *psxpath;
|
||||||
|
int regfd, bytes;
|
||||||
|
|
||||||
|
regfd = open("/proc/registry32/HKEY_LOCAL_MACHINE/Software/WinFsp/InstallDir", O_RDONLY);
|
||||||
|
if (-1 == regfd)
|
||||||
|
return cygfuse_init_fail();
|
||||||
|
|
||||||
|
bytes = read(regfd, winpath, sizeof winpath - sizeof CYGFUSE_WINFSP_PATH);
|
||||||
|
close(regfd);
|
||||||
|
if (-1 == bytes || 0 == bytes)
|
||||||
|
return cygfuse_init_fail();
|
||||||
|
|
||||||
|
if ('\0' == winpath[bytes - 1])
|
||||||
|
bytes--;
|
||||||
|
memcpy(winpath + bytes, CYGFUSE_WINFSP_PATH, sizeof CYGFUSE_WINFSP_PATH);
|
||||||
|
|
||||||
|
psxpath = (char *)cygwin_create_path(CCP_WIN_A_TO_POSIX | CCP_PROC_CYGDRIVE, winpath);
|
||||||
|
if (0 == psxpath)
|
||||||
|
return cygfuse_init_fail();
|
||||||
|
|
||||||
|
h = dlopen(psxpath, RTLD_NOW);
|
||||||
|
free(psxpath);
|
||||||
|
if (0 == h)
|
||||||
|
return cygfuse_init_fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* winfsp_fuse.h */
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_signal_handler);
|
||||||
|
|
||||||
|
/* fuse_common.h */
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_version);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_mount);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_unmount);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_parse_cmdline);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_ntstatus_from_errno);
|
||||||
|
|
||||||
|
/* fuse.h */
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_main_real);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_is_lib_option);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_new);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_destroy);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_loop);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_loop_mt);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_exit);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_get_context);
|
||||||
|
|
||||||
|
/* fuse_opt.h */
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_opt_parse);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_opt_add_arg);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_opt_insert_arg);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_opt_free_args);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_opt_add_opt);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_opt_add_opt_escaped);
|
||||||
|
CYGFUSE_GET_API(h, fsp_fuse_opt_match);
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *cygfuse_init_fail()
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
return 0;
|
||||||
|
}
|
35
opt/cygfuse/fuse.cygport
Normal file
35
opt/cygfuse/fuse.cygport
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
NAME="fuse"
|
||||||
|
VERSION=2.8
|
||||||
|
RELEASE=2
|
||||||
|
CATEGORY="Utils"
|
||||||
|
SUMMARY="WinFsp-FUSE compatibility layer"
|
||||||
|
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."
|
||||||
|
HOMEPAGE="http://www.secfs.net/winfsp/"
|
||||||
|
|
||||||
|
SRC_URI=${CYGPORT_SRC_URI:-"https://github.com/billziss-gh/winfsp/archive/master.tar.gz"}
|
||||||
|
SRC_DIR=${CYGPORT_SRC_DIR:-winfsp-master}
|
||||||
|
|
||||||
|
src_compile()
|
||||||
|
{
|
||||||
|
lndirs
|
||||||
|
cd ${B}/opt/cygfuse
|
||||||
|
make
|
||||||
|
}
|
||||||
|
|
||||||
|
src_install()
|
||||||
|
{
|
||||||
|
cd ${B}/inc/fuse
|
||||||
|
includeinto fuse
|
||||||
|
doinclude fuse.h
|
||||||
|
doinclude fuse_common.h
|
||||||
|
doinclude fuse_opt.h
|
||||||
|
doinclude winfsp_fuse.h
|
||||||
|
|
||||||
|
cd ${B}/opt/cygfuse
|
||||||
|
dobin cygfuse-${VERSION}.dll
|
||||||
|
dolib libfuse-${VERSION}.dll.a
|
||||||
|
dosym libfuse-${VERSION}.dll.a /usr/lib/libfuse.dll.a
|
||||||
|
dopkgconfig fuse.pc
|
||||||
|
}
|
||||||
|
|
||||||
|
RESTRICT="strip postinst-doc"
|
9
opt/cygfuse/fuse.pc.in
Normal file
9
opt/cygfuse/fuse.pc.in
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
prefix=/usr
|
||||||
|
incdir=${prefix}/include/fuse
|
||||||
|
|
||||||
|
Name: fuse
|
||||||
|
Description: WinFsp FUSE compatible API
|
||||||
|
Version: @Version@
|
||||||
|
URL: http://www.secfs.net/winfsp/
|
||||||
|
Libs: -lfuse-@Version@
|
||||||
|
Cflags: -I"${incdir}" -DCYGFUSE
|
114
src/dll/fs.c
114
src/dll/fs.c
@ -25,60 +25,34 @@ enum
|
|||||||
static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface;
|
static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface;
|
||||||
|
|
||||||
static INIT_ONCE FspFileSystemInitOnce = INIT_ONCE_STATIC_INIT;
|
static INIT_ONCE FspFileSystemInitOnce = INIT_ONCE_STATIC_INIT;
|
||||||
static BOOLEAN FspFileSystemInitialized;
|
static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
|
||||||
static CRITICAL_SECTION FspFileSystemMountListGuard;
|
PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
|
||||||
static LIST_ENTRY FspFileSystemMountList = { &FspFileSystemMountList, &FspFileSystemMountList };
|
static NTSTATUS (NTAPI *FspNtMakeTemporaryObject)(
|
||||||
|
HANDLE Handle);
|
||||||
|
static NTSTATUS (NTAPI *FspNtClose)(
|
||||||
|
HANDLE Handle);
|
||||||
|
|
||||||
static BOOL WINAPI FspFileSystemInitialize(
|
static BOOL WINAPI FspFileSystemInitialize(
|
||||||
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
||||||
{
|
{
|
||||||
InitializeCriticalSection(&FspFileSystemMountListGuard);
|
HANDLE Handle;
|
||||||
return FspFileSystemInitialized = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID FspFileSystemFinalize(BOOLEAN Dynamic)
|
Handle = GetModuleHandleW(L"ntdll.dll");
|
||||||
{
|
if (0 != Handle)
|
||||||
/*
|
|
||||||
* This function is called during DLL_PROCESS_DETACH. We must therefore keep
|
|
||||||
* finalization tasks to a minimum.
|
|
||||||
*
|
|
||||||
* We enter our FspFileSystemMountListGuard critical section here and then attempt to cleanup
|
|
||||||
* our mount points using DefineDosDeviceW. On Vista and later orphaned critical sections
|
|
||||||
* become "electrified", so our process will be forcefully terminated if one of its threads
|
|
||||||
* was already modifying the list when the ExitProcess happened. This is a good thing!
|
|
||||||
*
|
|
||||||
* The use of DefineDosDeviceW is rather suspect and probably unsafe. DefineDosDeviceW reaches
|
|
||||||
* out to CSRSS, which is probably not the safest thing to do when in DllMain! There is also
|
|
||||||
* some evidence that it may attempt to load DLL's under some circumstances, which is a
|
|
||||||
* definite no-no as we are under the loader lock!
|
|
||||||
*
|
|
||||||
* We only delete the criticaly section when being dynamically unloaded. On process exit the
|
|
||||||
* OS will clean it up for us.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!FspFileSystemInitialized)
|
|
||||||
return;
|
|
||||||
|
|
||||||
FSP_FILE_SYSTEM *FileSystem;
|
|
||||||
PLIST_ENTRY MountEntry;
|
|
||||||
|
|
||||||
EnterCriticalSection(&FspFileSystemMountListGuard);
|
|
||||||
|
|
||||||
for (MountEntry = FspFileSystemMountList.Flink;
|
|
||||||
&FspFileSystemMountList != MountEntry;
|
|
||||||
MountEntry = MountEntry->Flink)
|
|
||||||
{
|
{
|
||||||
FileSystem = CONTAINING_RECORD(MountEntry, FSP_FILE_SYSTEM, MountEntry);
|
FspNtOpenSymbolicLinkObject = (PVOID)GetProcAddress(Handle, "NtOpenSymbolicLinkObject");
|
||||||
|
FspNtMakeTemporaryObject = (PVOID)GetProcAddress(Handle, "NtMakeTemporaryObject");
|
||||||
|
FspNtClose = (PVOID)GetProcAddress(Handle, "NtClose");
|
||||||
|
|
||||||
DefineDosDeviceW(
|
if (0 == FspNtOpenSymbolicLinkObject || 0 == FspNtMakeTemporaryObject || 0 == FspNtClose)
|
||||||
DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
|
{
|
||||||
FileSystem->MountPoint, FileSystem->VolumeName);
|
FspNtOpenSymbolicLinkObject = 0;
|
||||||
|
FspNtMakeTemporaryObject = 0;
|
||||||
|
FspNtClose = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaveCriticalSection(&FspFileSystemMountListGuard);
|
return TRUE;
|
||||||
|
|
||||||
if (Dynamic)
|
|
||||||
DeleteCriticalSection(&FspFileSystemMountListGuard);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
||||||
@ -95,8 +69,6 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
|||||||
Interface = &FspFileSystemNullInterface;
|
Interface = &FspFileSystemNullInterface;
|
||||||
|
|
||||||
InitOnceExecuteOnce(&FspFileSystemInitOnce, FspFileSystemInitialize, 0, 0);
|
InitOnceExecuteOnce(&FspFileSystemInitOnce, FspFileSystemInitialize, 0, 0);
|
||||||
if (!FspFileSystemInitialized)
|
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
|
||||||
|
|
||||||
FileSystem = MemAlloc(sizeof *FileSystem);
|
FileSystem = MemAlloc(sizeof *FileSystem);
|
||||||
if (0 == FileSystem)
|
if (0 == FileSystem)
|
||||||
@ -151,6 +123,7 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
|
|||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
HANDLE MountHandle = 0;
|
||||||
|
|
||||||
if (0 == MountPoint)
|
if (0 == MountPoint)
|
||||||
{
|
{
|
||||||
@ -203,13 +176,41 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
|
|||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
if (NT_SUCCESS(Result) && 0 != FspNtOpenSymbolicLinkObject)
|
||||||
|
{
|
||||||
|
WCHAR SymlinkBuf[6];
|
||||||
|
UNICODE_STRING Symlink;
|
||||||
|
OBJECT_ATTRIBUTES Obja;
|
||||||
|
|
||||||
|
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
|
||||||
|
SymlinkBuf[4] = MountPoint[0];
|
||||||
|
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
|
||||||
|
Symlink.Buffer = SymlinkBuf;
|
||||||
|
|
||||||
|
memset(&Obja, 0, sizeof Obja);
|
||||||
|
Obja.Length = sizeof Obja;
|
||||||
|
Obja.ObjectName = &Symlink;
|
||||||
|
Obja.Attributes = OBJ_CASE_INSENSITIVE;
|
||||||
|
|
||||||
|
Result = FspNtOpenSymbolicLinkObject(&MountHandle, DELETE, &Obja);
|
||||||
|
if (NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
Result = FspNtMakeTemporaryObject(MountHandle);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
FspNtClose(MountHandle);
|
||||||
|
MountHandle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this path always considered successful regardless if we made symlink temporary */
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
if (NT_SUCCESS(Result))
|
if (NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
FileSystem->MountPoint = MountPoint;
|
FileSystem->MountPoint = MountPoint;
|
||||||
|
FileSystem->MountHandle = MountHandle;
|
||||||
EnterCriticalSection(&FspFileSystemMountListGuard);
|
|
||||||
InsertTailList(&FspFileSystemMountList, &FileSystem->MountEntry);
|
|
||||||
LeaveCriticalSection(&FspFileSystemMountListGuard);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
MemFree(MountPoint);
|
MemFree(MountPoint);
|
||||||
@ -222,15 +223,16 @@ FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
|
|||||||
if (0 == FileSystem->MountPoint)
|
if (0 == FileSystem->MountPoint)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
EnterCriticalSection(&FspFileSystemMountListGuard);
|
|
||||||
RemoveEntryList(&FileSystem->MountEntry);
|
|
||||||
LeaveCriticalSection(&FspFileSystemMountListGuard);
|
|
||||||
|
|
||||||
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
|
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
|
||||||
FileSystem->MountPoint, FileSystem->VolumeName);
|
FileSystem->MountPoint, FileSystem->VolumeName);
|
||||||
|
|
||||||
MemFree(FileSystem->MountPoint);
|
MemFree(FileSystem->MountPoint);
|
||||||
FileSystem->MountPoint = 0;
|
FileSystem->MountPoint = 0;
|
||||||
|
|
||||||
|
if (0 != FileSystem->MountHandle)
|
||||||
|
{
|
||||||
|
FspNtClose(FileSystem->MountHandle);
|
||||||
|
FileSystem->MountHandle = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
|
static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
|
||||||
|
@ -690,32 +690,17 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
&FileInfo);
|
&FileInfo);
|
||||||
break;
|
break;
|
||||||
case 19/*FileAllocationInformation*/:
|
case 19/*FileAllocationInformation*/:
|
||||||
if (0 != FileSystem->Interface->SetAllocationSize)
|
if (0 != FileSystem->Interface->SetFileSize)
|
||||||
Result = FileSystem->Interface->SetAllocationSize(FileSystem, Request,
|
|
||||||
(PVOID)Request->Req.SetInformation.UserContext,
|
|
||||||
Request->Req.SetInformation.Info.Allocation.AllocationSize,
|
|
||||||
&FileInfo);
|
|
||||||
else
|
|
||||||
if (0 != FileSystem->Interface->GetFileInfo &&
|
|
||||||
0 != FileSystem->Interface->SetFileSize)
|
|
||||||
{
|
|
||||||
Result = FileSystem->Interface->GetFileInfo(FileSystem, Request,
|
|
||||||
(PVOID)Request->Req.SetInformation.UserContext, &FileInfo);
|
|
||||||
if (NT_SUCCESS(Result) &&
|
|
||||||
Request->Req.SetInformation.Info.Allocation.AllocationSize < FileInfo.FileSize)
|
|
||||||
{
|
|
||||||
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
|
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
|
||||||
(PVOID)Request->Req.SetInformation.UserContext,
|
(PVOID)Request->Req.SetInformation.UserContext,
|
||||||
Request->Req.SetInformation.Info.Allocation.AllocationSize,
|
Request->Req.SetInformation.Info.Allocation.AllocationSize, TRUE,
|
||||||
&FileInfo);
|
&FileInfo);
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 20/*FileEndOfFileInformation*/:
|
case 20/*FileEndOfFileInformation*/:
|
||||||
if (0 != FileSystem->Interface->SetFileSize)
|
if (0 != FileSystem->Interface->SetFileSize)
|
||||||
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
|
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
|
||||||
(PVOID)Request->Req.SetInformation.UserContext,
|
(PVOID)Request->Req.SetInformation.UserContext,
|
||||||
Request->Req.SetInformation.Info.EndOfFile.FileSize,
|
Request->Req.SetInformation.Info.EndOfFile.FileSize, FALSE,
|
||||||
&FileInfo);
|
&FileInfo);
|
||||||
break;
|
break;
|
||||||
case 13/*FileDispositionInformation*/:
|
case 13/*FileDispositionInformation*/:
|
||||||
|
@ -935,9 +935,9 @@ static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_SetFileSizeCommon(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
PVOID FileNode, UINT64 NewFileSize, BOOLEAN OnlyIfTruncate,
|
PVOID FileNode, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
{
|
{
|
||||||
struct fuse *f = FileSystem->UserContext;
|
struct fuse *f = FileSystem->UserContext;
|
||||||
@ -962,21 +962,21 @@ static NTSTATUS fsp_fuse_intf_SetFileSizeCommon(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
if (!OnlyIfTruncate || FileInfoBuf.FileSize > NewFileSize)
|
if (!SetAllocationSize || FileInfoBuf.FileSize > NewSize)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* OnlyIfTruncate explanation:
|
* "FileInfoBuf.FileSize > NewSize" explanation:
|
||||||
* FUSE 2.8 does not support allocation size. However if the new AllocationSize
|
* FUSE 2.8 does not support allocation size. However if the new AllocationSize
|
||||||
* is less than the current FileSize we must truncate the file.
|
* is less than the current FileSize we must truncate the file.
|
||||||
*/
|
*/
|
||||||
if (0 != f->ops.ftruncate)
|
if (0 != f->ops.ftruncate)
|
||||||
{
|
{
|
||||||
err = f->ops.ftruncate(filedesc->PosixPath, NewFileSize, &fi);
|
err = f->ops.ftruncate(filedesc->PosixPath, NewSize, &fi);
|
||||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = f->ops.truncate(filedesc->PosixPath, NewFileSize);
|
err = f->ops.truncate(filedesc->PosixPath, NewSize);
|
||||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||||
}
|
}
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
@ -984,7 +984,7 @@ static NTSTATUS fsp_fuse_intf_SetFileSizeCommon(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
AllocationUnit = (UINT64)f->VolumeParams.SectorSize *
|
AllocationUnit = (UINT64)f->VolumeParams.SectorSize *
|
||||||
(UINT64)f->VolumeParams.SectorsPerAllocationUnit;
|
(UINT64)f->VolumeParams.SectorsPerAllocationUnit;
|
||||||
FileInfoBuf.FileSize = NewFileSize;
|
FileInfoBuf.FileSize = NewSize;
|
||||||
FileInfoBuf.AllocationSize =
|
FileInfoBuf.AllocationSize =
|
||||||
(FileInfoBuf.FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
(FileInfoBuf.FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
||||||
}
|
}
|
||||||
@ -994,24 +994,6 @@ static NTSTATUS fsp_fuse_intf_SetFileSizeCommon(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_SetAllocationSize(FSP_FILE_SYSTEM *FileSystem,
|
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode, UINT64 AllocationSize,
|
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
|
||||||
{
|
|
||||||
return fsp_fuse_intf_SetFileSizeCommon(FileSystem, Request, FileNode, AllocationSize, TRUE,
|
|
||||||
FileInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode, UINT64 FileSize,
|
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
|
||||||
{
|
|
||||||
return fsp_fuse_intf_SetFileSizeCommon(FileSystem, Request, FileNode, FileSize, FALSE,
|
|
||||||
FileInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fsp_fuse_intf_CanDeleteAddDirInfo(void *buf, const char *name,
|
static int fsp_fuse_intf_CanDeleteAddDirInfo(void *buf, const char *name,
|
||||||
const struct fuse_stat *stbuf, fuse_off_t off)
|
const struct fuse_stat *stbuf, fuse_off_t off)
|
||||||
{
|
{
|
||||||
@ -1448,7 +1430,6 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
|||||||
fsp_fuse_intf_Flush,
|
fsp_fuse_intf_Flush,
|
||||||
fsp_fuse_intf_GetFileInfo,
|
fsp_fuse_intf_GetFileInfo,
|
||||||
fsp_fuse_intf_SetBasicInfo,
|
fsp_fuse_intf_SetBasicInfo,
|
||||||
fsp_fuse_intf_SetAllocationSize,
|
|
||||||
fsp_fuse_intf_SetFileSize,
|
fsp_fuse_intf_SetFileSize,
|
||||||
fsp_fuse_intf_CanDelete,
|
fsp_fuse_intf_CanDelete,
|
||||||
fsp_fuse_intf_Rename,
|
fsp_fuse_intf_Rename,
|
||||||
|
@ -42,7 +42,6 @@ BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
|
|||||||
Dynamic = 0 == Reserved;
|
Dynamic = 0 == Reserved;
|
||||||
fsp_fuse_finalize(Dynamic);
|
fsp_fuse_finalize(Dynamic);
|
||||||
FspServiceFinalize(Dynamic);
|
FspServiceFinalize(Dynamic);
|
||||||
FspFileSystemFinalize(Dynamic);
|
|
||||||
FspEventLogFinalize(Dynamic);
|
FspEventLogFinalize(Dynamic);
|
||||||
FspPosixFinalize(Dynamic);
|
FspPosixFinalize(Dynamic);
|
||||||
break;
|
break;
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
|
|
||||||
VOID FspPosixFinalize(BOOLEAN Dynamic);
|
VOID FspPosixFinalize(BOOLEAN Dynamic);
|
||||||
VOID FspEventLogFinalize(BOOLEAN Dynamic);
|
VOID FspEventLogFinalize(BOOLEAN Dynamic);
|
||||||
VOID FspFileSystemFinalize(BOOLEAN Dynamic);
|
|
||||||
VOID FspServiceFinalize(BOOLEAN Dynamic);
|
VOID FspServiceFinalize(BOOLEAN Dynamic);
|
||||||
VOID fsp_fuse_finalize(BOOLEAN Dynamic);
|
VOID fsp_fuse_finalize(BOOLEAN Dynamic);
|
||||||
VOID fsp_fuse_finalize_thread(VOID);
|
VOID fsp_fuse_finalize_thread(VOID);
|
||||||
|
@ -36,8 +36,23 @@
|
|||||||
static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...);
|
static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...);
|
||||||
|
|
||||||
static INIT_ONCE FspPosixInitOnce = INIT_ONCE_STATIC_INIT;
|
static INIT_ONCE FspPosixInitOnce = INIT_ONCE_STATIC_INIT;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
SID V;
|
||||||
|
UINT8 B[sizeof(SID) - sizeof(DWORD) + (1 * sizeof(DWORD))];
|
||||||
|
} FspUnmappedSidBuf =
|
||||||
|
{
|
||||||
|
/* S-1-5-7 (Anonymous) */
|
||||||
|
.V.Revision = SID_REVISION,
|
||||||
|
.V.SubAuthorityCount = 1,
|
||||||
|
.V.IdentifierAuthority.Value[5] = 5,
|
||||||
|
.V.SubAuthority[0] = 7,
|
||||||
|
};
|
||||||
static PISID FspAccountDomainSid, FspPrimaryDomainSid;
|
static PISID FspAccountDomainSid, FspPrimaryDomainSid;
|
||||||
|
|
||||||
|
#define FspUnmappedSid (&FspUnmappedSidBuf.V)
|
||||||
|
#define FspUnmappedUid (7)
|
||||||
|
|
||||||
static BOOL WINAPI FspPosixInitialize(
|
static BOOL WINAPI FspPosixInitialize(
|
||||||
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
||||||
{
|
{
|
||||||
@ -104,6 +119,8 @@ VOID FspPosixFinalize(BOOLEAN Dynamic)
|
|||||||
|
|
||||||
FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
|
FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
|
||||||
{
|
{
|
||||||
|
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
|
||||||
|
|
||||||
*PSid = 0;
|
*PSid = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -157,8 +174,6 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
|
|||||||
*/
|
*/
|
||||||
else if (0x30000 <= Uid && Uid < 0x40000)
|
else if (0x30000 <= Uid && Uid < 0x40000)
|
||||||
{
|
{
|
||||||
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
|
|
||||||
|
|
||||||
if (0 != FspAccountDomainSid &&
|
if (0 != FspAccountDomainSid &&
|
||||||
5 == FspAccountDomainSid->IdentifierAuthority.Value[5] &&
|
5 == FspAccountDomainSid->IdentifierAuthority.Value[5] &&
|
||||||
4 == FspAccountDomainSid->SubAuthorityCount)
|
4 == FspAccountDomainSid->SubAuthorityCount)
|
||||||
@ -173,8 +188,6 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
|
|||||||
}
|
}
|
||||||
else if (0x100000 <= Uid && Uid < 0x200000)
|
else if (0x100000 <= Uid && Uid < 0x200000)
|
||||||
{
|
{
|
||||||
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
|
|
||||||
|
|
||||||
if (0 != FspPrimaryDomainSid &&
|
if (0 != FspPrimaryDomainSid &&
|
||||||
5 == FspPrimaryDomainSid->IdentifierAuthority.Value[5] &&
|
5 == FspPrimaryDomainSid->IdentifierAuthority.Value[5] &&
|
||||||
4 == FspPrimaryDomainSid->SubAuthorityCount)
|
4 == FspPrimaryDomainSid->SubAuthorityCount)
|
||||||
@ -214,13 +227,15 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
|
|||||||
*PSid = FspPosixCreateSid(5, 2, Uid >> 12, Uid & 0xfff);
|
*PSid = FspPosixCreateSid(5, 2, Uid >> 12, Uid & 0xfff);
|
||||||
|
|
||||||
if (0 == *PSid)
|
if (0 == *PSid)
|
||||||
return STATUS_NONE_MAPPED;
|
*PSid = FspUnmappedSid;
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
|
FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
|
||||||
{
|
{
|
||||||
|
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
|
||||||
|
|
||||||
BYTE Authority;
|
BYTE Authority;
|
||||||
BYTE Count;
|
BYTE Count;
|
||||||
UINT32 SubAuthority0, Rid;
|
UINT32 SubAuthority0, Rid;
|
||||||
@ -274,8 +289,6 @@ FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
|
|||||||
*/
|
*/
|
||||||
else if (5 <= Count && 21 == SubAuthority0)
|
else if (5 <= Count && 21 == SubAuthority0)
|
||||||
{
|
{
|
||||||
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The order is important! A server that is also a domain controller
|
* The order is important! A server that is also a domain controller
|
||||||
* has PrimaryDomainSid == AccountDomainSid.
|
* has PrimaryDomainSid == AccountDomainSid.
|
||||||
@ -322,7 +335,7 @@ FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-1 == *PUid)
|
if (-1 == *PUid)
|
||||||
return STATUS_NONE_MAPPED;
|
*PUid = FspUnmappedUid;
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -351,7 +364,9 @@ static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...)
|
|||||||
|
|
||||||
FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)())
|
FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)())
|
||||||
{
|
{
|
||||||
if ((NTSTATUS (*)())FspPosixMapUidToSid == CreateFunc)
|
if (FspUnmappedSid == Sid)
|
||||||
|
;
|
||||||
|
else if ((NTSTATUS (*)())FspPosixMapUidToSid == CreateFunc)
|
||||||
MemFree(Sid);
|
MemFree(Sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,7 +273,7 @@ BOOLEAN MemfsFileNodeMapEnumerateDescendants(MEMFS_FILE_NODE_MAP *FileNodeMap, M
|
|||||||
|
|
||||||
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
PVOID FileNode0, UINT64 FileSize,
|
PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo);
|
FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
|
|
||||||
static NTSTATUS GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||||
@ -564,7 +564,7 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
Offset = FileNode->FileInfo.FileSize;
|
Offset = FileNode->FileInfo.FileSize;
|
||||||
EndOffset = Offset + Length;
|
EndOffset = Offset + Length;
|
||||||
if (EndOffset > FileNode->FileInfo.FileSize)
|
if (EndOffset > FileNode->FileInfo.FileSize)
|
||||||
SetFileSize(FileSystem, Request, FileNode, EndOffset, FileInfo);
|
SetFileSize(FileSystem, Request, FileNode, EndOffset, FALSE, FileInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset));
|
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset));
|
||||||
@ -617,59 +617,52 @@ static NTSTATUS SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS SetAllocationSize(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
PVOID FileNode0, UINT64 AllocationSize,
|
PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
{
|
{
|
||||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
PVOID FileData;
|
|
||||||
|
|
||||||
if (FileNode->FileInfo.AllocationSize != AllocationSize)
|
if (SetAllocationSize)
|
||||||
{
|
{
|
||||||
if (AllocationSize > Memfs->MaxFileSize)
|
if (FileNode->FileInfo.AllocationSize != NewSize)
|
||||||
|
{
|
||||||
|
if (NewSize > Memfs->MaxFileSize)
|
||||||
return STATUS_DISK_FULL;
|
return STATUS_DISK_FULL;
|
||||||
|
|
||||||
FileData = realloc(FileNode->FileData, (size_t)AllocationSize);
|
PVOID FileData = realloc(FileNode->FileData, (size_t)NewSize);
|
||||||
if (0 == FileData && 0 != AllocationSize)
|
if (0 == FileData && 0 != NewSize)
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
FileNode->FileData = FileData;
|
FileNode->FileData = FileData;
|
||||||
|
|
||||||
FileNode->FileInfo.AllocationSize = AllocationSize;
|
FileNode->FileInfo.AllocationSize = NewSize;
|
||||||
if (FileNode->FileInfo.FileSize > AllocationSize)
|
if (FileNode->FileInfo.FileSize > NewSize)
|
||||||
FileNode->FileInfo.FileSize = AllocationSize;
|
FileNode->FileInfo.FileSize = NewSize;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
*FileInfo = FileNode->FileInfo;
|
else
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode0, UINT64 FileSize,
|
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
|
||||||
{
|
|
||||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
|
||||||
|
|
||||||
if (FileNode->FileInfo.FileSize != FileSize)
|
|
||||||
{
|
{
|
||||||
if (FileNode->FileInfo.AllocationSize < FileSize)
|
if (FileNode->FileInfo.FileSize != NewSize)
|
||||||
|
{
|
||||||
|
if (FileNode->FileInfo.AllocationSize < NewSize)
|
||||||
{
|
{
|
||||||
UINT64 AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
|
UINT64 AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
|
||||||
UINT64 AllocationSize = (FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
UINT64 AllocationSize = (NewSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
||||||
|
|
||||||
NTSTATUS Result = SetAllocationSize(FileSystem, Request, FileNode, AllocationSize, FileInfo);
|
NTSTATUS Result = SetFileSize(FileSystem, Request, FileNode, AllocationSize, TRUE,
|
||||||
|
FileInfo);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FileNode->FileInfo.FileSize < FileSize)
|
if (FileNode->FileInfo.FileSize < NewSize)
|
||||||
memset((PUINT8)FileNode->FileData + FileNode->FileInfo.FileSize, 0,
|
memset((PUINT8)FileNode->FileData + FileNode->FileInfo.FileSize, 0,
|
||||||
(size_t)(FileSize - FileNode->FileInfo.FileSize));
|
(size_t)(NewSize - FileNode->FileInfo.FileSize));
|
||||||
FileNode->FileInfo.FileSize = FileSize;
|
FileNode->FileInfo.FileSize = NewSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*FileInfo = FileNode->FileInfo;
|
*FileInfo = FileNode->FileInfo;
|
||||||
@ -952,7 +945,6 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
|||||||
Flush,
|
Flush,
|
||||||
GetFileInfo,
|
GetFileInfo,
|
||||||
SetBasicInfo,
|
SetBasicInfo,
|
||||||
SetAllocationSize,
|
|
||||||
SetFileSize,
|
SetFileSize,
|
||||||
CanDelete,
|
CanDelete,
|
||||||
Rename,
|
Rename,
|
||||||
|
Reference in New Issue
Block a user