Add OpenFile and CloseFile methods to IReadOnlyFilesystem.

This commit is contained in:
2022-12-19 00:26:55 +00:00
parent 4fb11eec25
commit 7e0dc0a251
19 changed files with 584 additions and 6 deletions

View File

@@ -31,6 +31,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
using Aaru.Helpers;
using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes;
@@ -74,6 +75,75 @@ public sealed partial class AppleDOS
return ErrorNumber.NoError;
}
public ErrorNumber OpenFile(string path, out IFileNode node)
{
node = null;
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
byte[] file;
string filename = pathElements[0].ToUpperInvariant();
if(filename.Length > 30)
return ErrorNumber.NameTooLong;
if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0))
if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0)
file = _catalogBlocks;
else if(string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)
file = _vtocBlocks;
else
file = _bootBlocks;
else
{
if(!_fileCache.TryGetValue(filename, out file))
{
ErrorNumber error = CacheFile(filename);
if(error != ErrorNumber.NoError)
return error;
if(!_fileCache.TryGetValue(filename, out file))
return ErrorNumber.InvalidArgument;
}
}
node = new AppleDosFileNode
{
Path = path,
Length = file.Length,
Offset = 0,
_cache = file
};
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber CloseFile(IFileNode node)
{
if(!_mounted)
return ErrorNumber.AccessDenied;
if(node is not AppleDosFileNode mynode)
return ErrorNumber.InvalidArgument;
mynode._cache = null;
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber Read(string path, long offset, long size, ref byte[] buf)
{

View File

@@ -27,6 +27,7 @@
// ****************************************************************************/
using System.Runtime.InteropServices;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Filesystems;
@@ -102,4 +103,15 @@ public sealed partial class AppleDOS
public readonly byte track;
public readonly byte sector;
}
sealed class AppleDosFileNode : IFileNode
{
internal byte[] _cache;
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; init; }
}
}

View File

@@ -29,6 +29,7 @@
using System;
using System.IO;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
using Aaru.Console;
using Aaru.Helpers;
@@ -153,6 +154,69 @@ public sealed partial class AppleMFS
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber OpenFile(string path, out IFileNode node)
{
node = null;
if(!_mounted)
return ErrorNumber.AccessDenied;
byte[] file;
ErrorNumber error = ErrorNumber.NoError;
switch(_debug)
{
case true when string.Compare(path, "$", StringComparison.InvariantCulture) == 0:
file = _directoryBlocks;
break;
case true when string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 && _bootBlocks != null:
file = _bootBlocks;
break;
case true when string.Compare(path, "$Bitmap", StringComparison.InvariantCulture) == 0:
file = _blockMapBytes;
break;
case true when string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0:
file = _mdbBlocks;
break;
default:
error = ReadFile(path, out file, false, false);
break;
}
if(error != ErrorNumber.NoError)
return error;
node = new AppleMfsFileNode
{
Path = path,
Length = file.Length,
Offset = 0,
_cache = file
};
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber CloseFile(IFileNode node)
{
if(!_mounted)
return ErrorNumber.AccessDenied;
if(node is not AppleMfsFileNode mynode)
return ErrorNumber.InvalidArgument;
mynode._cache = null;
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber Read(string path, long offset, long size, ref byte[] buf)
{

View File

@@ -28,6 +28,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Aaru.CommonTypes.Interfaces;
#pragma warning disable 169
@@ -107,4 +108,15 @@ public sealed partial class AppleMFS
/// <summary>0x32, file name prefixed with length</summary>
public byte[] flNam;
}
sealed class AppleMfsFileNode : IFileNode
{
internal byte[] _cache;
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; init; }
}
}

View File

@@ -28,6 +28,7 @@
using System;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
using Aaru.Helpers;
@@ -77,6 +78,50 @@ public sealed partial class CPM
return !_mounted ? ErrorNumber.AccessDenied : ErrorNumber.NotImplemented;
}
/// <inheritdoc />
public ErrorNumber OpenFile(string path, out IFileNode node)
{
node = null;
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
if(!_fileCache.TryGetValue(pathElements[0].ToUpperInvariant(), out byte[] file))
return ErrorNumber.NoSuchFile;
node = new CpmFileNode
{
Path = path,
Length = file.Length,
Offset = 0,
_cache = file
};
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber CloseFile(IFileNode node)
{
if(!_mounted)
return ErrorNumber.AccessDenied;
if(node is not CpmFileNode mynode)
return ErrorNumber.InvalidArgument;
mynode._cache = null;
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber Read(string path, long offset, long size, ref byte[] buf)
{

View File

@@ -34,6 +34,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Filesystems;
@@ -366,4 +367,15 @@ public sealed partial class CPM
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public readonly ushort[] allocations;
}
sealed class CpmFileNode : IFileNode
{
internal byte[] _cache;
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; init; }
}
}

View File

@@ -31,6 +31,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
using Aaru.Helpers;
using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes;
@@ -84,6 +85,53 @@ public sealed partial class FAT
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber OpenFile(string path, out IFileNode node)
{
node = null;
if(!_mounted)
return ErrorNumber.AccessDenied;
ErrorNumber err = Stat(path, out FileEntryInfo stat);
if(err != ErrorNumber.NoError)
return err;
if(stat.Attributes.HasFlag(FileAttributes.Directory) &&
!_debug)
return ErrorNumber.IsDirectory;
uint[] clusters = GetClusters((uint)stat.Inode);
if(clusters is null)
return ErrorNumber.InvalidArgument;
node = new FatFileNode
{
Path = path,
Length = stat.Length,
Offset = 0,
_clusters = clusters
};
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber CloseFile(IFileNode node)
{
if(!_mounted)
return ErrorNumber.AccessDenied;
if(node is not FatFileNode mynode)
return ErrorNumber.InvalidArgument;
mynode._clusters = null;
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber Read(string path, long offset, long size, ref byte[] buf)
{

View File

@@ -30,6 +30,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Filesystems;
@@ -983,4 +984,16 @@ public sealed partial class FAT
return !string.IsNullOrEmpty(Longname) ? Longname : Shortname;
}
}
sealed class FatFileNode : IFileNode
{
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; init; }
internal uint[] _clusters;
}
}

View File

@@ -31,6 +31,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
using Aaru.Helpers;
using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes;
@@ -84,6 +85,50 @@ public sealed partial class XboxFatPlugin
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber OpenFile(string path, out IFileNode node)
{
node = null;
if(!_mounted)
return ErrorNumber.AccessDenied;
ErrorNumber err = Stat(path, out FileEntryInfo stat);
if(err != ErrorNumber.NoError)
return err;
if(stat.Attributes.HasFlag(FileAttributes.Directory) &&
!_debug)
return ErrorNumber.IsDirectory;
uint[] clusters = GetClusters((uint)stat.Inode);
node = new FatxFileNode
{
Path = path,
Length = stat.Length,
Offset = 0,
_clusters = clusters
};
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber CloseFile(IFileNode node)
{
if(!_mounted)
return ErrorNumber.AccessDenied;
if(node is not FatxFileNode mynode)
return ErrorNumber.InvalidArgument;
mynode._clusters = null;
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber Read(string path, long offset, long size, ref byte[] buf)
{

View File

@@ -27,6 +27,7 @@
// ****************************************************************************/
using System.Runtime.InteropServices;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Filesystems;
@@ -61,4 +62,15 @@ public sealed partial class XboxFatPlugin
public readonly ushort creationTime;
public readonly ushort creationDate;
}
sealed class FatxFileNode : IFileNode
{
internal uint[] _clusters;
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; init; }
}
}

View File

@@ -34,6 +34,7 @@ using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
using Aaru.Console;
using Aaru.Helpers;
@@ -87,6 +88,51 @@ public sealed partial class ISO9660
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber OpenFile(string path, out IFileNode node)
{
node = null;
if(!_mounted)
return ErrorNumber.AccessDenied;
ErrorNumber err = GetFileEntry(path, out DecodedDirectoryEntry entry);
if(err != ErrorNumber.NoError)
return err;
if(entry.Flags.HasFlag(FileFlags.Directory) &&
!_debug)
return ErrorNumber.IsDirectory;
if(entry.Extents is null)
return ErrorNumber.InvalidArgument;
node = new Iso9660FileNode
{
Path = path,
Length = (long)entry.Size,
Offset = 0,
_dentry = entry
};
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber CloseFile(IFileNode node)
{
if(!_mounted)
return ErrorNumber.AccessDenied;
if(node is not Iso9660FileNode mynode)
return ErrorNumber.InvalidArgument;
mynode._dentry = null;
return ErrorNumber.NoError;
}
// TODO: Resolve symbolic link
/// <inheritdoc />
public ErrorNumber Read(string path, long offset, long size, ref byte[] buf)
@@ -157,11 +203,6 @@ public sealed partial class ISO9660
return ErrorNumber.UnexpectedException;
}
return ReadWithExtents(offset, size, entry.Extents,
entry.XA?.signature == XA_MAGIC &&
entry.XA?.attributes.HasFlag(XaAttributes.Interleaved) == true,
entry.XA?.filenumber ?? 0, out buf);
}
/// <inheritdoc />

View File

@@ -29,6 +29,7 @@
using System;
using System.Collections.Generic;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Filesystems;
@@ -102,4 +103,15 @@ public sealed partial class ISO9660
public override string ToString() => Name;
}
sealed class Iso9660FileNode : IFileNode
{
internal DecodedDirectoryEntry _dentry;
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; init; }
}
}

View File

@@ -28,6 +28,7 @@
using System;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
using Aaru.Console;
using Aaru.Decoders;
@@ -55,6 +56,50 @@ public sealed partial class LisaFS
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber OpenFile(string path, out IFileNode node)
{
node = null;
if(!_mounted)
return ErrorNumber.AccessDenied;
ErrorNumber error = LookupFileId(path, out short fileId, out bool isDir);
if(error != ErrorNumber.NoError)
return error;
if(isDir)
return ErrorNumber.IsDirectory;
error = Stat(fileId, out FileEntryInfo stat);
if(error != ErrorNumber.NoError)
return error;
node = new LisaFileNode
{
Path = path,
Length = stat.Length,
Offset = 0,
_fileId = fileId
};
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber CloseFile(IFileNode node)
{
if(!_mounted)
return ErrorNumber.AccessDenied;
if(node is not LisaFileNode mynode)
return ErrorNumber.InvalidArgument;
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber Read(string path, long offset, long size, ref byte[] buf)
{

View File

@@ -30,6 +30,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Aaru.CommonTypes.Interfaces;
#pragma warning disable CS0649
namespace Aaru.Filesystems;
@@ -397,4 +398,16 @@ public sealed partial class LisaFS
/// <summary>0x26, 16 bytes, unknown</summary>
public byte[] unknown3;
}
sealed class LisaFileNode : IFileNode
{
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; init; }
internal short _fileId;
}
}

View File

@@ -31,6 +31,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
namespace Aaru.Filesystems;
@@ -77,6 +78,49 @@ public sealed partial class OperaFS
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber OpenFile(string path, out IFileNode node)
{
node = null;
if(!_mounted)
return ErrorNumber.AccessDenied;
ErrorNumber err = GetFileEntry(path, out DirectoryEntryWithPointers entry);
if(err != ErrorNumber.NoError)
return err;
if((entry.Entry.flags & FLAGS_MASK) == (uint)FileFlags.Directory &&
!_debug)
return ErrorNumber.IsDirectory;
if(entry.Pointers.Length < 1)
return ErrorNumber.InvalidArgument;
node = new OperaFileNode
{
Path = path,
Length = entry.Entry.byte_count,
Offset = 0,
_dentry = entry
};
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber CloseFile(IFileNode node)
{
if(!_mounted)
return ErrorNumber.AccessDenied;
if(node is not OperaFileNode mynode)
return ErrorNumber.InvalidArgument;
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber Read(string path, long offset, long size, ref byte[] buf)
{

View File

@@ -27,6 +27,7 @@
// ****************************************************************************/
using System.Runtime.InteropServices;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Filesystems;
@@ -112,4 +113,15 @@ public sealed partial class OperaFS
public DirectoryEntry Entry;
public uint[] Pointers;
}
sealed class OperaFileNode : IFileNode
{
internal DirectoryEntryWithPointers _dentry;
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; init; }
}
}

View File

@@ -29,6 +29,7 @@
using System;
using System.Linq;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
using Aaru.Helpers;
@@ -71,6 +72,71 @@ public sealed partial class PascalPlugin
return error;
}
/// <inheritdoc />
public ErrorNumber OpenFile(string path, out IFileNode node)
{
node = null;
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
byte[] file;
if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0))
file = string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ? _catalogBlocks : _bootBlocks;
else
{
ErrorNumber error = GetFileEntry(path, out PascalFileEntry entry);
if(error != ErrorNumber.NoError)
return error;
error = _device.ReadSectors((ulong)entry.FirstBlock * _multiplier,
(uint)(entry.LastBlock - entry.FirstBlock) * _multiplier, out byte[] tmp);
if(error != ErrorNumber.NoError)
return error;
file = new byte[((entry.LastBlock - entry.FirstBlock - 1) * _device.Info.SectorSize * _multiplier) +
entry.LastBytes];
Array.Copy(tmp, 0, file, 0, file.Length);
}
node = new PascalFileNode
{
Path = path,
Length = file.Length,
Offset = 0,
_cache = file
};
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber CloseFile(IFileNode node)
{
if(!_mounted)
return ErrorNumber.AccessDenied;
if(node is not PascalFileNode mynode)
return ErrorNumber.InvalidArgument;
mynode._cache = null;
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber Read(string path, long offset, long size, ref byte[] buf)
{

View File

@@ -31,6 +31,7 @@
// ****************************************************************************/
using System.Diagnostics.CodeAnalysis;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Filesystems;
@@ -75,4 +76,15 @@ public sealed partial class PascalPlugin
/// <summary>0x18, modification time</summary>
public short ModificationTime;
}
sealed class PascalFileNode : IFileNode
{
internal byte[] _cache;
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; init; }
}
}