Files
Aaru/Aaru.Filesystems/ISO9660/Super.cs

768 lines
31 KiB
C#
Raw Normal View History

2019-07-31 20:10:27 +01:00
// /***************************************************************************
2020-02-27 12:31:25 +00:00
// Aaru Data Preservation Suite
2019-07-31 20:10:27 +01:00
// ----------------------------------------------------------------------------
//
// Filename : Super.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : ISO9660 filesystem plugin.
//
// --[ Description ] ----------------------------------------------------------
//
// Mounts ISO9660, CD-i and High Sierra Format filesystems.
//
// --[ 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
2020-01-03 17:51:30 +00:00
// Copyright © 2011-2020 Natalia Portillo
// In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24
2019-07-31 20:10:27 +01:00
// ****************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
2020-02-27 00:33:26 +00:00
using Aaru.CommonTypes;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
using Aaru.Console;
using Aaru.Decoders.Sega;
using Aaru.Helpers;
using Schemas;
2020-07-20 15:43:52 +01:00
namespace Aaru.Filesystems
{
2020-07-22 13:20:25 +01:00
public sealed partial class ISO9660
{
public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
Dictionary<string, string> options, string @namespace)
{
2019-07-23 06:20:00 +01:00
Encoding = encoding ?? Encoding.GetEncoding(1252);
byte[] vdMagic = new byte[5]; // Volume Descriptor magic "CD001"
byte[] hsMagic = new byte[5]; // Volume Descriptor magic "CDROM"
2020-07-22 13:20:25 +01:00
options ??= GetDefaultOptions();
if(options.TryGetValue("debug", out string debugString))
2020-07-20 21:11:32 +01:00
bool.TryParse(debugString, out _debug);
if(options.TryGetValue("use_path_table", out string usePathTableString))
2020-07-20 21:11:32 +01:00
bool.TryParse(usePathTableString, out _usePathTable);
2019-07-31 01:02:56 +01:00
if(options.TryGetValue("use_trans_tbl", out string useTransTblString))
2020-07-20 21:11:32 +01:00
bool.TryParse(useTransTblString, out _useTransTbl);
if(options.TryGetValue("use_evd", out string useEvdString))
2020-07-20 21:11:32 +01:00
bool.TryParse(useEvdString, out _useEvd);
// Default namespace
2020-07-22 13:20:25 +01:00
@namespace ??= "joliet";
switch(@namespace.ToLowerInvariant())
{
2020-02-29 18:03:35 +00:00
case "normal":
2020-07-20 21:11:32 +01:00
_namespace = Namespace.Normal;
break;
2020-02-29 18:03:35 +00:00
case "vms":
2020-07-20 21:11:32 +01:00
_namespace = Namespace.Vms;
break;
2020-02-29 18:03:35 +00:00
case "joliet":
2020-07-20 21:11:32 +01:00
_namespace = Namespace.Joliet;
break;
2020-02-29 18:03:35 +00:00
case "rrip":
2020-07-20 21:11:32 +01:00
_namespace = Namespace.Rrip;
break;
2020-02-29 18:03:35 +00:00
case "romeo":
2020-07-20 21:11:32 +01:00
_namespace = Namespace.Romeo;
2019-07-23 06:20:00 +01:00
break;
default: return Errno.InvalidArgument;
}
PrimaryVolumeDescriptor? pvd = null;
PrimaryVolumeDescriptor? jolietvd = null;
BootRecord? bvd = null;
HighSierraPrimaryVolumeDescriptor? hsvd = null;
FileStructureVolumeDescriptor? fsvd = null;
// ISO9660 is designed for 2048 bytes/sector devices
if(imagePlugin.Info.SectorSize < 2048)
return Errno.InvalidArgument;
// ISO9660 Primary Volume Descriptor starts at sector 16, so that's minimal size.
if(partition.End < 16)
return Errno.InvalidArgument;
ulong counter = 0;
byte[] vdSector = imagePlugin.ReadSector(16 + counter + partition.Start);
int xaOff = vdSector.Length == 2336 ? 8 : 0;
Array.Copy(vdSector, 0x009 + xaOff, hsMagic, 0, 5);
2020-07-20 21:11:32 +01:00
_highSierra = Encoding.GetString(hsMagic) == HIGH_SIERRA_MAGIC;
int hsOff = 0;
2020-07-20 21:11:32 +01:00
if(_highSierra)
hsOff = 8;
2020-07-20 21:11:32 +01:00
_cdi = false;
List<ulong> bvdSectors = new List<ulong>();
List<ulong> pvdSectors = new List<ulong>();
List<ulong> svdSectors = new List<ulong>();
List<ulong> evdSectors = new List<ulong>();
List<ulong> vpdSectors = new List<ulong>();
while(true)
{
2020-02-27 23:48:41 +00:00
AaruConsole.DebugWriteLine("ISO9660 plugin", "Processing VD loop no. {0}", counter);
// Seek to Volume Descriptor
2020-02-27 23:48:41 +00:00
AaruConsole.DebugWriteLine("ISO9660 plugin", "Reading sector {0}", 16 + counter + partition.Start);
byte[] vdSectorTmp = imagePlugin.ReadSector(16 + counter + partition.Start);
vdSector = new byte[vdSectorTmp.Length - xaOff];
Array.Copy(vdSectorTmp, xaOff, vdSector, 0, vdSector.Length);
byte vdType = vdSector[0 + hsOff]; // Volume Descriptor Type, should be 1 or 2.
2020-02-27 23:48:41 +00:00
AaruConsole.DebugWriteLine("ISO9660 plugin", "VDType = {0}", vdType);
if(vdType == 255) // Supposedly we are in the PVD.
{
if(counter == 0)
return Errno.InvalidArgument;
break;
}
Array.Copy(vdSector, 0x001, vdMagic, 0, 5);
Array.Copy(vdSector, 0x009, hsMagic, 0, 5);
if(Encoding.GetString(vdMagic) != ISO_MAGIC &&
Encoding.GetString(hsMagic) != HIGH_SIERRA_MAGIC &&
Encoding.GetString(vdMagic) != CDI_MAGIC
) // Recognized, it is an ISO9660, now check for rest of data.
{
if(counter == 0)
return Errno.InvalidArgument;
break;
}
2020-07-20 21:11:32 +01:00
_cdi |= Encoding.GetString(vdMagic) == CDI_MAGIC;
switch(vdType)
{
case 0:
{
2020-07-20 21:11:32 +01:00
if(_debug)
bvdSectors.Add(16 + counter + partition.Start);
break;
}
case 1:
{
2020-07-20 21:11:32 +01:00
if(_highSierra)
hsvd = Marshal.
ByteArrayToStructureLittleEndian<HighSierraPrimaryVolumeDescriptor>(vdSector);
2020-07-20 21:11:32 +01:00
else if(_cdi)
fsvd = Marshal.ByteArrayToStructureBigEndian<FileStructureVolumeDescriptor>(vdSector);
else
pvd = Marshal.ByteArrayToStructureLittleEndian<PrimaryVolumeDescriptor>(vdSector);
2020-07-20 21:11:32 +01:00
if(_debug)
pvdSectors.Add(16 + counter + partition.Start);
break;
}
case 2:
{
PrimaryVolumeDescriptor svd =
Marshal.ByteArrayToStructureLittleEndian<PrimaryVolumeDescriptor>(vdSector);
// TODO: Other escape sequences
// Check if this is Joliet
if(svd.version == 1)
{
if(svd.escape_sequences[0] == '%' &&
svd.escape_sequences[1] == '/')
if(svd.escape_sequences[2] == '@' ||
svd.escape_sequences[2] == 'C' ||
svd.escape_sequences[2] == 'E')
jolietvd = svd;
else
AaruConsole.DebugWriteLine("ISO9660 plugin",
"Found unknown supplementary volume descriptor");
2020-07-20 21:11:32 +01:00
if(_debug)
svdSectors.Add(16 + counter + partition.Start);
}
else
{
2020-07-20 21:11:32 +01:00
if(_debug)
evdSectors.Add(16 + counter + partition.Start);
2020-07-20 21:11:32 +01:00
if(_useEvd)
{
// Basically until escape sequences are implemented, let the user chose the encoding.
2020-07-22 13:20:25 +01:00
// This is the same as user choosing Romeo namespace, but using the EVD instead of the PVD
2020-07-20 21:11:32 +01:00
_namespace = Namespace.Romeo;
pvd = svd;
}
}
break;
}
case 3:
{
2020-07-20 21:11:32 +01:00
if(_debug)
vpdSectors.Add(16 + counter + partition.Start);
break;
}
}
counter++;
}
DecodedVolumeDescriptor decodedVd;
var decodedJolietVd = new DecodedVolumeDescriptor();
XmlFsType = new FileSystemType();
if(pvd == null &&
hsvd == null &&
fsvd == null)
{
2020-02-27 23:48:41 +00:00
AaruConsole.ErrorWriteLine("ERROR: Could not find primary volume descriptor");
return Errno.InvalidArgument;
}
2020-07-20 21:11:32 +01:00
if(_highSierra)
decodedVd = DecodeVolumeDescriptor(hsvd.Value);
2020-07-20 21:11:32 +01:00
else if(_cdi)
decodedVd = DecodeVolumeDescriptor(fsvd.Value);
else
decodedVd = DecodeVolumeDescriptor(pvd.Value);
if(jolietvd != null)
decodedJolietVd = DecodeJolietDescriptor(jolietvd.Value);
2020-07-20 21:11:32 +01:00
if(_namespace != Namespace.Romeo)
Encoding = Encoding.ASCII;
2019-07-29 02:45:46 +01:00
string fsFormat;
2019-07-29 02:45:46 +01:00
byte[] pathTableData;
uint pathTableMsbLocation;
2019-07-31 17:44:51 +01:00
uint pathTableLsbLocation = 0; // Initialize to 0 as ignored in CD-i
2020-07-20 21:11:32 +01:00
_image = imagePlugin;
2020-07-20 21:11:32 +01:00
if(_highSierra)
2019-07-29 02:45:46 +01:00
{
pathTableData = ReadSingleExtent(0, hsvd.Value.path_table_size,
Swapping.Swap(hsvd.Value.mandatory_path_table_msb));
2019-07-29 02:45:46 +01:00
fsFormat = "High Sierra Format";
pathTableMsbLocation = hsvd.Value.mandatory_path_table_msb;
pathTableLsbLocation = hsvd.Value.mandatory_path_table_lsb;
2019-07-29 02:45:46 +01:00
}
2020-07-20 21:11:32 +01:00
else if(_cdi)
{
pathTableData = ReadSingleExtent(0, fsvd.Value.path_table_size, fsvd.Value.path_table_addr);
2019-07-29 02:45:46 +01:00
fsFormat = "CD-i";
pathTableMsbLocation = fsvd.Value.path_table_addr;
// TODO: Until escape sequences are implemented this is the default CD-i encoding.
Encoding = Encoding.GetEncoding("iso8859-1");
}
2019-07-29 02:45:46 +01:00
else
{
pathTableData =
ReadSingleExtent(0, pvd.Value.path_table_size, Swapping.Swap(pvd.Value.type_m_path_table));
2019-07-29 02:45:46 +01:00
fsFormat = "ISO9660";
pathTableMsbLocation = pvd.Value.type_m_path_table;
pathTableLsbLocation = pvd.Value.type_l_path_table;
2019-07-29 02:45:46 +01:00
}
2020-07-20 21:11:32 +01:00
_pathTable = _highSierra ? DecodeHighSierraPathTable(pathTableData) : DecodePathTable(pathTableData);
// High Sierra and CD-i do not support Joliet or RRIP
2020-07-20 21:11:32 +01:00
if((_highSierra || _cdi) &&
_namespace != Namespace.Normal &&
_namespace != Namespace.Vms)
_namespace = Namespace.Normal;
if(jolietvd is null &&
2020-07-20 21:11:32 +01:00
_namespace == Namespace.Joliet)
_namespace = Namespace.Normal;
2019-07-31 19:53:47 +01:00
uint rootLocation;
uint rootSize;
byte rootXattrLength = 0;
2020-07-20 21:11:32 +01:00
if(!_cdi)
{
2020-07-20 21:11:32 +01:00
rootLocation = _highSierra ? hsvd.Value.root_directory_record.extent
: pvd.Value.root_directory_record.extent;
2020-07-20 21:11:32 +01:00
rootXattrLength = _highSierra ? hsvd.Value.root_directory_record.xattr_len
: pvd.Value.root_directory_record.xattr_len;
2020-07-22 13:20:25 +01:00
rootSize = _highSierra ? hsvd.Value.root_directory_record.size : pvd.Value.root_directory_record.size;
if(pathTableData.Length > 1 &&
2020-07-20 21:11:32 +01:00
rootLocation != _pathTable[0].Extent)
{
AaruConsole.DebugWriteLine("ISO9660 plugin",
"Path table and PVD do not point to the same location for the root directory!");
byte[] firstRootSector = ReadSector(rootLocation);
bool pvdWrongRoot = false;
2020-07-20 21:11:32 +01:00
if(_highSierra)
{
HighSierraDirectoryRecord rootEntry =
Marshal.ByteArrayToStructureLittleEndian<HighSierraDirectoryRecord>(firstRootSector);
if(rootEntry.extent != rootLocation)
pvdWrongRoot = true;
}
else
{
DirectoryRecord rootEntry =
Marshal.ByteArrayToStructureLittleEndian<DirectoryRecord>(firstRootSector);
if(rootEntry.extent != rootLocation)
pvdWrongRoot = true;
}
if(pvdWrongRoot)
{
AaruConsole.DebugWriteLine("ISO9660 plugin",
"PVD does not point to correct root directory, checking path table...");
bool pathTableWrongRoot = false;
2020-07-20 21:11:32 +01:00
rootLocation = _pathTable[0].Extent;
2020-07-20 21:11:32 +01:00
firstRootSector = ReadSector(_pathTable[0].Extent);
2020-07-20 21:11:32 +01:00
if(_highSierra)
{
HighSierraDirectoryRecord rootEntry =
Marshal.ByteArrayToStructureLittleEndian<HighSierraDirectoryRecord>(firstRootSector);
if(rootEntry.extent != rootLocation)
pathTableWrongRoot = true;
}
else
{
DirectoryRecord rootEntry =
Marshal.ByteArrayToStructureLittleEndian<DirectoryRecord>(firstRootSector);
if(rootEntry.extent != rootLocation)
pathTableWrongRoot = true;
}
if(pathTableWrongRoot)
{
AaruConsole.ErrorWriteLine("Cannot find root directory...");
return Errno.InvalidArgument;
}
2020-07-20 21:11:32 +01:00
_usePathTable = true;
}
}
}
2019-07-29 02:45:46 +01:00
else
{
2020-07-20 21:11:32 +01:00
rootLocation = _pathTable[0].Extent;
2019-07-29 02:45:46 +01:00
byte[] firstRootSector = ReadSector(rootLocation);
2019-07-29 02:45:46 +01:00
CdiDirectoryRecord rootEntry =
Marshal.ByteArrayToStructureBigEndian<CdiDirectoryRecord>(firstRootSector);
rootSize = rootEntry.size;
2020-07-20 21:11:32 +01:00
_usePathTable = _usePathTable || _pathTable.Length == 1;
_useTransTbl = false;
2019-07-29 02:45:46 +01:00
}
2019-07-31 17:44:51 +01:00
// In case the path table is incomplete
2020-07-20 21:11:32 +01:00
if(_usePathTable && pathTableData.Length == 1)
_usePathTable = false;
2019-07-31 17:44:51 +01:00
2020-07-20 21:11:32 +01:00
if(_usePathTable && !_cdi)
{
2020-07-20 21:11:32 +01:00
rootLocation = _pathTable[0].Extent;
byte[] firstRootSector = ReadSector(rootLocation);
2020-07-20 21:11:32 +01:00
if(_highSierra)
{
HighSierraDirectoryRecord rootEntry =
Marshal.ByteArrayToStructureLittleEndian<HighSierraDirectoryRecord>(firstRootSector);
rootSize = rootEntry.size;
}
else
{
DirectoryRecord rootEntry =
Marshal.ByteArrayToStructureLittleEndian<DirectoryRecord>(firstRootSector);
rootSize = rootEntry.size;
}
2020-07-20 21:11:32 +01:00
rootXattrLength = _pathTable[0].XattrLength;
}
try
{
2020-07-20 07:47:12 +01:00
_ = ReadSingleExtent(0, rootSize, rootLocation);
}
catch
{
return Errno.InvalidArgument;
}
byte[] ipbinSector = ReadSector(partition.Start);
CD.IPBin? segaCd = CD.DecodeIPBin(ipbinSector);
Saturn.IPBin? saturn = Saturn.DecodeIPBin(ipbinSector);
Dreamcast.IPBin? dreamcast = Dreamcast.DecodeIPBin(ipbinSector);
2020-07-20 21:11:32 +01:00
if(_namespace == Namespace.Joliet ||
_namespace == Namespace.Rrip)
2019-07-31 01:02:56 +01:00
{
2020-07-20 21:11:32 +01:00
_usePathTable = false;
_useTransTbl = false;
2019-07-31 01:02:56 +01:00
}
// Cannot traverse path table if we substitute the names for the ones in TRANS.TBL
2020-07-20 21:11:32 +01:00
if(_useTransTbl)
_usePathTable = false;
2020-07-20 21:11:32 +01:00
if(_namespace != Namespace.Joliet)
_rootDirectoryCache = _cdi
? DecodeCdiDirectory(rootLocation, rootSize, rootXattrLength)
: _highSierra
? DecodeHighSierraDirectory(rootLocation, rootSize, rootXattrLength)
: DecodeIsoDirectory(rootLocation, rootSize, rootXattrLength);
XmlFsType.Type = fsFormat;
if(jolietvd != null &&
2020-07-20 21:11:32 +01:00
(_namespace == Namespace.Joliet || _namespace == Namespace.Rrip))
{
rootLocation = jolietvd.Value.root_directory_record.extent;
rootXattrLength = jolietvd.Value.root_directory_record.xattr_len;
2019-07-22 02:42:17 +01:00
rootSize = jolietvd.Value.root_directory_record.size;
2019-07-22 02:42:17 +01:00
2020-07-20 21:11:32 +01:00
_joliet = true;
2019-07-22 02:58:56 +01:00
2020-07-20 21:11:32 +01:00
_rootDirectoryCache = DecodeIsoDirectory(rootLocation, rootSize, rootXattrLength);
2019-07-22 02:42:17 +01:00
XmlFsType.VolumeName = decodedJolietVd.VolumeIdentifier;
if(string.IsNullOrEmpty(decodedJolietVd.SystemIdentifier) ||
decodedVd.SystemIdentifier.Length > decodedJolietVd.SystemIdentifier.Length)
XmlFsType.SystemIdentifier = decodedVd.SystemIdentifier;
else
XmlFsType.SystemIdentifier = string.IsNullOrEmpty(decodedJolietVd.SystemIdentifier) ? null
: decodedJolietVd.SystemIdentifier;
if(string.IsNullOrEmpty(decodedJolietVd.VolumeSetIdentifier) ||
decodedVd.VolumeSetIdentifier.Length > decodedJolietVd.VolumeSetIdentifier.Length)
XmlFsType.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier;
else
XmlFsType.VolumeSetIdentifier = string.IsNullOrEmpty(decodedJolietVd.VolumeSetIdentifier) ? null
: decodedJolietVd.VolumeSetIdentifier;
if(string.IsNullOrEmpty(decodedJolietVd.PublisherIdentifier) ||
decodedVd.PublisherIdentifier.Length > decodedJolietVd.PublisherIdentifier.Length)
XmlFsType.PublisherIdentifier = decodedVd.PublisherIdentifier;
else
XmlFsType.PublisherIdentifier = string.IsNullOrEmpty(decodedJolietVd.PublisherIdentifier) ? null
: decodedJolietVd.PublisherIdentifier;
if(string.IsNullOrEmpty(decodedJolietVd.DataPreparerIdentifier) ||
decodedVd.DataPreparerIdentifier.Length > decodedJolietVd.DataPreparerIdentifier.Length)
XmlFsType.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier;
else
XmlFsType.DataPreparerIdentifier = string.IsNullOrEmpty(decodedJolietVd.DataPreparerIdentifier)
? null : decodedJolietVd.DataPreparerIdentifier;
if(string.IsNullOrEmpty(decodedJolietVd.ApplicationIdentifier) ||
decodedVd.ApplicationIdentifier.Length > decodedJolietVd.ApplicationIdentifier.Length)
XmlFsType.ApplicationIdentifier = decodedVd.ApplicationIdentifier;
else
XmlFsType.ApplicationIdentifier = string.IsNullOrEmpty(decodedJolietVd.ApplicationIdentifier) ? null
: decodedJolietVd.ApplicationIdentifier;
XmlFsType.CreationDate = decodedJolietVd.CreationTime;
XmlFsType.CreationDateSpecified = true;
if(decodedJolietVd.HasModificationTime)
{
XmlFsType.ModificationDate = decodedJolietVd.ModificationTime;
XmlFsType.ModificationDateSpecified = true;
}
if(decodedJolietVd.HasExpirationTime)
{
XmlFsType.ExpirationDate = decodedJolietVd.ExpirationTime;
XmlFsType.ExpirationDateSpecified = true;
}
if(decodedJolietVd.HasEffectiveTime)
{
XmlFsType.EffectiveDate = decodedJolietVd.EffectiveTime;
XmlFsType.EffectiveDateSpecified = true;
}
decodedVd = decodedJolietVd;
}
else
{
XmlFsType.SystemIdentifier = decodedVd.SystemIdentifier;
XmlFsType.VolumeName = decodedVd.VolumeIdentifier;
XmlFsType.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier;
XmlFsType.PublisherIdentifier = decodedVd.PublisherIdentifier;
XmlFsType.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier;
XmlFsType.ApplicationIdentifier = decodedVd.ApplicationIdentifier;
XmlFsType.CreationDate = decodedVd.CreationTime;
XmlFsType.CreationDateSpecified = true;
if(decodedVd.HasModificationTime)
{
XmlFsType.ModificationDate = decodedVd.ModificationTime;
XmlFsType.ModificationDateSpecified = true;
}
if(decodedVd.HasExpirationTime)
{
XmlFsType.ExpirationDate = decodedVd.ExpirationTime;
XmlFsType.ExpirationDateSpecified = true;
}
if(decodedVd.HasEffectiveTime)
{
XmlFsType.EffectiveDate = decodedVd.EffectiveTime;
XmlFsType.EffectiveDateSpecified = true;
}
}
2020-07-20 21:11:32 +01:00
if(_debug)
{
2020-07-20 21:11:32 +01:00
_rootDirectoryCache.Add("$", new DecodedDirectoryEntry
{
Extents = new List<(uint extent, uint size)>
{
(rootLocation, rootSize)
},
2020-07-20 04:34:16 +01:00
Filename = "$",
Size = rootSize,
Timestamp = decodedVd.CreationTime
});
2020-07-20 21:11:32 +01:00
if(!_cdi)
_rootDirectoryCache.Add("$PATH_TABLE.LSB", new DecodedDirectoryEntry
{
Extents = new List<(uint extent, uint size)>
{
(pathTableLsbLocation, (uint)pathTableData.Length)
},
2020-07-20 04:34:16 +01:00
Filename = "$PATH_TABLE.LSB",
Size = (uint)pathTableData.Length,
Timestamp = decodedVd.CreationTime
});
2020-07-20 21:11:32 +01:00
_rootDirectoryCache.Add("$PATH_TABLE.MSB", new DecodedDirectoryEntry
{
Extents = new List<(uint extent, uint size)>
{
(Swapping.Swap(pathTableMsbLocation), (uint)pathTableData.Length)
},
2020-07-20 04:34:16 +01:00
Filename = "$PATH_TABLE.MSB",
Size = (uint)pathTableData.Length,
Timestamp = decodedVd.CreationTime
});
for(int i = 0; i < bvdSectors.Count; i++)
2020-07-20 21:11:32 +01:00
_rootDirectoryCache.Add(i == 0 ? "$BOOT" : $"$BOOT_{i}", new DecodedDirectoryEntry
{
Extents = new List<(uint extent, uint size)>
{
((uint)i, 2048)
},
2020-07-20 04:34:16 +01:00
Filename = i == 0 ? "$BOOT" : $"$BOOT_{i}",
Size = 2048,
Timestamp = decodedVd.CreationTime
});
for(int i = 0; i < pvdSectors.Count; i++)
2020-07-20 21:11:32 +01:00
_rootDirectoryCache.Add(i == 0 ? "$PVD" : $"$PVD{i}", new DecodedDirectoryEntry
{
Extents = new List<(uint extent, uint size)>
{
((uint)i, 2048)
},
2020-07-20 04:34:16 +01:00
Filename = i == 0 ? "$PVD" : $"PVD_{i}",
Size = 2048,
Timestamp = decodedVd.CreationTime
});
for(int i = 0; i < svdSectors.Count; i++)
2020-07-20 21:11:32 +01:00
_rootDirectoryCache.Add(i == 0 ? "$SVD" : $"$SVD_{i}", new DecodedDirectoryEntry
{
Extents = new List<(uint extent, uint size)>
{
((uint)i, 2048)
},
2020-07-20 04:34:16 +01:00
Filename = i == 0 ? "$SVD" : $"$SVD_{i}",
Size = 2048,
Timestamp = decodedVd.CreationTime
});
for(int i = 0; i < evdSectors.Count; i++)
2020-07-20 21:11:32 +01:00
_rootDirectoryCache.Add(i == 0 ? "$EVD" : $"$EVD_{i}", new DecodedDirectoryEntry
{
Extents = new List<(uint extent, uint size)>
{
((uint)i, 2048)
},
2020-07-20 04:34:16 +01:00
Filename = i == 0 ? "$EVD" : $"$EVD_{i}",
Size = 2048,
Timestamp = decodedVd.CreationTime
});
for(int i = 0; i < vpdSectors.Count; i++)
2020-07-20 21:11:32 +01:00
_rootDirectoryCache.Add(i == 0 ? "$VPD" : $"$VPD_{i}", new DecodedDirectoryEntry
{
Extents = new List<(uint extent, uint size)>
{
((uint)i, 2048)
},
2020-07-20 04:34:16 +01:00
Filename = i == 0 ? "$VPD" : $"$VPD_{i}",
Size = 2048,
Timestamp = decodedVd.CreationTime
});
if(segaCd != null)
2020-07-20 21:11:32 +01:00
_rootDirectoryCache.Add("$IP.BIN", new DecodedDirectoryEntry
{
Extents = new List<(uint extent, uint size)>
{
((uint)partition.Start, (uint)Marshal.SizeOf<CD.IPBin>())
},
2020-07-20 04:34:16 +01:00
Filename = "$IP.BIN",
Size = (uint)Marshal.SizeOf<CD.IPBin>(),
Timestamp = decodedVd.CreationTime
});
if(saturn != null)
2020-07-20 21:11:32 +01:00
_rootDirectoryCache.Add("$IP.BIN", new DecodedDirectoryEntry
{
Extents = new List<(uint extent, uint size)>
{
((uint)partition.Start, (uint)Marshal.SizeOf<Saturn.IPBin>())
},
2020-07-20 04:34:16 +01:00
Filename = "$IP.BIN",
Size = (uint)Marshal.SizeOf<Saturn.IPBin>(),
Timestamp = decodedVd.CreationTime
});
if(dreamcast != null)
2020-07-20 21:11:32 +01:00
_rootDirectoryCache.Add("$IP.BIN", new DecodedDirectoryEntry
{
Extents = new List<(uint extent, uint size)>
{
((uint)partition.Start, (uint)Marshal.SizeOf<Dreamcast.IPBin>())
},
2020-07-20 04:34:16 +01:00
Filename = "$IP.BIN",
Size = (uint)Marshal.SizeOf<Dreamcast.IPBin>(),
Timestamp = decodedVd.CreationTime
});
}
XmlFsType.Bootable |= bvd != null || segaCd != null || saturn != null || dreamcast != null;
XmlFsType.Clusters = decodedVd.Blocks;
XmlFsType.ClusterSize = decodedVd.BlockSize;
2020-07-20 21:11:32 +01:00
_statfs = new FileSystemInfo
2019-07-19 15:15:00 +01:00
{
2020-07-20 04:34:16 +01:00
Blocks = decodedVd.Blocks,
2020-07-20 21:11:32 +01:00
FilenameLength = (ushort)(jolietvd != null ? _namespace == Namespace.Joliet
2020-07-20 04:34:16 +01:00
? 110
: 255 : 255),
PluginId = Id,
Type = fsFormat
2019-07-19 15:15:00 +01:00
};
2020-07-20 21:11:32 +01:00
_directoryCache = new Dictionary<string, Dictionary<string, DecodedDirectoryEntry>>();
2020-07-20 21:11:32 +01:00
if(_usePathTable)
foreach(DecodedDirectoryEntry subDirectory in _cdi
? GetSubdirsFromCdiPathTable("")
2020-07-20 21:11:32 +01:00
: _highSierra
? GetSubdirsFromHighSierraPathTable("")
: GetSubdirsFromIsoPathTable(""))
2020-07-20 21:11:32 +01:00
_rootDirectoryCache[subDirectory.Filename] = subDirectory;
2020-07-20 21:11:32 +01:00
_mounted = true;
return Errno.NoError;
}
public Errno Unmount()
{
2020-07-20 21:11:32 +01:00
if(!_mounted)
return Errno.AccessDenied;
2020-07-20 21:11:32 +01:00
_rootDirectoryCache = null;
_directoryCache = null;
_mounted = false;
return Errno.NoError;
}
2019-07-19 15:15:00 +01:00
public Errno StatFs(out FileSystemInfo stat)
{
stat = null;
2020-07-20 21:11:32 +01:00
if(!_mounted)
return Errno.AccessDenied;
2019-07-19 15:15:00 +01:00
2020-07-20 21:11:32 +01:00
stat = _statfs.ShallowCopy();
2019-07-19 15:15:00 +01:00
return Errno.NoError;
}
}
}