diff --git a/tst/airfs/airfs.cpp b/tst/airfs/airfs.cpp index 32347909..1b1ea50d 100644 --- a/tst/airfs/airfs.cpp +++ b/tst/airfs/airfs.cpp @@ -25,30 +25,7 @@ * root of this project. */ -#include -#include -#include -#include -#include -#include -#include // Used by SLOWIO. - -#define AIRFS_MAX_PATH 512 -FSP_FSCTL_STATIC_ASSERT(AIRFS_MAX_PATH > MAX_PATH, - "AIRFS_MAX_PATH must be greater than MAX_PATH."); - -#define AIRFS_NAME_NORMALIZATION // Include name normalization support. -#define AIRFS_REPARSE_POINTS // Include reparse points support. -#define AIRFS_NAMED_STREAMS // Include alternate data streams support. -#define AIRFS_DIRINFO_BY_NAME // Include GetDirInfoByName. -#define AIRFS_SLOWIO // Include delayed I/O response support. -#define AIRFS_CONTROL // Include DeviceIoControl support. - - -#define SECTOR_SIZE 512 -#define SECTORS_PER_ALLOCATION_UNIT 1 -#define ALLOCATION_UNIT ( SECTOR_SIZE * SECTORS_PER_ALLOCATION_UNIT ) -#define IN_ALLOCATION_UNITS(bytes) (((bytes) + ALLOCATION_UNIT - 1) / ALLOCATION_UNIT * ALLOCATION_UNIT) +#include "common.h" enum { @@ -61,135 +38,38 @@ enum ////////////////////////////////////////////////////////////////////// -// Heap Support - -static HANDLE AirfsHeap = 0; -std::once_flag AirfsHeapInitOnceFlag; - -static inline BOOLEAN AirfsHeapInitialize() -{ - std::call_once(AirfsHeapInitOnceFlag, [](){ AirfsHeap = HeapCreate(0, 0, 0); }); - return AirfsHeap != 0; -} - -static inline PVOID AirfsHeapAlloc(SIZE_T Size) -{ - return HeapAlloc(AirfsHeap, 0, Size); -} - -static inline PVOID AirfsHeapRealloc(PVOID Pointer, SIZE_T RequestedSize) -{ - if (!Pointer) - { - if (!RequestedSize) return 0; - return HeapAlloc(AirfsHeap, 0, RequestedSize); - } - if (!RequestedSize) return HeapFree(AirfsHeap, 0, Pointer), 0; - return HeapReAlloc(AirfsHeap, 0, Pointer, RequestedSize); -} - -static inline void AirfsHeapFree(PVOID Pointer) -{ - if (Pointer) HeapFree(AirfsHeap, 0, Pointer); -} - -static inline SIZE_T AirfsHeapSize(PVOID Pointer) -{ - if (!Pointer) return 0; - return HeapSize(AirfsHeap, 0, Pointer); -} - -////////////////////////////////////////////////////////////////////// - -typedef struct NODE NODE, *NODE_; - -struct NODE_LESS -{ - bool operator() (const NODE_ NodeA, const NODE_ NodeB) const - { - WCHAR* a = (WCHAR*) NodeA; - WCHAR* b = (WCHAR*) NodeB; - return (CaseInsensitive ? _wcsicmp(a, b) : wcscmp(a, b)) < 0; - } - NODE_LESS(BOOLEAN Insensitive) : CaseInsensitive(Insensitive){} - BOOLEAN CaseInsensitive; -}; - -typedef std::set NODES, *NODES_; - -////////////////////////////////////////////////////////////////////// - -struct NODE -{ - WCHAR Name[AIRFS_MAX_PATH]; - NODE_ Parent; - NODES_ Children; - FSP_FSCTL_FILE_INFO FileInfo; - SIZE_T SecurityDescriptorSize; - PVOID SecurityDescriptor; - PVOID FileData; -#if defined(AIRFS_REPARSE_POINTS) - SIZE_T ReparseDataSize; - PVOID ReparseData; -#endif - volatile LONG RefCount; -#if defined(AIRFS_NAMED_STREAMS) - NODES_ Streams; - BOOLEAN IsAStream; -#endif -}; - -////////////////////////////////////////////////////////////////////// - -typedef struct -{ - FSP_FILE_SYSTEM *FileSystem; - NODE_ Root; - ULONG NumNodes; - ULONG MaxNodes; - ULONG MaxFileSize; -#ifdef AIRFS_SLOWIO - ULONG SlowioMaxDelay; - ULONG SlowioPercentDelay; - ULONG SlowioRarefyDelay; - volatile LONG SlowioThreadsRunning; -#endif - UINT16 VolumeLabelLength; - WCHAR VolumeLabel[32]; - BOOLEAN CaseInsensitive; -} AIRFS, *AIRFS_; - -////////////////////////////////////////////////////////////////////// - -inline UINT64 GetSystemTime() -{ - FILETIME FileTime; - GetSystemTimeAsFileTime(&FileTime); - return ((PLARGE_INTEGER)&FileTime)->QuadPart; -} - -////////////////////////////////////////////////////////////////////// - NTSTATUS CreateNode(AIRFS_ Airfs, PWSTR Name, NODE_ *PNode) { static UINT64 IndexNumber = 1; - NODE_ Node = (NODE_) malloc(sizeof *Node); + + NODE_ Node = (NODE_) StorageAllocate(Airfs, sizeof NODE); + if (!Node) { *PNode = 0; return STATUS_INSUFFICIENT_RESOURCES; } - memset(Node, 0, sizeof *Node); - wcscpy_s(Node->Name, sizeof Node->Name / sizeof(WCHAR), Name); + memset(Node, 0, sizeof NODE); + + size_t NameNumBytes = (wcslen(Name)+1) * sizeof WCHAR; + WCHAR* NameAllocation = (WCHAR*) StorageAllocate(Airfs, NameNumBytes); + if (!NameAllocation) + { + StorageFree(Airfs, Node); + *PNode = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + memcpy(NameAllocation, Name, NameNumBytes); + Node->Name = NameAllocation; + Node->FileInfo.CreationTime = Node->FileInfo.LastAccessTime = Node->FileInfo.LastWriteTime = - Node->FileInfo.ChangeTime = GetSystemTime(); + Node->FileInfo.ChangeTime = SystemTime(); Node->FileInfo.IndexNumber = IndexNumber++; *PNode = Node; - Airfs->NumNodes++; return STATUS_SUCCESS; } @@ -197,28 +77,17 @@ NTSTATUS CreateNode(AIRFS_ Airfs, PWSTR Name, NODE_ *PNode) void DeleteNode(AIRFS_ Airfs, NODE_ Node) { -#if defined(AIRFS_REPARSE_POINTS) - free(Node->ReparseData); -#endif - AirfsHeapFree(Node->FileData); - free(Node->SecurityDescriptor); - - if (Node->Children) + NODE_ Block; + while (Block = Node->FileBlocks) { - assert(Node->Children->empty()); - delete Node->Children; + Detach(Node->FileBlocks, Block); + StorageFree(Airfs, Block); } -#if defined(AIRFS_NAMED_STREAMS) - if (Node->Streams) - { - assert(Node->Streams->empty()); - delete Node->Streams; - } -#endif - - free(Node); - Airfs->NumNodes--; + StorageFree(Airfs, Node->Name); + StorageFree(Airfs, Node->ReparseData); + StorageFree(Airfs, Node->SecurityDescriptor); + StorageFree(Airfs, Node); } ////////////////////////////////////////////////////////////////////// @@ -240,7 +109,6 @@ inline void DereferenceNode(AIRFS_ Airfs, NODE_ Node) void GetFileInfo(NODE_ Node, FSP_FSCTL_FILE_INFO *FileInfo) { -#if defined(AIRFS_NAMED_STREAMS) if (Node->IsAStream) { *FileInfo = Node->Parent->FileInfo; @@ -250,75 +118,15 @@ void GetFileInfo(NODE_ Node, FSP_FSCTL_FILE_INFO *FileInfo) FileInfo->FileSize = Node->FileInfo.FileSize; } else -#endif *FileInfo = Node->FileInfo; } ////////////////////////////////////////////////////////////////////// -void DumpNodes(NODE_ Node, int indent=0) +NTSTATUS FindNode(AIRFS_ Airfs, PWSTR Name, PWSTR *BaseName, NODE_ *PParent, NODE_ *PNode) { - UINT32 dir = FILE_ATTRIBUTE_DIRECTORY & Node->FileInfo.FileAttributes; - printf("%c%3d ", dir ? 'd' : 'f', (int)Node->RefCount); - for (int i = indent; i; i--) putchar('\t'); - printf("\"%S\"\n", Node->Name); - if (Node->Children) - for (auto& Child : *Node->Children) - DumpNodes(Child, indent+1); -} + CompareFunction* NodeCmp = Airfs->CaseInsensitive ? CaselessNameCmp : ExactNameCmp; -////////////////////////////////////////////////////////////////////// - -NTSTATUS CreateNodeSet(BOOLEAN CaseInsensitive, NODES_ *PNodeSet) -{ - try - { - *PNodeSet = new NODES(NODE_LESS(CaseInsensitive)); - return STATUS_SUCCESS; - } - catch (...) - { - *PNodeSet = 0; - return STATUS_INSUFFICIENT_RESOURCES; - } -} - -////////////////////////////////////////////////////////////////////// - -void DeleteAllNodes(AIRFS_ Airfs) -{ - NODE_ Node = Airfs->Root; - while (Node) - { - if (!Node->Children->empty()) - { - Node = *Node->Children->begin(); - } - else - { -#if defined(AIRFS_NAMED_STREAMS) - if (Node->Streams) - { - for (auto Iter = Node->Streams->begin(); Iter != Node->Streams->end(); ) - { - NODE_ Stream = *Iter++; - DeleteNode(Airfs, Stream); - } - delete Node->Streams; - } -#endif - NODE_ Parent = Node->Parent; - DeleteNode(Airfs, Node); - Node = Parent; - } - } -} - -////////////////////////////////////////////////////////////////////// - -NTSTATUS FindNode(AIRFS_ Airfs, PWSTR Name, PWSTR *BaseName, - NODE_ *PParent, NODE_ *PNode) -{ // Special case root. if (Name[0] == 0 || Name[1] == 0) { @@ -329,45 +137,39 @@ NTSTATUS FindNode(AIRFS_ Airfs, PWSTR Name, PWSTR *BaseName, } WCHAR ParsedName[AIRFS_MAX_PATH]; - wcscpy_s(ParsedName, sizeof ParsedName / sizeof(WCHAR), Name); + wcscpy_s(ParsedName, sizeof ParsedName / sizeof WCHAR, Name); // From root, for each ancestor... NODE_ Ancestor = Airfs->Root; WCHAR* fm; WCHAR* to = ParsedName; -#if defined(AIRFS_NAMED_STREAMS) WCHAR* Colon = 0; -#endif for (;;) { // Isolate the next base name. for (fm = to+1; *fm == L'\\'; fm++) {} for (to = fm; *to != L'\0' && *to != L'\\'; to++) - if (*to == ':'){Colon = to; break;} + if (*to == ':') {Colon = to; break;} if (*to == 0) break; *to = 0; // Find this name. - auto Iter = Ancestor->Children->find((NODE_)fm); - if (Iter == Ancestor->Children->end()) + NODE_ Child = Find(Ancestor->Children, fm, NodeCmp); + if (!Child) { if (PParent) *PParent = 0; *PNode = 0; -#if defined(AIRFS_NAMED_STREAMS) if (Colon) return STATUS_OBJECT_NAME_NOT_FOUND; -#endif return STATUS_OBJECT_PATH_NOT_FOUND; } - Ancestor = *Iter; + Ancestor = Child; -#if defined(AIRFS_NAMED_STREAMS) if (Colon) { fm = to+1; break; } -#endif if (!(Ancestor->FileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { @@ -378,12 +180,11 @@ NTSTATUS FindNode(AIRFS_ Airfs, PWSTR Name, PWSTR *BaseName, } if (BaseName) - *BaseName = Name + ( ( (UINT_PTR)fm - (UINT_PTR)ParsedName ) / sizeof(WCHAR)); + *BaseName = Name + ( ( (UINT_PTR)fm - (UINT_PTR)ParsedName ) / sizeof WCHAR); if (PParent) *PParent = Ancestor; -#if defined(AIRFS_NAMED_STREAMS) if (Colon) { // Find the stream, if it exists. @@ -392,86 +193,64 @@ NTSTATUS FindNode(AIRFS_ Airfs, PWSTR Name, PWSTR *BaseName, *PNode = 0; return STATUS_OBJECT_NAME_NOT_FOUND; } - auto Iter = Ancestor->Streams->find((NODE_)fm); - if (Iter == Ancestor->Streams->end()) + NODE_ Stream = Find(Ancestor->Streams, fm, NodeCmp); + if (!Stream) { *PNode = 0; return STATUS_OBJECT_NAME_NOT_FOUND; } - *PNode = *Iter; + *PNode = Stream; return 0; } -#endif // Find the directory entry, if it exists. - auto Iter = Ancestor->Children->find((NODE_)fm); - if (Iter == Ancestor->Children->end()) + NODE_ Found = Find(Ancestor->Children, fm, NodeCmp); + if (!Found) { *PNode = 0; return STATUS_OBJECT_NAME_NOT_FOUND; } - *PNode = *Iter; + *PNode = Found; return 0; } ////////////////////////////////////////////////////////////////////// -#if defined(AIRFS_NAMED_STREAMS) BOOLEAN AddStreamInfo(NODE_ Node, PWSTR StreamName, PVOID Buffer, ULONG Length, PULONG PBytesTransferred) { - UINT8 StreamInfoBuf[sizeof(FSP_FSCTL_STREAM_INFO) + sizeof Node->Name]; + UINT8 StreamInfoBuf[sizeof FSP_FSCTL_STREAM_INFO + AIRFS_MAX_PATH * sizeof WCHAR]; FSP_FSCTL_STREAM_INFO *StreamInfo = (FSP_FSCTL_STREAM_INFO *)StreamInfoBuf; - StreamInfo->Size = (UINT16)(sizeof(FSP_FSCTL_STREAM_INFO) + wcslen(StreamName) * sizeof(WCHAR)); + StreamInfo->Size = (UINT16)(sizeof FSP_FSCTL_STREAM_INFO + wcslen(StreamName) * sizeof WCHAR); StreamInfo->StreamSize = Node->FileInfo.FileSize; StreamInfo->StreamAllocationSize = Node->FileInfo.AllocationSize; - memcpy(StreamInfo->StreamNameBuf, StreamName, StreamInfo->Size - sizeof(FSP_FSCTL_STREAM_INFO)); + memcpy(StreamInfo->StreamNameBuf, StreamName, StreamInfo->Size - sizeof FSP_FSCTL_STREAM_INFO); return FspFileSystemAddStreamInfo(StreamInfo, Buffer, Length, PBytesTransferred); } -#endif ////////////////////////////////////////////////////////////////////// inline void TouchNode(NODE_ Node) { Node->FileInfo.LastAccessTime = Node->FileInfo.LastWriteTime = - Node->FileInfo.ChangeTime = GetSystemTime(); + Node->FileInfo.ChangeTime = SystemTime(); } ////////////////////////////////////////////////////////////////////// -NTSTATUS InsertNode(AIRFS_ Airfs, NODE_ Parent, NODE_ Node, PBOOLEAN PInserted) +void InsertNode(AIRFS_ Airfs, NODE_ Parent, NODE_ Node) { - try - { -#if defined(AIRFS_NAMED_STREAMS) - if (Node->IsAStream) - { - if (!Parent->Streams) - { - NTSTATUS Result = CreateNodeSet(Airfs->CaseInsensitive, &Parent->Streams); - if (Result) return Result; - } - *PInserted = Parent->Streams->insert(Node).second; - } - else -#endif - *PInserted = Parent->Children->insert(Node).second; - if (*PInserted) - { - Node->Parent = Parent; - ReferenceNode(Node); - TouchNode(Parent); - } - return STATUS_SUCCESS; - } - catch (...) - { - *PInserted = 0; - return STATUS_INSUFFICIENT_RESOURCES; - } + CompareFunction* NodeCmp = Airfs->CaseInsensitive ? CaselessNameCmp : ExactNameCmp; + + WCHAR* key = Node->Name; + if (Node->IsAStream) Attach(Parent->Streams , Node, NodeCmp, key); + else Attach(Parent->Children , Node, NodeCmp, key); + + Node->Parent = Parent; + ReferenceNode(Node); + TouchNode(Parent); } ////////////////////////////////////////////////////////////////////// @@ -481,239 +260,70 @@ void RemoveNode(AIRFS_ Airfs, NODE_ Node) NODE_ Parent = Node->Parent; TouchNode(Parent); -#if defined(AIRFS_NAMED_STREAMS) if (Node->IsAStream) { - if (Parent->Streams) - { - auto found = Parent->Streams->find(Node); - if (found != Parent->Streams->end()) - Parent->Streams->erase(found); - } + if (Parent->Streams) Detach(Parent->Streams, Node); } else -#endif - Parent->Children->erase(Node); + Detach(Parent->Children, Node); DereferenceNode(Airfs, Node); } ////////////////////////////////////////////////////////////////////// -inline BOOLEAN NodeHasChildren(NODE_ Node) -{ - return Node->Children && !Node->Children->empty(); -} - -////////////////////////////////////////////////////////////////////// - -#ifdef AIRFS_SLOWIO -/* - * SLOWIO - * - * This is included for two uses: - * - * 1) For testing winfsp, by allowing Airfs to act more like a non-ram file system, - * with some IO taking many milliseconds, and some IO completion delayed. - * - * 2) As sample code for how to use winfsp's STATUS_PENDING capabilities. - * - */ - -inline UINT64 Hash(UINT64 x) -{ - x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ull; - x = (x ^ (x >> 27)) * 0x94d049bb133111ebull; - x = x ^ (x >> 31); - return x; -} - -inline ULONG PseudoRandom(ULONG to) -{ - // John Oberschelp's PRNG - static UINT64 spin = 0; - InterlockedIncrement(&spin); - return Hash(spin) % to; -} - -inline BOOLEAN SlowioReturnPending(FSP_FILE_SYSTEM *FileSystem) -{ - AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; - if (!Airfs->SlowioMaxDelay) - return FALSE; - return PseudoRandom(100) < Airfs->SlowioPercentDelay; -} - -inline void SlowioSnooze(FSP_FILE_SYSTEM *FileSystem) -{ - AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; - if (!Airfs->SlowioMaxDelay) - return; - ULONG millis = PseudoRandom(Airfs->SlowioMaxDelay + 1) >> PseudoRandom(Airfs->SlowioRarefyDelay + 1); - Sleep(millis); -} - -void SlowioReadThread( - FSP_FILE_SYSTEM *FileSystem, - NODE_ Node, - PVOID Buffer, - UINT64 Offset, - UINT64 EndOffset, - UINT64 RequestHint) -{ - SlowioSnooze(FileSystem); - - memcpy(Buffer, (PUINT8)Node->FileData + Offset, (size_t)(EndOffset - Offset)); - UINT32 BytesTransferred = (ULONG)(EndOffset - Offset); - - FSP_FSCTL_TRANSACT_RSP ResponseBuf; - memset(&ResponseBuf, 0, sizeof ResponseBuf); - ResponseBuf.Size = sizeof ResponseBuf; - ResponseBuf.Kind = FspFsctlTransactReadKind; - ResponseBuf.Hint = RequestHint; // IRP that is being completed - ResponseBuf.IoStatus.Status = STATUS_SUCCESS; - ResponseBuf.IoStatus.Information = BytesTransferred; // bytes read - FspFileSystemSendResponse(FileSystem, &ResponseBuf); - - AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; - InterlockedDecrement(&Airfs->SlowioThreadsRunning); -} - -void SlowioWriteThread( - FSP_FILE_SYSTEM *FileSystem, - NODE_ Node, - PVOID Buffer, - UINT64 Offset, - UINT64 EndOffset, - UINT64 RequestHint) -{ - SlowioSnooze(FileSystem); - - memcpy((PUINT8)Node->FileData + Offset, Buffer, (size_t)(EndOffset - Offset)); - UINT32 BytesTransferred = (ULONG)(EndOffset - Offset); - - FSP_FSCTL_TRANSACT_RSP ResponseBuf; - memset(&ResponseBuf, 0, sizeof ResponseBuf); - ResponseBuf.Size = sizeof ResponseBuf; - ResponseBuf.Kind = FspFsctlTransactWriteKind; - ResponseBuf.Hint = RequestHint; // IRP that is being completed - ResponseBuf.IoStatus.Status = STATUS_SUCCESS; - ResponseBuf.IoStatus.Information = BytesTransferred; // bytes written - GetFileInfo(Node, &ResponseBuf.Rsp.Write.FileInfo); - FspFileSystemSendResponse(FileSystem, &ResponseBuf); - - AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; - InterlockedDecrement(&Airfs->SlowioThreadsRunning); -} - -void SlowioReadDirectoryThread( - FSP_FILE_SYSTEM *FileSystem, - ULONG BytesTransferred, - UINT64 RequestHint) -{ - SlowioSnooze(FileSystem); - - FSP_FSCTL_TRANSACT_RSP ResponseBuf; - memset(&ResponseBuf, 0, sizeof ResponseBuf); - ResponseBuf.Size = sizeof ResponseBuf; - ResponseBuf.Kind = FspFsctlTransactQueryDirectoryKind; - ResponseBuf.Hint = RequestHint; // IRP that is being completed - ResponseBuf.IoStatus.Status = STATUS_SUCCESS; - ResponseBuf.IoStatus.Information = BytesTransferred; // bytes of directory info read - FspFileSystemSendResponse(FileSystem, &ResponseBuf); - - AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; - InterlockedDecrement(&Airfs->SlowioThreadsRunning); -} -#endif -////////////////////////////////////////////////////////////////////// -#if defined(AIRFS_REPARSE_POINTS) - NTSTATUS GetReparsePointByName(FSP_FILE_SYSTEM *FileSystem, PVOID Context, PWSTR Name, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize) { AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; NODE_ Node; -#if defined(AIRFS_NAMED_STREAMS) - // GetReparsePointByName will never receive a named stream. - assert(wcschr(Name, L':') == 0); -#endif - NTSTATUS Result = FindNode(Airfs, Name, 0, 0, &Node); - if (!Node) - return STATUS_OBJECT_NAME_NOT_FOUND; - - if (!(Node->FileInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) - return STATUS_NOT_A_REPARSE_POINT; + if (!Node) return STATUS_OBJECT_NAME_NOT_FOUND; + if (!(Node->FileInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) return STATUS_NOT_A_REPARSE_POINT; if (Buffer) { - if (Node->ReparseDataSize > *PSize) - return STATUS_BUFFER_TOO_SMALL; - + if (Node->ReparseDataSize > *PSize) return STATUS_BUFFER_TOO_SMALL; *PSize = Node->ReparseDataSize; - memcpy(Buffer, Node->ReparseData, Node->ReparseDataSize); + memcpy(Buffer, Node->ReparseData.Address(), Node->ReparseDataSize); } return STATUS_SUCCESS; } -#endif ////////////////////////////////////////////////////////////////////// -NTSTATUS SetAllocSize(FSP_FILE_SYSTEM *FileSystem, NODE_ Node, - UINT64 RequestedAllocSize) +NTSTATUS SetAllocSize(AIRFS_ Airfs, NODE_ Node, UINT64 RequestedAllocSize) { - AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; - - RequestedAllocSize = IN_ALLOCATION_UNITS(RequestedAllocSize); - - if (Node->FileInfo.AllocationSize != RequestedAllocSize) + NTSTATUS Result = StorageSetFileCapacity(Airfs, Node, RequestedAllocSize); + if (!Result) { - if (RequestedAllocSize > Airfs->MaxFileSize) return STATUS_DISK_FULL; - - // Reallocate only if the file is made smaller, or if it will not fit in the actual memory footprint. - size_t ActualSize = AirfsHeapSize(Node->FileData); - if (RequestedAllocSize < Node->FileInfo.AllocationSize || RequestedAllocSize > ActualSize) - { - // If the file grow request was modest, guess that it might happen again, and grow the file by 50%. - if (RequestedAllocSize > Node->FileInfo.AllocationSize && RequestedAllocSize <= ActualSize + ActualSize / 8) - RequestedAllocSize = IN_ALLOCATION_UNITS(ActualSize + ActualSize / 2); - - PVOID FileData = AirfsHeapRealloc(Node->FileData, (size_t)RequestedAllocSize); - if (!FileData && RequestedAllocSize > 0) - return STATUS_INSUFFICIENT_RESOURCES; - - Node->FileData = FileData; - } - Node->FileInfo.AllocationSize = RequestedAllocSize; - if (Node->FileInfo.FileSize > RequestedAllocSize) - Node->FileInfo.FileSize = RequestedAllocSize; - } + if (Node->FileInfo.FileSize > Node->FileInfo.AllocationSize) + Node->FileInfo.FileSize = Node->FileInfo.AllocationSize; - return STATUS_SUCCESS; + } + return Result; } ////////////////////////////////////////////////////////////////////// -NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem, NODE_ Node, - UINT64 RequestedFileSize) +NTSTATUS SetFileSize(AIRFS_ Airfs, NODE_ Node, UINT64 RequestedFileSize) { if (Node->FileInfo.FileSize != RequestedFileSize) { if (Node->FileInfo.AllocationSize < RequestedFileSize) { - NTSTATUS Result = SetAllocSize(FileSystem, Node, RequestedFileSize); + NTSTATUS Result = SetAllocSize(Airfs, Node, RequestedFileSize); if (!NT_SUCCESS(Result)) return Result; } if (Node->FileInfo.FileSize < RequestedFileSize) - memset((PUINT8)Node->FileData + Node->FileInfo.FileSize, 0, - (size_t)(RequestedFileSize - Node->FileInfo.FileSize)); + StorageAccessFile(ZERO, Node, Node->FileInfo.FileSize, RequestedFileSize - Node->FileInfo.FileSize, 0); + Node->FileInfo.FileSize = RequestedFileSize; } @@ -722,25 +332,15 @@ NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem, NODE_ Node, ////////////////////////////////////////////////////////////////////// -BOOLEAN AddDirInfo(NODE_ Node, PWSTR Name, PVOID Buffer, ULONG Length, - PULONG PBytesTransferred) +BOOLEAN AddDirInfo(NODE_ Node, PWSTR Name, PVOID Buffer, ULONG Length, PULONG PBytesTransferred) { - UINT8 DirInfoBuf[sizeof(FSP_FSCTL_DIR_INFO) + sizeof Node->Name]; + size_t NameBytes = wcslen(Name) * sizeof WCHAR; + UINT8 DirInfoBuf[sizeof FSP_FSCTL_DIR_INFO + AIRFS_MAX_PATH * sizeof WCHAR]; FSP_FSCTL_DIR_INFO *DirInfo = (FSP_FSCTL_DIR_INFO *)DirInfoBuf; - WCHAR Root[2] = L"\\"; - PWSTR Remain, Suffix; - - if (!Name) - { - FspPathSuffix(Node->Name, &Remain, &Suffix, Root); - Name = Suffix; - FspPathCombine(Node->Name, Suffix); - } - - memset(DirInfo->Padding, 0, sizeof DirInfo->Padding); - DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + wcslen(Name) * sizeof(WCHAR)); + DirInfo->Size = (UINT16)(sizeof FSP_FSCTL_DIR_INFO + NameBytes); DirInfo->FileInfo = Node->FileInfo; - memcpy(DirInfo->FileNameBuf, Name, DirInfo->Size - sizeof(FSP_FSCTL_DIR_INFO)); + memset(DirInfo->Padding, 0, sizeof DirInfo->Padding); + memcpy(DirInfo->FileNameBuf, Name, NameBytes + sizeof WCHAR); return FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred); } @@ -751,11 +351,11 @@ NTSTATUS ApiGetVolumeInfo(FSP_FILE_SYSTEM *FileSystem, FSP_FSCTL_VOLUME_INFO *Vo { AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; - VolumeInfo->TotalSize = Airfs->MaxNodes * (UINT64)Airfs->MaxFileSize; - VolumeInfo->FreeSize = (Airfs->MaxNodes - Airfs->NumNodes) * - (UINT64)Airfs->MaxFileSize; + VolumeInfo->TotalSize = Airfs->VolumeSize; + VolumeInfo->FreeSize = Airfs->FreeSize; VolumeInfo->VolumeLabelLength = Airfs->VolumeLabelLength; memcpy(VolumeInfo->VolumeLabel, Airfs->VolumeLabel, Airfs->VolumeLabelLength); + return STATUS_SUCCESS; } @@ -766,14 +366,13 @@ NTSTATUS ApiSetVolumeLabel(FSP_FILE_SYSTEM *FileSystem, PWSTR VolumeLabel, { AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; - Airfs->VolumeLabelLength = (UINT16)(wcslen(VolumeLabel) * sizeof(WCHAR)); + Airfs->VolumeLabelLength = (UINT16)(wcslen(VolumeLabel) * sizeof WCHAR); if (Airfs->VolumeLabelLength > sizeof Airfs->VolumeLabel) Airfs->VolumeLabelLength = sizeof Airfs->VolumeLabel; memcpy(Airfs->VolumeLabel, VolumeLabel, Airfs->VolumeLabelLength); - VolumeInfo->TotalSize = Airfs->MaxNodes * Airfs->MaxFileSize; - VolumeInfo->FreeSize = - (Airfs->MaxNodes - Airfs->NumNodes) * Airfs->MaxFileSize; + VolumeInfo->TotalSize = Airfs->VolumeSize; + VolumeInfo->FreeSize = Airfs->FreeSize; VolumeInfo->VolumeLabelLength = Airfs->VolumeLabelLength; memcpy(VolumeInfo->VolumeLabel, Airfs->VolumeLabel, Airfs->VolumeLabelLength); @@ -790,17 +389,14 @@ NTSTATUS ApiGetSecurityByName(FSP_FILE_SYSTEM *FileSystem, PWSTR Name, PUINT32 P NTSTATUS Result = FindNode(Airfs, Name, 0, 0, &Node); if (!Node) { -#if defined(AIRFS_REPARSE_POINTS) if (FspFileSystemFindReparsePoint(FileSystem, GetReparsePointByName, 0, Name, PFileAttributes)) { return STATUS_REPARSE; } -#endif return Result; } -#if defined(AIRFS_NAMED_STREAMS) UINT32 FileAttributesMask = ~(UINT32)0; if (Node->IsAStream) { @@ -810,10 +406,6 @@ NTSTATUS ApiGetSecurityByName(FSP_FILE_SYSTEM *FileSystem, PWSTR Name, PUINT32 P if (PFileAttributes) *PFileAttributes = Node->FileInfo.FileAttributes & FileAttributesMask; -#else - if (PFileAttributes) - *PFileAttributes = Node->FileInfo.FileAttributes; -#endif if (PSecurityDescriptorSize) { @@ -825,7 +417,7 @@ NTSTATUS ApiGetSecurityByName(FSP_FILE_SYSTEM *FileSystem, PWSTR Name, PUINT32 P *PSecurityDescriptorSize = Node->SecurityDescriptorSize; if (SecurityDescriptor) - memcpy(SecurityDescriptor, Node->SecurityDescriptor, Node->SecurityDescriptorSize); + memcpy(SecurityDescriptor, Node->SecurityDescriptor.Address(), Node->SecurityDescriptorSize); } return STATUS_SUCCESS; @@ -841,7 +433,6 @@ NTSTATUS ApiCreate(FSP_FILE_SYSTEM *FileSystem, PWSTR Name, UINT32 CreateOptions NODE_ Node; NODE_ Parent; NTSTATUS Result; - BOOLEAN Inserted; PWSTR BaseName; if (AIRFS_MAX_PATH <= wcslen(Name)) @@ -851,36 +442,13 @@ NTSTATUS ApiCreate(FSP_FILE_SYSTEM *FileSystem, PWSTR Name, UINT32 CreateOptions AllocationSize = 0; Result = FindNode(Airfs, Name, &BaseName, &Parent, &Node); - - if (Node) - return STATUS_OBJECT_NAME_COLLISION; - - if (!Parent) - return Result; - - if (Airfs->NumNodes >= Airfs->MaxNodes) - return STATUS_CANNOT_MAKE; - - if (AllocationSize > Airfs->MaxFileSize) - return STATUS_DISK_FULL; + if (Node) return STATUS_OBJECT_NAME_COLLISION; + if (!Parent) return Result; Result = CreateNode(Airfs, BaseName, &Node); - if (!NT_SUCCESS(Result)) - return Result; + if (!NT_SUCCESS(Result)) return Result; -#if defined(AIRFS_NAMED_STREAMS) Node->IsAStream = BaseName[-1] == L':'; -#endif - - if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - Result = CreateNodeSet(Airfs->CaseInsensitive, &Node->Children); - if (Result) - { - DeleteNode(Airfs, Node); - return STATUS_INSUFFICIENT_RESOURCES; - } - } Node->FileInfo.FileAttributes = (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FileAttributes : FileAttributes | FILE_ATTRIBUTE_ARCHIVE; @@ -888,51 +456,40 @@ NTSTATUS ApiCreate(FSP_FILE_SYSTEM *FileSystem, PWSTR Name, UINT32 CreateOptions if (SecurityDescriptor) { Node->SecurityDescriptorSize = GetSecurityDescriptorLength(SecurityDescriptor); - Node->SecurityDescriptor = (PSECURITY_DESCRIPTOR)malloc(Node->SecurityDescriptorSize); + Node->SecurityDescriptor = StorageAllocate(Airfs, (int)Node->SecurityDescriptorSize); if (!Node->SecurityDescriptor) { DeleteNode(Airfs, Node); return STATUS_INSUFFICIENT_RESOURCES; } - memcpy(Node->SecurityDescriptor, SecurityDescriptor, Node->SecurityDescriptorSize); + memcpy(Node->SecurityDescriptor.Address(), SecurityDescriptor, Node->SecurityDescriptorSize); } - Node->FileInfo.AllocationSize = AllocationSize; - if (Node->FileInfo.AllocationSize) + if (AllocationSize) { - Node->FileData = AirfsHeapAlloc((size_t)Node->FileInfo.AllocationSize); - if (!Node->FileData) + NTSTATUS Result = SetAllocSize(Airfs, Node, AllocationSize); + if (Result) { DeleteNode(Airfs, Node); - return STATUS_INSUFFICIENT_RESOURCES; + return Result; } } - Result = InsertNode(Airfs, Parent, Node, &Inserted); - if (!NT_SUCCESS(Result) || !Inserted) - { - DeleteNode(Airfs, Node); - if (NT_SUCCESS(Result)) - Result = STATUS_OBJECT_NAME_COLLISION; // Should not happen! - return Result; - } - + InsertNode(Airfs, Parent, Node); ReferenceNode(Node); *PNode = Node; GetFileInfo(Node, FileInfo); -#if defined(AIRFS_NAME_NORMALIZATION) if (Airfs->CaseInsensitive) { int ParentPathNumBytes = (int)( (char*)BaseName - (char*)Name ); - int NodeNameNumBytes = (int)( wcslen(Node->Name) * sizeof(WCHAR) ); + int NodeNameNumBytes = (int)( wcslen(Node->Name) * sizeof WCHAR ); FSP_FSCTL_OPEN_FILE_INFO *OpenFileInfo = FspFileSystemGetOpenFileInfo(FileInfo); memcpy(OpenFileInfo->NormalizedName, Name, ParentPathNumBytes); - memcpy(OpenFileInfo->NormalizedName+ParentPathNumBytes / sizeof(WCHAR), Node->Name, NodeNameNumBytes); + memcpy(OpenFileInfo->NormalizedName+ParentPathNumBytes / sizeof WCHAR, Node->Name, NodeNameNumBytes); OpenFileInfo->NormalizedNameSize = ParentPathNumBytes + NodeNameNumBytes; } -#endif return STATUS_SUCCESS; } @@ -961,18 +518,16 @@ NTSTATUS ApiOpen(FSP_FILE_SYSTEM *FileSystem, PWSTR Name, UINT32 CreateOptions, *PNode = Node; GetFileInfo(Node, FileInfo); -#if defined(AIRFS_NAME_NORMALIZATION) if (Airfs->CaseInsensitive) { int ParentPathNumBytes = (int)( (char*)baseName - (char*)Name ); - int NodeNameNumBytes = (int)( wcslen(Node->Name) * sizeof(WCHAR) ); + int NodeNameNumBytes = (int)( wcslen(Node->Name) * sizeof WCHAR ); FSP_FSCTL_OPEN_FILE_INFO *OpenFileInfo = FspFileSystemGetOpenFileInfo(FileInfo); memcpy(OpenFileInfo->NormalizedName, Name, ParentPathNumBytes); - memcpy(OpenFileInfo->NormalizedName+ParentPathNumBytes / sizeof(WCHAR), Node->Name, NodeNameNumBytes); + memcpy(OpenFileInfo->NormalizedName+ParentPathNumBytes / sizeof WCHAR, Node->Name, NodeNameNumBytes); OpenFileInfo->NormalizedNameSize = ParentPathNumBytes + NodeNameNumBytes; } -#endif return STATUS_SUCCESS; } @@ -984,42 +539,30 @@ NTSTATUS ApiOverwrite(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, UINT32 FileAttri { AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; NODE_ Node = (NODE_) Node0; - NTSTATUS Result; -#if defined(AIRFS_NAMED_STREAMS) - if (Node->Streams) + for (NODE_ Stream = First(Node->Streams); Stream; ) { - for (auto Iter = Node->Streams->begin(); Iter != Node->Streams->end(); ) + NODE_ NextStream = Next(Stream); + LONG RefCount = Stream->RefCount; + MemoryBarrier(); + if (RefCount <= 1) { - NODE_ Stream = *Iter++; - LONG RefCount = Stream->RefCount; - MemoryBarrier(); - if (RefCount <= 1) - { - RemoveNode(Airfs, Stream); - } - } - if (Node->Streams->empty()) - { - delete Node->Streams; - Node->Streams = 0; + RemoveNode(Airfs, Stream); } + Stream = NextStream; } -#endif - Result = SetAllocSize(FileSystem, Node, AllocationSize); + NTSTATUS Result = SetAllocSize(Airfs, Node, AllocationSize); if (!NT_SUCCESS(Result)) return Result; - if (ReplaceFileAttributes) - Node->FileInfo.FileAttributes = FileAttributes | FILE_ATTRIBUTE_ARCHIVE; - else - Node->FileInfo.FileAttributes |= FileAttributes | FILE_ATTRIBUTE_ARCHIVE; + if (ReplaceFileAttributes) Node->FileInfo.FileAttributes = FileAttributes | FILE_ATTRIBUTE_ARCHIVE; + else Node->FileInfo.FileAttributes |= FileAttributes | FILE_ATTRIBUTE_ARCHIVE; Node->FileInfo.FileSize = 0; Node->FileInfo.LastAccessTime = Node->FileInfo.LastWriteTime = - Node->FileInfo.ChangeTime = GetSystemTime(); + Node->FileInfo.ChangeTime = SystemTime(); GetFileInfo(Node, FileInfo); @@ -1032,53 +575,36 @@ void ApiCleanup(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, PWSTR Name, ULONG Flag { AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; NODE_ Node = (NODE_) Node0; -#if defined(AIRFS_NAMED_STREAMS) - NODE_ MainNode = Node->IsAStream ? Node->Parent : Node; -#else - NODE_ MainNode = Node; -#endif - assert(Flags); // FSP_FSCTL_VOLUME_PARAMS::PostCleanupWhenModifiedOnly ensures this. + NODE_ MainNode = Node->IsAStream ? Node->Parent : Node; if (Flags & FspCleanupSetArchiveBit) { if (!(MainNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - MainNode->FileInfo.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; + MainNode->FileInfo.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; } if (Flags & (FspCleanupSetLastAccessTime | FspCleanupSetLastWriteTime | FspCleanupSetChangeTime)) { - UINT64 SystemTime = GetSystemTime(); - - if (Flags & FspCleanupSetLastAccessTime) - MainNode->FileInfo.LastAccessTime = SystemTime; - if (Flags & FspCleanupSetLastWriteTime) - MainNode->FileInfo.LastWriteTime = SystemTime; - if (Flags & FspCleanupSetChangeTime) - MainNode->FileInfo.ChangeTime = SystemTime; + UINT64 Time = SystemTime(); + if (Flags & FspCleanupSetLastAccessTime ) MainNode->FileInfo.LastAccessTime = Time; + if (Flags & FspCleanupSetLastWriteTime ) MainNode->FileInfo.LastWriteTime = Time; + if (Flags & FspCleanupSetChangeTime ) MainNode->FileInfo.ChangeTime = Time; } if (Flags & FspCleanupSetAllocationSize) { - SetAllocSize(FileSystem, Node, Node->FileInfo.FileSize); + SetAllocSize(Airfs, Node, Node->FileInfo.FileSize); } - if ((Flags & FspCleanupDelete) && !NodeHasChildren(Node)) + if ((Flags & FspCleanupDelete) && !Node->Children) { - -#if defined(AIRFS_NAMED_STREAMS) - if (Node->Streams) + NODE_ Stream; + while (Stream = Node->Streams) { - for (auto Iter = Node->Streams->begin(); Iter != Node->Streams->end(); ) - { - NODE_ Stream = *Iter++; - DeleteNode(Airfs, Stream); - } - delete Node->Streams; - Node->Streams = 0; + Detach(Node->Streams, Stream); + DeleteNode(Airfs, Stream); } -#endif - RemoveNode(Airfs, Node); } } @@ -1095,42 +621,21 @@ void ApiClose(FSP_FILE_SYSTEM *FileSystem, PVOID Node0) ////////////////////////////////////////////////////////////////////// NTSTATUS ApiRead(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, PVOID Buffer, - UINT64 Offset, ULONG Length, PULONG PBytesTransferred) + UINT64 BegOffset, ULONG Length, PULONG PBytesTransferred) { NODE_ Node = (NODE_) Node0; UINT64 EndOffset; - if (Offset >= Node->FileInfo.FileSize) + if (BegOffset >= Node->FileInfo.FileSize) return STATUS_END_OF_FILE; - EndOffset = Offset + Length; + EndOffset = BegOffset + Length; if (EndOffset > Node->FileInfo.FileSize) EndOffset = Node->FileInfo.FileSize; -#ifdef AIRFS_SLOWIO - if (SlowioReturnPending(FileSystem)) - { - AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; - try - { - InterlockedIncrement(&Airfs->SlowioThreadsRunning); - std::thread(SlowioReadThread, - FileSystem, Node, Buffer, Offset, EndOffset, - FspFileSystemGetOperationContext()->Request->Hint). - detach(); - return STATUS_PENDING; - } - catch (...) - { - InterlockedDecrement(&Airfs->SlowioThreadsRunning); - } - } - SlowioSnooze(FileSystem); -#endif + StorageAccessFile(READ, Node, BegOffset, EndOffset - BegOffset, (char*)Buffer); - memcpy(Buffer, (PUINT8)Node->FileData + Offset, (size_t)(EndOffset - Offset)); - - *PBytesTransferred = (ULONG)(EndOffset - Offset); + *PBytesTransferred = (ULONG)(EndOffset - BegOffset); return STATUS_SUCCESS; } @@ -1138,58 +643,38 @@ NTSTATUS ApiRead(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, PVOID Buffer, ////////////////////////////////////////////////////////////////////// NTSTATUS ApiWrite(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, PVOID Buffer, - UINT64 Offset, ULONG Length, BOOLEAN WriteToEndOfFile, + UINT64 BegOffset, ULONG Length, BOOLEAN WriteToEndOfFile, BOOLEAN ConstrainedIo, PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo) { + AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; NODE_ Node = (NODE_) Node0; UINT64 EndOffset; NTSTATUS Result; if (ConstrainedIo) { - if (Offset >= Node->FileInfo.FileSize) + if (BegOffset >= Node->FileInfo.FileSize) return STATUS_SUCCESS; - EndOffset = Offset + Length; + EndOffset = BegOffset + Length; if (EndOffset > Node->FileInfo.FileSize) EndOffset = Node->FileInfo.FileSize; } else { if (WriteToEndOfFile) - Offset = Node->FileInfo.FileSize; - EndOffset = Offset + Length; + BegOffset = Node->FileInfo.FileSize; + EndOffset = BegOffset + Length; if (EndOffset > Node->FileInfo.FileSize) { - Result = SetFileSize(FileSystem, Node, EndOffset); + Result = SetFileSize(Airfs, Node, EndOffset); if (!NT_SUCCESS(Result)) return Result; } } -#ifdef AIRFS_SLOWIO - if (SlowioReturnPending(FileSystem)) - { - AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; - try - { - InterlockedIncrement(&Airfs->SlowioThreadsRunning); - std::thread(SlowioWriteThread, - FileSystem, Node, Buffer, Offset, EndOffset, - FspFileSystemGetOperationContext()->Request->Hint). - detach(); - return STATUS_PENDING; - } - catch (...) - { - InterlockedDecrement(&Airfs->SlowioThreadsRunning); - } - } - SlowioSnooze(FileSystem); -#endif + StorageAccessFile(WRITE, Node, BegOffset, EndOffset - BegOffset, (char*)Buffer); - memcpy((PUINT8)Node->FileData + Offset, Buffer, (size_t)(EndOffset - Offset)); - - *PBytesTransferred = (ULONG)(EndOffset - Offset); + *PBytesTransferred = (ULONG)(EndOffset - BegOffset); GetFileInfo(Node, FileInfo); return STATUS_SUCCESS; @@ -1197,30 +682,11 @@ NTSTATUS ApiWrite(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, PVOID Buffer, ////////////////////////////////////////////////////////////////////// -NTSTATUS ApiFlush(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, - FSP_FSCTL_FILE_INFO *FileInfo) +NTSTATUS ApiFlush(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, FSP_FSCTL_FILE_INFO *FileInfo) { NODE_ Node = (NODE_) Node0; - // Nothing to flush, since we do not cache anything. - - if (Node) - { -#if 0 -#if defined(AIRFS_NAMED_STREAMS) - if (Node->IsAStream) - Node->MainNode->FileInfo.LastAccessTime = - Node->MainNode->FileInfo.LastWriteTime = - Node->MainNode->FileInfo.ChangeTime = GetSystemTime(); - else -#endif - Node->FileInfo.LastAccessTime = - Node->FileInfo.LastWriteTime = - Node->FileInfo.ChangeTime = GetSystemTime(); -#endif - - GetFileInfo(Node, FileInfo); - } + if (Node) GetFileInfo(Node, FileInfo); return STATUS_SUCCESS; } @@ -1245,9 +711,7 @@ NTSTATUS ApiSetBasicInfo(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, UINT32 FileAt { NODE_ Node = (NODE_) Node0; -#if defined(AIRFS_NAMED_STREAMS) if (Node->IsAStream) Node = Node->Parent; -#endif if (INVALID_FILE_ATTRIBUTES != FileAttributes) Node->FileInfo.FileAttributes = FileAttributes; @@ -1266,10 +730,11 @@ NTSTATUS ApiSetBasicInfo(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, UINT32 FileAt NTSTATUS ApiSetFileSize(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, UINT64 NewSize, BOOLEAN SetAllocationSize, FSP_FSCTL_FILE_INFO *FileInfo) { + AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; NODE_ Node = (NODE_) Node0; NTSTATUS Result = SetAllocationSize - ? SetAllocSize(FileSystem, Node, NewSize) - : SetFileSize(FileSystem, Node, NewSize); + ? SetAllocSize (Airfs, Node, NewSize) + : SetFileSize (Airfs, Node, NewSize); if (!NT_SUCCESS(Result)) return Result; @@ -1284,7 +749,7 @@ NTSTATUS ApiCanDelete(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, PWSTR Name) { NODE_ Node = (NODE_) Node0; - if (NodeHasChildren(Node)) + if (Node->Children) return STATUS_DIRECTORY_NOT_EMPTY; return STATUS_SUCCESS; @@ -1298,19 +763,33 @@ NTSTATUS ApiRename(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, PWSTR Name, AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; NODE_ Node = (NODE_) Node0; NODE_ NewNode; - BOOLEAN Inserted; NTSTATUS Result; - PWSTR newBaseName; + PWSTR NewBaseName; NODE_ NewParent; - Result = FindNode(Airfs, NewFileName, &newBaseName, &NewParent, &NewNode); + Result = FindNode(Airfs, NewFileName, &NewBaseName, &NewParent, &NewNode); + + // Create the replacement name. + size_t NewBaseNameNumBytes = (wcslen(NewBaseName)+1) * sizeof WCHAR; + WCHAR* NewBaseNameAlloc = (WCHAR*) StorageAllocate(Airfs, NewBaseNameNumBytes); + if (!NewBaseNameAlloc) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + memcpy(NewBaseNameAlloc, NewBaseName, NewBaseNameNumBytes); if (NewNode && Node != NewNode) { if (!ReplaceIfExists) + { + StorageFree(Airfs, NewBaseNameAlloc); return STATUS_OBJECT_NAME_COLLISION; + } if (NewNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + StorageFree(Airfs, NewBaseNameAlloc); return STATUS_ACCESS_DENIED; + } ReferenceNode(NewNode); RemoveNode(Airfs, NewNode); @@ -1319,8 +798,11 @@ NTSTATUS ApiRename(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, PWSTR Name, ReferenceNode(Node); RemoveNode(Airfs, Node); - wcscpy_s(Node->Name, sizeof Node->Name / sizeof(WCHAR), newBaseName); - Result = InsertNode(Airfs, NewParent, Node, &Inserted); + + StorageFree(Airfs, Node->Name); + Node->Name = NewBaseNameAlloc; + + InsertNode(Airfs, NewParent, Node); DereferenceNode(Airfs, Node); return STATUS_SUCCESS; @@ -1333,9 +815,7 @@ NTSTATUS ApiGetSecurity(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, { NODE_ Node = (NODE_) Node0; -#if defined(AIRFS_NAMED_STREAMS) if (Node->IsAStream) Node = Node->Parent; -#endif if (Node->SecurityDescriptorSize > *PSecurityDescriptorSize) { @@ -1345,7 +825,7 @@ NTSTATUS ApiGetSecurity(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, *PSecurityDescriptorSize = Node->SecurityDescriptorSize; if (SecurityDescriptor) - memcpy(SecurityDescriptor, Node->SecurityDescriptor, Node->SecurityDescriptorSize); + memcpy(SecurityDescriptor, Node->SecurityDescriptor.Address(), Node->SecurityDescriptorSize); return STATUS_SUCCESS; } @@ -1355,49 +835,58 @@ NTSTATUS ApiGetSecurity(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, NTSTATUS ApiSetSecurity(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor) { + AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; NODE_ Node = (NODE_) Node0; - PSECURITY_DESCRIPTOR NewSecurityDescriptor, SecurityDescriptor; - SIZE_T SecurityDescriptorSize; - NTSTATUS Result; + PSECURITY_DESCRIPTOR NewSecurityDescriptor, MallocSecurityDescriptor; -#if defined(AIRFS_NAMED_STREAMS) if (Node->IsAStream) Node = Node->Parent; -#endif - Result = FspSetSecurityDescriptor( - Node->SecurityDescriptor, + NTSTATUS Result = FspSetSecurityDescriptor( + Node->SecurityDescriptor.Address(), SecurityInformation, ModificationDescriptor, &NewSecurityDescriptor); if (!NT_SUCCESS(Result)) return Result; - SecurityDescriptorSize = GetSecurityDescriptorLength(NewSecurityDescriptor); - SecurityDescriptor = (PSECURITY_DESCRIPTOR)malloc(SecurityDescriptorSize); - if (!SecurityDescriptor) + uint64_t SecurityDescriptorSize = GetSecurityDescriptorLength(NewSecurityDescriptor); + MallocSecurityDescriptor = (PSECURITY_DESCRIPTOR) malloc(SecurityDescriptorSize); + if (!MallocSecurityDescriptor) { FspDeleteSecurityDescriptor(NewSecurityDescriptor, (NTSTATUS (*)())FspSetSecurityDescriptor); return STATUS_INSUFFICIENT_RESOURCES; } - memcpy(SecurityDescriptor, NewSecurityDescriptor, SecurityDescriptorSize); + memcpy(MallocSecurityDescriptor, NewSecurityDescriptor, SecurityDescriptorSize); FspDeleteSecurityDescriptor(NewSecurityDescriptor, (NTSTATUS (*)())FspSetSecurityDescriptor); - free(Node->SecurityDescriptor); - Node->SecurityDescriptorSize = SecurityDescriptorSize; - Node->SecurityDescriptor = SecurityDescriptor; + NODE_ NewHunk = (NODE_) StorageReallocate(Airfs, Node->SecurityDescriptor, SecurityDescriptorSize); + if (!NewHunk && SecurityDescriptorSize) + { + free(MallocSecurityDescriptor); + return STATUS_INSUFFICIENT_RESOURCES; + } + Node->SecurityDescriptorSize = SecurityDescriptorSize; + if (!SecurityDescriptorSize) Node->SecurityDescriptor = 0; + else + { + Node->SecurityDescriptor = NewHunk; + memcpy(Node->SecurityDescriptor.Address(), MallocSecurityDescriptor, SecurityDescriptorSize); + } + + free(MallocSecurityDescriptor); return STATUS_SUCCESS; } ////////////////////////////////////////////////////////////////////// -NTSTATUS ApiReadDirectory(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, - PWSTR Pattern, PWSTR Marker, PVOID Buffer, ULONG Length, - PULONG PBytesTransferred) +NTSTATUS ApiReadDirectory(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, PWSTR Pattern, + PWSTR Marker, PVOID Buffer, ULONG Length, PULONG PBytesTransferred) { - assert(!Pattern); - AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; + + CompareFunction* NodeCmp = Airfs->CaseInsensitive ? CaselessNameCmp : ExactNameCmp; + NODE_ Node = (NODE_) Node0; NODE_ Parent = Node->Parent; if (Parent) @@ -1416,65 +905,45 @@ NTSTATUS ApiReadDirectory(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, } } - auto Iter = Marker ? Node->Children->upper_bound((NODE_)Marker) : Node->Children->begin(); - for (; Iter != Node->Children->end(); ++Iter) + // Find the next Child, even if the Marker child no longer exists. + NODE_ Child; + if (!Marker) Child = First(Node->Children); + else Child = Near(Node->Children, Marker, NodeCmp, GT); + + for (; Child; Child = Next(Child)) { - NODE_ Node = *Iter; - if (!AddDirInfo(Node, Node->Name, Buffer, Length, PBytesTransferred)) - { + if (!AddDirInfo(Child, Child->Name, Buffer, Length, PBytesTransferred)) goto bufferReady; - } } FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred); bufferReady: -#ifdef AIRFS_SLOWIO - if (SlowioReturnPending(FileSystem)) - { - try - { - InterlockedIncrement(&Airfs->SlowioThreadsRunning); - std::thread(SlowioReadDirectoryThread, - FileSystem, *PBytesTransferred, - FspFileSystemGetOperationContext()->Request->Hint). - detach(); - return STATUS_PENDING; - } - catch (...) - { - InterlockedDecrement(&Airfs->SlowioThreadsRunning); - } - } - SlowioSnooze(FileSystem); -#endif - return STATUS_SUCCESS; } ////////////////////////////////////////////////////////////////////// -#if defined(AIRFS_DIRINFO_BY_NAME) NTSTATUS ApiGetDirInfoByName(FSP_FILE_SYSTEM *FileSystem, PVOID ParentNode0, PWSTR Name, FSP_FSCTL_DIR_INFO *DirInfo) { - NODE_ Parent = (NODE_) ParentNode0; - NODE_ Node; - auto Iter = Parent->Children->find((NODE_)Name); - if (Iter == Parent->Children->end()) - return STATUS_OBJECT_NAME_NOT_FOUND; - Node = *Iter; + AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; - DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + wcslen(Node->Name) * sizeof(WCHAR)); + CompareFunction* NodeCmp = Airfs->CaseInsensitive ? CaselessNameCmp : ExactNameCmp; + + NODE_ Parent = (NODE_) ParentNode0; + NODE_ Node = Find(Parent->Children, Name, NodeCmp); + if (!Node) + return STATUS_OBJECT_NAME_NOT_FOUND; + + DirInfo->Size = (UINT16)(sizeof FSP_FSCTL_DIR_INFO + wcslen(Node->Name) * sizeof WCHAR); DirInfo->FileInfo = Node->FileInfo; - memcpy(DirInfo->FileNameBuf, Node->Name, DirInfo->Size - sizeof(FSP_FSCTL_DIR_INFO)); + memcpy(DirInfo->FileNameBuf, Node->Name, DirInfo->Size - sizeof FSP_FSCTL_DIR_INFO); return STATUS_SUCCESS; } -#endif ////////////////////////////////////////////////////////////////////// -#if defined(AIRFS_REPARSE_POINTS) NTSTATUS ApiResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem, PWSTR Name, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent, @@ -1492,9 +961,7 @@ NTSTATUS ApiGetReparsePoint(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, { NODE_ Node = (NODE_) Node0; -#if defined(AIRFS_NAMED_STREAMS) if (Node->IsAStream) Node = Node->Parent; -#endif if (!(Node->FileInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) return STATUS_NOT_A_REPARSE_POINT; @@ -1503,7 +970,7 @@ NTSTATUS ApiGetReparsePoint(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, return STATUS_BUFFER_TOO_SMALL; *PSize = Node->ReparseDataSize; - memcpy(Buffer, Node->ReparseData, Node->ReparseDataSize); + memcpy(Buffer, Node->ReparseData.Address(), Node->ReparseDataSize); return STATUS_SUCCESS; } @@ -1513,27 +980,25 @@ NTSTATUS ApiGetReparsePoint(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, NTSTATUS ApiSetReparsePoint(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, PWSTR Name, PVOID Buffer, SIZE_T Size) { + AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; NODE_ Node = (NODE_) Node0; - PVOID ReparseData; NTSTATUS Result; -#if defined(AIRFS_NAMED_STREAMS) if (Node->IsAStream) Node = Node->Parent; -#endif - if (NodeHasChildren(Node)) + if (Node->Children) return STATUS_DIRECTORY_NOT_EMPTY; if (Node->ReparseData) { Result = FspFileSystemCanReplaceReparsePoint( - Node->ReparseData, Node->ReparseDataSize, + Node->ReparseData.Address(), Node->ReparseDataSize, Buffer, Size); if (!NT_SUCCESS(Result)) return Result; } - ReparseData = realloc(Node->ReparseData, Size); + NODE_ ReparseData = (NODE_) StorageReallocate(Airfs, Node->ReparseData, Size); if (!ReparseData && Size) return STATUS_INSUFFICIENT_RESOURCES; @@ -1542,7 +1007,7 @@ NTSTATUS ApiSetReparsePoint(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, // The first field in a reparse buffer is the reparse tag. Node->ReparseDataSize = Size; Node->ReparseData = ReparseData; - memcpy(Node->ReparseData, Buffer, Size); + memcpy(Node->ReparseData.Address(), Buffer, Size); return STATUS_SUCCESS; } @@ -1552,17 +1017,16 @@ NTSTATUS ApiSetReparsePoint(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, NTSTATUS ApiDeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, PWSTR Name, PVOID Buffer, SIZE_T Size) { + AIRFS_ Airfs = (AIRFS_) FileSystem->UserContext; NODE_ Node = (NODE_) Node0; NTSTATUS Result; -#if defined(AIRFS_NAMED_STREAMS) if (Node->IsAStream) Node = Node->Parent; -#endif if (Node->ReparseData) { Result = FspFileSystemCanReplaceReparsePoint( - Node->ReparseData, Node->ReparseDataSize, + Node->ReparseData.Address(), Node->ReparseDataSize, Buffer, Size); if (!NT_SUCCESS(Result)) return Result; @@ -1570,7 +1034,7 @@ NTSTATUS ApiDeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, else return STATUS_NOT_A_REPARSE_POINT; - free(Node->ReparseData); + StorageFree(Airfs, Node->ReparseData); Node->FileInfo.FileAttributes &= ~FILE_ATTRIBUTE_REPARSE_POINT; Node->FileInfo.ReparseTag = 0; @@ -1580,9 +1044,7 @@ NTSTATUS ApiDeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, return STATUS_SUCCESS; } -#endif ////////////////////////////////////////////////////////////////////// -#if defined(AIRFS_NAMED_STREAMS) NTSTATUS ApiGetStreamInfo(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, PVOID Buffer, ULONG Length, PULONG PBytesTransferred) @@ -1595,15 +1057,12 @@ NTSTATUS ApiGetStreamInfo(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, if (!AddStreamInfo(Node, L"", Buffer, Length, PBytesTransferred)) return STATUS_SUCCESS; - if (Node->Streams) + for (NODE_ Stream = First(Node->Streams); Stream; Stream = Next(Stream)) { - // TODO: how to handle out-of-response-buffer-space condition? - for (auto Iter = Node->Streams->begin(); Iter != Node->Streams->end(); ++Iter) - { - BOOLEAN added = AddStreamInfo(*Iter, (*Iter)->Name, Buffer, Length, PBytesTransferred); - if (!added) goto done; - } + BOOLEAN added = AddStreamInfo(Stream, Stream->Name, Buffer, Length, PBytesTransferred); + if (!added) goto done; } + FspFileSystemAddStreamInfo(0, Buffer, Length, PBytesTransferred); done: @@ -1611,9 +1070,7 @@ NTSTATUS ApiGetStreamInfo(FSP_FILE_SYSTEM *FileSystem, PVOID Node0, return STATUS_SUCCESS; } -#endif ////////////////////////////////////////////////////////////////////// -#if defined(AIRFS_CONTROL) NTSTATUS ApiControl(FSP_FILE_SYSTEM *FileSystem, PVOID FileContext, UINT32 ControlCode, @@ -1639,7 +1096,6 @@ NTSTATUS ApiControl(FSP_FILE_SYSTEM *FileSystem, return STATUS_INVALID_DEVICE_REQUEST; } -#endif ////////////////////////////////////////////////////////////////////// FSP_FILE_SYSTEM_INTERFACE AirfsInterface = @@ -1663,32 +1119,13 @@ FSP_FILE_SYSTEM_INTERFACE AirfsInterface = ApiGetSecurity, ApiSetSecurity, ApiReadDirectory, -#if defined(AIRFS_REPARSE_POINTS) ApiResolveReparsePoints, ApiGetReparsePoint, ApiSetReparsePoint, ApiDeleteReparsePoint, -#else - 0, - 0, - 0, - 0, -#endif -#if defined(AIRFS_NAMED_STREAMS) ApiGetStreamInfo, -#else - 0, -#endif -#if defined(AIRFS_DIRINFO_BY_NAME) ApiGetDirInfoByName, -#else - 0, -#endif -#if defined(AIRFS_CONTROL) ApiControl, -#else - 0, -#endif }; ////////////////////////////////////////////////////////////////////// @@ -1696,192 +1133,143 @@ FSP_FILE_SYSTEM_INTERFACE AirfsInterface = void AirfsDelete(AIRFS_ Airfs) { FspFileSystemDelete(Airfs->FileSystem); - - DeleteAllNodes(Airfs); - - free(Airfs); -} - -////////////////////////////////////////////////////////////////////// - -NTSTATUS AirfsStart(AIRFS_ Airfs) -{ -#ifdef AIRFS_SLOWIO - Airfs->SlowioThreadsRunning = 0; -#endif - - return FspFileSystemStartDispatcher(Airfs->FileSystem, 0); -} - -////////////////////////////////////////////////////////////////////// - -void AirfsStop(AIRFS_ Airfs) -{ - FspFileSystemStopDispatcher(Airfs->FileSystem); - -#ifdef AIRFS_SLOWIO - while (Airfs->SlowioThreadsRunning) - Sleep(1); -#endif + StorageShutdown(Airfs); } ////////////////////////////////////////////////////////////////////// NTSTATUS AirfsCreate( + PWSTR VolumeName, + PWSTR MapName, ULONG Flags, ULONG FileInfoTimeout, - ULONG MaxNodes, - ULONG MaxFileSize, - ULONG SlowioMaxDelay, - ULONG SlowioPercentDelay, - ULONG SlowioRarefyDelay, + UINT64 VolumeSize, PWSTR FileSystemName, PWSTR VolumePrefix, PWSTR RootSddl, AIRFS_ *PAirfs) { NTSTATUS Result; - FSP_FSCTL_VOLUME_PARAMS VolumeParams; BOOLEAN CaseInsensitive = !!(Flags & AirfsCaseInsensitive); BOOLEAN FlushAndPurgeOnCleanup = !!(Flags & AirfsFlushAndPurgeOnCleanup); PWSTR DevicePath = AirfsNet == (Flags & AirfsDeviceMask) ? L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME; AIRFS_ Airfs; - NODE_ RootNode; - PSECURITY_DESCRIPTOR RootSecurity; + PSECURITY_DESCRIPTOR RootSecurity = 0; ULONG RootSecuritySize; *PAirfs = 0; - if (!AirfsHeapInitialize()) - return STATUS_INSUFFICIENT_RESOURCES; + boolean VolumeExists = *VolumeName && (_waccess(VolumeName, 0) != -1); - if (!RootSddl) - RootSddl = L"O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;FA;;;WD)"; - if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(RootSddl, SDDL_REVISION_1, - &RootSecurity, &RootSecuritySize)) - return FspNtStatusFromWin32(GetLastError()); + Result = StorageStartup(Airfs, MapName, VolumeName, VolumeSize); + if (Result) return Result; - Airfs = (AIRFS_) malloc(sizeof *Airfs); - if (!Airfs) + boolean ShouldFormat = !VolumeExists || memcmp(Airfs->VolumeLabel, L"AIRFS", 10); + + if (ShouldFormat) { + memcpy(Airfs->Signature,"Airfs\0\0\0" "\1\0\0\0" "\0\0\0\0", 16); + + if (!RootSddl) + RootSddl = L"O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;FA;;;WD)"; + if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(RootSddl, SDDL_REVISION_1, + &RootSecurity, &RootSecuritySize)) + return GetLastErrorAsStatus(); + + Airfs->VolumeName[0] = 0; + Airfs->VolumeSize = ROUND_DOWN(VolumeSize, ALLOCATION_UNIT); + + Airfs->CaseInsensitive = CaseInsensitive; + + FSP_FSCTL_VOLUME_PARAMS V; + memset(&V, 0, sizeof V); + V.Version = sizeof FSP_FSCTL_VOLUME_PARAMS; + V.SectorSize = SECTOR_SIZE; + V.SectorsPerAllocationUnit = SECTORS_PER_ALLOCATION_UNIT; + V.VolumeCreationTime = SystemTime(); + V.VolumeSerialNumber = (UINT32)(SystemTime() / (10000 * 1000)); + V.FileInfoTimeout = FileInfoTimeout; + V.CaseSensitiveSearch = !CaseInsensitive; + V.CasePreservedNames = 1; + V.UnicodeOnDisk = 1; + V.PersistentAcls = 1; + V.ReparsePoints = 1; + V.ReparsePointsAccessCheck = 0; + V.NamedStreams = 1; + V.PostCleanupWhenModifiedOnly = 1; + V.PassQueryDirectoryFileName = 1; + V.FlushAndPurgeOnCleanup = FlushAndPurgeOnCleanup; + V.DeviceControl = 1; + wcscpy_s(V.Prefix, sizeof V.Prefix / sizeof WCHAR, VolumePrefix); + wcscpy_s(V.FileSystemName, sizeof V.FileSystemName / sizeof WCHAR, + FileSystemName ? FileSystemName : L"-AIRFS"); + Airfs->VolumeParams = V; + + Airfs->VolumeLabelLength = sizeof L"AIRFS" - sizeof WCHAR; + memcpy(Airfs->VolumeLabel, L"AIRFS", Airfs->VolumeLabelLength); + + // Set up the available storage in chunks. + Airfs->FreeSize = 0; + Airfs->Available = 0; + uint64_t to = 4096; + for (;;) + { + uint64_t fm = to + sizeof int32_t; + to = fm + MAXIMUM_ALLOCSIZE; + if (to > Airfs->VolumeSize - MINIMUM_ALLOCSIZE) to = Airfs->VolumeSize; + int32_t Size = (int32_t)( to - fm ); + char* Addr = (char*)Airfs + fm;// + sizeof int32_t; + NODE_ NewItem = (NODE_) Addr; + ((int32_t*)NewItem)[-1] = Size; + Attach(Airfs->Available, NewItem, SizeCmp, &Size); + Airfs->FreeSize += Size; + if (to == Airfs->VolumeSize) break; + } + + // Create the root directory. + Airfs->Root = 0; + NODE_ RootNode; + Result = CreateNode(Airfs, L"", &RootNode); + if (!NT_SUCCESS(Result)) + { + AirfsDelete(Airfs); + LocalFree(RootSecurity); + return Result; + } + RootNode->P = RootNode->L = RootNode->R = RootNode->E = RootNode->Parent = 0; + RootNode->FileInfo.FileAttributes = FILE_ATTRIBUTE_DIRECTORY; + RootNode->SecurityDescriptor = StorageAllocate(Airfs, RootSecuritySize); + if (!RootNode->SecurityDescriptor) + { + DeleteNode(Airfs, RootNode); + AirfsDelete(Airfs); + LocalFree(RootSecurity); + return STATUS_INSUFFICIENT_RESOURCES; + } + RootNode->SecurityDescriptorSize = RootSecuritySize; + memcpy(RootNode->SecurityDescriptor.Address(), RootSecurity, RootSecuritySize); + Airfs->Root = RootNode; + ReferenceNode(RootNode); LocalFree(RootSecurity); - return STATUS_INSUFFICIENT_RESOURCES; } - memset(Airfs, 0, sizeof *Airfs); - Airfs->MaxNodes = MaxNodes; - Airfs->MaxFileSize = IN_ALLOCATION_UNITS(MaxFileSize); - -#ifdef AIRFS_SLOWIO - Airfs->SlowioMaxDelay = SlowioMaxDelay; - Airfs->SlowioPercentDelay = SlowioPercentDelay; - Airfs->SlowioRarefyDelay = SlowioRarefyDelay; -#endif - - Airfs->CaseInsensitive = CaseInsensitive; - - memset(&VolumeParams, 0, sizeof VolumeParams); - VolumeParams.Version = sizeof FSP_FSCTL_VOLUME_PARAMS; - VolumeParams.SectorSize = SECTOR_SIZE; - VolumeParams.SectorsPerAllocationUnit = SECTORS_PER_ALLOCATION_UNIT; - VolumeParams.VolumeCreationTime = GetSystemTime(); - VolumeParams.VolumeSerialNumber = (UINT32)(GetSystemTime() / (10000 * 1000)); - VolumeParams.FileInfoTimeout = FileInfoTimeout; - VolumeParams.CaseSensitiveSearch = !CaseInsensitive; - VolumeParams.CasePreservedNames = 1; - VolumeParams.UnicodeOnDisk = 1; - VolumeParams.PersistentAcls = 1; - VolumeParams.ReparsePoints = 1; - VolumeParams.ReparsePointsAccessCheck = 0; -#if defined(AIRFS_NAMED_STREAMS) - VolumeParams.NamedStreams = 1; -#endif - VolumeParams.PostCleanupWhenModifiedOnly = 1; -#if defined(AIRFS_DIRINFO_BY_NAME) - VolumeParams.PassQueryDirectoryFileName = 1; -#endif - VolumeParams.FlushAndPurgeOnCleanup = FlushAndPurgeOnCleanup; -#if defined(AIRFS_CONTROL) - VolumeParams.DeviceControl = 1; -#endif - if (VolumePrefix) - wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix); - wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR), - FileSystemName ? FileSystemName : L"-AIRFS"); - - Result = FspFileSystemCreate(DevicePath, &VolumeParams, &AirfsInterface, &Airfs->FileSystem); + Result = FspFileSystemCreate(DevicePath, &Airfs->VolumeParams, &AirfsInterface, &Airfs->FileSystem); if (!NT_SUCCESS(Result)) { - DeleteAllNodes(Airfs); - free(Airfs); LocalFree(RootSecurity); return Result; } Airfs->FileSystem->UserContext = Airfs; - Airfs->VolumeLabelLength = sizeof L"AIRFS" - sizeof(WCHAR); - memcpy(Airfs->VolumeLabel, L"AIRFS", Airfs->VolumeLabelLength); -#if 0 - FspFileSystemSetOperationGuardStrategy(Airfs->FileSystem, - FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE); -#endif - - // Create the root directory. - Result = CreateNode(Airfs, L"", &RootNode); - if (!NT_SUCCESS(Result)) - { - AirfsDelete(Airfs); - LocalFree(RootSecurity); - return Result; - } - Result = CreateNodeSet(Airfs->CaseInsensitive, &RootNode->Children); - if (Result) - { - AirfsDelete(Airfs); - LocalFree(RootSecurity); - return STATUS_INSUFFICIENT_RESOURCES; - } - RootNode->FileInfo.FileAttributes = FILE_ATTRIBUTE_DIRECTORY; - RootNode->SecurityDescriptor = malloc(RootSecuritySize); - if (!RootNode->SecurityDescriptor) - { - DeleteNode(Airfs, RootNode); - AirfsDelete(Airfs); - LocalFree(RootSecurity); - return STATUS_INSUFFICIENT_RESOURCES; - } - RootNode->SecurityDescriptorSize = RootSecuritySize; - memcpy(RootNode->SecurityDescriptor, RootSecurity, RootSecuritySize); - Airfs->Root = RootNode; - ReferenceNode(RootNode); - - LocalFree(RootSecurity); *PAirfs = Airfs; + return STATUS_SUCCESS; } ////////////////////////////////////////////////////////////////////// -#define PROGNAME "airfs" - -#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__) - -#define argtos(v) if (arge > ++argp) v = *argp; else goto usage -#define argtol(v) if (arge > ++argp) v = wcstol_default(*argp, v); else goto usage - -static ULONG wcstol_default(wchar_t *w, ULONG deflt) -{ - wchar_t *endp; - ULONG ul = wcstol(w, &endp, 0); - return L'\0' != w[0] && L'\0' == *endp ? ul : deflt; -} - -////////////////////////////////////////////////////////////////////// - NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) { wchar_t **argp, **arge; @@ -1890,14 +1278,12 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) ULONG Flags = AirfsDisk; ULONG OtherFlags = 0; ULONG FileInfoTimeout = INFINITE; - ULONG MaxNodes = 1024; - ULONG MaxFileSize = 16 * 1024 * 1024; - ULONG SlowioMaxDelay = 0; // -M: maximum slow IO delay in milliseconds - ULONG SlowioPercentDelay = 0; // -P: percent of slow IO to make pending - ULONG SlowioRarefyDelay = 0; // -R: adjust the rarity of pending slow IO + PWSTR VolumeName = L""; + PWSTR MapName = L""; + UINT64 VolumeSize = 16LL * 1024 * 1024; PWSTR FileSystemName = 0; PWSTR MountPoint = 0; - PWSTR VolumePrefix = 0; + PWSTR VolumePrefix = L""; PWSTR RootSddl = 0; HANDLE DebugLogHandle = INVALID_HANDLE_VALUE; AIRFS_ Airfs = 0; @@ -1910,23 +1296,20 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) switch (argp[0][1]) { case L'?': goto usage; - case L'd': argtol(DebugFlags); break; - case L'D': argtos(DebugLogFile); break; + case L'd': ARG_TO_4(DebugFlags); break; + case L'D': ARG_TO_S(DebugLogFile); break; case L'f': OtherFlags = AirfsFlushAndPurgeOnCleanup; break; - case L'F': argtos(FileSystemName); break; + case L'F': ARG_TO_S(FileSystemName); break; case L'i': OtherFlags = AirfsCaseInsensitive; break; - case L'm': argtos(MountPoint); break; - case L'M': argtol(SlowioMaxDelay); break; - case L'n': argtol(MaxNodes); break; - case L'P': argtol(SlowioPercentDelay); break; - case L'R': argtol(SlowioRarefyDelay); break; - case L'S': argtos(RootSddl); break; - case L's': argtol(MaxFileSize); break; - case L't': argtol(FileInfoTimeout); break; + case L'm': ARG_TO_S(MountPoint); break; + case L'N': ARG_TO_S(VolumeName); break; + case L'n': ARG_TO_S(MapName); break; + case L'S': ARG_TO_S(RootSddl); break; + case L's': ARG_TO_8(VolumeSize); break; + case L't': ARG_TO_4(FileInfoTimeout); break; case L'u': - argtos(VolumePrefix); - if (VolumePrefix && L'\0' != VolumePrefix[0]) - Flags = AirfsNet; + ARG_TO_S(VolumePrefix); + if (*VolumePrefix) Flags = AirfsNet; break; default: goto usage; @@ -1954,7 +1337,7 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) 0); if (INVALID_HANDLE_VALUE == DebugLogHandle) { - fail(L"cannot open debug log file"); + FAIL(L"cannot open debug log file"); goto usage; } @@ -1962,20 +1345,19 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) } Result = AirfsCreate( + VolumeName, + MapName, Flags | OtherFlags, FileInfoTimeout, - MaxNodes, - MaxFileSize, - SlowioMaxDelay, - SlowioPercentDelay, - SlowioRarefyDelay, + VolumeSize, FileSystemName, VolumePrefix, RootSddl, &Airfs); + if (!NT_SUCCESS(Result)) { - fail(L"cannot create AIRFS"); + FAIL(L"cannot create AIRFS"); goto exit; } @@ -1987,57 +1369,60 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) L'*' == MountPoint[0] && L'\0' == MountPoint[1] ? 0 : MountPoint); if (!NT_SUCCESS(Result)) { - fail(L"cannot mount AIRFS"); + FAIL(L"cannot mount AIRFS"); goto exit; } } - Result = AirfsStart(Airfs); + Result = FspFileSystemStartDispatcher(Airfs->FileSystem, 0); if (!NT_SUCCESS(Result)) { - fail(L"cannot start AIRFS"); + FAIL(L"cannot start AIRFS"); goto exit; } MountPoint = FspFileSystemMountPoint(Airfs->FileSystem); - info(L"%s -t %ld -n %ld -s %ld%s%s%s%s%s%s", - L"" PROGNAME, FileInfoTimeout, MaxNodes, MaxFileSize, - RootSddl ? L" -S " : L"", RootSddl ? RootSddl : L"", - VolumePrefix && L'\0' != VolumePrefix[0] ? L" -u " : L"", - VolumePrefix && L'\0' != VolumePrefix[0] ? VolumePrefix : L"", - MountPoint ? L" -m " : L"", MountPoint ? MountPoint : L""); + WCHAR buffer[1024]; + _snwprintf_s(buffer, 1024, L"%S%S%s%S%s -t %ld -s %lld%S%s%S%s%S%s", + PROGNAME, + *VolumeName ? " -N " : "", *VolumeName ? VolumeName : L"", + *MapName ? " -n " : "", *MapName ? MapName : L"", + FileInfoTimeout, VolumeSize, + RootSddl ? " -S " : "", RootSddl ? RootSddl : L"", + *VolumePrefix ? " -u " : "", *VolumePrefix ? VolumePrefix : L"", + MountPoint ? " -m " : "", MountPoint ? MountPoint : L""); + INFO(buffer); Service->UserContext = Airfs; Result = STATUS_SUCCESS; exit: + if (!NT_SUCCESS(Result) && Airfs) AirfsDelete(Airfs); - 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" - " -i [case insensitive file system]\n" " -f [flush and purge cache on cleanup]\n" - " -t FileInfoTimeout [millis]\n" - " -n MaxNodes\n" - " -s MaxFileSize [bytes]\n" - " -M MaxDelay [maximum slow IO delay in millis]\n" - " -P PercentDelay [percent of slow IO to make pending]\n" - " -R RarefyDelay [adjust the rarity of pending slow IO]\n" " -F FileSystemName\n" + " -i [case insensitive file system]\n" + " -m MountPoint [X:|* (required if no UNC prefix)]\n" + " -n MapName [(ex) \"Local\\Airfs\"]\n" + " -N VolumeName [\"\": in memory only]\n" + " -s VolumeSize [bytes]\n" " -S RootSddl [file rights: FA, etc; NO generic rights: GA, etc.]\n" - " -u \\Server\\Share [UNC prefix (single backslash)]\n" - " -m MountPoint [X:|* (required if no UNC prefix)]\n"; + " -t FileInfoTimeout [millis]\n" + " -u \\Server\\Share [UNC prefix (single backslash)]\n"; - fail(usage, L"" PROGNAME); + FAIL(usage, L"" PROGNAME); return STATUS_UNSUCCESSFUL; } @@ -2047,10 +1432,8 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) NTSTATUS SvcStop(FSP_SERVICE *Service) { AIRFS_ Airfs = (AIRFS_) Service->UserContext; - - AirfsStop(Airfs); + FspFileSystemStopDispatcher(Airfs->FileSystem); AirfsDelete(Airfs); - return STATUS_SUCCESS; } @@ -2065,3 +1448,4 @@ int wmain(int argc, wchar_t **argv) } ////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////