diff --git a/Aaru.Filesystems/CBM/CBM.cs b/Aaru.Filesystems/CBM/CBM.cs
index f57e1fe61..7224ee55b 100644
--- a/Aaru.Filesystems/CBM/CBM.cs
+++ b/Aaru.Filesystems/CBM/CBM.cs
@@ -27,15 +27,27 @@
// ****************************************************************************/
using System;
+using System.Collections.Generic;
+using Aaru.CommonTypes.AaruMetadata;
+using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
+using Aaru.CommonTypes.Structs;
namespace Aaru.Filesystems;
///
/// Implements detection of the filesystem used in 8-bit Commodore microcomputers
-public sealed partial class CBM : IFilesystem
+public sealed partial class CBM : IReadOnlyFilesystem
{
-#region IFilesystem Members
+ byte[] _bam;
+ Dictionary _cache;
+ bool _debug;
+ byte[] _diskHeader;
+ bool _mounted;
+ byte[] _root;
+ FileSystemInfo _statfs;
+
+#region IReadOnlyFilesystem Members
///
public string Name => Localization.CBM_Name;
@@ -46,5 +58,41 @@ public sealed partial class CBM : IFilesystem
///
public string Author => Authors.NataliaPortillo;
+ ///
+ public ErrorNumber ListXAttr(string path, out List xattrs)
+ {
+ xattrs = null;
+
+ return ErrorNumber.NotSupported;
+ }
+
+ ///
+ public ErrorNumber GetXattr(string path, string xattr, ref byte[] buf) => ErrorNumber.NotSupported;
+
+ ///
+ public ErrorNumber ReadLink(string path, out string dest)
+ {
+ dest = null;
+
+ return ErrorNumber.NotSupported;
+ }
+
+ ///
+ public FileSystem Metadata { get; private set; }
+
+ ///
+ public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
+ Array.Empty<(string name, Type type, string description)>();
+
+ ///
+ public Dictionary Namespaces => null;
+
#endregion
+
+ static Dictionary GetDefaultOptions() => new()
+ {
+ {
+ "debug", false.ToString()
+ }
+ };
}
\ No newline at end of file
diff --git a/Aaru.Filesystems/CBM/Dir.cs b/Aaru.Filesystems/CBM/Dir.cs
new file mode 100644
index 000000000..87fa13308
--- /dev/null
+++ b/Aaru.Filesystems/CBM/Dir.cs
@@ -0,0 +1,100 @@
+// /***************************************************************************
+// Aaru Data Preservation Suite
+// ----------------------------------------------------------------------------
+//
+// Filename : CBM.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Commodore file system plugin.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2023 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Linq;
+using Aaru.CommonTypes.Enums;
+using Aaru.CommonTypes.Interfaces;
+
+namespace Aaru.Filesystems;
+
+///
+/// Implements detection of the filesystem used in 8-bit Commodore microcomputers
+public sealed partial class CBM
+{
+#region IReadOnlyFilesystem Members
+
+ ///
+ public ErrorNumber OpenDir(string path, out IDirNode node)
+ {
+ node = null;
+
+ if(!_mounted)
+ return ErrorNumber.AccessDenied;
+
+ if(!string.IsNullOrEmpty(path) && string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0)
+ return ErrorNumber.NotSupported;
+
+ var contents = _cache.Keys.ToList();
+
+ contents.Sort();
+
+ node = new CbmDirNode
+ {
+ Path = path, Position = 0, Contents = contents.ToArray()
+ };
+
+ return ErrorNumber.NoError;
+ }
+
+ ///
+ public ErrorNumber CloseDir(IDirNode node)
+ {
+ if(node is not CbmDirNode mynode)
+ return ErrorNumber.InvalidArgument;
+
+ mynode.Position = -1;
+ mynode.Contents = null;
+
+ return ErrorNumber.NoError;
+ }
+
+ ///
+ public ErrorNumber ReadDir(IDirNode node, out string filename)
+ {
+ filename = null;
+
+ if(!_mounted)
+ return ErrorNumber.AccessDenied;
+
+ if(node is not CbmDirNode mynode)
+ return ErrorNumber.InvalidArgument;
+
+ if(mynode.Position < 0)
+ return ErrorNumber.InvalidArgument;
+
+ if(mynode.Position >= mynode.Contents.Length)
+ return ErrorNumber.NoError;
+
+ filename = mynode.Contents[mynode.Position++];
+
+ return ErrorNumber.NoError;
+ }
+
+#endregion
+}
\ No newline at end of file
diff --git a/Aaru.Filesystems/CBM/File.cs b/Aaru.Filesystems/CBM/File.cs
new file mode 100644
index 000000000..01dec4c0f
--- /dev/null
+++ b/Aaru.Filesystems/CBM/File.cs
@@ -0,0 +1,178 @@
+// /***************************************************************************
+// Aaru Data Preservation Suite
+// ----------------------------------------------------------------------------
+//
+// Filename : CBM.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Commodore file system plugin.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2023 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using Aaru.CommonTypes.Enums;
+using Aaru.CommonTypes.Interfaces;
+using Aaru.CommonTypes.Structs;
+
+namespace Aaru.Filesystems;
+
+///
+/// Implements detection of the filesystem used in 8-bit Commodore microcomputers
+public sealed partial class CBM
+{
+#region IReadOnlyFilesystem Members
+
+ ///
+ public ErrorNumber GetAttributes(string path, out FileAttributes attributes)
+ {
+ attributes = new FileAttributes();
+
+ if(!_mounted)
+ return ErrorNumber.AccessDenied;
+
+ string[] pathElements = path.Split(new[]
+ {
+ '/'
+ }, StringSplitOptions.RemoveEmptyEntries);
+
+ if(pathElements.Length != 1)
+ return ErrorNumber.NotSupported;
+
+ string filename = pathElements[0].ToUpperInvariant();
+
+ if(!_cache.TryGetValue(filename, out CachedFile file))
+ return ErrorNumber.NoSuchFile;
+
+ attributes = file.attributes;
+
+ return ErrorNumber.NoError;
+ }
+
+ ///
+ public ErrorNumber Stat(string path, out FileEntryInfo stat)
+ {
+ stat = null;
+
+ if(!_mounted)
+ return ErrorNumber.AccessDenied;
+
+ string[] pathElements = path.Split(new[]
+ {
+ '/'
+ }, StringSplitOptions.RemoveEmptyEntries);
+
+ if(pathElements.Length != 1)
+ return ErrorNumber.NotSupported;
+
+ string filename = pathElements[0].ToUpperInvariant();
+
+ if(filename.Length > 14)
+ return ErrorNumber.NameTooLong;
+
+ if(!_cache.TryGetValue(filename, out CachedFile file))
+ return ErrorNumber.NoSuchFile;
+
+ stat = new FileEntryInfo
+ {
+ Attributes = file.attributes,
+ BlockSize = 256,
+ Length = (long)file.length,
+ Blocks = file.blocks,
+ Inode = file.id,
+ Links = 1
+ };
+
+ 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;
+
+ string filename = pathElements[0].ToUpperInvariant();
+
+ if(filename.Length > 14)
+ return ErrorNumber.NameTooLong;
+
+ if(!_cache.TryGetValue(filename, out CachedFile file))
+ return ErrorNumber.NoSuchFile;
+
+ node = new CbmFileNode
+ {
+ Path = path, Length = (long)file.length, Offset = 0, Cache = file.data
+ };
+
+ return ErrorNumber.NoError;
+ }
+
+ ///
+ public ErrorNumber CloseFile(IFileNode node)
+ {
+ if(!_mounted)
+ return ErrorNumber.AccessDenied;
+
+ if(node is not CbmFileNode mynode)
+ return ErrorNumber.InvalidArgument;
+
+ mynode.Cache = null;
+
+ return ErrorNumber.NoError;
+ }
+
+ ///
+ public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read)
+ {
+ read = 0;
+
+ if(!_mounted)
+ return ErrorNumber.AccessDenied;
+
+ if(buffer is null || buffer.Length < length)
+ return ErrorNumber.InvalidArgument;
+
+ if(node is not CbmFileNode mynode)
+ return ErrorNumber.InvalidArgument;
+
+ read = length;
+
+ if(length + mynode.Offset >= mynode.Length)
+ read = mynode.Length - mynode.Offset;
+
+ Array.Copy(mynode.Cache, mynode.Offset, buffer, 0, read);
+
+ mynode.Offset += read;
+
+ return ErrorNumber.NoError;
+ }
+
+#endregion
+}
\ No newline at end of file
diff --git a/Aaru.Filesystems/CBM/Structs.cs b/Aaru.Filesystems/CBM/Structs.cs
index d65c26645..8e62ff492 100644
--- a/Aaru.Filesystems/CBM/Structs.cs
+++ b/Aaru.Filesystems/CBM/Structs.cs
@@ -27,6 +27,8 @@
// ****************************************************************************/
using System.Runtime.InteropServices;
+using Aaru.CommonTypes.Interfaces;
+using Aaru.CommonTypes.Structs;
namespace Aaru.Filesystems;
@@ -81,6 +83,81 @@ public sealed partial class CBM
#endregion
+#region Nested type: CachedFile
+
+ struct CachedFile
+ {
+ public byte[] data;
+ public ulong length;
+ public FileAttributes attributes;
+ public int blocks;
+ public ulong id;
+ }
+
+#endregion
+
+#region Nested type: CbmDirNode
+
+ sealed class CbmDirNode : IDirNode
+ {
+ internal string[] Contents;
+ internal int Position;
+
+ #region IDirNode Members
+
+ ///
+ public string Path { get; init; }
+
+ #endregion
+ }
+
+#endregion
+
+#region Nested type: CbmFileNode
+
+ sealed class CbmFileNode : IFileNode
+ {
+ internal byte[] Cache;
+
+ #region IFileNode Members
+
+ ///
+ public string Path { get; init; }
+
+ ///
+ public long Length { get; init; }
+
+ ///
+ public long Offset { get; set; }
+
+ #endregion
+ }
+
+#endregion
+
+#region Nested type: DirectoryEntry
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ readonly struct DirectoryEntry
+ {
+ public readonly byte nextDirBlockTrack;
+ public readonly byte nextDirBlockSector;
+ public readonly byte fileType;
+ public readonly byte firstFileBlockTrack;
+ public readonly byte firstFileBlockSector;
+ /// Filename
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ public readonly byte[] name;
+ public readonly byte firstSideBlockTrack;
+ public readonly byte firstSideBlockSector;
+ public readonly ulong unused;
+ public readonly byte replacementTrack;
+ public readonly byte replacementSector;
+ public readonly short blocks;
+ }
+
+#endregion
+
#region Nested type: Header
[StructLayout(LayoutKind.Sequential, Pack = 1)]
diff --git a/Aaru.Filesystems/CBM/Super.cs b/Aaru.Filesystems/CBM/Super.cs
new file mode 100644
index 000000000..674debd5f
--- /dev/null
+++ b/Aaru.Filesystems/CBM/Super.cs
@@ -0,0 +1,328 @@
+// /***************************************************************************
+// Aaru Data Preservation Suite
+// ----------------------------------------------------------------------------
+//
+// Filename : CBM.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Commodore file system plugin.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2023 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Aaru.CommonTypes.AaruMetadata;
+using Aaru.CommonTypes.Enums;
+using Aaru.CommonTypes.Interfaces;
+using Aaru.CommonTypes.Structs;
+using Aaru.Console;
+using Aaru.Helpers;
+using Claunia.Encoding;
+using Encoding = System.Text.Encoding;
+using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes;
+using FileSystemInfo = Aaru.CommonTypes.Structs.FileSystemInfo;
+using Partition = Aaru.CommonTypes.Partition;
+
+namespace Aaru.Filesystems;
+
+///
+/// Implements detection of the filesystem used in 8-bit Commodore microcomputers
+public sealed partial class CBM
+{
+#region IReadOnlyFilesystem Members
+
+ ///
+ public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
+ Dictionary options, string @namespace)
+ {
+ if(partition.Start > 0)
+ return ErrorNumber.InvalidArgument;
+
+ if(imagePlugin.Info.SectorSize != 256)
+ return ErrorNumber.InvalidArgument;
+
+ if(imagePlugin.Info.Sectors != 683 &&
+ imagePlugin.Info.Sectors != 768 &&
+ imagePlugin.Info.Sectors != 1366 &&
+ imagePlugin.Info.Sectors != 3200)
+ return ErrorNumber.InvalidArgument;
+
+ options ??= GetDefaultOptions();
+
+ if(options.TryGetValue("debug", out string debugString))
+ bool.TryParse(debugString, out _debug);
+
+ encoding = new PETSCII();
+ byte[] sector;
+ ulong rootLba;
+ string volumeName = null;
+ Metadata = new FileSystem
+ {
+ Type = FS_TYPE, Clusters = imagePlugin.Info.Sectors, ClusterSize = 256
+ };
+ uint serial;
+ // Commodore 1581
+ if(imagePlugin.Info.Sectors == 3200)
+ {
+ ErrorNumber errno = imagePlugin.ReadSector(1560, out _diskHeader);
+
+ if(errno != ErrorNumber.NoError)
+ return errno;
+
+ Header cbmHdr = Marshal.ByteArrayToStructureLittleEndian(_diskHeader);
+
+ if(cbmHdr.diskDosVersion != 0x44 || cbmHdr is not { dosVersion: 0x33, diskVersion: 0x44 })
+ return ErrorNumber.InvalidArgument;
+
+ _bam = new byte[512];
+ // Got to first BAM sector
+ errno = imagePlugin.ReadSector(1561, out sector);
+
+ if(errno != ErrorNumber.NoError)
+ return errno;
+
+ Array.Copy(sector, 0, _bam, 0, 256);
+
+ if(_bam[0] > 0)
+ {
+ // Got to next (and last) BAM sector
+ errno = imagePlugin.ReadSector((ulong)((_bam[0] - 1) * 40), out sector);
+
+ if(errno != ErrorNumber.NoError)
+ return errno;
+
+ Array.Copy(sector, 0, _bam, 256, 256);
+ }
+
+ if(cbmHdr.directoryTrack == 0)
+ return ErrorNumber.InvalidArgument;
+
+ rootLba = (ulong)((cbmHdr.directoryTrack - 1) * 40 + cbmHdr.directorySector - 1);
+ serial = cbmHdr.diskId;
+ Metadata.VolumeName = StringHandlers.CToString(cbmHdr.name, encoding);
+ Metadata.VolumeSerial = $"{cbmHdr.diskId}";
+ }
+ else
+ {
+ ErrorNumber errno = imagePlugin.ReadSector(357, out _bam);
+
+ if(errno != ErrorNumber.NoError)
+ return errno;
+
+ BAM cbmBam = Marshal.ByteArrayToStructureLittleEndian(_bam);
+
+ if(cbmBam is not ({ dosVersion: 0x41, doubleSided : 0x00 or 0x80 }
+ and { unused1 : 0x00, directoryTrack: 0x12 }))
+ return ErrorNumber.InvalidArgument;
+
+ rootLba = (ulong)((cbmBam.directoryTrack - 1) * 40 + cbmBam.directorySector - 1);
+ serial = cbmBam.diskId;
+
+ Metadata.VolumeName = StringHandlers.CToString(cbmBam.name, encoding);
+ Metadata.VolumeSerial = $"{cbmBam.diskId}";
+ }
+
+ if(rootLba >= imagePlugin.Info.Sectors)
+ return ErrorNumber.IllegalSeek;
+
+ ulong nextLba = rootLba;
+ var rootMs = new MemoryStream();
+ var relativeFileWarningShown = false;
+
+ do
+ {
+ ErrorNumber errno = imagePlugin.ReadSector(nextLba, out sector);
+
+ if(errno != ErrorNumber.NoError)
+ return errno;
+
+ rootMs.Write(sector, 0, 256);
+
+ if(sector[0] == 0)
+ break;
+
+ nextLba = (ulong)((sector[0] - 1) * 40 + sector[1] - 1);
+ } while(nextLba > 0);
+
+ _root = rootMs.ToArray();
+
+ _statfs = new FileSystemInfo
+ {
+ Blocks = imagePlugin.Info.Sectors,
+ FilenameLength = 14,
+ Files = 0,
+ FreeBlocks =
+ imagePlugin.Info.Sectors -
+ (ulong)(_diskHeader?.Length ?? 0 / 256 - _bam.Length / 256 - _root.Length / 256),
+ FreeFiles = (ulong)(_root.Length / 32),
+ Id = new FileSystemId
+ {
+ Serial32 = serial, IsInt = true
+ },
+ PluginId = Id,
+ Type = "CBMFS"
+ };
+
+ // As this filesystem comes in (by nowadays standards) very small sizes, we can cache all files
+ _cache = new Dictionary();
+ var offset = 0;
+ ulong fileId = 0;
+
+ if(_debug)
+ {
+ // Root
+ _cache.Add("$", new CachedFile
+ {
+ attributes = FileAttributes.Directory | FileAttributes.Hidden | FileAttributes.System,
+ length = (ulong)_root.Length,
+ data = _root,
+ blocks = _root.Length / 256,
+ id = fileId++
+ });
+
+ // BAM
+ _cache.Add("$BAM", new CachedFile
+ {
+ attributes = FileAttributes.File | FileAttributes.Hidden | FileAttributes.System,
+ length = (ulong)_bam.Length,
+ data = _bam,
+ blocks = _bam.Length / 256,
+ id = fileId++
+ });
+
+ _statfs.Files += 2;
+
+ // 1581 disk header
+ if(_diskHeader != null)
+ {
+ _cache.Add("$DISK_HEADER", new CachedFile
+ {
+ attributes = FileAttributes.File | FileAttributes.Hidden | FileAttributes.System,
+ length = (ulong)_diskHeader.Length,
+ data = _diskHeader,
+ blocks = _diskHeader.Length / 256,
+ id = fileId++
+ });
+ _statfs.Files++;
+ }
+ }
+
+ while(offset < _root.Length)
+ {
+ DirectoryEntry dirEntry = Marshal.ByteArrayToStructureLittleEndian(_root, offset, 32);
+
+ if(dirEntry.fileType == 0)
+ {
+ offset += 32;
+ continue;
+ }
+
+ _statfs.Files++;
+ _statfs.FreeFiles--;
+
+ for(var i = 0; i < dirEntry.name.Length; i++)
+ {
+ if(dirEntry.name[i] == 0xA0)
+ dirEntry.name[i] = 0;
+ }
+
+ string name = StringHandlers.CToString(dirEntry.name, encoding);
+
+ if((dirEntry.fileType & 0x07) == 4 && !relativeFileWarningShown)
+ {
+ AaruConsole.WriteLine(Localization.CBM_Mount_REL_file_warning);
+ relativeFileWarningShown = true;
+ }
+
+ var data = new MemoryStream();
+
+ nextLba = (ulong)((dirEntry.firstFileBlockTrack - 1) * 40 + dirEntry.firstFileBlockSector - 1);
+
+ _statfs.FreeBlocks -= (ulong)dirEntry.blocks;
+
+ while(dirEntry.blocks > 0)
+ {
+ if(dirEntry.firstFileBlockTrack == 0)
+ break;
+
+ ErrorNumber errno = imagePlugin.ReadSector(nextLba, out sector);
+ if(errno != ErrorNumber.NoError)
+ break;
+
+ data.Write(sector, 2, 254);
+
+ if(sector[0] == 0)
+ break;
+
+ nextLba = (ulong)((sector[0] - 1) * 40 + sector[1] - 1);
+ }
+
+ FileAttributes attributes = FileAttributes.File;
+
+ if((dirEntry.fileType & 0x80) != 0x80)
+ attributes |= FileAttributes.Open;
+ if((dirEntry.fileType & 0x40) > 0)
+ attributes |= FileAttributes.ReadOnly;
+ if((dirEntry.fileType & 7) == 2)
+ attributes |= FileAttributes.Executable;
+
+ _cache.Add(name, new CachedFile
+ {
+ attributes = attributes,
+ length = (ulong)data.Length,
+ data = data.ToArray(),
+ blocks = dirEntry.blocks,
+ id = fileId++
+ });
+
+ offset += 32;
+ }
+
+ _mounted = true;
+ return ErrorNumber.NoError;
+ }
+
+ ///
+ public ErrorNumber Unmount()
+ {
+ if(!_mounted)
+ return ErrorNumber.AccessDenied;
+
+ _mounted = false;
+
+ return ErrorNumber.NoError;
+ }
+
+ ///
+ public ErrorNumber StatFs(out FileSystemInfo stat)
+ {
+ stat = null;
+
+ if(!_mounted)
+ return ErrorNumber.AccessDenied;
+
+ stat = _statfs.ShallowCopy();
+
+ return ErrorNumber.NoError;
+ }
+
+#endregion
+}
\ No newline at end of file
diff --git a/Aaru.Filesystems/Localization/Localization.Designer.cs b/Aaru.Filesystems/Localization/Localization.Designer.cs
index de09465bc..50998d04c 100644
--- a/Aaru.Filesystems/Localization/Localization.Designer.cs
+++ b/Aaru.Filesystems/Localization/Localization.Designer.cs
@@ -2517,6 +2517,15 @@ namespace Aaru.Filesystems {
}
}
+ ///
+ /// Looks up a localized string similar to This disk contains a relative file. These have not been fully tested, please open a bug report and include this disk image..
+ ///
+ internal static string CBM_Mount_REL_file_warning {
+ get {
+ return ResourceManager.GetString("CBM_Mount_REL_file_warning", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Commodore file system.
///
diff --git a/Aaru.Filesystems/Localization/Localization.es.resx b/Aaru.Filesystems/Localization/Localization.es.resx
index 2545e6419..34b78fdda 100644
--- a/Aaru.Filesystems/Localization/Localization.es.resx
+++ b/Aaru.Filesystems/Localization/Localization.es.resx
@@ -3680,4 +3680,7 @@
512 bytes por bloque
+
+ Este disco contiene un fichero relativo. Estos no han sido totalmente probados, por favor abra un reporte de errores y adjunte esta imagen de disco.
+
\ No newline at end of file
diff --git a/Aaru.Filesystems/Localization/Localization.resx b/Aaru.Filesystems/Localization/Localization.resx
index c23a711fe..a8b4a9784 100644
--- a/Aaru.Filesystems/Localization/Localization.resx
+++ b/Aaru.Filesystems/Localization/Localization.resx
@@ -3689,4 +3689,7 @@
{0} = Unknown data type {1}
+
+ This disk contains a relative file. These have not been fully tested, please open a bug report and include this disk image.
+
\ No newline at end of file
diff --git a/README.md b/README.md
index a584bbd6b..322d9726c 100644
--- a/README.md
+++ b/README.md
@@ -127,6 +127,7 @@ Supported disk image formats (read and write)
Supported disk image formats (read-only)
========================================
+
* Symbian Installation File (.SIS)
Supported partitioning schemes
@@ -165,6 +166,7 @@ Supported file systems for read-only operations
* Apple Lisa file system
* Apple Macintosh File System (MFS)
* CD-i file system
+* Commodore 1540/1541/1571/1581 filesystems
* CP/M file system
* High Sierra Format
* ISO9660, including Apple, Amiga, Rock Ridge, Joliet and Romeo extensions
@@ -192,7 +194,6 @@ Supported file systems for identification and information only
* BSD Unix File System 2 (UFS2)
* B-tree file system (btrfs)
* Coherent UNIX file system
-* Commodore 1540/1541/1571/1581 filesystems
* Cram file system
* DEC Files-11 (only checked with On Disk Structure 2, ODS-2)
* DEC RT-11 file system