Move DevDrive project to repo root
This commit is contained in:
201
SymlinkHandler.cs
Normal file
201
SymlinkHandler.cs
Normal file
@@ -0,0 +1,201 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user