mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
tst: memfs-dotnet: WIP
This commit is contained in:
parent
151627091b
commit
4278cec465
@ -408,7 +408,7 @@ namespace Fsp
|
||||
Marker, Buffer, Length, out BytesTransferred);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
public Int32 FindReparsePoint(
|
||||
public Boolean FindReparsePoint(
|
||||
String FileName,
|
||||
out UInt32 ReparsePointIndex)
|
||||
{
|
||||
|
@ -471,7 +471,8 @@ namespace Fsp.Interop
|
||||
UInt32 Length,
|
||||
out UInt32 PBytesTransferred);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate Int32 FspFileSystemFindReparsePoint(
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal delegate Boolean FspFileSystemFindReparsePoint(
|
||||
IntPtr FileSystem,
|
||||
GetReparsePointByName GetReparsePointByName,
|
||||
IntPtr Context,
|
||||
|
@ -59,6 +59,7 @@ namespace memfs
|
||||
public Byte[] FileData;
|
||||
public Byte[] ReparseData;
|
||||
public FileNode MainFileNode;
|
||||
public int OpenCount;
|
||||
}
|
||||
|
||||
class FileNodeMap
|
||||
@ -84,7 +85,7 @@ namespace memfs
|
||||
int Index = FileName.IndexOf(':');
|
||||
if (0 > Index)
|
||||
return null;
|
||||
return Map[FileName.Substring(Index + 1)];
|
||||
return Map[FileName.Substring(0, Index)];
|
||||
}
|
||||
public FileNode GetParent(String FileName, out Int32 Result)
|
||||
{
|
||||
@ -114,12 +115,11 @@ namespace memfs
|
||||
Parent.FileInfo.LastWriteTime =
|
||||
Parent.FileInfo.ChangeTime = (UInt64)DateTime.Now.ToFileTimeUtc();
|
||||
}
|
||||
public Int32 Insert(FileNode FileNode)
|
||||
public void Insert(FileNode FileNode)
|
||||
{
|
||||
Set.Add(FileNode.FileName);
|
||||
Map.Add(FileNode.FileName, FileNode);
|
||||
TouchParent(FileNode);
|
||||
return FileSystemBase.STATUS_SUCCESS;
|
||||
}
|
||||
public void Remove(FileNode FileNode)
|
||||
{
|
||||
@ -135,11 +135,12 @@ namespace memfs
|
||||
String MaxName = FileNode.FileName + "]";
|
||||
SortedSet<String> View = Set.GetViewBetween(MinName, MaxName);
|
||||
foreach (String Name in View)
|
||||
if (Name != MaxName)
|
||||
if (Name.StartsWith(MinName, CaseInsensitive ?
|
||||
StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
public IEnumerator<String> GetChildrenFileNames(FileNode FileNode)
|
||||
public IEnumerable<String> GetChildrenFileNames(FileNode FileNode)
|
||||
{
|
||||
String MinName = FileNode.FileName + "\\";
|
||||
String MaxName = FileNode.FileName + "]";
|
||||
@ -149,22 +150,26 @@ namespace memfs
|
||||
StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
|
||||
yield return Name;
|
||||
}
|
||||
public IEnumerator<String> GetStreamNames(FileNode FileNode)
|
||||
public IEnumerable<String> GetStreamFileNames(FileNode FileNode)
|
||||
{
|
||||
String MinName = FileNode.FileName + ":";
|
||||
String MaxName = FileNode.FileName + ";";
|
||||
SortedSet<String> View = Set.GetViewBetween(MinName, MaxName);
|
||||
foreach (String Name in View)
|
||||
if (Name != MaxName)
|
||||
if (Name.StartsWith(MinName, CaseInsensitive ?
|
||||
StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
|
||||
yield return Name;
|
||||
}
|
||||
public IEnumerator<String> GetDescendantFileNames(FileNode FileNode)
|
||||
public IEnumerable<String> GetDescendantFileNames(FileNode FileNode)
|
||||
{
|
||||
String MinName = FileNode.FileName + "\\";
|
||||
String MinName = FileNode.FileName;
|
||||
String MaxName = FileNode.FileName + "]";
|
||||
SortedSet<String> View = Set.GetViewBetween(MinName, MaxName);
|
||||
foreach (String Name in View)
|
||||
if (Name != MaxName)
|
||||
if (Name.StartsWith(MinName, CaseInsensitive ?
|
||||
StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) &&
|
||||
Name.Length == MinName.Length || (1 == MinName.Length && '\\' == MinName[0]) ||
|
||||
'\\' == Name[MinName.Length] || ':' == Name[MinName.Length])
|
||||
yield return Name;
|
||||
}
|
||||
|
||||
@ -182,6 +187,7 @@ namespace memfs
|
||||
Boolean CaseInsensitive, UInt32 MaxFileNodes, UInt32 MaxFileSize, String RootSddl)
|
||||
{
|
||||
this.FileNodeMap = new FileNodeMap(CaseInsensitive);
|
||||
this.OpenNodeSet = new HashSet<FileNode>();
|
||||
this.MaxFileNodes = MaxFileNodes;
|
||||
this.MaxFileSize = MaxFileSize;
|
||||
|
||||
@ -217,6 +223,7 @@ namespace memfs
|
||||
Host.PostCleanupWhenModifiedOnly = true;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public override Int32 GetVolumeInfo(
|
||||
out VolumeInfo VolumeInfo)
|
||||
{
|
||||
@ -226,6 +233,7 @@ namespace memfs
|
||||
VolumeInfo.SetVolumeLabel(VolumeLabel);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public override Int32 SetVolumeLabel(
|
||||
String VolumeLabel,
|
||||
out VolumeInfo VolumeInfo)
|
||||
@ -239,9 +247,30 @@ namespace memfs
|
||||
out UInt32 FileAttributes/* or ReparsePointIndex */,
|
||||
ref Byte[] SecurityDescriptor)
|
||||
{
|
||||
FileAttributes = default(UInt32);
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
FileNode FileNode = FileNodeMap.Get(FileName);
|
||||
if (null == FileNode)
|
||||
{
|
||||
Int32 Result = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
if (FindReparsePoint(FileName, out FileAttributes))
|
||||
Result = STATUS_REPARSE;
|
||||
else
|
||||
FileNodeMap.GetParent(FileName, out Result);
|
||||
return Result;
|
||||
}
|
||||
|
||||
UInt32 FileAttributesMask = ~(UInt32)0;
|
||||
if (null != FileNode.MainFileNode)
|
||||
{
|
||||
FileAttributesMask = ~(UInt32)System.IO.FileAttributes.Directory;
|
||||
FileNode = FileNode.MainFileNode;
|
||||
}
|
||||
FileAttributes = FileNode.FileInfo.FileAttributes & FileAttributesMask;
|
||||
if (null != SecurityDescriptor)
|
||||
SecurityDescriptor = FileNode.FileSecurity;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public override Int32 Create(
|
||||
String FileName,
|
||||
UInt32 CreateOptions,
|
||||
@ -249,34 +278,89 @@ namespace memfs
|
||||
UInt32 FileAttributes,
|
||||
Byte[] SecurityDescriptor,
|
||||
UInt64 AllocationSize,
|
||||
out Object FileNode,
|
||||
out Object FileNode0,
|
||||
out Object FileDesc,
|
||||
out FileInfo FileInfo,
|
||||
out String NormalizedName)
|
||||
{
|
||||
FileNode = default(Object);
|
||||
FileNode0 = default(Object);
|
||||
FileDesc = default(Object);
|
||||
FileInfo = default(FileInfo);
|
||||
NormalizedName = default(String);
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
FileNode FileNode;
|
||||
FileNode ParentNode;
|
||||
Int32 Result;
|
||||
|
||||
FileNode = FileNodeMap.Get(FileName);
|
||||
if (null != FileNode)
|
||||
return STATUS_OBJECT_NAME_COLLISION;
|
||||
ParentNode = FileNodeMap.GetParent(FileName, out Result);
|
||||
if (null == ParentNode)
|
||||
return Result;
|
||||
|
||||
if (0 != (CreateOptions & FILE_DIRECTORY_FILE))
|
||||
AllocationSize = 0;
|
||||
if (FileNodeMap.Count() >= MaxFileNodes)
|
||||
return STATUS_CANNOT_MAKE;
|
||||
if (AllocationSize > MaxFileSize)
|
||||
return STATUS_DISK_FULL;
|
||||
|
||||
FileName = Path.Combine(ParentNode.FileName, Path.GetFileName(FileName));
|
||||
/* normalize name */
|
||||
FileNode = new FileNode(FileName);
|
||||
FileNode.MainFileNode = FileNodeMap.GetMain(FileName);
|
||||
FileNode.FileInfo.FileAttributes = 0 != (FileAttributes & (UInt32)System.IO.FileAttributes.Directory) ?
|
||||
FileAttributes : FileAttributes | (UInt32)System.IO.FileAttributes.Archive;
|
||||
FileNode.FileSecurity = SecurityDescriptor;
|
||||
FileNode.FileInfo.AllocationSize = AllocationSize;
|
||||
if (0 != AllocationSize)
|
||||
FileNode.FileData = new byte[AllocationSize];
|
||||
FileNodeMap.Insert(FileNode);
|
||||
|
||||
InsertOpenNode(FileNode);
|
||||
FileNode0 = FileNode;
|
||||
FileInfo = FileNode.GetFileInfo();
|
||||
NormalizedName = FileNode.FileName;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public override Int32 Open(
|
||||
String FileName,
|
||||
UInt32 CreateOptions,
|
||||
UInt32 GrantedAccess,
|
||||
out Object FileNode,
|
||||
out Object FileNode0,
|
||||
out Object FileDesc,
|
||||
out FileInfo FileInfo,
|
||||
out String NormalizedName)
|
||||
{
|
||||
FileNode = default(Object);
|
||||
FileNode0 = default(Object);
|
||||
FileDesc = default(Object);
|
||||
FileInfo = default(FileInfo);
|
||||
NormalizedName = default(String);
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
FileNode FileNode;
|
||||
Int32 Result;
|
||||
|
||||
FileNode = FileNodeMap.Get(FileName);
|
||||
if (null == FileNode)
|
||||
{
|
||||
Result = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
FileNodeMap.GetParent(FileName, out Result);
|
||||
return Result;
|
||||
}
|
||||
|
||||
InsertOpenNode(FileNode);
|
||||
FileNode0 = FileNode;
|
||||
FileInfo = FileNode.GetFileInfo();
|
||||
NormalizedName = FileNode.FileName;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public override Int32 Overwrite(
|
||||
Object FileNode,
|
||||
Object FileNode0,
|
||||
Object FileDesc,
|
||||
UInt32 FileAttributes,
|
||||
Boolean ReplaceFileAttributes,
|
||||
@ -284,20 +368,98 @@ namespace memfs
|
||||
out FileInfo FileInfo)
|
||||
{
|
||||
FileInfo = default(FileInfo);
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
FileNode FileNode = (FileNode)FileNode0;
|
||||
Int32 Result;
|
||||
|
||||
List<String> StreamFileNames = new List<String>(FileNodeMap.GetStreamFileNames(FileNode));
|
||||
lock (OpenNodeSet)
|
||||
{
|
||||
foreach (String StreamFileName in StreamFileNames)
|
||||
{
|
||||
FileNode StreamNode = FileNodeMap.Get(StreamFileName);
|
||||
if (null == StreamNode)
|
||||
continue; /* should not happen */
|
||||
if (!OpenNodeSet.Contains(StreamNode))
|
||||
FileNodeMap.Remove(StreamNode);
|
||||
}
|
||||
}
|
||||
|
||||
Result = SetFileSizeInternal(FileNode, AllocationSize, true);
|
||||
if (0 > Result)
|
||||
return Result;
|
||||
if (ReplaceFileAttributes)
|
||||
FileNode.FileInfo.FileAttributes = FileAttributes | (UInt32)System.IO.FileAttributes.Archive;
|
||||
else
|
||||
FileNode.FileInfo.FileAttributes |= FileAttributes | (UInt32)System.IO.FileAttributes.Archive;
|
||||
FileNode.FileInfo.FileSize = 0;
|
||||
FileNode.FileInfo.LastAccessTime =
|
||||
FileNode.FileInfo.LastWriteTime =
|
||||
FileNode.FileInfo.ChangeTime = (UInt64)DateTime.Now.ToFileTimeUtc();
|
||||
|
||||
FileInfo = FileNode.GetFileInfo();
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public override void Cleanup(
|
||||
Object FileNode,
|
||||
Object FileNode0,
|
||||
Object FileDesc,
|
||||
String FileName,
|
||||
UInt32 Flags)
|
||||
{
|
||||
FileNode FileNode = (FileNode)FileNode0;
|
||||
FileNode MainFileNode = null != FileNode.MainFileNode ?
|
||||
FileNode.MainFileNode : FileNode;
|
||||
|
||||
if (0 != (Flags & CleanupSetArchiveBit))
|
||||
{
|
||||
if (0 == (MainFileNode.FileInfo.FileAttributes & (UInt32)FileAttributes.Directory))
|
||||
MainFileNode.FileInfo.FileAttributes |= (UInt32)FileAttributes.Archive;
|
||||
}
|
||||
|
||||
if (0 != (Flags & (CleanupSetLastAccessTime | CleanupSetLastWriteTime | CleanupSetChangeTime)))
|
||||
{
|
||||
UInt64 SystemTime = (UInt64)DateTime.Now.ToFileTimeUtc();
|
||||
|
||||
if (0 != (Flags & CleanupSetLastAccessTime))
|
||||
MainFileNode.FileInfo.LastAccessTime = SystemTime;
|
||||
if (0 != (Flags & CleanupSetLastWriteTime))
|
||||
MainFileNode.FileInfo.LastWriteTime = SystemTime;
|
||||
if (0 != (Flags & CleanupSetChangeTime))
|
||||
MainFileNode.FileInfo.ChangeTime = SystemTime;
|
||||
}
|
||||
|
||||
if (0 != (Flags & CleanupSetAllocationSize))
|
||||
{
|
||||
UInt64 AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
|
||||
UInt64 AllocationSize = (FileNode.FileInfo.FileSize + AllocationUnit - 1) /
|
||||
AllocationUnit * AllocationUnit;
|
||||
SetFileSizeInternal(FileNode, AllocationSize, true);
|
||||
}
|
||||
|
||||
if (0 != (Flags & CleanupDelete) && !FileNodeMap.HasChild(FileNode))
|
||||
{
|
||||
List<String> StreamFileNames = new List<String>(FileNodeMap.GetStreamFileNames(FileNode));
|
||||
foreach (String StreamFileName in StreamFileNames)
|
||||
{
|
||||
FileNode StreamNode = FileNodeMap.Get(StreamFileName);
|
||||
if (null == StreamNode)
|
||||
continue; /* should not happen */
|
||||
FileNodeMap.Remove(StreamNode);
|
||||
}
|
||||
FileNodeMap.Remove(FileNode);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close(
|
||||
Object FileNode,
|
||||
Object FileNode0,
|
||||
Object FileDesc)
|
||||
{
|
||||
FileNode FileNode = (FileNode)FileNode0;
|
||||
RemoveOpenNode(FileNode);
|
||||
}
|
||||
|
||||
public override Int32 Read(
|
||||
Object FileNode,
|
||||
Object FileDesc,
|
||||
@ -363,6 +525,13 @@ namespace memfs
|
||||
FileInfo = default(FileInfo);
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
private Int32 SetFileSizeInternal(
|
||||
FileNode FileNode,
|
||||
UInt64 NewSize,
|
||||
Boolean SetAllocationSize)
|
||||
{
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
public override Int32 CanDelete(
|
||||
Object FileNode,
|
||||
Object FileDesc,
|
||||
@ -454,10 +623,28 @@ namespace memfs
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
private void InsertOpenNode(FileNode FileNode)
|
||||
{
|
||||
lock (OpenNodeSet)
|
||||
{
|
||||
if (1 == ++FileNode.OpenCount)
|
||||
OpenNodeSet.Add(FileNode);
|
||||
}
|
||||
}
|
||||
private void RemoveOpenNode(FileNode FileNode)
|
||||
{
|
||||
lock (OpenNodeSet)
|
||||
{
|
||||
if (0 == --FileNode.OpenCount)
|
||||
OpenNodeSet.Remove(FileNode);
|
||||
}
|
||||
}
|
||||
|
||||
private FileNodeMap FileNodeMap;
|
||||
UInt32 MaxFileNodes;
|
||||
UInt32 MaxFileSize;
|
||||
String VolumeLabel;
|
||||
private HashSet<FileNode> OpenNodeSet;
|
||||
private UInt32 MaxFileNodes;
|
||||
private UInt32 MaxFileSize;
|
||||
private String VolumeLabel;
|
||||
}
|
||||
|
||||
class MemfsService : Service
|
||||
|
Loading…
x
Reference in New Issue
Block a user