mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Implement reading of ISO9660 root directory.
This commit is contained in:
@@ -71,6 +71,8 @@
|
||||
<Compile Include="FAT\Super.cs" />
|
||||
<Compile Include="FAT\Xattr.cs" />
|
||||
<Compile Include="HPOFS.cs" />
|
||||
<Compile Include="ISO9660\Consts\Internal.cs" />
|
||||
<Compile Include="ISO9660\Date.cs" />
|
||||
<Compile Include="ISO9660\Dir.cs" />
|
||||
<Compile Include="ISO9660\File.cs" />
|
||||
<Compile Include="ISO9660\Super.cs" />
|
||||
@@ -184,7 +186,7 @@
|
||||
<Compile Include="ISO9660\Structs\XA.cs" />
|
||||
<Compile Include="ISO9660\Structs\Ziso.cs" />
|
||||
<Compile Include="ISO9660\Structs\Joliet.cs" />
|
||||
<Compile Include="ISO9660\Structs\Common.cs" />
|
||||
<Compile Include="ISO9660\Structs\Internal.cs" />
|
||||
<Compile Include="ISO9660\Consts\ISO.cs" />
|
||||
<Compile Include="ISO9660\Consts\HighSierra.cs" />
|
||||
<Compile Include="ISO9660\Consts\XA.cs" />
|
||||
|
||||
53
DiscImageChef.Filesystems/ISO9660/Consts/Internal.cs
Normal file
53
DiscImageChef.Filesystems/ISO9660/Consts/Internal.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : AAIP.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : ISO9660 filesystem plugin.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// AAIP extensions constants and enumerations.
|
||||
//
|
||||
// --[ 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/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using DiscImageChef.Helpers;
|
||||
|
||||
namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
public partial class ISO9660
|
||||
{
|
||||
static readonly int DirectoryRecordSize = Marshal.SizeOf<DirectoryRecord>();
|
||||
|
||||
enum Namespace
|
||||
{
|
||||
Normal,
|
||||
Vms,
|
||||
Joliet,
|
||||
JolietNormal,
|
||||
Rrip,
|
||||
RripNormal,
|
||||
RripJoliet,
|
||||
RripJolietNormal
|
||||
}
|
||||
}
|
||||
}
|
||||
9
DiscImageChef.Filesystems/ISO9660/Date.cs
Normal file
9
DiscImageChef.Filesystems/ISO9660/Date.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
public partial class ISO9660
|
||||
{
|
||||
DateTime DecodeIsoDateTime(byte[] date) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Helpers;
|
||||
|
||||
namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
public partial class ISO9660
|
||||
{
|
||||
public Errno ReadDir(string path, out List<string> contents) => throw new NotImplementedException();
|
||||
|
||||
List<DecodedDirectoryEntry> DecodeCdiDirectory(byte[] data) => throw new NotImplementedException();
|
||||
|
||||
List<DecodedDirectoryEntry> DecodeHighSierraDirectory(byte[] data) => throw new NotImplementedException();
|
||||
|
||||
// TODO: Implement system area
|
||||
List<DecodedDirectoryEntry> DecodeIsoDirectory(byte[] data)
|
||||
{
|
||||
List<DecodedDirectoryEntry> entries = new List<DecodedDirectoryEntry>();
|
||||
int entryOff = 0;
|
||||
|
||||
while(entryOff + DirectoryRecordSize < data.Length)
|
||||
{
|
||||
DirectoryRecord record =
|
||||
Marshal.ByteArrayToStructureLittleEndian<DirectoryRecord>(data, entryOff,
|
||||
Marshal.SizeOf<DirectoryRecord>());
|
||||
|
||||
if(record.length == 0) break;
|
||||
|
||||
// Special entries for current and parent directories, skip them
|
||||
if(record.name_len == 1)
|
||||
if(data[entryOff + DirectoryRecordSize] == 0 || data[entryOff + DirectoryRecordSize] == 1)
|
||||
{
|
||||
entryOff += record.length;
|
||||
continue;
|
||||
}
|
||||
|
||||
DecodedDirectoryEntry entry = new DecodedDirectoryEntry();
|
||||
|
||||
entry.Extent = record.extent;
|
||||
entry.Size = record.size;
|
||||
entry.Flags = record.flags;
|
||||
entry.FileUnitSize = record.file_unit_size;
|
||||
entry.Interleave = record.interleave;
|
||||
entry.VolumeSequenceNumber = record.volume_sequence_number;
|
||||
entry.IsoFilename =
|
||||
Encoding.ASCII.GetString(data, entryOff + DirectoryRecordSize, record.name_len);
|
||||
entry.Timestamp = DecodeIsoDateTime(record.date);
|
||||
|
||||
// TODO: Multi-extent files
|
||||
if(entries.All(e => e.IsoFilename != entry.IsoFilename)) entries.Add(entry);
|
||||
|
||||
entryOff += record.length;
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,8 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
// This is coded following ECMA-119.
|
||||
public partial class ISO9660 : IReadOnlyFilesystem
|
||||
{
|
||||
Namespace @namespace;
|
||||
|
||||
public FileSystemType XmlFsType { get; private set; }
|
||||
public Encoding Encoding { get; private set; }
|
||||
public string Name => "ISO9660 Filesystem";
|
||||
@@ -57,7 +59,11 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
{"normal", "Primary Volume Descriptor, ignoring ;1 suffixes"},
|
||||
{"vms", "Primary Volume Descriptor, showing version suffixes"},
|
||||
{"joliet", "Joliet Volume Descriptor"},
|
||||
{"joliet+normal", "Joliet with fallback to normal"}
|
||||
{"joliet+normal", "Joliet with fallback to normal"},
|
||||
{"rrip", "Rock Ridge"},
|
||||
{"rrip+normal", "Rock Ridge with fallback to normal"},
|
||||
{"rrip+joliet", "Rock Ridge with fallback to Joliet"},
|
||||
{"rrip+joliet+normal", "Rock Ridge with fallback to Joliet and then to normal (default)"}
|
||||
};
|
||||
|
||||
public Errno ReadLink(string path, out string dest)
|
||||
|
||||
@@ -54,5 +54,19 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
public ushort BlockSize;
|
||||
public uint Blocks;
|
||||
}
|
||||
|
||||
struct DecodedDirectoryEntry
|
||||
{
|
||||
public uint Extent;
|
||||
public uint Size;
|
||||
public FileFlags Flags;
|
||||
public byte FileUnitSize;
|
||||
public byte Interleave;
|
||||
public ushort VolumeSequenceNumber;
|
||||
public string IsoFilename;
|
||||
public DateTime Timestamp;
|
||||
|
||||
public override string ToString() => IsoFilename;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,16 +4,342 @@ using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Decoders.Sega;
|
||||
using DiscImageChef.Helpers;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
public partial class ISO9660
|
||||
{
|
||||
public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
|
||||
Dictionary<string, string> options, string @namespace) =>
|
||||
throw new NotImplementedException();
|
||||
bool debug;
|
||||
IMediaImage image;
|
||||
bool mounted;
|
||||
List<DecodedDirectoryEntry> rootDirectory;
|
||||
|
||||
public Errno Unmount() => throw new NotImplementedException();
|
||||
public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
|
||||
Dictionary<string, string> options, string @namespace)
|
||||
{
|
||||
Encoding = encoding ?? Encoding.ASCII;
|
||||
byte[] vdMagic = new byte[5]; // Volume Descriptor magic "CD001"
|
||||
byte[] hsMagic = new byte[5]; // Volume Descriptor magic "CDROM"
|
||||
|
||||
if(options == null) options = GetDefaultOptions();
|
||||
if(options.TryGetValue("debug", out string debugString)) bool.TryParse(debugString, out debug);
|
||||
|
||||
// Default namespace
|
||||
if(@namespace is null) @namespace = "rrip+joliet+normal";
|
||||
|
||||
switch(@namespace.ToLowerInvariant())
|
||||
{
|
||||
case "normal":
|
||||
this.@namespace = Namespace.Normal;
|
||||
break;
|
||||
case "vms":
|
||||
this.@namespace = Namespace.Vms;
|
||||
break;
|
||||
case "joliet":
|
||||
this.@namespace = Namespace.Joliet;
|
||||
break;
|
||||
case "joliet+normal":
|
||||
this.@namespace = Namespace.JolietNormal;
|
||||
break;
|
||||
case "rrip":
|
||||
this.@namespace = Namespace.Rrip;
|
||||
break;
|
||||
case "rrip+normal":
|
||||
this.@namespace = Namespace.RripNormal;
|
||||
break;
|
||||
case "rrip+joliet":
|
||||
this.@namespace = Namespace.RripJoliet;
|
||||
break;
|
||||
case "rrip+joliet+normal":
|
||||
this.@namespace = Namespace.RripJolietNormal;
|
||||
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);
|
||||
bool highSierra = Encoding.GetString(hsMagic) == HIGH_SIERRA_MAGIC;
|
||||
int hsOff = 0;
|
||||
if(highSierra) hsOff = 8;
|
||||
bool cdi = false;
|
||||
|
||||
while(true)
|
||||
{
|
||||
DicConsole.DebugWriteLine("ISO9660 plugin", "Processing VD loop no. {0}", counter);
|
||||
// Seek to Volume Descriptor
|
||||
DicConsole.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.
|
||||
DicConsole.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;
|
||||
}
|
||||
|
||||
cdi |= Encoding.GetString(vdMagic) == CDI_MAGIC;
|
||||
|
||||
switch(vdType)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
bvd = Marshal.ByteArrayToStructureLittleEndian<BootRecord>(vdSector, hsOff, 2048 - hsOff);
|
||||
|
||||
// TODO: Add boot file to debug root directory
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 1:
|
||||
{
|
||||
if(highSierra)
|
||||
hsvd = Marshal
|
||||
.ByteArrayToStructureLittleEndian<HighSierraPrimaryVolumeDescriptor>(vdSector);
|
||||
else if(cdi)
|
||||
fsvd = Marshal.ByteArrayToStructureBigEndian<FileStructureVolumeDescriptor>(vdSector);
|
||||
else pvd = Marshal.ByteArrayToStructureLittleEndian<PrimaryVolumeDescriptor>(vdSector);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
PrimaryVolumeDescriptor svd =
|
||||
Marshal.ByteArrayToStructureLittleEndian<PrimaryVolumeDescriptor>(vdSector);
|
||||
|
||||
// Check if this is Joliet
|
||||
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
|
||||
DicConsole.WriteLine("ISO9660 plugin", "Found unknown supplementary volume descriptor");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
|
||||
DecodedVolumeDescriptor decodedVd;
|
||||
DecodedVolumeDescriptor decodedJolietVd = new DecodedVolumeDescriptor();
|
||||
|
||||
XmlFsType = new FileSystemType();
|
||||
|
||||
if(pvd == null && hsvd == null && fsvd == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("ERROR: Could not find primary volume descriptor");
|
||||
return Errno.InvalidArgument;
|
||||
}
|
||||
|
||||
if(highSierra) decodedVd = DecodeVolumeDescriptor(hsvd.Value);
|
||||
else if(cdi) decodedVd = DecodeVolumeDescriptor(fsvd.Value);
|
||||
else decodedVd = DecodeVolumeDescriptor(pvd.Value);
|
||||
|
||||
if(jolietvd != null) decodedJolietVd = DecodeJolietDescriptor(jolietvd.Value);
|
||||
|
||||
string fsFormat;
|
||||
if(highSierra) fsFormat = "High Sierra Format";
|
||||
else if(cdi)
|
||||
{
|
||||
fsFormat = "CD-i";
|
||||
// TODO: Implement CD-i
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
else fsFormat = "ISO9660";
|
||||
|
||||
uint rootLocation = 0;
|
||||
uint rootSize = 0;
|
||||
|
||||
// TODO: Read CD-i root directory
|
||||
if(!cdi)
|
||||
{
|
||||
rootLocation = highSierra
|
||||
? hsvd.Value.root_directory_record.extent
|
||||
: pvd.Value.root_directory_record.extent;
|
||||
|
||||
if(highSierra)
|
||||
{
|
||||
rootSize = hsvd.Value.root_directory_record.size / hsvd.Value.logical_block_size;
|
||||
if(hsvd.Value.root_directory_record.size % hsvd.Value.logical_block_size > 0) rootSize++;
|
||||
}
|
||||
else
|
||||
{
|
||||
rootSize = pvd.Value.root_directory_record.size / pvd.Value.logical_block_size;
|
||||
if(pvd.Value.root_directory_record.size % pvd.Value.logical_block_size > 0) rootSize++;
|
||||
}
|
||||
}
|
||||
|
||||
if(rootLocation + rootSize >= imagePlugin.Info.Sectors) return Errno.InvalidArgument;
|
||||
|
||||
byte[] rootDir = imagePlugin.ReadSectors(rootLocation, rootSize);
|
||||
|
||||
byte[] ipbinSector = imagePlugin.ReadSector(0 + partition.Start);
|
||||
CD.IPBin? segaCd = CD.DecodeIPBin(ipbinSector);
|
||||
Saturn.IPBin? saturn = Saturn.DecodeIPBin(ipbinSector);
|
||||
Dreamcast.IPBin? dreamcast = Dreamcast.DecodeIPBin(ipbinSector);
|
||||
|
||||
// TODO: Add IP.BIN to debug root directory
|
||||
// TODO: Add volume descriptors to debug root directory
|
||||
// TODO: Decode Joliet directory
|
||||
|
||||
rootDirectory = cdi
|
||||
? DecodeCdiDirectory(rootDir)
|
||||
: highSierra
|
||||
? DecodeHighSierraDirectory(rootDir)
|
||||
: DecodeIsoDirectory(rootDir);
|
||||
|
||||
XmlFsType.Type = fsFormat;
|
||||
|
||||
if(jolietvd != null && this.@namespace != Namespace.Normal &&
|
||||
this.@namespace != Namespace.Vms &&
|
||||
this.@namespace != Namespace.Rrip && this.@namespace != Namespace.RripNormal)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
XmlFsType.Bootable |= bvd != null || segaCd != null || saturn != null || dreamcast != null;
|
||||
XmlFsType.Clusters = decodedVd.Blocks;
|
||||
XmlFsType.ClusterSize = decodedVd.BlockSize;
|
||||
|
||||
image = imagePlugin;
|
||||
mounted = true;
|
||||
return Errno.NoError;
|
||||
}
|
||||
|
||||
public Errno Unmount()
|
||||
{
|
||||
if(!mounted) return Errno.AccessDenied;
|
||||
|
||||
rootDirectory = null;
|
||||
mounted = false;
|
||||
|
||||
return Errno.NoError;
|
||||
}
|
||||
|
||||
public Errno StatFs(out FileSystemInfo stat) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user