winfsp/tst/ntptfs/lfs.c
2022-01-07 17:30:49 +00:00

333 lines
8.3 KiB
C

/**
* @file lfs.c
*
* @copyright 2015-2022 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;
}