mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-26 20:42:50 -05:00
tst: ntptfs: new passthrough file system
This commit is contained in:
332
tst/ntptfs/lfs.c
Normal file
332
tst/ntptfs/lfs.c
Normal 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;
|
||||
}
|
Reference in New Issue
Block a user