tst: ntptfs: new passthrough file system

This commit is contained in:
Bill Zissimopoulos 2022-01-06 13:40:26 +00:00
parent 423c70757c
commit 27b52fd167
No known key found for this signature in database
GPG Key ID: 3D4F95D52C7B3EA3
11 changed files with 2447 additions and 3 deletions

8
tst/ntptfs/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
build
*.ncb
*.suo
*.vcproj.*
*.vcxproj.user
*.VC.db
*.VC.opendb
.vs

332
tst/ntptfs/lfs.c Normal file
View File

@ -0,0 +1,332 @@
/**
* @file lfs.c
*
* @copyright 2015-2021 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this software
* in accordance with the commercial license agreement provided in
* conjunction with the software. The terms and conditions of any such
* commercial license agreement shall govern, supersede, and render
* ineffective any application of the GPLv3 license to this software,
* notwithstanding of any reference thereto in the software or
* associated repository.
*/
#include "ptfs.h"
static inline HANDLE LfsThreadEvent(VOID)
{
static __declspec(thread) HANDLE Event;
if (0 == Event)
Event = CreateEventW(0, TRUE, FALSE, 0);
return Event;
}
NTSTATUS LfsCreateFile(
PHANDLE PHandle,
ACCESS_MASK DesiredAccess,
HANDLE RootHandle,
PWSTR FileName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PLARGE_INTEGER AllocationSize,
ULONG FileAttributes,
ULONG CreateDisposition,
ULONG CreateOptions,
PVOID EaBuffer,
ULONG EaLength)
{
UNICODE_STRING Ufnm;
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK Iosb;
NTSTATUS Result;
RtlInitUnicodeString(&Ufnm, FileName + 1);
InitializeObjectAttributes(&Obja, &Ufnm, 0, RootHandle, SecurityDescriptor);
Result = NtCreateFile(
PHandle,
FILE_READ_ATTRIBUTES | DesiredAccess,
&Obja,
&Iosb,
AllocationSize,
FileAttributes,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
CreateDisposition,
CreateOptions,
EaBuffer,
EaLength);
#if 0
if (STATUS_DELETE_PENDING == Result && IsDebuggerPresent())
DebugBreak();
#endif
return Result;
}
NTSTATUS LfsOpenFile(
PHANDLE PHandle,
ACCESS_MASK DesiredAccess,
HANDLE RootHandle,
PWSTR FileName,
ULONG OpenOptions)
{
UNICODE_STRING Ufnm;
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK Iosb;
NTSTATUS Result;
RtlInitUnicodeString(&Ufnm, FileName + 1);
InitializeObjectAttributes(&Obja, &Ufnm, 0, RootHandle, 0);
Result = NtOpenFile(
PHandle,
FILE_READ_ATTRIBUTES | DesiredAccess,
&Obja,
&Iosb,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
OpenOptions);
#if 0
if (STATUS_DELETE_PENDING == Result && IsDebuggerPresent())
DebugBreak();
#endif
return Result;
}
NTSTATUS LfsGetFileInfo(
HANDLE Handle,
ULONG RootPrefixLength,
FSP_FSCTL_FILE_INFO *FileInfo)
{
FSP_FSCTL_OPEN_FILE_INFO *OpenFileInfo = -1 != RootPrefixLength ?
FspFileSystemGetOpenFileInfo(FileInfo) : 0;
IO_STATUS_BLOCK Iosb;
union
{
FILE_ALL_INFORMATION V;
UINT8 B[FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + FSP_FSCTL_TRANSACT_PATH_SIZEMAX];
} FileAllInfo;
FILE_ATTRIBUTE_TAG_INFORMATION FileAttrInfo;
NTSTATUS Result;
Result = NtQueryInformationFile(
Handle,
&Iosb,
&FileAllInfo,
sizeof FileAllInfo,
18/*FileAllInformation*/);
if (STATUS_BUFFER_OVERFLOW == Result)
OpenFileInfo = 0;
else if (!NT_SUCCESS(Result))
return Result;
if (0 != (FILE_ATTRIBUTE_REPARSE_POINT & FileAllInfo.V.BasicInformation.FileAttributes))
{
Result = NtQueryInformationFile(
Handle,
&Iosb,
&FileAttrInfo,
sizeof FileAttrInfo,
35/*FileAttributeTagInformation*/);
if (!NT_SUCCESS(Result))
return Result;
}
Result = STATUS_SUCCESS;
FileInfo->FileAttributes = FileAllInfo.V.BasicInformation.FileAttributes;
FileInfo->ReparseTag = 0 != (FILE_ATTRIBUTE_REPARSE_POINT & FileAllInfo.V.BasicInformation.FileAttributes) ?
FileAttrInfo.ReparseTag : 0;
FileInfo->AllocationSize = FileAllInfo.V.StandardInformation.AllocationSize.QuadPart;
FileInfo->FileSize = FileAllInfo.V.StandardInformation.EndOfFile.QuadPart;
FileInfo->CreationTime = FileAllInfo.V.BasicInformation.CreationTime.QuadPart;
FileInfo->LastAccessTime = FileAllInfo.V.BasicInformation.LastAccessTime.QuadPart;
FileInfo->LastWriteTime = FileAllInfo.V.BasicInformation.LastWriteTime.QuadPart;
FileInfo->ChangeTime = FileAllInfo.V.BasicInformation.ChangeTime.QuadPart;
FileInfo->IndexNumber = FileAllInfo.V.InternalInformation.IndexNumber.QuadPart;
FileInfo->HardLinks = 0;
FileInfo->EaSize = FileAllInfo.V.EaInformation.EaSize;
if (0 != OpenFileInfo &&
OpenFileInfo->NormalizedNameSize > sizeof(WCHAR) + FileAllInfo.V.NameInformation.FileNameLength &&
RootPrefixLength <= FileAllInfo.V.NameInformation.FileNameLength)
{
PWSTR P = (PVOID)((PUINT8)FileAllInfo.V.NameInformation.FileName + RootPrefixLength);
ULONG L = FileAllInfo.V.NameInformation.FileNameLength - RootPrefixLength;
if (L'\\' == *P)
{
memcpy(OpenFileInfo->NormalizedName, P, L);
OpenFileInfo->NormalizedNameSize = (UINT16)L;
}
else
{
*OpenFileInfo->NormalizedName = L'\\';
memcpy(OpenFileInfo->NormalizedName + 1, P, L);
OpenFileInfo->NormalizedNameSize = (UINT16)(L + sizeof(WCHAR));
}
}
return Result;
}
NTSTATUS LfsReadFile(
HANDLE Handle,
PVOID Buffer,
UINT64 Offset,
ULONG Length,
PULONG PBytesTransferred)
{
HANDLE Event;
IO_STATUS_BLOCK Iosb;
NTSTATUS Result;
Event = LfsThreadEvent();
if (0 == Event)
return STATUS_INSUFFICIENT_RESOURCES;
Result = NtReadFile(
Handle,
Event,
0,
0,
&Iosb,
Buffer,
Length,
(PLARGE_INTEGER)&Offset,
0);
if (STATUS_PENDING == Result)
{
WaitForSingleObject(Event, INFINITE);
Result = Iosb.Status;
}
*PBytesTransferred = (ULONG)Iosb.Information;
return Result;
}
NTSTATUS LfsWriteFile(
HANDLE Handle,
PVOID Buffer,
UINT64 Offset,
ULONG Length,
PULONG PBytesTransferred)
{
HANDLE Event;
IO_STATUS_BLOCK Iosb;
NTSTATUS Result;
Event = LfsThreadEvent();
if (0 == Event)
return STATUS_INSUFFICIENT_RESOURCES;
Result = NtWriteFile(
Handle,
Event,
0,
0,
&Iosb,
Buffer,
Length,
(PLARGE_INTEGER)&Offset,
0);
if (STATUS_PENDING == Result)
{
WaitForSingleObject(Event, INFINITE);
Result = Iosb.Status;
}
*PBytesTransferred = (ULONG)Iosb.Information;
return Result;
}
NTSTATUS LfsQueryDirectoryFile(
HANDLE Handle,
PVOID Buffer,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass,
BOOLEAN ReturnSingleEntry,
PWSTR FileName,
BOOLEAN RestartScan,
PULONG PBytesTransferred)
{
HANDLE Event;
UNICODE_STRING Ufnm;
IO_STATUS_BLOCK Iosb;
NTSTATUS Result;
Event = LfsThreadEvent();
if (0 == Event)
return STATUS_INSUFFICIENT_RESOURCES;
if (0 != FileName)
RtlInitUnicodeString(&Ufnm, FileName);
Result = NtQueryDirectoryFile(
Handle,
Event,
0,
0,
&Iosb,
Buffer,
Length,
FileInformationClass,
ReturnSingleEntry,
0 != FileName ? &Ufnm : 0,
RestartScan);
if (STATUS_PENDING == Result)
{
WaitForSingleObject(Event, INFINITE);
Result = Iosb.Status;
}
*PBytesTransferred = (ULONG)Iosb.Information;
return Result;
}
NTSTATUS LfsFsControlFile(
HANDLE Handle,
ULONG FsControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength,
PULONG PBytesTransferred)
{
HANDLE Event;
IO_STATUS_BLOCK Iosb;
NTSTATUS Result;
Event = LfsThreadEvent();
if (0 == Event)
return STATUS_INSUFFICIENT_RESOURCES;
Result = NtFsControlFile(
Handle,
Event,
0,
0,
&Iosb,
FsControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength);
if (STATUS_PENDING == Result)
{
WaitForSingleObject(Event, INFINITE);
Result = Iosb.Status;
}
*PBytesTransferred = (ULONG)Iosb.Information;
return Result;
}

275
tst/ntptfs/ptfs-main.c Normal file
View File

@ -0,0 +1,275 @@
/**
* @file ptfs-main.c
*
* @copyright 2015-2021 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this software
* in accordance with the commercial license agreement provided in
* conjunction with the software. The terms and conditions of any such
* commercial license agreement shall govern, supersede, and render
* ineffective any application of the GPLv3 license to this software,
* notwithstanding of any reference thereto in the software or
* associated repository.
*/
#include "ptfs.h"
static NTSTATUS EnablePrivileges(PWSTR PrivilegeName, ...)
{
va_list ap;
HANDLE Token = 0;
TOKEN_PRIVILEGES Privileges;
WCHAR WarnNames[1024], *WarnNameP = WarnNames;
NTSTATUS Result;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &Token))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
va_start(ap, PrivilegeName);
for (PWSTR Name = PrivilegeName; 0 != Name; Name = va_arg(ap, PWSTR))
{
Privileges.PrivilegeCount = 1;
Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!LookupPrivilegeValueW(0, Name, &Privileges.Privileges[0].Luid) ||
!AdjustTokenPrivileges(Token, FALSE, &Privileges, 0, 0, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (ERROR_NOT_ALL_ASSIGNED == GetLastError())
{
*WarnNameP++ = ' ';
size_t len = wcslen(Name);
memcpy(WarnNameP, Name, len * sizeof(WCHAR));
WarnNameP += len;
*WarnNameP = '\0';
}
}
va_end(ap);
if (WarnNames != WarnNameP)
warn(L"cannot enable privileges:%s", WarnNames);
Result = STATUS_SUCCESS;
exit:
if (0 != Token)
CloseHandle(Token);
return Result;
}
static ULONG wcstol_deflt(wchar_t *w, ULONG deflt)
{
wchar_t *endp;
ULONG ul = wcstol(w, &endp, 0);
return L'\0' != w[0] && L'\0' == *endp ? ul : deflt;
}
static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
{
#define argtos(v) if (arge > ++argp) v = *argp; else goto usage
#define argtol(v) if (arge > ++argp) v = wcstol_deflt(*argp, v); else goto usage
wchar_t **argp, **arge;
PWSTR RootPath = 0;
ULONG FileInfoTimeout = INFINITE;
ULONG FsAttributeMask = 0;
PWSTR VolumePrefix = 0;
PWSTR MountPoint = 0;
PWSTR OptionString = 0;
PWSTR DebugLogFile = 0;
ULONG DebugFlags = 0;
HANDLE DebugLogHandle = INVALID_HANDLE_VALUE;
WCHAR RootPathBuf[MAX_PATH];
PTFS *Ptfs = 0;
NTSTATUS Result;
for (argp = argv + 1, arge = argv + argc; arge > argp; argp++)
{
if (L'-' != argp[0][0])
break;
switch (argp[0][1])
{
case L'?':
goto usage;
case L'd':
argtol(DebugFlags);
break;
case L'D':
argtos(DebugLogFile);
break;
case L'm':
argtos(MountPoint);
break;
case L'o':
argtos(OptionString);
if (0 == _wcsicmp(L"ReparsePoints", OptionString))
FsAttributeMask |= PtfsReparsePoints;
else if (0 == _wcsicmp(L"NamedStreams", OptionString))
FsAttributeMask |= PtfsNamedStreams;
else if (0 == _wcsicmp(L"ExtendedAttributes", OptionString))
FsAttributeMask |= PtfsExtendedAttributes;
else if (0 == _wcsicmp(L"FlushAndPurgeOnCleanup", OptionString))
FsAttributeMask |= PtfsFlushAndPurgeOnCleanup;
else
goto usage;
break;
case L'p':
argtos(RootPath);
break;
case L't':
argtol(FileInfoTimeout);
break;
case L'u':
argtos(VolumePrefix);
break;
default:
goto usage;
}
}
if (arge > argp)
goto usage;
if (0 == RootPath && 0 != VolumePrefix)
{
PWSTR P;
P = wcschr(VolumePrefix, L'\\');
if (0 != P && L'\\' != P[1])
{
P = wcschr(P + 1, L'\\');
if (0 != P &&
(
(L'A' <= P[1] && P[1] <= L'Z') ||
(L'a' <= P[1] && P[1] <= L'z')
) &&
L'$' == P[2])
{
StringCbPrintf(RootPathBuf, sizeof RootPathBuf, L"%c:%s", P[1], P + 3);
RootPath = RootPathBuf;
}
}
}
if (0 == RootPath || 0 == MountPoint)
goto usage;
if (0 != DebugLogFile)
{
if (0 == wcscmp(L"-", DebugLogFile))
DebugLogHandle = GetStdHandle(STD_ERROR_HANDLE);
else
DebugLogHandle = CreateFileW(
DebugLogFile,
FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
if (INVALID_HANDLE_VALUE == DebugLogHandle)
{
fail(L"cannot open debug log file");
goto usage;
}
FspDebugLogSetHandle(DebugLogHandle);
}
EnablePrivileges(SE_BACKUP_NAME, SE_RESTORE_NAME, SE_CREATE_SYMBOLIC_LINK_NAME, 0);
Result = PtfsCreate(
RootPath,
FileInfoTimeout,
FsAttributeMask,
VolumePrefix,
MountPoint,
DebugFlags,
&Ptfs);
if (!NT_SUCCESS(Result))
{
fail(L"cannot create file system");
goto exit;
}
Result = FspFileSystemStartDispatcher(Ptfs->FileSystem, 0);
if (!NT_SUCCESS(Result))
{
fail(L"cannot start file system");
goto exit;
}
MountPoint = FspFileSystemMountPoint(Ptfs->FileSystem);
info(L"%s -t %ld%s%s -p %s -m %s",
L"" PROGNAME,
FileInfoTimeout,
0 != VolumePrefix && L'\0' != VolumePrefix[0] ? L" -u " : L"",
0 != VolumePrefix && L'\0' != VolumePrefix[0] ? VolumePrefix : L"",
RootPath,
MountPoint);
Service->UserContext = Ptfs;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result) && 0 != Ptfs)
PtfsDelete(Ptfs);
return Result;
usage:
static wchar_t usage[] = L""
"usage: %s OPTIONS\n"
"\n"
"options:\n"
" -d DebugFlags [-1: enable all debug logs]\n"
" -D DebugLogFile [file path; use - for stderr]\n"
" -t FileInfoTimeout [millis]\n"
" -o ReparsePoints\n"
" -o NamedStreams\n"
" -o ExtendedAttributes\n"
" -o FlushAndPurgeOnCleanup\n"
" -u \\Server\\Share [UNC prefix (single backslash)]\n"
" -p Directory [directory to expose as pass through file system]\n"
" -m MountPoint [X:|*|directory]\n";
fail(usage, L"" PROGNAME);
return STATUS_UNSUCCESSFUL;
#undef argtos
#undef argtol
}
static NTSTATUS SvcStop(FSP_SERVICE *Service)
{
PTFS *Ptfs = Service->UserContext;
FspFileSystemStopDispatcher(Ptfs->FileSystem);
PtfsDelete(Ptfs);
return STATUS_SUCCESS;
}
int wmain(int argc, wchar_t **argv)
{
if (!NT_SUCCESS(FspLoad(0)))
return ERROR_DELAY_LOAD_FAILED;
return FspServiceRun(L"" PROGNAME, SvcStart, SvcStop, 0);
}

1220
tst/ntptfs/ptfs.c Normal file

File diff suppressed because it is too large Load Diff

364
tst/ntptfs/ptfs.h Normal file
View File

@ -0,0 +1,364 @@
/**
* @file ptfs.h
*
* @copyright 2015-2021 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this software
* in accordance with the commercial license agreement provided in
* conjunction with the software. The terms and conditions of any such
* commercial license agreement shall govern, supersede, and render
* ineffective any application of the GPLv3 license to this software,
* notwithstanding of any reference thereto in the software or
* associated repository.
*/
#ifndef PTFS_H_INCLUDED
#define PTFS_H_INCLUDED
#include <winfsp/winfsp.h>
#include <strsafe.h>
#define PROGNAME "ptfs"
#define info(format, ...) FspServiceLog(EVENTLOG_INFORMATION_TYPE, format, __VA_ARGS__)
#define warn(format, ...) FspServiceLog(EVENTLOG_WARNING_TYPE, format, __VA_ARGS__)
#define fail(format, ...) FspServiceLog(EVENTLOG_ERROR_TYPE, format, __VA_ARGS__)
/*
* PTFS
*/
enum
{
PtfsReparsePoints = 0x00000010,
PtfsNamedStreams = 0x00000040,
PtfsExtendedAttributes = 0x00000100,
PtfsFlushAndPurgeOnCleanup = 0x00004000,
PtfsAttributesMask =
PtfsReparsePoints |
PtfsNamedStreams |
PtfsExtendedAttributes |
PtfsFlushAndPurgeOnCleanup,
};
typedef struct
{
FSP_FILE_SYSTEM *FileSystem;
HANDLE RootHandle;
ULONG RootPrefixLength;
ULONG FsAttributes;
UINT64 AllocationUnit;
} PTFS;
NTSTATUS PtfsCreate(
PWSTR RootPath,
ULONG FileInfoTimeout,
ULONG FsAttributeMask,
PWSTR VolumePrefix,
PWSTR MountPoint,
UINT32 DebugFlags,
PTFS **PPtfs);
VOID PtfsDelete(PTFS *Ptfs);
/*
* Lower file system
*/
NTSTATUS LfsCreateFile(
PHANDLE PHandle,
ACCESS_MASK DesiredAccess,
HANDLE RootHandle,
PWSTR FileName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PLARGE_INTEGER AllocationSize,
ULONG FileAttributes,
ULONG CreateDisposition,
ULONG CreateOptions,
PVOID EaBuffer,
ULONG EaLength);
NTSTATUS LfsOpenFile(
PHANDLE PHandle,
ACCESS_MASK DesiredAccess,
HANDLE RootHandle,
PWSTR FileName,
ULONG OpenOptions);
NTSTATUS LfsGetFileInfo(
HANDLE Handle,
ULONG RootPrefixLength,
FSP_FSCTL_FILE_INFO *FileInfo);
NTSTATUS LfsReadFile(
HANDLE Handle,
PVOID Buffer,
UINT64 Offset,
ULONG Length,
PULONG PBytesTransferred);
NTSTATUS LfsWriteFile(
HANDLE Handle,
PVOID Buffer,
UINT64 Offset,
ULONG Length,
PULONG PBytesTransferred);
NTSTATUS LfsQueryDirectoryFile(
HANDLE Handle,
PVOID Buffer,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass,
BOOLEAN ReturnSingleEntry,
PWSTR FileName,
BOOLEAN RestartScan,
PULONG PBytesTransferred);
NTSTATUS LfsFsControlFile(
HANDLE Handle,
ULONG FsControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength,
PULONG PBytesTransferred);
/*
* Missing NTDLL definitions
*/
typedef struct
{
ACCESS_MASK AccessFlags;
} FILE_ACCESS_INFORMATION;
typedef struct
{
ULONG AlignmentRequirement;
} FILE_ALIGNMENT_INFORMATION;
typedef struct
{
LARGE_INTEGER AllocationSize;
} FILE_ALLOCATION_INFORMATION;
typedef struct
{
ULONG FileAttributes;
ULONG ReparseTag;
} FILE_ATTRIBUTE_TAG_INFORMATION;
typedef struct
{
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
ULONG FileAttributes;
} FILE_BASIC_INFORMATION;
typedef struct
{
BOOLEAN DeleteFile;
} FILE_DISPOSITION_INFORMATION;
typedef struct
{
ULONG Flags;
} FILE_DISPOSITION_INFORMATION_EX;
typedef struct
{
ULONG EaSize;
} FILE_EA_INFORMATION;
typedef struct
{
LARGE_INTEGER EndOfFile;
} FILE_END_OF_FILE_INFORMATION;
typedef struct
{
LARGE_INTEGER IndexNumber;
} FILE_INTERNAL_INFORMATION;
typedef struct
{
ULONG Mode;
} FILE_MODE_INFORMATION;
typedef struct
{
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAME_INFORMATION;
typedef struct
{
LARGE_INTEGER CurrentByteOffset;
} FILE_POSITION_INFORMATION;
typedef struct
{
union
{
BOOLEAN ReplaceIfExists;
ULONG Flags;
} DUMMYUNIONNAME;
HANDLE RootDirectory;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_RENAME_INFORMATION;
typedef struct
{
LARGE_INTEGER AllocationSize;
LARGE_INTEGER EndOfFile;
ULONG NumberOfLinks;
BOOLEAN DeletePending;
BOOLEAN Directory;
} FILE_STANDARD_INFORMATION;
typedef struct
{
ULONG NextEntryOffset;
ULONG StreamNameLength;
LARGE_INTEGER StreamSize;
LARGE_INTEGER StreamAllocationSize;
WCHAR StreamName[1];
} FILE_STREAM_INFORMATION;
typedef struct
{
FILE_BASIC_INFORMATION BasicInformation;
FILE_STANDARD_INFORMATION StandardInformation;
FILE_INTERNAL_INFORMATION InternalInformation;
FILE_EA_INFORMATION EaInformation;
FILE_ACCESS_INFORMATION AccessInformation;
FILE_POSITION_INFORMATION PositionInformation;
FILE_MODE_INFORMATION ModeInformation;
FILE_ALIGNMENT_INFORMATION AlignmentInformation;
FILE_NAME_INFORMATION NameInformation;
} FILE_ALL_INFORMATION;
typedef struct
{
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
ULONG EaSize;
CCHAR ShortNameLength;
WCHAR ShortName[12];
LARGE_INTEGER FileId;
WCHAR FileName[1];
} FILE_ID_BOTH_DIR_INFORMATION;
typedef struct
{
ULONG FileSystemAttributes;
LONG MaximumComponentNameLength;
ULONG FileSystemNameLength;
WCHAR FileSystemName[1];
} FILE_FS_ATTRIBUTE_INFORMATION;
typedef struct
{
LARGE_INTEGER TotalAllocationUnits;
LARGE_INTEGER AvailableAllocationUnits;
ULONG SectorsPerAllocationUnit;
ULONG BytesPerSector;
} FILE_FS_SIZE_INFORMATION;
NTSTATUS NTAPI NtFlushBuffersFile(
HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock);
NTSTATUS NTAPI NtFsControlFile(
HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG FsControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength);
NTSTATUS NTAPI NtQueryEaFile(
HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID Buffer,
ULONG Length,
BOOLEAN ReturnSingleEntry,
PVOID EaList,
ULONG EaListLength,
PULONG EaIndex,
BOOLEAN RestartScan);
NTSTATUS NTAPI NtQueryDirectoryFile(
HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass,
BOOLEAN ReturnSingleEntry,
PUNICODE_STRING FileName,
BOOLEAN RestartScan);
NTSTATUS NTAPI NtQueryInformationFile(
HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass);
NTSTATUS NTAPI NtQuerySecurityObject(
HANDLE Handle,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor,
ULONG Length,
PULONG LengthNeeded);
NTSTATUS NTAPI NtQueryVolumeInformationFile(
HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FsInformation,
ULONG Length,
ULONG FsInformationClass);
NTSTATUS NTAPI NtReadFile(
HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID Buffer,
ULONG Length,
PLARGE_INTEGER ByteOffset,
PULONG Key);
NTSTATUS NTAPI NtSetEaFile(
HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID Buffer,
ULONG Length);
NTSTATUS NTAPI NtSetInformationFile(
HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass);
NTSTATUS NTAPI NtSetSecurityObject(
HANDLE Handle,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor);
NTSTATUS NTAPI NtWriteFile(
HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID Buffer,
ULONG Length,
PLARGE_INTEGER ByteOffset,
PULONG Key);
#endif

28
tst/ntptfs/ptfs.sln Normal file
View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ptfs", "ptfs.vcxproj", "{BA69F863-4426-4CAE-8676-331B985C5DA8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BA69F863-4426-4CAE-8676-331B985C5DA8}.Debug|x64.ActiveCfg = Debug|x64
{BA69F863-4426-4CAE-8676-331B985C5DA8}.Debug|x64.Build.0 = Debug|x64
{BA69F863-4426-4CAE-8676-331B985C5DA8}.Debug|x86.ActiveCfg = Debug|Win32
{BA69F863-4426-4CAE-8676-331B985C5DA8}.Debug|x86.Build.0 = Debug|Win32
{BA69F863-4426-4CAE-8676-331B985C5DA8}.Release|x64.ActiveCfg = Release|x64
{BA69F863-4426-4CAE-8676-331B985C5DA8}.Release|x64.Build.0 = Release|x64
{BA69F863-4426-4CAE-8676-331B985C5DA8}.Release|x86.ActiveCfg = Release|Win32
{BA69F863-4426-4CAE-8676-331B985C5DA8}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

187
tst/ntptfs/ptfs.vcxproj Normal file
View File

@ -0,0 +1,187 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="lfs.c" />
<ClCompile Include="ptfs-main.c" />
<ClCompile Include="ptfs.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="ptfs.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{BA69F863-4426-4CAE-8676-331B985C5DA8}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>passthrough</RootNamespace>
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ptfs.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="ptfs-main.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="lfs.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ptfs.h">
<Filter>Source</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -506,7 +506,7 @@ static void delete_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
Success = RemoveDirectoryW(Dir1Path);
Success = RealRemoveDirectoryW(Dir1Path);
ASSERT(!Success);
ASSERT(ERROR_DIR_NOT_EMPTY == GetLastError());

View File

@ -1341,7 +1341,7 @@ static void stream_delete_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeou
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
Success = RemoveDirectoryW(Dir1Path);
Success = RealRemoveDirectoryW(Dir1Path);
ASSERT(!Success);
ASSERT(ERROR_DIR_NOT_EMPTY == GetLastError());
@ -1425,7 +1425,7 @@ static void stream_delete_pending_dotest(ULONG Flags, PWSTR Prefix, ULONG FileIn
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
Success = RemoveDirectoryW(Dir1Path);
Success = RealRemoveDirectoryW(Dir1Path);
ASSERT(!Success);
ASSERT(ERROR_DIR_NOT_EMPTY == GetLastError());

View File

@ -52,6 +52,11 @@ BOOL WINAPI HookDeleteFileW(
LPCWSTR lpFileName);
BOOL WINAPI HookRemoveDirectoryW(
LPCWSTR lpPathName);
static inline BOOL RealRemoveDirectoryW(
LPCWSTR lpPathName)
{
return RemoveDirectoryW(lpPathName);
}
BOOL WINAPI HookMoveFileExW(
LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName,