diff --git a/Aaru.Filesystems/VxFS/File.cs b/Aaru.Filesystems/VxFS/File.cs index 0a9dd5c33..7324fa53f 100644 --- a/Aaru.Filesystems/VxFS/File.cs +++ b/Aaru.Filesystems/VxFS/File.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Helpers; @@ -54,6 +55,100 @@ public sealed partial class VxFS return ErrorNumber.NoError; } + /// + public ErrorNumber OpenFile(string path, out IFileNode node) + { + node = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(string.IsNullOrEmpty(path) || path == "/") return ErrorNumber.IsDirectory; + + ErrorNumber errno = LookupInode(path, out DiskInode inode, out uint inodeNumber); + + if(errno != ErrorNumber.NoError) return errno; + + var fileType = (VxfsFileType)(inode.vdi_mode & VXFS_TYPE_MASK); + + if(fileType == VxfsFileType.Dir) return ErrorNumber.IsDirectory; + + node = new VxFsFileNode + { + Path = path, + Length = (long)inode.vdi_size, + Offset = 0, + InodeNumber = inodeNumber, + Inode = inode + }; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseFile(IFileNode node) + { + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not VxFsFileNode) return ErrorNumber.InvalidArgument; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) + { + read = 0; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not VxFsFileNode fileNode) return ErrorNumber.InvalidArgument; + + if(buffer == null) return ErrorNumber.InvalidArgument; + + if(fileNode.Offset < 0 || fileNode.Offset >= fileNode.Length) return ErrorNumber.InvalidArgument; + + long toRead = length; + + if(fileNode.Offset + toRead > fileNode.Length) toRead = fileNode.Length - fileNode.Offset; + + if(toRead <= 0) return ErrorNumber.NoError; + + if(toRead > buffer.Length) toRead = buffer.Length; + + int blockSize = _superblock.vs_bsize; + long bytesRead = 0; + long currentOffset = fileNode.Offset; + + while(bytesRead < toRead) + { + var blockNum = (uint)(currentOffset / blockSize); + var offsetInBlock = (int)(currentOffset % blockSize); + + byte[] blockData = ReadInodeBlock(fileNode.Inode, blockNum); + + if(blockData == null) + { + // Sparse block / hole — fill with zeros + long bytesToZero = Math.Min(blockSize - offsetInBlock, toRead - bytesRead); + Array.Clear(buffer, (int)bytesRead, (int)bytesToZero); + bytesRead += bytesToZero; + currentOffset += bytesToZero; + + continue; + } + + long bytesToCopy = Math.Min(blockSize - offsetInBlock, toRead - bytesRead); + Array.Copy(blockData, offsetInBlock, buffer, bytesRead, bytesToCopy); + bytesRead += bytesToCopy; + currentOffset += bytesToCopy; + } + + read = bytesRead; + fileNode.Offset += bytesRead; + + return ErrorNumber.NoError; + } + /// Resolves a path to its inode /// Path to resolve /// Output inode diff --git a/Aaru.Filesystems/VxFS/Internal.cs b/Aaru.Filesystems/VxFS/Internal.cs index 385f46208..c005ef47e 100644 --- a/Aaru.Filesystems/VxFS/Internal.cs +++ b/Aaru.Filesystems/VxFS/Internal.cs @@ -46,4 +46,23 @@ public sealed partial class VxFS /// public string Path { get; init; } } + + /// File node for reading file contents + sealed class VxFsFileNode : IFileNode + { + /// The inode number + internal uint InodeNumber { get; init; } + + /// The file's disk inode containing metadata and extent pointers + internal DiskInode Inode { get; init; } + + /// + public string Path { get; init; } + + /// + public long Length { get; init; } + + /// + public long Offset { get; set; } + } } \ No newline at end of file diff --git a/Aaru.Filesystems/VxFS/Unimplemented.cs b/Aaru.Filesystems/VxFS/Unimplemented.cs index 3a0081547..843e3bf51 100644 --- a/Aaru.Filesystems/VxFS/Unimplemented.cs +++ b/Aaru.Filesystems/VxFS/Unimplemented.cs @@ -28,7 +28,6 @@ using System; using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; namespace Aaru.Filesystems; @@ -40,14 +39,4 @@ public sealed partial class VxFS /// public ErrorNumber ReadLink(string path, out string dest) => throw new NotImplementedException(); - - /// - public ErrorNumber OpenFile(string path, out IFileNode node) => throw new NotImplementedException(); - - /// - public ErrorNumber CloseFile(IFileNode node) => throw new NotImplementedException(); - - /// - public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) => - throw new NotImplementedException(); } \ No newline at end of file