Compare commits

...

18 Commits

Author SHA1 Message Date
2a3eabfab2 changelog: v1.2POST1 2017-12-12 10:07:54 -08:00
35255526d3 launcher: work around Win7 CreateProcess problem 2017-12-11 21:40:47 -08:00
b2e474658d launcher: work around Win7 CreateProcess problem 2017-12-11 21:23:38 -08:00
a2ec40008f build: choco: update chocolatey package as per guidelines from chocolatey admin 2017-12-06 16:24:27 -08:00
f3819ba839 tst: passthrough-dotnet: fix ReadDirectoryEntry when running fs over drive root 2017-12-05 18:50:39 -08:00
ead599e337 tst: passthrough-dotnet: handle undoc wildcards in ReadDirectoryEntry
- reported by Pavel Franc over email
2017-12-05 10:32:58 -08:00
eb88f25f40 tst: passthrough-dotnet: Create,Overwrite: set archive bit 2017-12-04 16:24:48 -08:00
c2b066a054 dll: fuse: Create: do not add FILE_ATTRIBUTE_ARCHIVE for directories 2017-12-04 14:16:24 -08:00
266e0f4bab dll: fuse: call chflags from Create and Overwrite
tst: winfsp-tests: file attributes test
2017-12-04 14:08:44 -08:00
d02030897d dll: fuse: add O_EXCL during FUSE create op 2017-12-03 19:56:36 -08:00
c87ff75b8f sys: fix filename length check during query directory operations 2017-12-01 17:01:59 -08:00
2ca33665ef update changelog 2017-11-29 16:28:21 -08:00
391dcf8a21 build: update version to 1.2 (Gold) 2017-11-29 16:24:19 -08:00
69d68eb22f launcher: compute user name from client token
dll: np: do not pass user name as launcher argument
2017-11-29 16:20:15 -08:00
d58f4b84a5 opt: cygfuse: update tarballs 2017-11-28 16:53:21 -08:00
61935e4671 tst: passthrough-fuse: gix cygwin build 2017-11-28 16:52:36 -08:00
41838627c0 update README 2017-11-28 15:55:06 -08:00
0b67329fc2 doc: update known file systems 2017-11-28 15:46:07 -08:00
27 changed files with 498 additions and 83 deletions

View File

@ -1,6 +1,32 @@
= Changelog = Changelog
v1.2POST1 (2017.2; issue #127)::
Changes since v1.1:
- WinFsp-FUSE now supports BSD flags (Windows file attributes) during `getattr` and `fgetattr`. It also adds the `chflags` operation. BSD flags support requires use of the `FSP_FUSE_CAP_STAT_EX` capability and the new `struct fuse_stat_ex` which includes an `st_flags` field. If the preprocessor macro `FSP_FUSE_USE_STAT_EX` is defined before inclusion of `<fuse.h>` then `struct fuse_stat` will also be defined to include the `st_flags` field.
- WinFsp-FUSE also adds the following OSXFUSE operations: `setcrtime`, `setchgtime`. These can be used to set the creation (birth) time and change (ctime) time of a file.
- New `GetDirInfoByName` file system operation adds fast queries of directory info by file name rather than pattern [e.g. `FindFirstFileW(L"foobar", FindData)`]. Tests with fsbench showed that such queries are sped up by an order of magnitude when using `GetDirInfoByName` in MEMFS. Case-sensitive FUSE file systems get this optimization for free. The .NET layer also adds `GetDirInfoByName`.
- New `FspFileSystemOperationProcessId` API adds support for getting the originating process ID (PID) during `Create`, `Open` and `Rename` calls. FUSE file systems can now access `fuse_context::pid`. The .NET layer also adds `GetOperationProcessId`.
- New command line tool `fsptool` allows command line access to some WinFsp features.
- The WinFsp launcher now passes the name of the user who launched the file system as a special parameter %U. This is useful to file systems that use the launcher infrastructure, such as SSHFS-Win. [Please note that in earlier betas the user name was passed as parameter %3; the previous method was insecure and is no longer supported.]
- Important GitHub issues fixed: #96, #97, #103, #107, #127
v1.2 (2017.2)::
Changes since v1.1:
- WinFsp-FUSE now supports BSD flags (Windows file attributes) during `getattr` and `fgetattr`. It also adds the `chflags` operation. BSD flags support requires use of the `FSP_FUSE_CAP_STAT_EX` capability and the new `struct fuse_stat_ex` which includes an `st_flags` field. If the preprocessor macro `FSP_FUSE_USE_STAT_EX` is defined before inclusion of `<fuse.h>` then `struct fuse_stat` will also be defined to include the `st_flags` field.
- WinFsp-FUSE also adds the following OSXFUSE operations: `setcrtime`, `setchgtime`. These can be used to set the creation (birth) time and change (ctime) time of a file.
- New `GetDirInfoByName` file system operation adds fast queries of directory info by file name rather than pattern [e.g. `FindFirstFileW(L"foobar", FindData)`]. Tests with fsbench showed that such queries are sped up by an order of magnitude when using `GetDirInfoByName` in MEMFS. Case-sensitive FUSE file systems get this optimization for free. The .NET layer also adds `GetDirInfoByName`.
- New `FspFileSystemOperationProcessId` API adds support for getting the originating process ID (PID) during `Create`, `Open` and `Rename` calls. FUSE file systems can now access `fuse_context::pid`. The .NET layer also adds `GetOperationProcessId`.
- New command line tool `fsptool` allows command line access to some WinFsp features.
- The WinFsp launcher now passes the name of the user who launched the file system as a special parameter %U. This is useful to file systems that use the launcher infrastructure, such as SSHFS-Win. [Please note that in earlier betas the user name was passed as parameter %3; the previous method was insecure and is no longer supported.]
- Important GitHub issues fixed: #96, #97, #103, #107
v1.2B3 (2017.2 B3):: v1.2B3 (2017.2 B3)::
Changes since v1.1: Changes since v1.1:

View File

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

View File

@ -310,12 +310,12 @@
<Directory Id="OPTDIR.cygfuse" Name="cygfuse" FileSource="..\..\..\opt\cygfuse\dist"> <Directory Id="OPTDIR.cygfuse" Name="cygfuse" FileSource="..\..\..\opt\cygfuse\dist">
<Directory Id="OPTDIR.cygfuse.x64" Name="x64"> <Directory Id="OPTDIR.cygfuse.x64" Name="x64">
<Component Id="C.fuse.tar.xz.x64"> <Component Id="C.fuse.tar.xz.x64">
<File Id="FILE.fuse.tar.xz.x64" Name="fuse-2.8-6.tar.xz" KeyPath="yes" /> <File Id="FILE.fuse.tar.xz.x64" Name="fuse-2.8-7.tar.xz" KeyPath="yes" />
</Component> </Component>
</Directory> </Directory>
<Directory Id="OPTDIR.cygfuse.x86" Name="x86"> <Directory Id="OPTDIR.cygfuse.x86" Name="x86">
<Component Id="C.fuse.tar.xz.x86"> <Component Id="C.fuse.tar.xz.x86">
<File Id="FILE.fuse.tar.xz.x86" Name="fuse-2.8-6.tar.xz" KeyPath="yes" /> <File Id="FILE.fuse.tar.xz.x86" Name="fuse-2.8-7.tar.xz" KeyPath="yes" />
</Component> </Component>
</Directory> </Directory>
<Component Id="C.fuse.install.sh"> <Component Id="C.fuse.install.sh">

View File

@ -18,8 +18,8 @@
<MyCanonicalVersion>1.2</MyCanonicalVersion> <MyCanonicalVersion>1.2</MyCanonicalVersion>
<MyProductVersion>2017.2 B3</MyProductVersion> <MyProductVersion>2017.2</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

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

View File

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

View File

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

View File

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

View File

@ -4,6 +4,8 @@ This document contains a list of known file systems and file system libraries th
== File Systems == 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/billziss-gh/nfs-win[nfs-win] - NFS for Windows
- https://github.com/ncw/rclone[rclone] - rsync for cloud storage - https://github.com/ncw/rclone[rclone] - rsync for cloud storage
- https://github.com/hasse69/rar2fs[rar2fs] - FUSE file system for reading RAR archives - https://github.com/hasse69/rar2fs[rar2fs] - FUSE file system for reading RAR archives

View File

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

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

View File

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

View File

@ -765,9 +765,9 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
memset(&fi, 0, sizeof fi); memset(&fi, 0, sizeof fi);
if ('C' == f->env->environment) /* Cygwin */ if ('C' == f->env->environment) /* Cygwin */
fi.flags = 0x0200 | 2 /*O_CREAT|O_RDWR*/; fi.flags = 0x0200 | 0x0800 | 2 /*O_CREAT|O_EXCL|O_RDWR*/;
else else
fi.flags = 0x0100 | 2 /*O_CREAT|O_RDWR*/; fi.flags = 0x0100 | 0x0400 | 2 /*O_CREAT|O_EXCL|O_RDWR*/;
if (CreateOptions & FILE_DIRECTORY_FILE) if (CreateOptions & FILE_DIRECTORY_FILE)
{ {
@ -821,15 +821,24 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
Opened = TRUE; Opened = TRUE;
if (Uid != context->uid || Gid != context->gid) if (0 != FileAttributes &&
if (0 != f->ops.chown) 0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX) && 0 != f->ops.chflags)
{
err = f->ops.chown(contexthdr->PosixPath, Uid, Gid);
if (0 != err)
{ {
err = f->ops.chflags(contexthdr->PosixPath,
fsp_fuse_intf_MapFileAttributesToFlags(CreateOptions & FILE_DIRECTORY_FILE ?
FileAttributes : FileAttributes | FILE_ATTRIBUTE_ARCHIVE));
Result = fsp_fuse_ntstatus_from_errno(f->env, err); Result = fsp_fuse_ntstatus_from_errno(f->env, err);
if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result)
goto exit; goto exit;
} }
if ((Uid != context->uid || Gid != context->gid) &&
0 != f->ops.chown)
{
err = f->ops.chown(contexthdr->PosixPath, Uid, Gid);
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result)
goto exit;
} }
/* /*
@ -1015,6 +1024,22 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
if (0 != FileAttributes &&
0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX) && 0 != f->ops.chflags)
{
/*
* The code below is not strictly correct. File attributes should be
* replaced when ReplaceFileAttributes is TRUE and merged (or'ed) when
* ReplaceFileAttributes is FALSE. I am punting on this detail for now.
*/
err = f->ops.chflags(filedesc->PosixPath,
fsp_fuse_intf_MapFileAttributesToFlags(FileAttributes | FILE_ATTRIBUTE_ARCHIVE));
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result)
return Result;
}
return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi,
&Uid, &Gid, &Mode, FileInfo); &Uid, &Gid, &Mode, FileInfo);
} }

View File

@ -17,7 +17,6 @@
#include <dll/library.h> #include <dll/library.h>
#include <launcher/launcher.h> #include <launcher/launcher.h>
#include <lmcons.h>
#include <npapi.h> #include <npapi.h>
#include <wincred.h> #include <wincred.h>
@ -169,12 +168,6 @@ static inline BOOLEAN FspNpParseRemoteUserName(PWSTR RemoteName,
return FALSE; return FALSE;
} }
static inline BOOLEAN FspNpGetLocalUserName(
PWSTR UserName, ULONG UserNameSize/* in chars */)
{
return GetUserName(UserName, &UserNameSize);
}
static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize) static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
{ {
DWORD NpResult; DWORD NpResult;
@ -496,7 +489,6 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
WCHAR LocalNameBuf[3]; WCHAR LocalNameBuf[3];
PWSTR ClassName, InstanceName, RemoteName, P; PWSTR ClassName, InstanceName, RemoteName, P;
ULONG ClassNameLen, InstanceNameLen; ULONG ClassNameLen, InstanceNameLen;
WCHAR LocalUserName[UNLEN + 1];
DWORD CredentialsKind; DWORD CredentialsKind;
PWSTR PipeBuf = 0; PWSTR PipeBuf = 0;
#if defined(FSP_NP_CREDENTIAL_MANAGER) #if defined(FSP_NP_CREDENTIAL_MANAGER)
@ -525,9 +517,6 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
return WN_ALREADY_CONNECTED; return WN_ALREADY_CONNECTED;
} }
if (!FspNpGetLocalUserName(LocalUserName, sizeof LocalUserName / sizeof LocalUserName[0]))
LocalUserName[0] = L'\0';
FspNpGetCredentialsKind(lpRemoteName, &CredentialsKind); FspNpGetCredentialsKind(lpRemoteName, &CredentialsKind);
#if defined(FSP_NP_CREDENTIAL_MANAGER) #if defined(FSP_NP_CREDENTIAL_MANAGER)
@ -582,7 +571,6 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0'; memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
lstrcpyW(P, RemoteName); P += lstrlenW(RemoteName) + 1; lstrcpyW(P, RemoteName); P += lstrlenW(RemoteName) + 1;
lstrcpyW(P, LocalNameBuf); P += lstrlenW(LocalNameBuf) + 1; lstrcpyW(P, LocalNameBuf); P += lstrlenW(LocalNameBuf) + 1;
lstrcpyW(P, LocalUserName); P += lstrlenW(LocalUserName) + 1;
if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind) if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
{ {
lstrcpyW(P, lpUserName); P += lstrlenW(lpUserName) + 1; lstrcpyW(P, lpUserName); P += lstrlenW(lpUserName) + 1;

View File

@ -21,12 +21,16 @@
#define PROGNAME "WinFsp.Launcher" #define PROGNAME "WinFsp.Launcher"
BOOL CreateOverlappedPipe( BOOL CreateOverlappedPipe(
PHANDLE PReadPipe, PHANDLE PWritePipe, PSECURITY_ATTRIBUTES SecurityAttributes, DWORD Size, PHANDLE PReadPipe, PHANDLE PWritePipe,
DWORD Size,
BOOL ReadInherit, BOOL WriteInherit,
DWORD ReadMode, DWORD WriteMode) DWORD ReadMode, DWORD WriteMode)
{ {
RPC_STATUS RpcStatus; RPC_STATUS RpcStatus;
UUID Uuid; UUID Uuid;
WCHAR PipeNameBuf[MAX_PATH]; WCHAR PipeNameBuf[MAX_PATH];
SECURITY_ATTRIBUTES ReadSecurityAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, ReadInherit };
SECURITY_ATTRIBUTES WriteSecurityAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, WriteInherit };
HANDLE ReadPipe, WritePipe; HANDLE ReadPipe, WritePipe;
DWORD LastError; DWORD LastError;
@ -46,13 +50,13 @@ BOOL CreateOverlappedPipe(
ReadPipe = CreateNamedPipeW(PipeNameBuf, ReadPipe = CreateNamedPipeW(PipeNameBuf,
PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | ReadMode, PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | ReadMode,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
1, Size, Size, 120 * 1000, SecurityAttributes); 1, Size, Size, 120 * 1000, &ReadSecurityAttributes);
if (INVALID_HANDLE_VALUE == ReadPipe) if (INVALID_HANDLE_VALUE == ReadPipe)
return FALSE; return FALSE;
WritePipe = CreateFileW(PipeNameBuf, WritePipe = CreateFileW(PipeNameBuf,
GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
SecurityAttributes, OPEN_EXISTING, WriteMode, 0); &WriteSecurityAttributes, OPEN_EXISTING, WriteMode, 0);
if (INVALID_HANDLE_VALUE == WritePipe) if (INVALID_HANDLE_VALUE == WritePipe)
{ {
LastError = GetLastError(); LastError = GetLastError();
@ -67,6 +71,76 @@ BOOL CreateOverlappedPipe(
return TRUE; 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 typedef struct
{ {
HANDLE Process; HANDLE Process;
@ -142,6 +216,17 @@ typedef struct
static CRITICAL_SECTION SvcInstanceLock; static CRITICAL_SECTION SvcInstanceLock;
static HANDLE SvcInstanceEvent; static HANDLE SvcInstanceEvent;
static LIST_ENTRY SvcInstanceList = { &SvcInstanceList, &SvcInstanceList }; static LIST_ENTRY SvcInstanceList = { &SvcInstanceList, &SvcInstanceList };
static DWORD SvcInstanceTlsKey = TLS_OUT_OF_INDEXES;
static inline PWSTR SvcInstanceUserName(VOID)
{
return TlsGetValue(SvcInstanceTlsKey);
}
static inline VOID SvcInstanceSetUserName(PWSTR UserName)
{
TlsSetValue(SvcInstanceTlsKey, UserName);
}
static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Timeout); static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Timeout);
@ -210,6 +295,14 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
else else
Length += SvcInstanceArgumentLength(EmptyArg); Length += SvcInstanceArgumentLength(EmptyArg);
} }
else
if (L'U' == *P)
{
if (0 != SvcInstanceUserName())
Length += SvcInstanceArgumentLength(SvcInstanceUserName());
else
Length += SvcInstanceArgumentLength(EmptyArg);
}
else else
Length++; Length++;
break; break;
@ -236,6 +329,14 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
else else
Q = SvcInstanceArgumentCopy(Q, EmptyArg); Q = SvcInstanceArgumentCopy(Q, EmptyArg);
} }
else
if (L'U' == *P)
{
if (0 != SvcInstanceUserName())
Q = SvcInstanceArgumentCopy(Q, SvcInstanceUserName());
else
Q = SvcInstanceArgumentCopy(Q, EmptyArg);
}
else else
*Q++ = *P; *Q++ = *P;
break; break;
@ -286,7 +387,6 @@ NTSTATUS SvcInstanceCreateProcess(PWSTR Executable, PWSTR CommandLine,
STARTUPINFOEXW StartupInfoEx; STARTUPINFOEXW StartupInfoEx;
HANDLE ChildHandles[3] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0/* DO NOT CLOSE!*/ }; HANDLE ChildHandles[3] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0/* DO NOT CLOSE!*/ };
HANDLE ParentHandles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; HANDLE ParentHandles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
SECURITY_ATTRIBUTES PipeAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, TRUE };
PPROC_THREAD_ATTRIBUTE_LIST AttrList = 0; PPROC_THREAD_ATTRIBUTE_LIST AttrList = 0;
SIZE_T Size; SIZE_T Size;
NTSTATUS Result; NTSTATUS Result;
@ -304,16 +404,16 @@ NTSTATUS SvcInstanceCreateProcess(PWSTR Executable, PWSTR CommandLine,
*/ */
/* create stdin read/write ends; make them inheritable */ /* create stdin read/write ends; make them inheritable */
if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0], &PipeAttributes, 0, if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0],
0, 0)) 0, TRUE, FALSE, 0, 0))
{ {
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());
goto exit; goto exit;
} }
/* create stdout read/write ends; make them inheritable */ /* create stdout read/write ends; make them inheritable */
if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1], &PipeAttributes, 0, if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1],
FILE_FLAG_OVERLAPPED, 0)) 0, FALSE, TRUE, FILE_FLAG_OVERLAPPED, 0))
{ {
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());
goto exit; goto exit;
@ -360,10 +460,30 @@ NTSTATUS SvcInstanceCreateProcess(PWSTR Executable, PWSTR CommandLine,
if (!CreateProcessW(Executable, CommandLine, 0, 0, TRUE, if (!CreateProcessW(Executable, CommandLine, 0, 0, TRUE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT, 0, 0, CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT, 0, 0,
&StartupInfoEx.StartupInfo, ProcessInfo)) &StartupInfoEx.StartupInfo, ProcessInfo))
{
if (ERROR_NO_SYSTEM_RESOURCES != GetLastError())
{ {
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());
goto exit; goto exit;
} }
/*
* On Win7 CreateProcessW with EXTENDED_STARTUPINFO_PRESENT
* may fail with ERROR_NO_SYSTEM_RESOURCES.
*
* In that case go ahead and retry with a CreateProcessW with
* bInheritHandles==TRUE, but without EXTENDED_STARTUPINFO_PRESENT.
* Not ideal, but...
*/
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo;
if (!CreateProcessW(Executable, CommandLine, 0, 0, TRUE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP, 0, 0,
&StartupInfoEx.StartupInfo, ProcessInfo))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
} }
else else
{ {
@ -752,6 +872,10 @@ exit:
SvcInstanceRelease(SvcInstance); SvcInstanceRelease(SvcInstance);
if (STATUS_TIMEOUT == Result)
/* convert to an error! */
Result = 0x80070000 | ERROR_TIMEOUT;
return Result; return Result;
} }
@ -918,6 +1042,10 @@ static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
if (0 == SvcInstanceEvent) if (0 == SvcInstanceEvent)
goto fail; goto fail;
SvcInstanceTlsKey = TlsAlloc();
if (TLS_OUT_OF_INDEXES == SvcInstanceTlsKey)
goto fail;
SvcJob = CreateJobObjectW(0, 0); SvcJob = CreateJobObjectW(0, 0);
if (0 != SvcJob) if (0 != SvcJob)
{ {
@ -980,6 +1108,9 @@ fail:
if (0 != SvcJob) if (0 != SvcJob)
CloseHandle(SvcJob); CloseHandle(SvcJob);
if (TLS_OUT_OF_INDEXES != SvcInstanceTlsKey)
TlsFree(SvcInstanceTlsKey);
if (0 != SvcInstanceEvent) if (0 != SvcInstanceEvent)
CloseHandle(SvcInstanceEvent); CloseHandle(SvcInstanceEvent);
@ -1023,6 +1154,9 @@ static NTSTATUS SvcStop(FSP_SERVICE *Service)
if (0 != SvcJob) if (0 != SvcJob)
CloseHandle(SvcJob); CloseHandle(SvcJob);
if (TLS_OUT_OF_INDEXES != SvcInstanceTlsKey)
TlsFree(SvcInstanceTlsKey);
if (0 != SvcInstanceEvent) if (0 != SvcInstanceEvent)
CloseHandle(SvcInstanceEvent); CloseHandle(SvcInstanceEvent);
@ -1194,13 +1328,16 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
return; return;
PWSTR P = PipeBuf, PipeBufEnd = PipeBuf + *PSize / sizeof(WCHAR); PWSTR P = PipeBuf, PipeBufEnd = PipeBuf + *PSize / sizeof(WCHAR);
PWSTR ClassName, InstanceName; PWSTR ClassName, InstanceName, UserName;
ULONG Argc; PWSTR Argv[9]; ULONG Argc; PWSTR Argv[9];
BOOLEAN HasSecret = FALSE; BOOLEAN HasSecret = FALSE;
NTSTATUS Result; NTSTATUS Result;
*PSize = 0; *PSize = 0;
GetTokenUserName(ClientToken, &UserName);
SvcInstanceSetUserName(UserName);
switch (*P++) switch (*P++)
{ {
case LauncherSvcInstanceStartWithSecret: case LauncherSvcInstanceStartWithSecret:
@ -1264,6 +1401,9 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
SvcPipeTransactResult(STATUS_INVALID_PARAMETER, PipeBuf, PSize); SvcPipeTransactResult(STATUS_INVALID_PARAMETER, PipeBuf, PSize);
break; break;
} }
SvcInstanceSetUserName(0);
MemFree(UserName);
} }
int wmain(int argc, wchar_t **argv) int wmain(int argc, wchar_t **argv)

View File

@ -611,7 +611,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
if (0 != FileDesc->DirectoryMarker.Buffer) if (0 != FileDesc->DirectoryMarker.Buffer)
{ {
ASSERT( ASSERT(
FsvolDeviceExtension->VolumeParams.MaxComponentLength >= FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR) >=
FileDesc->DirectoryMarker.Length); FileDesc->DirectoryMarker.Length);
Request->Req.QueryDirectory.Marker.Offset = Request->Req.QueryDirectory.Marker.Offset =
@ -921,7 +921,7 @@ NTSTATUS FspFsvolDirectoryControlComplete(
if (0 != FileDesc->DirectoryMarker.Buffer) if (0 != FileDesc->DirectoryMarker.Buffer)
{ {
ASSERT( ASSERT(
FsvolDeviceExtension->VolumeParams.MaxComponentLength >= FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR) >=
FileDesc->DirectoryMarker.Length); FileDesc->DirectoryMarker.Length);
Request->Req.QueryDirectory.Marker.Offset = Request->Req.QueryDirectory.Marker.Offset =

View File

@ -2166,7 +2166,7 @@ NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
FspFsvolDeviceExtension(FileDesc->FileNode->FsvolDeviceObject); FspFsvolDeviceExtension(FileDesc->FileNode->FsvolDeviceObject);
UNICODE_STRING DirectoryMarker; UNICODE_STRING DirectoryMarker;
if (FsvolDeviceExtension->VolumeParams.MaxComponentLength < FileName->Length) if (FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR) < FileName->Length)
return STATUS_OBJECT_NAME_INVALID; return STATUS_OBJECT_NAME_INVALID;
DirectoryMarker.Length = DirectoryMarker.MaximumLength = FileName->Length; DirectoryMarker.Length = DirectoryMarker.MaximumLength = FileName->Length;

View File

@ -657,7 +657,7 @@ exit /b 0
:sample-passthrough-dotnet :sample-passthrough-dotnet
call :__run_sample_test passthrough-dotnet anycpu passthrough-dotnet winfsp-tests-x64 ^ call :__run_sample_test passthrough-dotnet anycpu passthrough-dotnet winfsp-tests-x64 ^
"-create_backup_test -create_restore_test -create_namelen_test -delete_access_test" "-create_backup_test -create_restore_test -create_namelen_test -delete_access_test -querydir_namelen_test"
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
@ -725,7 +725,7 @@ L:
"%ProjRoot%\build\VStudio\build\%Configuration%\%4.exe" ^ "%ProjRoot%\build\VStudio\build\%Configuration%\%4.exe" ^
--external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^ --external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^
-create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^ -create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^
-getfileinfo_name_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test -exec_rename_dir_test ^ -getfileinfo_name_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test -querydir_namelen_test -exec_rename_dir_test ^
-reparse* -stream* -reparse* -stream*
if !ERRORLEVEL! neq 0 set RunSampleTestExit=1 if !ERRORLEVEL! neq 0 set RunSampleTestExit=1
popd popd
@ -784,8 +784,8 @@ cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail)
L: L:
"%ProjRoot%\build\VStudio\build\%Configuration%\%3.exe" ^ "%ProjRoot%\build\VStudio\build\%Configuration%\%3.exe" ^
--external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^ --external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^
-create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^ -create_fileattr_test -create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^
-getfileinfo_name_test -setfileinfo_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test -exec_rename_dir_test ^ -getfileinfo_name_test -setfileinfo_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test -querydir_namelen_test -exec_rename_dir_test ^
-reparse* -stream* -reparse* -stream*
if !ERRORLEVEL! neq 0 set RunSampleTestExit=1 if !ERRORLEVEL! neq 0 set RunSampleTestExit=1
popd popd

View File

@ -375,6 +375,7 @@ namespace passthrough
4096, 4096,
0, 0,
Security)); Security));
FileDesc.SetFileAttributes(FileAttributes | (UInt32)System.IO.FileAttributes.Archive);
} }
else else
{ {
@ -388,8 +389,8 @@ namespace passthrough
} }
FileDesc = new FileDesc( FileDesc = new FileDesc(
Directory.CreateDirectory(FileName, Security)); Directory.CreateDirectory(FileName, Security));
}
FileDesc.SetFileAttributes(FileAttributes); FileDesc.SetFileAttributes(FileAttributes);
}
FileNode = default(Object); FileNode = default(Object);
FileDesc0 = FileDesc; FileDesc0 = FileDesc;
NormalizedName = default(String); NormalizedName = default(String);
@ -453,9 +454,11 @@ namespace passthrough
{ {
FileDesc FileDesc = (FileDesc)FileDesc0; FileDesc FileDesc = (FileDesc)FileDesc0;
if (ReplaceFileAttributes) if (ReplaceFileAttributes)
FileDesc.SetFileAttributes(FileAttributes); FileDesc.SetFileAttributes(FileAttributes |
(UInt32)System.IO.FileAttributes.Archive);
else if (0 != FileAttributes) else if (0 != FileAttributes)
FileDesc.SetFileAttributes(FileDesc.GetFileAttributes() | FileAttributes); FileDesc.SetFileAttributes(FileDesc.GetFileAttributes() | FileAttributes |
(UInt32)System.IO.FileAttributes.Archive);
FileDesc.Stream.SetLength(0); FileDesc.Stream.SetLength(0);
return FileDesc.GetFileInfo(out FileInfo); return FileDesc.GetFileInfo(out FileInfo);
} }
@ -637,11 +640,17 @@ namespace passthrough
FileDesc FileDesc = (FileDesc)FileDesc0; FileDesc FileDesc = (FileDesc)FileDesc0;
if (null == FileDesc.FileSystemInfos) if (null == FileDesc.FileSystemInfos)
{ {
IEnumerable Enum = FileDesc.DirInfo.EnumerateFileSystemInfos( if (null != Pattern)
null != Pattern ? Pattern : "*"); Pattern = Pattern.Replace('<', '*').Replace('>', '?').Replace('"', '.');
else
Pattern = "*";
IEnumerable Enum = FileDesc.DirInfo.EnumerateFileSystemInfos(Pattern);
SortedList List = new SortedList(); SortedList List = new SortedList();
if (null != FileDesc.DirInfo && null != FileDesc.DirInfo.Parent)
{
List.Add(".", FileDesc.DirInfo); List.Add(".", FileDesc.DirInfo);
List.Add("..", FileDesc.DirInfo.Parent); List.Add("..", FileDesc.DirInfo.Parent);
}
foreach (FileSystemInfo Info in Enum) foreach (FileSystemInfo Info in Enum)
List.Add(Info.Name, Info); List.Add(Info.Name, Info);
FileDesc.FileSystemInfos = new DictionaryEntry[List.Count]; FileDesc.FileSystemInfos = new DictionaryEntry[List.Count];

View File

@ -41,8 +41,8 @@
#define fi_fh(fi, MASK) ((fi)->fh & (MASK)) #define fi_fh(fi, MASK) ((fi)->fh & (MASK))
#define fi_setfh(fi, FH, MASK) ((fi)->fh = (intptr_t)(FH) | (MASK)) #define fi_setfh(fi, FH, MASK) ((fi)->fh = (intptr_t)(FH) | (MASK))
#define fi_fd(fi) (fi_fh(fi, fi_dirbit) ? \ #define fi_fd(fi) (fi_fh(fi, fi_dirbit) ? \
dirfd((DIR *)fi_fh(fi, ~fi_dirbit)) : (int)fi_fh(fi, ~fi_dirbit)) dirfd((DIR *)(intptr_t)fi_fh(fi, ~fi_dirbit)) : (int)fi_fh(fi, ~fi_dirbit))
#define fi_dirp(fi) ((DIR *)fi_fh(fi, ~fi_dirbit)) #define fi_dirp(fi) ((DIR *)(intptr_t)fi_fh(fi, ~fi_dirbit))
#define fi_setfd(fi, fd) (fi_setfh(fi, fd, 0)) #define fi_setfd(fi, fd) (fi_setfh(fi, fd, 0))
#define fi_setdirp(fi, dirp) (fi_setfh(fi, dirp, fi_dirbit)) #define fi_setdirp(fi, dirp) (fi_setfh(fi, dirp, fi_dirbit))
@ -255,7 +255,7 @@ static int ptfs_utimens(const char *path, const struct fuse_timespec tv[2])
{ {
ptfs_impl_fullpath(path); ptfs_impl_fullpath(path);
return -1 != utimensat(AT_FDCWD, path, tv) ? 0 : -errno; return -1 != utimensat(AT_FDCWD, path, tv, AT_SYMLINK_NOFOLLOW) ? 0 : -errno;
} }
#endif #endif

View File

@ -334,7 +334,7 @@ int truncate(const char *path, fuse_off_t size)
int utime(const char *path, const struct fuse_utimbuf *timbuf) int utime(const char *path, const struct fuse_utimbuf *timbuf)
{ {
if (0 == timbuf) if (0 == timbuf)
return utimensat(AT_FDCWD, path, 0); return utimensat(AT_FDCWD, path, 0, AT_SYMLINK_NOFOLLOW);
else else
{ {
struct fuse_timespec times[2]; struct fuse_timespec times[2];
@ -342,13 +342,14 @@ int utime(const char *path, const struct fuse_utimbuf *timbuf)
times[0].tv_nsec = 0; times[0].tv_nsec = 0;
times[1].tv_sec = timbuf->modtime; times[1].tv_sec = timbuf->modtime;
times[1].tv_nsec = 0; times[1].tv_nsec = 0;
return utimensat(AT_FDCWD, path, times); return utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW);
} }
} }
int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2]) int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2], int flag)
{ {
/* ignore dirfd and assume that it is always AT_FDCWD */ /* ignore dirfd and assume that it is always AT_FDCWD */
/* ignore flag and assume that it is always AT_SYMLINK_NOFOLLOW */
HANDLE h = CreateFileA(path, HANDLE h = CreateFileA(path,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,

View File

@ -28,6 +28,7 @@
#define PATH_MAX 1024 #define PATH_MAX 1024
#define AT_FDCWD -2 #define AT_FDCWD -2
#define AT_SYMLINK_NOFOLLOW 2
typedef struct _DIR DIR; typedef struct _DIR DIR;
struct dirent struct dirent
@ -54,7 +55,7 @@ int lchown(const char *path, fuse_uid_t uid, fuse_gid_t gid);
int lchflags(const char *path, uint32_t flags); int lchflags(const char *path, uint32_t flags);
int truncate(const char *path, fuse_off_t size); int truncate(const char *path, fuse_off_t size);
int utime(const char *path, const struct fuse_utimbuf *timbuf); int utime(const char *path, const struct fuse_utimbuf *timbuf);
int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2]); int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2], int flag);
int setcrtime(const char *path, const struct fuse_timespec *tv); int setcrtime(const char *path, const struct fuse_timespec *tv);
int unlink(const char *path); int unlink(const char *path);
int rename(const char *oldpath, const char *newpath); int rename(const char *oldpath, const char *newpath);

View File

@ -39,6 +39,11 @@ void create_dotest(ULONG Flags, PWSTR Prefix)
ASSERT(INVALID_HANDLE_VALUE != Handle); ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle); CloseHandle(Handle);
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE == Handle);
ASSERT(ERROR_FILE_EXISTS == GetLastError());
Handle = CreateFileW(FilePath, Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle); ASSERT(INVALID_HANDLE_VALUE != Handle);
@ -227,6 +232,122 @@ void create_test(void)
create_dotest(MemfsNet, L"\\\\memfs\\share"); create_dotest(MemfsNet, L"\\\\memfs\\share");
} }
static void create_fileattr_dotest(ULONG Flags, PWSTR Prefix)
{
void *memfs = memfs_start(Flags);
HANDLE Handle;
BOOLEAN Success;
DWORD FileAttributes;
WCHAR FilePath[MAX_PATH];
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
FileAttributes = GetFileAttributesW(FilePath);
ASSERT(FILE_ATTRIBUTE_ARCHIVE == FileAttributes);
Success = DeleteFileW(FilePath);
ASSERT(Success);
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_READONLY, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
FileAttributes = GetFileAttributesW(FilePath);
ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY) == FileAttributes);
Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL);
ASSERT(Success);
Success = DeleteFileW(FilePath);
ASSERT(Success);
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_SYSTEM, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
FileAttributes = GetFileAttributesW(FilePath);
ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_SYSTEM) == FileAttributes);
Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL);
ASSERT(Success);
Success = DeleteFileW(FilePath);
ASSERT(Success);
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_HIDDEN, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
FileAttributes = GetFileAttributesW(FilePath);
ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN) == FileAttributes);
Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL);
ASSERT(Success);
Success = DeleteFileW(FilePath);
ASSERT(Success);
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
FileAttributes = GetFileAttributesW(FilePath);
ASSERT(FILE_ATTRIBUTE_ARCHIVE == FileAttributes);
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
FileAttributes = GetFileAttributesW(FilePath);
ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY) == FileAttributes);
Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL);
ASSERT(Success);
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
FileAttributes = GetFileAttributesW(FilePath);
ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_SYSTEM) == FileAttributes);
Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL);
ASSERT(Success);
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
FileAttributes = GetFileAttributesW(FilePath);
ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN) == FileAttributes);
Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL);
ASSERT(Success);
Success = DeleteFileW(FilePath);
ASSERT(Success);
memfs_stop(memfs);
}
static void create_fileattr_test(void)
{
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
create_fileattr_dotest(-1, DirBuf);
}
if (WinFspDiskTests)
create_fileattr_dotest(MemfsDisk, 0);
if (WinFspNetTests)
create_fileattr_dotest(MemfsNet, L"\\\\memfs\\share");
}
void create_related_dotest(ULONG Flags, PWSTR Prefix) void create_related_dotest(ULONG Flags, PWSTR Prefix)
{ {
void *memfs = memfs_start(Flags); void *memfs = memfs_start(Flags);
@ -1136,6 +1257,7 @@ void create_pid_test(void)
void create_tests(void) void create_tests(void)
{ {
TEST(create_test); TEST(create_test);
TEST(create_fileattr_test);
TEST(create_related_test); TEST(create_related_test);
TEST(create_allocation_test); TEST(create_allocation_test);
TEST(create_sd_test); TEST(create_sd_test);

View File

@ -416,6 +416,98 @@ void querydir_buffer_overflow_test(void)
} }
} }
static VOID querydir_namelen_exists(PWSTR FilePath)
{
HANDLE Handle;
WIN32_FIND_DATAW FindData;
Handle = FindFirstFileW(FilePath, &FindData);
ASSERT(INVALID_HANDLE_VALUE != Handle);
FindClose(Handle);
}
static void querydir_namelen_dotest(ULONG Flags, PWSTR Prefix, PWSTR Drive)
{
/* based on create_namelen_dotest */
void *memfs = memfs_start(Flags);
WCHAR FilePath[1024];
PWSTR FilePathBgn, P, EndP;
DWORD MaxComponentLength;
HANDLE Handle;
BOOL Success;
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Drive ? Drive : memfs_volumename(memfs));
Success = GetVolumeInformationW(FilePath,
0, 0,
0, &MaxComponentLength, 0,
0, 0);
ASSERT(Success);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
FilePathBgn = FilePath + wcslen(FilePath);
for (P = FilePathBgn, EndP = P + MaxComponentLength - 1; EndP > P; P++)
*P = (P - FilePathBgn) % 10 + '0';
*P = L'\0';
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
querydir_namelen_exists(FilePath);
Success = CloseHandle(Handle);
ASSERT(Success);
for (P = FilePathBgn, EndP = P + MaxComponentLength; EndP > P; P++)
*P = (P - FilePathBgn) % 10 + '0';
*P = L'\0';
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
querydir_namelen_exists(FilePath);
Success = CloseHandle(Handle);
ASSERT(Success);
for (P = FilePathBgn, EndP = P + MaxComponentLength + 1; EndP > P; P++)
*P = (P - FilePathBgn) % 10 + '0';
*P = L'\0';
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
ASSERT(INVALID_HANDLE_VALUE == Handle);
ASSERT(ERROR_INVALID_NAME == GetLastError());
memfs_stop(memfs);
}
static void querydir_namelen_test(void)
{
if (OptShareName || OptMountPoint)
return;
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH], DriveBuf[3];
GetTestDirectoryAndDrive(DirBuf, DriveBuf);
querydir_namelen_dotest(-1, DirBuf, DriveBuf);
}
if (WinFspDiskTests)
querydir_namelen_dotest(MemfsDisk, 0, 0);
#if 0
/* This test does not work when going through the MUP! */
if (WinFspNetTests)
querydir_namelen_dotest(MemfsNet, L"\\\\memfs\\share", L"\\\\memfs\\share");
#endif
}
static unsigned __stdcall dirnotify_dotest_thread(void *FilePath) static unsigned __stdcall dirnotify_dotest_thread(void *FilePath)
{ {
FspDebugLog(__FUNCTION__ ": \"%S\"\n", FilePath); FspDebugLog(__FUNCTION__ ": \"%S\"\n", FilePath);
@ -552,5 +644,7 @@ void dirctl_tests(void)
TEST(querydir_expire_cache_test); TEST(querydir_expire_cache_test);
if (!OptShareName) if (!OptShareName)
TEST(querydir_buffer_overflow_test); TEST(querydir_buffer_overflow_test);
if (!OptShareName && !OptMountPoint)
TEST(querydir_namelen_test);
TEST(dirnotify_test); TEST(dirnotify_test);
} }