diff --git a/appveyor.yml b/appveyor.yml
index ba087bbe..77957461 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -15,6 +15,13 @@ init:
#- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
install:
+- ps: |
+ # Hack to make WDK 1903 work on VS2015.
+ # See https://github.com/appveyor-tests/WDK-10.0.14393.0/blob/31cf12217fe0c92b218c70d7027dfe145be4f4cb/appveyor.yml#L7
+ [xml]$targets = get-content "C:\Program Files (x86)\Windows Kits\10\build\WindowsDriver.Common.targets"
+ $usingTask = $targets.ChildNodes[1].UsingTask | ? {$_.TaskName -eq "ValidateNTTargetVersion"}
+ $usingTask.AssemblyFile = '$(WDKContentRoot)build\bin\Microsoft.DriverKit.Build.Tasks.16.0.dll'
+ $targets.Save("C:\Program Files (x86)\Windows Kits\10\build\WindowsDriver.Common.targets")
- git submodule update --init --recursive
- appveyor AddMessage "Change boot configuration and reboot" -Category Information
- bcdedit /set testsigning on
diff --git a/build/VStudio/installer/Product.wxs b/build/VStudio/installer/Product.wxs
index 86c89dd1..b10f28ba 100644
--- a/build/VStudio/installer/Product.wxs
+++ b/build/VStudio/installer/Product.wxs
@@ -391,6 +391,12 @@
+
+
+
+
+
+
@@ -587,6 +593,8 @@
+
+
@@ -750,4 +758,4 @@
-
\ No newline at end of file
+
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)
}
//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
diff --git a/tst/airfs/airfs.vcxproj b/tst/airfs/airfs.vcxproj
index f21301e1..3cd9bf9e 100644
--- a/tst/airfs/airfs.vcxproj
+++ b/tst/airfs/airfs.vcxproj
@@ -1,4 +1,4 @@
-
+
@@ -171,8 +171,12 @@
+
+
+
+
-
\ No newline at end of file
+
diff --git a/tst/airfs/airfs.vcxproj.filters b/tst/airfs/airfs.vcxproj.filters
index f67a722d..8ade23f2 100644
--- a/tst/airfs/airfs.vcxproj.filters
+++ b/tst/airfs/airfs.vcxproj.filters
@@ -1,4 +1,4 @@
-
+
@@ -10,5 +10,13 @@
Source
+
+ Source
+
-
\ No newline at end of file
+
+
+ Source
+
+
+
diff --git a/tst/airfs/common.h b/tst/airfs/common.h
new file mode 100644
index 00000000..57adff35
--- /dev/null
+++ b/tst/airfs/common.h
@@ -0,0 +1,212 @@
+/**
+ * @file common.h
+ *
+ * @copyright 2015-2019 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.
+ */
+/*
+ * Airfs is based on Memfs with changes contributed by John Oberschelp.
+ * The contributed changes are under joint copyright by Bill Zissimopoulos
+ * and John Oberschelp per the Contributor Agreement found at the
+ * root of this project.
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#define PROGNAME "airfs"
+#define ROUND_UP( bytes, units ) (((bytes) + (units) - 1) / (units) * (units))
+#define ROUND_DOWN( bytes, units ) (((bytes) ) / (units) * (units))
+#define MINIMUM_ALLOCSIZE 196
+#define MAXIMUM_ALLOCSIZE ROUND_DOWN(10*1024*1024, MINIMUM_ALLOCSIZE)
+#define SECTOR_SIZE 512
+#define SECTORS_PER_ALLOCATION_UNIT 1
+#define ALLOCATION_UNIT ( SECTOR_SIZE * SECTORS_PER_ALLOCATION_UNIT )
+#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 AIRFS_MAX_PATH 512
+#define FILEBLOCK_OVERHEAD 40 // size of ( P + E + L + R + FileOffset ) = 8 * 5 = 40
+#define ARG_TO_S(v) if (arge > ++argp) v = *argp; else goto usage
+#define ARG_TO_4(v) if (arge > ++argp) v = (int32_t) wcstoll_default(*argp, v); else goto usage
+#define ARG_TO_8(v) if (arge > ++argp) v = wcstoll_default(*argp, v); else goto usage
+
+enum StorageFileAccessType {ZERO=0,READ,WRITE};
+enum Neighbor {LT=-2,LE=-1,EQ=0,GE=1,GT=2};
+
+struct NODE;
+typedef NODE* NODE_;
+
+typedef int CompareFunction (void* key, NODE_);
+
+inline NTSTATUS GetLastErrorAsStatus()
+{
+ return FspNtStatusFromWin32(GetLastError());
+}
+
+inline UINT64 SystemTime()
+{
+ FILETIME FileTime;
+ GetSystemTimeAsFileTime(&FileTime);
+ return ((PLARGE_INTEGER)&FileTime)->QuadPart;
+}
+
+static int64_t wcstoll_default(wchar_t *w, int64_t deflt)
+{
+ wchar_t *endp;
+ int64_t i = wcstoll(w, &endp, 0);
+ return L'\0' != w[0] && L'\0' == *endp ? i : deflt;
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Where Class: This class manages an offset within our memory-mapped
+// volume to another location within our memory-mapped volume. Because it is
+// a self-relative offset, this delta is constant regardless of where in
+// memory the file system is mapped, so we can always reoptain its address.
+// A delta of 0 is the special case for "null".
+//
+
+template class Where
+{
+ int64_t delta;
+
+ public:
+
+ Where() = default;
+ ~Where() = default;
+ Where(T t) : delta( t ?( (char*)t -(char*)this ):0) {}
+ Where(Where& w) : delta( w.delta?( ((char*)&w+w.delta)-(char*)this ):0) {}
+
+ operator bool () { return delta != 0; }
+ operator T () { return (T) ( delta?( (char*)this+delta ):0); }
+ T operator -> () { return (T) ( delta?( (char*)this+delta ):0); }
+ operator void* () { return (void*)( delta?( (char*)this+delta ):0); }
+
+ bool operator == (Where& rhs) { return (char*)this+delta == (char*)&rhs+rhs.delta; }
+ bool operator != (Where& rhs) { return (char*)this+delta != (char*)&rhs+rhs.delta; }
+ bool operator == (T rhs) { return (char*)this+delta == (char*)rhs; }
+ bool operator != (T rhs) { return (char*)this+delta != (char*)rhs; }
+
+ Where& operator = (Where& rhs) { delta = rhs.delta?( ((char*)&rhs+rhs.delta) - ((char*)this) ):0; return *this; }
+ Where& operator = (void* rhs) { delta = rhs ?( (char*)rhs - ((char*)this) ):0; return *this; }
+
+ char* Address () { return (char*)this+delta; }
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// The header for an Airfs volume
+//
+
+typedef struct
+{
+ char Signature[8]; // Airfs\0\0\0
+ char MapFormatVersion[4]; // Major.Minor.Patch.Build
+ char filler[4];
+ Where Root;
+ Where Available;
+ UINT64 VolumeSize;
+ UINT64 FreeSize;
+ WCHAR VolumeLabel[32];
+ UINT16 VolumeLabelLength;
+ UINT16 filler1,filler2,filler3;
+ UINT32 CaseInsensitive;
+ UINT32 filler4;
+ WCHAR MapName[256];
+ WCHAR VolumeName[256]; // Use "" for a memory-only page file.
+ int64_t VolumeLength;
+ FSP_FSCTL_VOLUME_PARAMS VolumeParams;
+ FSP_FILE_SYSTEM *FileSystem;
+ HANDLE MapFileHandle;
+ HANDLE MapHandle;
+} AIRFS, *AIRFS_;
+
+//////////////////////////////////////////////////////////////////////
+//
+// Information per file or directory
+//
+struct NODE
+{
+ Where P,L,R,E; // Sorted sibling tree: Parent, Left, Right, and Equal
+ union
+ {
+ Where Name;
+ int64_t FileOffset;
+ };
+ Where Parent;
+ Where Children;
+ FSP_FSCTL_FILE_INFO FileInfo;
+ uint64_t SecurityDescriptorSize;
+ Where SecurityDescriptor;
+ Where FileBlocks;
+ uint64_t ReparseDataSize;
+ Where ReparseData;
+ volatile LONG RefCount;
+ Where Streams;
+ BOOLEAN IsAStream;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+class SpinLock
+{
+ LONG C; // Counter
+ HANDLE S; // Semaphore
+
+ public:
+
+ SpinLock() { C = 0; S = CreateSemaphore(NULL, 0, 1, NULL); }
+ ~SpinLock() { CloseHandle(S); }
+
+ void Acquire() { if (_InterlockedIncrement(&C) > 1) WaitForSingleObject(S, INFINITE); }
+ void Release() { if (_InterlockedDecrement(&C) > 0) ReleaseSemaphore(S, 1, NULL); }
+};
+
+//////////////////////////////////////////////////////////////////////
+
+void Airprint (const char * format, ...);
+
+int SizeCmp (void* key, NODE_);
+int ExactNameCmp (void* key, NODE_);
+int CaselessNameCmp (void* key, NODE_);
+
+NODE_ Find (Where &root, void* key, CompareFunction);
+NODE_ Near (Where &root, void* key, CompareFunction, Neighbor);
+void Attach (Where &root, NODE_ attach, CompareFunction, void* key);
+void Detach (Where &root, NODE_ detach);
+NODE_ First (NODE_ start);
+NODE_ Last (NODE_ start);
+NODE_ Next (NODE_);
+NODE_ Prev (NODE_);
+
+NTSTATUS StorageStartup (AIRFS_ &, WCHAR* MapName, WCHAR* VolumeName, int64_t Length);
+NTSTATUS StorageShutdown (AIRFS_);
+void* StorageAllocate (AIRFS_ Airfs, int64_t RequestedSize);
+void* StorageReallocate (AIRFS_ Airfs, void* Reallocate, int64_t RequestedSize);
+void StorageFree (AIRFS_ Airfs, void* Release);
+NTSTATUS StorageSetFileCapacity (AIRFS_, NODE_, int64_t MinimumRequiredCapacity);
+void StorageAccessFile (StorageFileAccessType, NODE_, int64_t Offset, int64_t NumBytes, char* Address);
+
+static_assert(AIRFS_MAX_PATH > MAX_PATH, "AIRFS_MAX_PATH must be greater than MAX_PATH.");
+static_assert(sizeof NODE + sizeof int32_t == MINIMUM_ALLOCSIZE, "MINIMUM_ALLOCSIZE should be 196.");
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
diff --git a/tst/airfs/persistence.cpp b/tst/airfs/persistence.cpp
new file mode 100644
index 00000000..85cd6d77
--- /dev/null
+++ b/tst/airfs/persistence.cpp
@@ -0,0 +1,597 @@
+/**
+ * @file persistence.cpp
+ *
+ * @copyright 2015-2019 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.
+ */
+/*
+ * Airfs is based on Memfs with changes contributed by John Oberschelp.
+ * The contributed changes are under joint copyright by Bill Zissimopoulos
+ * and John Oberschelp per the Contributor Agreement found at the
+ * root of this project.
+ */
+/*
+ * Airfs uses a memory-mapped file per volume to achieve persistence.
+ * The primary advantage of this is that volume loads and saves are automatic.
+ * The two primary disadvantages, and our workarounds are:
+ * 1. We can't use standard containers or memory management,
+ * so the below Rubbertree and Storage functions are used instead.
+ * 2. Each process will map the volume to an arbitrary address,
+ * so Where offsets are used in place of pointers.
+ */
+
+#include "common.h"
+
+SpinLock StorageLock, AirprintLock, SetLock;
+
+int SizeCmp ( void* key, NODE_ x)
+{
+ return *(int32_t*)key - ((int32_t*)x)[-1];
+}
+
+int BlockCmp ( void* key, NODE_ x)
+{
+ int64_t left = *(int64_t*)key;
+ int64_t right = x->FileOffset;
+ return left == right ? 0 : (left < right ? -1 : 1);
+}
+
+int CaselessNameCmp ( void* key, NODE_ x)
+{
+ WCHAR* c1 = (WCHAR*) key;
+ WCHAR* c2 = x->Name;
+ return _wcsicmp(c1,c2);
+}
+
+int ExactNameCmp ( void* key, NODE_ x)
+{
+ WCHAR* c1 = (WCHAR*) key;
+ WCHAR* c2 = x->Name;
+ return wcscmp(c1,c2);
+}
+
+//////////////////////////////////////////////////////////////////////
+
+void Airprint (const char * format, ...)
+{
+ AirprintLock.Acquire();
+ va_list args;
+ va_start(args, format);
+ char szBuffer[512];
+ sprintf_s(szBuffer, 511, "Airfs %5.5f ----", SystemTime() / 10'000'000.0);
+ vsnprintf(szBuffer+25, 511-25, format, args);
+ OutputDebugStringA(szBuffer);
+ va_end(args);
+ AirprintLock.Release();
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Rubbertree (because it is flexible!)
+// Implements a sorted set of elements, using a binary tree.
+// Has a function, Near, that finds nodes at or adjacent to a key.
+// Has an equal branch for trees that require handling equivalent
+// nodes, like Airfs' memory heap manager.
+// Attach, Find, and Near use splay to improve random access times.
+// First, Last, Next, and Prev do not, to improve sequential access times.
+// Replacing Where with NODE_ would make it a pointer-based tree.
+
+//--------------------------------------------------------------------
+
+inline void rotateL(Where &root, NODE_ x)
+{
+ NODE_ y = x->R, p = x->P;
+ if (x->R = y->L) y->L->P = x;
+ if (!(y->P = p))
+ root = y;
+ else
+ {
+ if (x == p->L) p->L = y;
+ else p->R = y;
+ }
+ (y->L = x)->P = y;
+}
+
+//--------------------------------------------------------------------
+
+inline void rotateR(Where &root, NODE_ y)
+{
+ NODE_ x = y->L, p = y->P;
+ if (y->L = x->R) x->R->P = y;
+ if (!(x->P = p))
+ root = x;
+ else
+ {
+ if (y == p->L) p->L = x;
+ else p->R = x;
+ }
+ (x->R = y)->P = x;
+}
+
+//--------------------------------------------------------------------
+
+static void splay(Where &root, NODE_ x)
+{
+ while (NODE_ p = x->P)
+ {
+ if (!p->P)
+ {
+ if (p->L == x) rotateR(root, p);
+ else rotateL(root, p);
+ }
+ else
+ {
+ if (p == p->P->R)
+ {
+ if (p->R == x) rotateL(root, p->P);
+ else rotateR(root, p);
+ rotateL(root, x->P);
+ }
+ else
+ {
+ if (p->L == x) rotateR(root, p->P);
+ else rotateL(root, p);
+ rotateR(root, x->P);
+ }
+ }
+ }
+}
+
+//--------------------------------------------------------------------
+
+inline int seek(Where &root, NODE_ &x, void* key, CompareFunction CMP)
+{
+ x = root;
+ for (;;)
+ {
+ int diff = CMP(key, x);
+ if (diff < 0)
+ {
+ if (!x->L) return -1;
+ x = x->L;
+ }
+ else if (diff > 0)
+ {
+ if (!x->R) return 1;
+ x = x->R;
+ }
+ else return 0;
+ }
+}
+
+//--------------------------------------------------------------------
+
+inline NODE_ next(NODE_ x)
+{
+ if (x->R) { x = x->R; while (x->L) x = x->L; return x; }
+ NODE_ p = x->P;
+ while (p && x == p->R) { x = p; p = p->P; }
+ return p;
+}
+
+//--------------------------------------------------------------------
+
+inline NODE_ prev(NODE_ x)
+{
+ if (x->L) { x = x->L; while (x->R) x = x->R; return x; }
+ NODE_ p = x->P;
+ while (p && x == p->L) { x = p; p = p->P; }
+ return p;
+}
+
+//--------------------------------------------------------------------
+
+NODE_ First(NODE_ x)
+{
+ SetLock.Acquire();
+ if (x) while (x->L) x = x->L;
+ SetLock.Release();
+ return x;
+}
+
+//--------------------------------------------------------------------
+
+NODE_ Last(NODE_ x)
+{
+ SetLock.Acquire();
+ if (x) while (x->R) x = x->R;
+ SetLock.Release();
+ return x;
+}
+
+//--------------------------------------------------------------------
+
+NODE_ Next(NODE_ x)
+{
+ SetLock.Acquire();
+ x = next(x);
+ SetLock.Release();
+ return x;
+}
+
+//--------------------------------------------------------------------
+
+NODE_ Prev(NODE_ x)
+{
+ SetLock.Acquire();
+ x = prev(x);
+ SetLock.Release();
+ return x;
+}
+
+//--------------------------------------------------------------------
+
+NODE_ Near(Where &root, void* key, CompareFunction CMP, Neighbor want)
+{
+ // Return a node relative to (just <, <=, ==, >=, or >) a key.
+ if (!root) return 0;
+ SetLock.Acquire();
+ NODE_ x;
+ int dir = seek(root, x, key, CMP);
+ if ((dir == 0 && want == GT) || (dir > 0 && want >= GE)) x = next(x);
+ else
+ if ((dir == 0 && want == LT) || (dir < 0 && want <= LE)) x = prev(x);
+ else
+ if (dir != 0 && want == EQ) x = 0;
+ if (x) splay(root, x);
+ SetLock.Release();
+ return x;
+}
+
+//--------------------------------------------------------------------
+
+NODE_ Find(Where &root, void* key, CompareFunction CMP)
+{
+ if (!root) return 0;
+ SetLock.Acquire();
+ NODE_ x;
+ int direction = seek(root, x, key, CMP);
+ splay(root, x);
+ SetLock.Release();
+ return direction?0:x;
+}
+
+//--------------------------------------------------------------------
+
+void Attach(Where &root, NODE_ x, CompareFunction CMP, void* key)
+{
+ SetLock.Acquire();
+ if (!root)
+ {
+ root = x;
+ x->P = x->L = x->R = x->E = 0;
+ SetLock.Release();
+ return;
+ }
+ NODE_ f;
+ int diff = seek(root, f, key, CMP);
+ if (!diff)
+ {
+ if (x->L = f->L) x->L->P = x;
+ if (x->R = f->R) x->R->P = x;
+ NODE_ p = f->P;
+ if (x->P = p) { if (p->L == f) p->L = x; else p->R = x; }
+ else root = x;
+ (x->E = f)->P = x;
+ f->L = f->R = 0;
+ splay(root, x);
+ SetLock.Release();
+ return;
+ }
+ if (diff < 0) f->L = x; else f->R = x;
+ x->P = f;
+ x->L = x->R = x->E = 0;
+ splay(root, x);
+ SetLock.Release();
+}
+
+//--------------------------------------------------------------------
+
+void Detach(Where &root, NODE_ x)
+{
+ SetLock.Acquire();
+ NODE_ e = x->E, p = x->P;
+ if (p && p->E == x) { if (p->E = e) e->P = p; }
+ else if (e)
+ {
+ if (e->L = x->L) e->L->P = e;
+ if (e->R = x->R) e->R->P = e;
+ if (e->P = p) { if (p->L == x) p->L = e; else p->R = e; }
+ else root = e;
+ }
+ else if (!x->L)
+ {
+ if (p) { if ( p->L == x) p->L = x->R; else p->R = x->R; }
+ else root = x->R;
+ if (x->R) x->R->P = p;
+ }
+ else if (!x->R)
+ {
+ if (p) { if ( p->L == x) p->L = x->L; else p->R = x->L; }
+ else root = x->L;
+ if (x->L) x->L->P = p;
+ }
+ else
+ {
+ e = x->L;
+ if (e->R)
+ {
+ do { e = e->R; } while (e->R);
+ if (e->P->R = e->L) e->L->P = e->P;
+ (e->L = x->L)->P = e;
+ }
+ (e->R = x->R)->P = e;
+ if (e->P = x->P) { if (e->P->L == x) e->P->L = e; else e->P->R = e; }
+ else root = e;
+ }
+ SetLock.Release();
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Storage Functions for our memory-mapped file-based persistent volumes
+
+//--------------------------------------------------------------------
+
+void* StorageAllocate(AIRFS_ Airfs, int64_t RequestedSize)
+{
+ if (!RequestedSize) return 0;
+ if (RequestedSize + sizeof int32_t > MAXIMUM_ALLOCSIZE) return 0;
+
+ StorageLock.Acquire();
+ int32_t RoundedSize = (int32_t) ROUND_UP(RequestedSize, MINIMUM_ALLOCSIZE - sizeof int32_t);
+ int32_t SplitableSize = RoundedSize + MINIMUM_ALLOCSIZE;
+
+ // See if we have a freed node of the size we requested.
+ NODE_ NewItem = Near(Airfs->Available, &RoundedSize, SizeCmp, GE);
+ if (NewItem)
+ {
+ int32_t FoundSize = ((int32_t*)NewItem)[-1];
+ if (FoundSize < SplitableSize)
+ {
+ Detach(Airfs->Available, NewItem);
+ Airfs->FreeSize -= FoundSize;
+ StorageLock.Release();
+ return NewItem;
+ }
+ }
+
+ // If not, see if we can downsize a larger freed element.
+ NewItem = Near(Airfs->Available, &SplitableSize, SizeCmp, GE);
+ if (NewItem)
+ {
+ int32_t FoundSize = ((int32_t*)NewItem)[-1];
+ Detach(Airfs->Available, NewItem);
+ Airfs->FreeSize -= FoundSize;
+ char* Addr = (char*)NewItem + RoundedSize + sizeof int32_t;
+ NODE_ Remainder = (NODE_) Addr;
+ int32_t RemainderSize = FoundSize - (RoundedSize + sizeof int32_t);
+ ((int32_t*)Remainder)[-1] = RemainderSize;
+ Attach(Airfs->Available, Remainder, SizeCmp, &RemainderSize);
+ Airfs->FreeSize += RemainderSize;
+ ((int32_t*)NewItem)[-1] = RoundedSize;
+ StorageLock.Release();
+ return NewItem;
+ }
+
+ // If not, give up.
+ StorageLock.Release();
+ return 0;
+}
+
+//--------------------------------------------------------------------
+
+void* StorageReallocate(AIRFS_ Airfs, void* OldAlloc, int64_t RequestedSize)
+{
+ if (!OldAlloc)
+ {
+ return StorageAllocate(Airfs, RequestedSize);
+ }
+
+ if (!RequestedSize)
+ {
+ StorageFree(Airfs, OldAlloc);
+ return 0;
+ }
+
+ int32_t OldSize = ((int32_t*)OldAlloc)[-1];
+ void* NewAlloc = StorageAllocate(Airfs, RequestedSize);
+ if (!NewAlloc) return 0;
+ memcpy(NewAlloc, OldAlloc, min(RequestedSize, OldSize));
+ StorageFree(Airfs, OldAlloc);
+ return NewAlloc;
+}
+
+//--------------------------------------------------------------------
+
+void StorageFree(AIRFS_ Airfs, void* r)
+{
+ if (!r) return;
+ StorageLock.Acquire();
+ NODE_ release = (NODE_) r;
+ int32_t Size = ((int32_t*)r)[-1];
+ Attach(Airfs->Available, release, SizeCmp, &Size);
+ Airfs->FreeSize += Size;
+ StorageLock.Release();
+}
+
+//--------------------------------------------------------------------
+
+void StorageAccessFile(StorageFileAccessType Type, NODE_ Node, int64_t AccessOffset, int64_t NumBytes, char* MemoryAddress)
+{
+ StorageLock.Acquire();
+
+ NODE_ Block = Near(Node->FileBlocks, &AccessOffset, BlockCmp, LE);
+ for (;;)
+ {
+ int32_t BlockSize = ((int32_t*)Block)[-1];
+ int64_t BlockOffset = Block->FileOffset;
+ int64_t BlockIndex = AccessOffset - BlockOffset + FILEBLOCK_OVERHEAD;
+ int64_t BlockNum = min(BlockSize-BlockIndex, NumBytes);
+
+ switch (Type)
+ {
+ case ZERO : { memset((char*)Block + BlockIndex, 0, BlockNum); break; }
+ case READ : { memcpy(MemoryAddress, (char*)Block + BlockIndex, BlockNum); break; }
+ case WRITE : { memcpy((char*)Block + BlockIndex, MemoryAddress, BlockNum); break; }
+ }
+ NumBytes -= BlockNum;
+ if (!NumBytes) break;
+ MemoryAddress += BlockNum;
+ AccessOffset += BlockNum;
+ Block = Next(Block);
+ }
+
+ StorageLock.Release();
+}
+
+//--------------------------------------------------------------------
+
+NTSTATUS StorageSetFileCapacity(AIRFS_ Airfs, NODE_ Node, int64_t minimumRequiredCapacity)
+{
+ StorageLock.Acquire();
+
+ int64_t TargetCapacity = ROUND_UP(minimumRequiredCapacity, ALLOCATION_UNIT);
+ NODE_ Block = Last(Node->FileBlocks);
+ int32_t BlockSize = Block ? ((int32_t*)Block)[-1] : 0;
+ int64_t CurrentCapacity = Block ? Block->FileOffset + BlockSize - FILEBLOCK_OVERHEAD: 0;
+ int64_t Add = TargetCapacity - CurrentCapacity;
+
+ while (Add > 0)
+ {
+ // Add a block if we can, preferably as large or larger than we need.
+ Add += FILEBLOCK_OVERHEAD;
+ Block = Near(Airfs->Available, &Add, SizeCmp, GE);
+ if (!Block) Block = Near(Airfs->Available, &Add, SizeCmp, LT);
+ Add -= FILEBLOCK_OVERHEAD;
+ if (Block)
+ {
+ Detach(Airfs->Available, Block);
+ BlockSize = ((int32_t*)Block)[-1];
+ Airfs->FreeSize -= BlockSize;
+ Block->FileOffset = CurrentCapacity;
+ Attach(Node->FileBlocks, Block, BlockCmp, &CurrentCapacity);
+ CurrentCapacity += BlockSize - FILEBLOCK_OVERHEAD;
+ Add -= BlockSize - FILEBLOCK_OVERHEAD;
+ continue;
+ }
+
+ StorageLock.Release();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Throw away any trailing blocks that are no longer needed.
+ while (Add < 0)
+ {
+ Block = Last(Node->FileBlocks);
+ BlockSize = ((int32_t*)Block)[-1];
+ if (BlockSize - FILEBLOCK_OVERHEAD > -Add) break;
+ Add += BlockSize - FILEBLOCK_OVERHEAD;
+ Detach(Node->FileBlocks, Block);
+ Attach(Airfs->Available, Block, SizeCmp, &BlockSize);
+ Airfs->FreeSize += BlockSize;
+ }
+
+ // Possibly downsize the last block.
+ if (Add < 0)
+ {
+ Block = Last(Node->FileBlocks);
+ int32_t OldBlockSize = ((int32_t*)Block)[-1];
+ int32_t NewBlockSize = OldBlockSize - (int32_t) ROUND_DOWN(-Add, MINIMUM_ALLOCSIZE);
+ if (NewBlockSize < MINIMUM_ALLOCSIZE) NewBlockSize = MINIMUM_ALLOCSIZE;
+ int32_t RemainderBlockSize = OldBlockSize - NewBlockSize - sizeof int32_t;
+ if (RemainderBlockSize >= MINIMUM_ALLOCSIZE) // i.e. if not too near the end
+ {
+ char* Addr = (char*)Block + NewBlockSize + sizeof int32_t;
+ NODE_ Remainder = (NODE_) Addr;
+ ((int32_t*)Remainder)[-1] = RemainderBlockSize;
+ Attach(Airfs->Available, Remainder, SizeCmp, &RemainderBlockSize);
+ Airfs->FreeSize += RemainderBlockSize;
+ ((int32_t*)Block)[-1] = NewBlockSize;
+ }
+ }
+
+ StorageLock.Release();
+ return 0;
+}
+
+//--------------------------------------------------------------------
+
+NTSTATUS StorageStartup(AIRFS_ &Airfs, WCHAR* MapName, WCHAR* VolumeName, int64_t VolumeLength)
+{
+ HANDLE MapFileHandle = INVALID_HANDLE_VALUE;
+ Airfs = 0;
+
+ // Open.
+ if (*VolumeName)
+ {
+ MapFileHandle = CreateFileW(VolumeName, GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE, 0, NULL, OPEN_ALWAYS, NULL, NULL);
+ if (MapFileHandle == INVALID_HANDLE_VALUE) return GetLastErrorAsStatus();
+ }
+
+ // Map.
+ HANDLE MapHandle = CreateFileMappingW(MapFileHandle, NULL, PAGE_EXECUTE_READWRITE, VolumeLength>>32, VolumeLength & 0xFFFFFFFF, MapName);
+ if (!MapHandle) return GetLastErrorAsStatus();
+
+ // Point.
+ char* MappedAddress = (char*) MapViewOfFile(MapHandle, FILE_MAP_ALL_ACCESS, 0, 0, VolumeLength);
+ if (!MappedAddress) return GetLastErrorAsStatus();
+
+ // Keep.
+ Airfs = (AIRFS_) MappedAddress;
+ Airfs->MapFileHandle = MapFileHandle;
+ Airfs->MapHandle = MapHandle;
+ wcscpy_s(Airfs->VolumeName, 256, VolumeName); // Use "" for a memory-only page file.
+ wcscpy_s(Airfs->MapName, 256, MapName);
+ Airfs->VolumeLength = VolumeLength;
+
+ return 0;
+}
+
+//--------------------------------------------------------------------
+
+NTSTATUS StorageShutdown(AIRFS_ Airfs)
+{
+ BOOL Ok;
+ NTSTATUS Result = 0;
+ HANDLE M = Airfs->MapHandle;
+ HANDLE F = Airfs->MapFileHandle;
+
+ if (Airfs)
+ {
+ Ok = FlushViewOfFile(Airfs, 0); if (!Ok && !Result) Result = GetLastErrorAsStatus();
+ if (F != INVALID_HANDLE_VALUE)
+ {
+ Ok = FlushFileBuffers(F); if (!Ok && !Result) Result = GetLastErrorAsStatus();
+ }
+ Ok = UnmapViewOfFile(Airfs); if (!Ok && !Result) Result = GetLastErrorAsStatus();
+ }
+
+ if (M)
+ {
+ Ok = CloseHandle(M); if (!Ok && !Result) Result = GetLastErrorAsStatus();
+ }
+ if (F != INVALID_HANDLE_VALUE)
+ {
+ Ok = CloseHandle(F); if (!Ok && !Result) Result = GetLastErrorAsStatus();
+ }
+
+ return Result;
+}
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////