Compare commits

...

4 Commits
v1.3B3 ... v1.3

5 changed files with 82 additions and 79 deletions

View File

@ -1,6 +1,24 @@
= Changelog = Changelog
v1.3 (2018.1)::
Changes since v1.2POST1:
* Multiple Launcher changes:
** New `FspLaunch` API. File systems can be started, stopped, queried and listed using `FspLaunchStart`, `FspLaunchStop`, `FspLaunchGetInfo` and `FspLaunchGetNameList`. The API is available in <winfsp/launch.h>
** New Launcher registry settings `RunAs` and `WorkDirectory`. `RunAs` allows the laucher to launch a file system process under the service accounts LocalService and NetworkService. `WorkDirectory` can be used to specify the work directory for a newly launched file system process.
* `FSP_FSCTL_VOLUME_PARAMS::FlushAndPurgeOnCleanup` limits the time that Windows keeps files open after an application has closed them. This purges the cache on the last `CloseHandle`, which is a performance drawback.
** This is now the default behavior on FUSE. To revert to the previous behavior of keeping files open indefinitely use `-o KeepFileCache`.
* `FSP_FSCTL_VOLUME_PARAMS` has been extended with fine-grained timeouts: `VolumeInfoTimeout`, `DirInfoTimeout`, `SecurityTimeout`, `StreamInfoTimeout`. Set `FSP_FSCTL_VOLUME_PARAMS::Version == sizeof(FSP_FSCTL_VOLUME_PARAMS)` to access the new fields.
** New FUSE optons `VolumeInfoTimeout`, `DirInfoTimeout` complement the existing `FileInfoTimeout`.
* The FSD (File System Driver) and its interaction with the Windows MUP (Multiple UNC Provider) has been changed. In practice this eliminates the delays experienced when right-clicking on a WinFsp-backed network drive in the Windows Explorer. (GitHub issue #87.)
* The WinFsp network provider is now added first in the provider order list. Previously it was added last. (GitHub PR #131; thanks @felfert.)
* The WinFsp installer now uses the Wix `Provides` dependency extension to provide a `WinFsp` dependency key. (GitHub PR #129; thanks @felfert.)
* New FUSE `create_umask` option. (GitHub issue #138.)
* Fix C++ compilation error for WinFsp-FUSE. (GitHub PR #154; thanks @benrubson.)
v1.3B3 (2018.1 B3):: v1.3B3 (2018.1 B3)::
Changes since v1.2POST1: Changes since v1.2POST1:

View File

@ -18,8 +18,8 @@
<MyCanonicalVersion>1.3</MyCanonicalVersion> <MyCanonicalVersion>1.3</MyCanonicalVersion>
<MyProductVersion>2018.1 B3</MyProductVersion> <MyProductVersion>2018.1</MyProductVersion>
<MyProductStage>Beta</MyProductStage> <MyProductStage>Gold</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion> <MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas> <MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>

View File

@ -376,6 +376,15 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
&f->VolumeParams.VolumeCreationTime); &f->VolumeParams.VolumeCreationTime);
} }
} }
if (0 != f->ops.readlink)
{
char buf[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
int err;
/* this should always fail with ENOSYS or EINVAL */
err = f->ops.readlink("/", buf, sizeof buf);
f->has_symlinks = -ENOSYS != err;
}
/* the FSD does not currently limit these VolumeParams fields; do so here! */ /* the FSD does not currently limit these VolumeParams fields; do so here! */
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN || if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN ||

View File

@ -29,7 +29,7 @@
#define FSP_FUSE_CONTEXT_FROM_HDR(h) \ #define FSP_FUSE_CONTEXT_FROM_HDR(h) \
(struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header)) (struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header))
#define FSP_FUSE_HAS_SYMLINKS(f) (0 != (f)->ops.readlink) #define FSP_FUSE_HAS_SYMLINKS(f) ((f)->has_symlinks)
struct fuse struct fuse
{ {
@ -44,6 +44,7 @@ struct fuse
void *data; void *data;
unsigned conn_want; unsigned conn_want;
BOOLEAN fsinit; BOOLEAN fsinit;
BOOLEAN has_symlinks;
UINT32 DebugLog; UINT32 DebugLog;
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy; FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
FSP_FSCTL_VOLUME_PARAMS VolumeParams; FSP_FSCTL_VOLUME_PARAMS VolumeParams;

View File

@ -150,92 +150,67 @@ UINT64 MemfsGetSystemTime(VOID)
} }
static inline static inline
int MemfsFileNameCompare(PWSTR a0, int alen, PWSTR b0, int blen, BOOLEAN CaseInsensitive) int MemfsFileNameCompare(PWSTR a, int alen, PWSTR b, int blen, BOOLEAN CaseInsensitive)
{ {
/* PWSTR p, endp, partp, q, endq, partq;
* HACKFIX GITHUB ISSUE #103 WCHAR c, d;
* int plen, qlen, len, res;
* MEMFS stores the whole file system in a single map. This was to keep the file system
* "simple", but in retrospect it was probably a bad decision as it creates multiple problems.
*
* One of these problems was what caused GitHub issue #103. A directory that had both "Firefox"
* and "Firefox64" subdirectories in it would cause directory listings of "Firefox" to fail,
* because "Firefox\\" (and "Firefox:") comes *after* "Firefox64" in case-sensitive or
* case-insensitive order!
*
* The hackfix is this: copy our input strings into temporary buffers and then translate ':' to
* '\x1' and '\\' to '\x2' so they always order the FileName map properly.
*/
WCHAR a[MEMFS_MAX_PATH], b[MEMFS_MAX_PATH];
int len, res;
if (-1 == alen) if (-1 == alen)
{ alen = lstrlenW(a);
PWSTR p = a0, q = a;
for (; *p; p++, q++)
if (L':' == *p)
*q = L'\x1';
else if (L'\\' == *p)
*q = L'\x2';
else
*q = *p;
alen = (int)(p - a0);
}
else
{
PWSTR p = a0, q = a;
for (PWSTR endp = p + alen; endp > p; p++, q++)
if (L':' == *p)
*q = L'\x1';
else if (L'\\' == *p)
*q = L'\x2';
else
*q = *p;
}
if (-1 == blen) if (-1 == blen)
{ blen = lstrlenW(b);
PWSTR p = b0, q = b;
for (; *p; p++, q++)
if (L':' == *p)
*q = L'\x1';
else if (L'\\' == *p)
*q = L'\x2';
else
*q = *p;
blen = (int)(p - b0);
}
else
{
PWSTR p = b0, q = b;
for (PWSTR endp = p + blen; endp > p; p++, q++)
if (L':' == *p)
*q = L'\x1';
else if (L'\\' == *p)
*q = L'\x2';
else
*q = *p;
}
len = alen < blen ? alen : blen; for (p = a, endp = p + alen, q = b, endq = q + blen; endp > p && endq > q;)
{
c = d = 0;
for (; endp > p && (L':' == *p || L'\\' == *p); p++)
c = *p;
for (; endq > q && (L':' == *q || L'\\' == *q); q++)
d = *q;
if (L':' == c)
c = 1;
else if (L'\\' == c)
c = 2;
if (L':' == d)
d = 1;
else if (L'\\' == d)
d = 2;
res = c - d;
if (0 != res)
return res;
for (partp = p; endp > p && L':' != *p && L'\\' != *p; p++)
;
for (partq = q; endq > q && L':' != *q && L'\\' != *q; q++)
;
plen = (int)(p - partp);
qlen = (int)(q - partq);
len = plen < qlen ? plen : qlen;
if (CaseInsensitive) if (CaseInsensitive)
{ {
/* better Unicode comparison when case-insensitive */ res = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, partp, plen, partq, qlen);
res = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, a, alen, b, blen);
if (0 != res) if (0 != res)
res -= 2; res -= 2;
else else
res = _wcsnicmp(a, b, len); res = _wcsnicmp(partp, partq, len);
} }
else else
res = wcsncmp(a, b, len); res = wcsncmp(partp, partq, len);
if (0 == res) if (0 == res)
res = alen - blen; res = plen - qlen;
if (0 != res)
return res; return res;
}
return -(endp <= p) + (endq <= q);
} }
static inline static inline