202 lines
5.8 KiB
C#
202 lines
5.8 KiB
C#
using DokanNet;
|
|
|
|
namespace DevDrive;
|
|
|
|
/// <summary>
|
|
/// Handles passthrough operations for symlinks to real file system paths.
|
|
/// </summary>
|
|
public static class SymlinkHandler
|
|
{
|
|
public static bool TryResolveSymlink(string virtualPath, FloppyStorage storage, out string? realPath)
|
|
{
|
|
realPath = null;
|
|
virtualPath = FloppyStorage.NormalizePath(virtualPath);
|
|
|
|
var node = storage.GetNode(virtualPath);
|
|
if (node?.IsSymlink == true)
|
|
{
|
|
realPath = node.SymlinkTarget;
|
|
return true;
|
|
}
|
|
|
|
var parts = virtualPath.Split('\\', StringSplitOptions.RemoveEmptyEntries);
|
|
var currentPath = "\\";
|
|
|
|
for (var i = 0; i < parts.Length; i++)
|
|
{
|
|
currentPath = currentPath == "\\" ? "\\" + parts[i] : currentPath + "\\" + parts[i];
|
|
var currentNode = storage.GetNode(currentPath);
|
|
|
|
if (currentNode?.IsSymlink == true)
|
|
{
|
|
var remainingPath = string.Join("\\", parts.Skip(i + 1));
|
|
realPath = string.IsNullOrEmpty(remainingPath)
|
|
? currentNode.SymlinkTarget
|
|
: Path.Combine(currentNode.SymlinkTarget!, remainingPath);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static IList<FileInformation> ListRealDirectory(string realPath)
|
|
{
|
|
var files = new List<FileInformation>();
|
|
|
|
try
|
|
{
|
|
if (!Directory.Exists(realPath))
|
|
{
|
|
return files;
|
|
}
|
|
|
|
foreach (var entry in new DirectoryInfo(realPath).EnumerateFileSystemInfos())
|
|
{
|
|
files.Add(new FileInformation
|
|
{
|
|
FileName = entry.Name,
|
|
Attributes = entry.Attributes,
|
|
CreationTime = entry.CreationTime,
|
|
LastAccessTime = entry.LastAccessTime,
|
|
LastWriteTime = entry.LastWriteTime,
|
|
Length = entry is FileInfo fi ? fi.Length : 0
|
|
});
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
return files;
|
|
}
|
|
|
|
public static bool GetRealFileInfo(string realPath, out FileInformation fileInfo)
|
|
{
|
|
fileInfo = default;
|
|
|
|
try
|
|
{
|
|
if (File.Exists(realPath))
|
|
{
|
|
var fi = new FileInfo(realPath);
|
|
fileInfo = new FileInformation
|
|
{
|
|
FileName = fi.Name,
|
|
Attributes = fi.Attributes,
|
|
CreationTime = fi.CreationTime,
|
|
LastAccessTime = fi.LastAccessTime,
|
|
LastWriteTime = fi.LastWriteTime,
|
|
Length = fi.Length
|
|
};
|
|
return true;
|
|
}
|
|
|
|
if (Directory.Exists(realPath))
|
|
{
|
|
var di = new DirectoryInfo(realPath);
|
|
fileInfo = new FileInformation
|
|
{
|
|
FileName = di.Name,
|
|
Attributes = di.Attributes,
|
|
CreationTime = di.CreationTime,
|
|
LastAccessTime = di.LastAccessTime,
|
|
LastWriteTime = di.LastWriteTime,
|
|
Length = 0
|
|
};
|
|
return true;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static NtStatus ReadRealFile(string realPath, byte[] buffer, out int bytesRead, long offset)
|
|
{
|
|
bytesRead = 0;
|
|
|
|
try
|
|
{
|
|
using var stream = new FileStream(realPath, System.IO.FileMode.Open, System.IO.FileAccess.Read, FileShare.ReadWrite);
|
|
stream.Seek(offset, SeekOrigin.Begin);
|
|
bytesRead = stream.Read(buffer, 0, buffer.Length);
|
|
return DokanResult.Success;
|
|
}
|
|
catch (FileNotFoundException)
|
|
{
|
|
return DokanResult.FileNotFound;
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
return DokanResult.AccessDenied;
|
|
}
|
|
catch
|
|
{
|
|
return DokanResult.Error;
|
|
}
|
|
}
|
|
|
|
public static NtStatus WriteRealFile(string realPath, byte[] buffer, out int bytesWritten, long offset)
|
|
{
|
|
bytesWritten = 0;
|
|
|
|
try
|
|
{
|
|
using var stream = new FileStream(realPath, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, FileShare.ReadWrite);
|
|
stream.Seek(offset, SeekOrigin.Begin);
|
|
stream.Write(buffer, 0, buffer.Length);
|
|
bytesWritten = buffer.Length;
|
|
return DokanResult.Success;
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
return DokanResult.AccessDenied;
|
|
}
|
|
catch
|
|
{
|
|
return DokanResult.Error;
|
|
}
|
|
}
|
|
|
|
public static NtStatus CreateRealFileOrDirectory(string realPath, bool isDirectory, FileMode mode)
|
|
{
|
|
try
|
|
{
|
|
if (isDirectory)
|
|
{
|
|
if (mode == FileMode.CreateNew)
|
|
{
|
|
Directory.CreateDirectory(realPath);
|
|
}
|
|
return DokanResult.Success;
|
|
}
|
|
|
|
switch (mode)
|
|
{
|
|
case FileMode.CreateNew:
|
|
using (File.Create(realPath)) { }
|
|
break;
|
|
case FileMode.Create:
|
|
case FileMode.OpenOrCreate:
|
|
using (new FileStream(realPath, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite)) { }
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return DokanResult.Success;
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
return DokanResult.AccessDenied;
|
|
}
|
|
catch
|
|
{
|
|
return DokanResult.Error;
|
|
}
|
|
}
|
|
}
|