mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 16:33:02 -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);
|
Marker, Buffer, Length, out BytesTransferred);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
public Int32 FindReparsePoint(
|
public Boolean FindReparsePoint(
|
||||||
String FileName,
|
String FileName,
|
||||||
out UInt32 ReparsePointIndex)
|
out UInt32 ReparsePointIndex)
|
||||||
{
|
{
|
||||||
|
@ -471,7 +471,8 @@ namespace Fsp.Interop
|
|||||||
UInt32 Length,
|
UInt32 Length,
|
||||||
out UInt32 PBytesTransferred);
|
out UInt32 PBytesTransferred);
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate Int32 FspFileSystemFindReparsePoint(
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
|
internal delegate Boolean FspFileSystemFindReparsePoint(
|
||||||
IntPtr FileSystem,
|
IntPtr FileSystem,
|
||||||
GetReparsePointByName GetReparsePointByName,
|
GetReparsePointByName GetReparsePointByName,
|
||||||
IntPtr Context,
|
IntPtr Context,
|
||||||
|
@ -59,6 +59,7 @@ namespace memfs
|
|||||||
public Byte[] FileData;
|
public Byte[] FileData;
|
||||||
public Byte[] ReparseData;
|
public Byte[] ReparseData;
|
||||||
public FileNode MainFileNode;
|
public FileNode MainFileNode;
|
||||||
|
public int OpenCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FileNodeMap
|
class FileNodeMap
|
||||||
@ -84,7 +85,7 @@ namespace memfs
|
|||||||
int Index = FileName.IndexOf(':');
|
int Index = FileName.IndexOf(':');
|
||||||
if (0 > Index)
|
if (0 > Index)
|
||||||
return null;
|
return null;
|
||||||
return Map[FileName.Substring(Index + 1)];
|
return Map[FileName.Substring(0, Index)];
|
||||||
}
|
}
|
||||||
public FileNode GetParent(String FileName, out Int32 Result)
|
public FileNode GetParent(String FileName, out Int32 Result)
|
||||||
{
|
{
|
||||||
@ -114,12 +115,11 @@ namespace memfs
|
|||||||
Parent.FileInfo.LastWriteTime =
|
Parent.FileInfo.LastWriteTime =
|
||||||
Parent.FileInfo.ChangeTime = (UInt64)DateTime.Now.ToFileTimeUtc();
|
Parent.FileInfo.ChangeTime = (UInt64)DateTime.Now.ToFileTimeUtc();
|
||||||
}
|
}
|
||||||
public Int32 Insert(FileNode FileNode)
|
public void Insert(FileNode FileNode)
|
||||||
{
|
{
|
||||||
Set.Add(FileNode.FileName);
|
Set.Add(FileNode.FileName);
|
||||||
Map.Add(FileNode.FileName, FileNode);
|
Map.Add(FileNode.FileName, FileNode);
|
||||||
TouchParent(FileNode);
|
TouchParent(FileNode);
|
||||||
return FileSystemBase.STATUS_SUCCESS;
|
|
||||||
}
|
}
|
||||||
public void Remove(FileNode FileNode)
|
public void Remove(FileNode FileNode)
|
||||||
{
|
{
|
||||||
@ -135,11 +135,12 @@ namespace memfs
|
|||||||
String MaxName = FileNode.FileName + "]";
|
String MaxName = FileNode.FileName + "]";
|
||||||
SortedSet<String> View = Set.GetViewBetween(MinName, MaxName);
|
SortedSet<String> View = Set.GetViewBetween(MinName, MaxName);
|
||||||
foreach (String Name in View)
|
foreach (String Name in View)
|
||||||
if (Name != MaxName)
|
if (Name.StartsWith(MinName, CaseInsensitive ?
|
||||||
|
StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public IEnumerator<String> GetChildrenFileNames(FileNode FileNode)
|
public IEnumerable<String> GetChildrenFileNames(FileNode FileNode)
|
||||||
{
|
{
|
||||||
String MinName = FileNode.FileName + "\\";
|
String MinName = FileNode.FileName + "\\";
|
||||||
String MaxName = FileNode.FileName + "]";
|
String MaxName = FileNode.FileName + "]";
|
||||||
@ -149,22 +150,26 @@ namespace memfs
|
|||||||
StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
|
StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
|
||||||
yield return Name;
|
yield return Name;
|
||||||
}
|
}
|
||||||
public IEnumerator<String> GetStreamNames(FileNode FileNode)
|
public IEnumerable<String> GetStreamFileNames(FileNode FileNode)
|
||||||
{
|
{
|
||||||
String MinName = FileNode.FileName + ":";
|
String MinName = FileNode.FileName + ":";
|
||||||
String MaxName = FileNode.FileName + ";";
|
String MaxName = FileNode.FileName + ";";
|
||||||
SortedSet<String> View = Set.GetViewBetween(MinName, MaxName);
|
SortedSet<String> View = Set.GetViewBetween(MinName, MaxName);
|
||||||
foreach (String Name in View)
|
foreach (String Name in View)
|
||||||
if (Name != MaxName)
|
if (Name.StartsWith(MinName, CaseInsensitive ?
|
||||||
|
StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
|
||||||
yield return Name;
|
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 + "]";
|
String MaxName = FileNode.FileName + "]";
|
||||||
SortedSet<String> View = Set.GetViewBetween(MinName, MaxName);
|
SortedSet<String> View = Set.GetViewBetween(MinName, MaxName);
|
||||||
foreach (String Name in View)
|
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;
|
yield return Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,6 +187,7 @@ namespace memfs
|
|||||||
Boolean CaseInsensitive, UInt32 MaxFileNodes, UInt32 MaxFileSize, String RootSddl)
|
Boolean CaseInsensitive, UInt32 MaxFileNodes, UInt32 MaxFileSize, String RootSddl)
|
||||||
{
|
{
|
||||||
this.FileNodeMap = new FileNodeMap(CaseInsensitive);
|
this.FileNodeMap = new FileNodeMap(CaseInsensitive);
|
||||||
|
this.OpenNodeSet = new HashSet<FileNode>();
|
||||||
this.MaxFileNodes = MaxFileNodes;
|
this.MaxFileNodes = MaxFileNodes;
|
||||||
this.MaxFileSize = MaxFileSize;
|
this.MaxFileSize = MaxFileSize;
|
||||||
|
|
||||||
@ -217,6 +223,7 @@ namespace memfs
|
|||||||
Host.PostCleanupWhenModifiedOnly = true;
|
Host.PostCleanupWhenModifiedOnly = true;
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 GetVolumeInfo(
|
public override Int32 GetVolumeInfo(
|
||||||
out VolumeInfo VolumeInfo)
|
out VolumeInfo VolumeInfo)
|
||||||
{
|
{
|
||||||
@ -226,6 +233,7 @@ namespace memfs
|
|||||||
VolumeInfo.SetVolumeLabel(VolumeLabel);
|
VolumeInfo.SetVolumeLabel(VolumeLabel);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 SetVolumeLabel(
|
public override Int32 SetVolumeLabel(
|
||||||
String VolumeLabel,
|
String VolumeLabel,
|
||||||
out VolumeInfo VolumeInfo)
|
out VolumeInfo VolumeInfo)
|
||||||
@ -239,9 +247,30 @@ namespace memfs
|
|||||||
out UInt32 FileAttributes/* or ReparsePointIndex */,
|
out UInt32 FileAttributes/* or ReparsePointIndex */,
|
||||||
ref Byte[] SecurityDescriptor)
|
ref Byte[] SecurityDescriptor)
|
||||||
{
|
{
|
||||||
FileAttributes = default(UInt32);
|
FileNode FileNode = FileNodeMap.Get(FileName);
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
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(
|
public override Int32 Create(
|
||||||
String FileName,
|
String FileName,
|
||||||
UInt32 CreateOptions,
|
UInt32 CreateOptions,
|
||||||
@ -249,34 +278,89 @@ namespace memfs
|
|||||||
UInt32 FileAttributes,
|
UInt32 FileAttributes,
|
||||||
Byte[] SecurityDescriptor,
|
Byte[] SecurityDescriptor,
|
||||||
UInt64 AllocationSize,
|
UInt64 AllocationSize,
|
||||||
out Object FileNode,
|
out Object FileNode0,
|
||||||
out Object FileDesc,
|
out Object FileDesc,
|
||||||
out FileInfo FileInfo,
|
out FileInfo FileInfo,
|
||||||
out String NormalizedName)
|
out String NormalizedName)
|
||||||
{
|
{
|
||||||
FileNode = default(Object);
|
FileNode0 = default(Object);
|
||||||
FileDesc = default(Object);
|
FileDesc = default(Object);
|
||||||
FileInfo = default(FileInfo);
|
FileInfo = default(FileInfo);
|
||||||
NormalizedName = default(String);
|
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(
|
public override Int32 Open(
|
||||||
String FileName,
|
String FileName,
|
||||||
UInt32 CreateOptions,
|
UInt32 CreateOptions,
|
||||||
UInt32 GrantedAccess,
|
UInt32 GrantedAccess,
|
||||||
out Object FileNode,
|
out Object FileNode0,
|
||||||
out Object FileDesc,
|
out Object FileDesc,
|
||||||
out FileInfo FileInfo,
|
out FileInfo FileInfo,
|
||||||
out String NormalizedName)
|
out String NormalizedName)
|
||||||
{
|
{
|
||||||
FileNode = default(Object);
|
FileNode0 = default(Object);
|
||||||
FileDesc = default(Object);
|
FileDesc = default(Object);
|
||||||
FileInfo = default(FileInfo);
|
FileInfo = default(FileInfo);
|
||||||
NormalizedName = default(String);
|
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(
|
public override Int32 Overwrite(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
UInt32 FileAttributes,
|
UInt32 FileAttributes,
|
||||||
Boolean ReplaceFileAttributes,
|
Boolean ReplaceFileAttributes,
|
||||||
@ -284,20 +368,98 @@ namespace memfs
|
|||||||
out FileInfo FileInfo)
|
out FileInfo FileInfo)
|
||||||
{
|
{
|
||||||
FileInfo = default(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(
|
public override void Cleanup(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
String FileName,
|
String FileName,
|
||||||
UInt32 Flags)
|
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(
|
public override void Close(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc)
|
Object FileDesc)
|
||||||
{
|
{
|
||||||
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
|
RemoveOpenNode(FileNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 Read(
|
public override Int32 Read(
|
||||||
Object FileNode,
|
Object FileNode,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
@ -363,6 +525,13 @@ namespace memfs
|
|||||||
FileInfo = default(FileInfo);
|
FileInfo = default(FileInfo);
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
}
|
}
|
||||||
|
private Int32 SetFileSizeInternal(
|
||||||
|
FileNode FileNode,
|
||||||
|
UInt64 NewSize,
|
||||||
|
Boolean SetAllocationSize)
|
||||||
|
{
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
}
|
||||||
public override Int32 CanDelete(
|
public override Int32 CanDelete(
|
||||||
Object FileNode,
|
Object FileNode,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
@ -454,10 +623,28 @@ namespace memfs
|
|||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
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;
|
private FileNodeMap FileNodeMap;
|
||||||
UInt32 MaxFileNodes;
|
private HashSet<FileNode> OpenNodeSet;
|
||||||
UInt32 MaxFileSize;
|
private UInt32 MaxFileNodes;
|
||||||
String VolumeLabel;
|
private UInt32 MaxFileSize;
|
||||||
|
private String VolumeLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MemfsService : Service
|
class MemfsService : Service
|
||||||
|
Loading…
x
Reference in New Issue
Block a user