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
4278cec465
commit
f36cacaf84
@ -18,6 +18,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
|
|
||||||
using Fsp;
|
using Fsp;
|
||||||
@ -315,7 +316,11 @@ namespace memfs
|
|||||||
FileNode.FileSecurity = SecurityDescriptor;
|
FileNode.FileSecurity = SecurityDescriptor;
|
||||||
FileNode.FileInfo.AllocationSize = AllocationSize;
|
FileNode.FileInfo.AllocationSize = AllocationSize;
|
||||||
if (0 != AllocationSize)
|
if (0 != AllocationSize)
|
||||||
FileNode.FileData = new byte[AllocationSize];
|
{
|
||||||
|
Result = SetFileSizeInternal(FileNode, AllocationSize, true);
|
||||||
|
if (0 > Result)
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
FileNodeMap.Insert(FileNode);
|
FileNodeMap.Insert(FileNode);
|
||||||
|
|
||||||
InsertOpenNode(FileNode);
|
InsertOpenNode(FileNode);
|
||||||
@ -461,18 +466,34 @@ namespace memfs
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 Read(
|
public override Int32 Read(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
IntPtr Buffer,
|
IntPtr Buffer,
|
||||||
UInt64 Offset,
|
UInt64 Offset,
|
||||||
UInt32 Length,
|
UInt32 Length,
|
||||||
out UInt32 BytesTransferred)
|
out UInt32 BytesTransferred)
|
||||||
{
|
{
|
||||||
BytesTransferred = default(UInt32);
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
UInt64 EndOffset;
|
||||||
|
|
||||||
|
if (Offset >= FileNode.FileInfo.FileSize)
|
||||||
|
{
|
||||||
|
BytesTransferred = default(UInt32);
|
||||||
|
return STATUS_END_OF_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EndOffset = Offset + Length;
|
||||||
|
if (EndOffset > FileNode.FileInfo.FileSize)
|
||||||
|
EndOffset = FileNode.FileInfo.FileSize;
|
||||||
|
|
||||||
|
BytesTransferred = (UInt32)(EndOffset - Offset);
|
||||||
|
Marshal.Copy(FileNode.FileData, 0, Buffer, (int)BytesTransferred);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 Write(
|
public override Int32 Write(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
IntPtr Buffer,
|
IntPtr Buffer,
|
||||||
UInt64 Offset,
|
UInt64 Offset,
|
||||||
@ -482,28 +503,73 @@ namespace memfs
|
|||||||
out UInt32 BytesTransferred,
|
out UInt32 BytesTransferred,
|
||||||
out FileInfo FileInfo)
|
out FileInfo FileInfo)
|
||||||
{
|
{
|
||||||
BytesTransferred = default(UInt32);
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
FileInfo = default(FileInfo);
|
UInt64 EndOffset;
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
|
||||||
|
if (ConstrainedIo)
|
||||||
|
{
|
||||||
|
if (Offset >= FileNode.FileInfo.FileSize)
|
||||||
|
{
|
||||||
|
BytesTransferred = default(UInt32);
|
||||||
|
FileInfo = default(FileInfo);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
EndOffset = Offset + Length;
|
||||||
|
if (EndOffset > FileNode.FileInfo.FileSize)
|
||||||
|
EndOffset = FileNode.FileInfo.FileSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (WriteToEndOfFile)
|
||||||
|
Offset = FileNode.FileInfo.FileSize;
|
||||||
|
EndOffset = Offset + Length;
|
||||||
|
if (EndOffset > FileNode.FileInfo.FileSize)
|
||||||
|
{
|
||||||
|
Int32 Result = SetFileSizeInternal(FileNode, EndOffset, false);
|
||||||
|
if (0 > Result)
|
||||||
|
{
|
||||||
|
BytesTransferred = default(UInt32);
|
||||||
|
FileInfo = default(FileInfo);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BytesTransferred = (UInt32)(EndOffset - Offset);
|
||||||
|
Marshal.Copy(Buffer, FileNode.FileData, 0, (int)BytesTransferred);
|
||||||
|
|
||||||
|
FileInfo = FileNode.GetFileInfo();
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 Flush(
|
public override Int32 Flush(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
out FileInfo FileInfo)
|
out FileInfo FileInfo)
|
||||||
{
|
{
|
||||||
FileInfo = default(FileInfo);
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
|
||||||
|
/* nothing to flush, since we do not cache anything */
|
||||||
|
FileInfo = null != FileNode ? FileNode.GetFileInfo() : default(FileInfo);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 GetFileInfo(
|
public override Int32 GetFileInfo(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
out FileInfo FileInfo)
|
out FileInfo FileInfo)
|
||||||
{
|
{
|
||||||
FileInfo = default(FileInfo);
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
|
||||||
|
FileInfo = FileNode.GetFileInfo();
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 SetBasicInfo(
|
public override Int32 SetBasicInfo(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
UInt32 FileAttributes,
|
UInt32 FileAttributes,
|
||||||
UInt64 CreationTime,
|
UInt64 CreationTime,
|
||||||
@ -512,59 +578,184 @@ namespace memfs
|
|||||||
UInt64 ChangeTime,
|
UInt64 ChangeTime,
|
||||||
out FileInfo FileInfo)
|
out FileInfo FileInfo)
|
||||||
{
|
{
|
||||||
FileInfo = default(FileInfo);
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
|
||||||
|
if (null != FileNode.MainFileNode)
|
||||||
|
FileNode = FileNode.MainFileNode;
|
||||||
|
|
||||||
|
if (unchecked((UInt32)(-1)) != FileAttributes)
|
||||||
|
FileNode.FileInfo.FileAttributes = FileAttributes;
|
||||||
|
if (0 != CreationTime)
|
||||||
|
FileNode.FileInfo.CreationTime = CreationTime;
|
||||||
|
if (0 != LastAccessTime)
|
||||||
|
FileNode.FileInfo.LastAccessTime = LastAccessTime;
|
||||||
|
if (0 != LastWriteTime)
|
||||||
|
FileNode.FileInfo.LastWriteTime = LastWriteTime;
|
||||||
|
if (0 != ChangeTime)
|
||||||
|
FileNode.FileInfo.ChangeTime = ChangeTime;
|
||||||
|
|
||||||
|
FileInfo = FileNode.GetFileInfo();
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 SetFileSize(
|
public override Int32 SetFileSize(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
UInt64 NewSize,
|
UInt64 NewSize,
|
||||||
Boolean SetAllocationSize,
|
Boolean SetAllocationSize,
|
||||||
out FileInfo FileInfo)
|
out FileInfo FileInfo)
|
||||||
{
|
{
|
||||||
FileInfo = default(FileInfo);
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
Int32 Result;
|
||||||
|
|
||||||
|
Result = SetFileSizeInternal(FileNode, NewSize, SetAllocationSize);
|
||||||
|
FileInfo = 0 <= Result ? FileNode.GetFileInfo() : default(FileInfo);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Int32 SetFileSizeInternal(
|
private Int32 SetFileSizeInternal(
|
||||||
FileNode FileNode,
|
FileNode FileNode,
|
||||||
UInt64 NewSize,
|
UInt64 NewSize,
|
||||||
Boolean SetAllocationSize)
|
Boolean SetAllocationSize)
|
||||||
{
|
{
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
if (SetAllocationSize)
|
||||||
|
{
|
||||||
|
if (FileNode.FileInfo.AllocationSize != NewSize)
|
||||||
|
{
|
||||||
|
if (NewSize > MaxFileSize)
|
||||||
|
return STATUS_DISK_FULL;
|
||||||
|
|
||||||
|
byte[] FileData = null;
|
||||||
|
if (0 != NewSize)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FileData = new byte[NewSize];
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
Array.Copy(FileNode.FileData, FileData,
|
||||||
|
(int)Math.Min(FileNode.FileInfo.AllocationSize, NewSize));
|
||||||
|
|
||||||
|
FileNode.FileData = FileData;
|
||||||
|
FileNode.FileInfo.AllocationSize = NewSize;
|
||||||
|
if (FileNode.FileInfo.FileSize > NewSize)
|
||||||
|
FileNode.FileInfo.FileSize = NewSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (FileNode.FileInfo.FileSize != NewSize)
|
||||||
|
{
|
||||||
|
if (FileNode.FileInfo.AllocationSize < NewSize)
|
||||||
|
{
|
||||||
|
UInt64 AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
|
||||||
|
UInt64 AllocationSize = (NewSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
||||||
|
Int32 Result = SetFileSizeInternal(FileNode, AllocationSize, true);
|
||||||
|
if (0 > Result)
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FileNode.FileInfo.FileSize < NewSize)
|
||||||
|
Array.Clear(FileNode.FileData,
|
||||||
|
(int)FileNode.FileInfo.FileSize, (int)(NewSize - FileNode.FileInfo.FileSize));
|
||||||
|
FileNode.FileInfo.FileSize = NewSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 CanDelete(
|
public override Int32 CanDelete(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
String FileName)
|
String FileName)
|
||||||
{
|
{
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
|
|
||||||
|
if (FileNodeMap.HasChild(FileNode))
|
||||||
|
return STATUS_DIRECTORY_NOT_EMPTY;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 Rename(
|
public override Int32 Rename(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
String FileName,
|
String FileName,
|
||||||
String NewFileName,
|
String NewFileName,
|
||||||
Boolean ReplaceIfExists)
|
Boolean ReplaceIfExists)
|
||||||
{
|
{
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
|
FileNode NewFileNode;
|
||||||
|
|
||||||
|
NewFileNode = FileNodeMap.Get(NewFileName);
|
||||||
|
if (null != NewFileNode && FileNode != NewFileNode)
|
||||||
|
{
|
||||||
|
if (!ReplaceIfExists)
|
||||||
|
return STATUS_OBJECT_NAME_COLLISION;
|
||||||
|
if (0 != (NewFileNode.FileInfo.FileAttributes & (UInt32)FileAttributes.Directory))
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
if (null != NewFileNode)
|
||||||
|
FileNodeMap.Remove(NewFileNode);
|
||||||
|
|
||||||
|
List<String> DescendantFileNames = new List<String>(FileNodeMap.GetDescendantFileNames(FileNode));
|
||||||
|
foreach (String DescendantFileName in DescendantFileNames)
|
||||||
|
{
|
||||||
|
FileNode DescendantFileNode = FileNodeMap.Get(DescendantFileName);
|
||||||
|
if (null == DescendantFileNode)
|
||||||
|
continue; /* should not happen */
|
||||||
|
FileNodeMap.Remove(DescendantFileNode);
|
||||||
|
DescendantFileNode.FileName =
|
||||||
|
NewFileName + DescendantFileNode.FileName.Substring(FileName.Length);
|
||||||
|
FileNodeMap.Insert(DescendantFileNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 GetSecurity(
|
public override Int32 GetSecurity(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
ref Byte[] SecurityDescriptor)
|
ref Byte[] SecurityDescriptor)
|
||||||
{
|
{
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
|
|
||||||
|
if (null != FileNode.MainFileNode)
|
||||||
|
FileNode = FileNode.MainFileNode;
|
||||||
|
|
||||||
|
SecurityDescriptor = FileNode.FileSecurity;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Int32 SetSecurity(
|
public override Int32 SetSecurity(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
AccessControlSections Sections,
|
AccessControlSections Sections,
|
||||||
Byte[] SecurityDescriptor)
|
Byte[] SecurityDescriptor)
|
||||||
{
|
{
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
|
|
||||||
|
if (null != FileNode.MainFileNode)
|
||||||
|
FileNode = FileNode.MainFileNode;
|
||||||
|
|
||||||
|
ObjectSecurity ObjectSecurity =
|
||||||
|
0 != (FileNode.FileInfo.FileAttributes & (UInt32)FileAttributes.Directory) ?
|
||||||
|
(ObjectSecurity)new DirectorySecurity() : (ObjectSecurity)new FileSecurity();
|
||||||
|
ObjectSecurity.SetSecurityDescriptorBinaryForm(FileNode.FileSecurity);
|
||||||
|
ObjectSecurity.SetSecurityDescriptorBinaryForm(SecurityDescriptor, Sections);
|
||||||
|
FileNode.FileSecurity = ObjectSecurity.GetSecurityDescriptorBinaryForm();
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Boolean ReadDirectoryEntry(
|
public override Boolean ReadDirectoryEntry(
|
||||||
Object FileNode,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
String Pattern,
|
String Pattern,
|
||||||
String Marker,
|
String Marker,
|
||||||
@ -572,6 +763,51 @@ namespace memfs
|
|||||||
out String FileName,
|
out String FileName,
|
||||||
out FileInfo FileInfo)
|
out FileInfo FileInfo)
|
||||||
{
|
{
|
||||||
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
|
IEnumerator<String> Enumerator = (IEnumerator<String>)Context;
|
||||||
|
|
||||||
|
if (null == Enumerator)
|
||||||
|
{
|
||||||
|
List<String> ChildrenFileNames = new List<String>();
|
||||||
|
if ("\\" != FileNode.FileName)
|
||||||
|
{
|
||||||
|
/* if this is not the root directory add the dot entries */
|
||||||
|
ChildrenFileNames.Add(".");
|
||||||
|
ChildrenFileNames.Add("..");
|
||||||
|
}
|
||||||
|
ChildrenFileNames.AddRange(FileNodeMap.GetChildrenFileNames(FileNode));
|
||||||
|
Context = Enumerator = ChildrenFileNames.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Enumerator.MoveNext())
|
||||||
|
{
|
||||||
|
FileName = Enumerator.Current;
|
||||||
|
if ("." == FileName)
|
||||||
|
{
|
||||||
|
FileInfo = FileNode.GetFileInfo();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (".." == FileName)
|
||||||
|
{
|
||||||
|
Int32 Result;
|
||||||
|
FileNode ParentNode = FileNodeMap.GetParent(FileNode.FileName, out Result);
|
||||||
|
if (null != ParentNode)
|
||||||
|
{
|
||||||
|
FileInfo = ParentNode.GetFileInfo();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FileNode ChildFileNode = FileNodeMap.Get(FileName);
|
||||||
|
if (null != ChildFileNode)
|
||||||
|
{
|
||||||
|
FileInfo = ChildFileNode.GetFileInfo();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FileName = default(String);
|
FileName = default(String);
|
||||||
FileInfo = default(FileInfo);
|
FileInfo = default(FileInfo);
|
||||||
return false;
|
return false;
|
||||||
@ -1246,15 +1482,15 @@ namespace memfs
|
|||||||
IntPtr Buffer,
|
IntPtr Buffer,
|
||||||
UInt64 Offset,
|
UInt64 Offset,
|
||||||
UInt32 Length,
|
UInt32 Length,
|
||||||
out UInt32 PBytesTransferred)
|
out UInt32 BytesTransferred)
|
||||||
{
|
{
|
||||||
FileDesc FileDesc = (FileDesc)FileDesc0;
|
FileDesc FileDesc = (FileDesc)FileDesc0;
|
||||||
if (Offset >= (UInt64)FileDesc.Stream.Length)
|
if (Offset >= (UInt64)FileDesc.Stream.Length)
|
||||||
ThrowIoExceptionWithNtStatus(STATUS_END_OF_FILE);
|
ThrowIoExceptionWithNtStatus(STATUS_END_OF_FILE);
|
||||||
Byte[] Bytes = new byte[Length];
|
Byte[] Bytes = new byte[Length];
|
||||||
FileDesc.Stream.Seek((Int64)Offset, SeekOrigin.Begin);
|
FileDesc.Stream.Seek((Int64)Offset, SeekOrigin.Begin);
|
||||||
PBytesTransferred = (UInt32)FileDesc.Stream.Read(Bytes, 0, Bytes.Length);
|
BytesTransferred = (UInt32)FileDesc.Stream.Read(Bytes, 0, Bytes.Length);
|
||||||
Marshal.Copy(Bytes, 0, Buffer, Bytes.Length);
|
Marshal.Copy(Bytes, 0, Buffer, BytesTransferred);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
public override Int32 Write(
|
public override Int32 Write(
|
||||||
@ -1265,7 +1501,7 @@ namespace memfs
|
|||||||
UInt32 Length,
|
UInt32 Length,
|
||||||
Boolean WriteToEndOfFile,
|
Boolean WriteToEndOfFile,
|
||||||
Boolean ConstrainedIo,
|
Boolean ConstrainedIo,
|
||||||
out UInt32 PBytesTransferred,
|
out UInt32 BytesTransferred,
|
||||||
out FileInfo FileInfo)
|
out FileInfo FileInfo)
|
||||||
{
|
{
|
||||||
FileDesc FileDesc = (FileDesc)FileDesc0;
|
FileDesc FileDesc = (FileDesc)FileDesc0;
|
||||||
@ -1273,7 +1509,7 @@ namespace memfs
|
|||||||
{
|
{
|
||||||
if (Offset >= (UInt64)FileDesc.Stream.Length)
|
if (Offset >= (UInt64)FileDesc.Stream.Length)
|
||||||
{
|
{
|
||||||
PBytesTransferred = default(UInt32);
|
BytesTransferred = default(UInt32);
|
||||||
FileInfo = default(FileInfo);
|
FileInfo = default(FileInfo);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -1285,7 +1521,7 @@ namespace memfs
|
|||||||
if (!WriteToEndOfFile)
|
if (!WriteToEndOfFile)
|
||||||
FileDesc.Stream.Seek((Int64)Offset, SeekOrigin.Begin);
|
FileDesc.Stream.Seek((Int64)Offset, SeekOrigin.Begin);
|
||||||
FileDesc.Stream.Write(Bytes, 0, Bytes.Length);
|
FileDesc.Stream.Write(Bytes, 0, Bytes.Length);
|
||||||
PBytesTransferred = (UInt32)Bytes.Length;
|
BytesTransferred = (UInt32)Bytes.Length;
|
||||||
return FileDesc.GetFileInfo(out FileInfo);
|
return FileDesc.GetFileInfo(out FileInfo);
|
||||||
}
|
}
|
||||||
public override Int32 Flush(
|
public override Int32 Flush(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user