Fix reading ISO9660, CD-i and HSF directories that span several sectors.

This commit is contained in:
2019-07-31 22:21:03 +01:00
parent d6da209fdc
commit 9aac84c702
2 changed files with 198 additions and 192 deletions

View File

@@ -94,35 +94,17 @@ namespace DiscImageChef.Filesystems.ISO9660
if(entry.Value.Extents.Count == 0) return Errno.InvalidArgument;
byte[] directoryBuffer;
if(entry.Value.Extents.Count == 1)
{
uint dirSizeInSectors = entry.Value.Extents[0].size / 2048;
if(entry.Value.Size % 2048 > 0) dirSizeInSectors++;
directoryBuffer = ReadSectors(entry.Value.Extents[0].extent, dirSizeInSectors);
}
else
{
MemoryStream ms = new MemoryStream();
foreach((uint extent, uint size) extent in entry.Value.Extents)
{
uint extentSizeInSectors = extent.size / 2048;
if(extent.size % 2048 > 0) extentSizeInSectors++;
byte[] extentData = ReadSectors(extent.extent, extentSizeInSectors);
ms.Write(extentData, 0, extentData.Length);
}
directoryBuffer = ms.ToArray();
}
currentDirectory = cdi
? DecodeCdiDirectory(directoryBuffer, entry.Value.XattrLength)
? DecodeCdiDirectory(entry.Value.Extents[0].extent, dirSizeInSectors,
entry.Value.XattrLength)
: highSierra
? DecodeHighSierraDirectory(directoryBuffer, entry.Value.XattrLength)
: DecodeIsoDirectory(directoryBuffer, entry.Value.XattrLength);
? DecodeHighSierraDirectory(entry.Value.Extents[0].extent, dirSizeInSectors,
entry.Value.XattrLength)
: DecodeIsoDirectory(entry.Value.Extents[0].extent, dirSizeInSectors,
entry.Value.XattrLength);
if(usePathTable)
foreach(DecodedDirectoryEntry subDirectory in cdi
@@ -163,15 +145,20 @@ namespace DiscImageChef.Filesystems.ISO9660
return contents;
}
Dictionary<string, DecodedDirectoryEntry> DecodeCdiDirectory(byte[] data, byte xattrLength)
Dictionary<string, DecodedDirectoryEntry> DecodeCdiDirectory(ulong start, uint count, byte xattrLength)
{
Dictionary<string, DecodedDirectoryEntry> entries = new Dictionary<string, DecodedDirectoryEntry>();
int entryOff = xattrLength;
for(ulong sector = start; sector < start + count; sector++)
{
byte[] data = ReadSectors(sector, 1);
while(entryOff + CdiDirectoryRecordSize < data.Length)
{
CdiDirectoryRecord record =
Marshal.ByteArrayToStructureBigEndian<CdiDirectoryRecord>(data, entryOff, CdiDirectoryRecordSize);
Marshal.ByteArrayToStructureBigEndian<CdiDirectoryRecord>(data, entryOff,
CdiDirectoryRecordSize);
if(record.length == 0) break;
@@ -186,7 +173,8 @@ namespace DiscImageChef.Filesystems.ISO9660
DecodedDirectoryEntry entry = new DecodedDirectoryEntry
{
Size = record.size,
Filename = Encoding.GetString(data, entryOff + DirectoryRecordSize, record.name_len),
Filename =
Encoding.GetString(data, entryOff + DirectoryRecordSize, record.name_len),
VolumeSequenceNumber = record.volume_sequence_number,
Timestamp = DecodeHighSierraDateTime(record.date),
XattrLength = record.xattr_len
@@ -218,14 +206,21 @@ namespace DiscImageChef.Filesystems.ISO9660
entryOff += record.length;
}
entryOff = 0;
}
return entries;
}
Dictionary<string, DecodedDirectoryEntry> DecodeHighSierraDirectory(byte[] data, byte xattrLength)
Dictionary<string, DecodedDirectoryEntry> DecodeHighSierraDirectory(ulong start, uint count, byte xattrLength)
{
Dictionary<string, DecodedDirectoryEntry> entries = new Dictionary<string, DecodedDirectoryEntry>();
int entryOff = xattrLength;
for(ulong sector = start; sector < start + count; sector++)
{
byte[] data = ReadSectors(sector, 1);
while(entryOff + DirectoryRecordSize < data.Length)
{
HighSierraDirectoryRecord record =
@@ -248,12 +243,14 @@ namespace DiscImageChef.Filesystems.ISO9660
Flags = record.flags,
Interleave = record.interleave,
VolumeSequenceNumber = record.volume_sequence_number,
Filename = Encoding.GetString(data, entryOff + DirectoryRecordSize, record.name_len),
Filename =
Encoding.GetString(data, entryOff + DirectoryRecordSize, record.name_len),
Timestamp = DecodeHighSierraDateTime(record.date),
XattrLength = record.xattr_len
};
if(record.size != 0) entry.Extents = new List<(uint extent, uint size)> {(record.extent, record.size)};
if(record.size != 0)
entry.Extents = new List<(uint extent, uint size)> {(record.extent, record.size)};
if(entry.Flags.HasFlag(FileFlags.Directory) && usePathTable)
{
@@ -266,16 +263,23 @@ namespace DiscImageChef.Filesystems.ISO9660
entryOff += record.length;
}
entryOff = 0;
}
if(useTransTbl) DecodeTransTable(entries);
return entries;
}
Dictionary<string, DecodedDirectoryEntry> DecodeIsoDirectory(byte[] data, byte xattrLength)
Dictionary<string, DecodedDirectoryEntry> DecodeIsoDirectory(ulong start, uint count, byte xattrLength)
{
Dictionary<string, DecodedDirectoryEntry> entries = new Dictionary<string, DecodedDirectoryEntry>();
int entryOff = xattrLength;
for(ulong sector = start; sector < start + count; sector++)
{
byte[] data = ReadSectors(sector, 1);
while(entryOff + DirectoryRecordSize < data.Length)
{
DirectoryRecord record =
@@ -307,7 +311,8 @@ namespace DiscImageChef.Filesystems.ISO9660
XattrLength = record.xattr_len
};
if(record.size != 0) entry.Extents = new List<(uint extent, uint size)> {(record.extent, record.size)};
if(record.size != 0)
entry.Extents = new List<(uint extent, uint size)> {(record.extent, record.size)};
if(entry.Flags.HasFlag(FileFlags.Directory) && usePathTable)
{
@@ -401,6 +406,9 @@ namespace DiscImageChef.Filesystems.ISO9660
entryOff += record.length;
}
entryOff = 0;
}
if(useTransTbl) DecodeTransTable(entries);
// Relocated directories should be shown in correct place when using Rock Ridge namespace

View File

@@ -348,10 +348,10 @@ namespace DiscImageChef.Filesystems.ISO9660
if(this.@namespace != Namespace.Joliet)
rootDirectoryCache = cdi
? DecodeCdiDirectory(rootDir, rootXattrLength)
? DecodeCdiDirectory(rootLocation, rootSize, rootXattrLength)
: highSierra
? DecodeHighSierraDirectory(rootDir, rootXattrLength)
: DecodeIsoDirectory(rootDir, rootXattrLength);
? DecodeHighSierraDirectory(rootLocation, rootSize, rootXattrLength)
: DecodeIsoDirectory(rootLocation, rootSize, rootXattrLength);
XmlFsType.Type = fsFormat;
@@ -500,9 +500,7 @@ namespace DiscImageChef.Filesystems.ISO9660
joliet = true;
rootDir = ReadSectors(rootLocation, rootSize);
rootDirectoryCache = DecodeIsoDirectory(rootDir, rootXattrLength);
rootDirectoryCache = DecodeIsoDirectory(rootLocation, rootSize, rootXattrLength);
XmlFsType.VolumeName = decodedJolietVd.VolumeIdentifier;