Implement path table traversal in ISO9660.

This commit is contained in:
2019-07-29 04:00:51 +01:00
parent 28ad9dac86
commit 93b5c483ec
4 changed files with 155 additions and 4 deletions

View File

@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ContentModelStore"> <component name="ContentModelStore">
<e p="$APPLICATION_CONFIG_DIR$/consoles/db" t="IncludeRecursive" />
<e p="$APPLICATION_CONFIG_DIR$/extensions" t="IncludeRecursive" />
<e p="$APPLICATION_PLUGINS_DIR$/puppet/lib/stubs" t="IncludeRecursive" /> <e p="$APPLICATION_PLUGINS_DIR$/puppet/lib/stubs" t="IncludeRecursive" />
<e p="$USER_HOME$/.Rider2019.1/system/extResources" t="IncludeRecursive" /> <e p="$USER_HOME$/.Rider2019.1/system/extResources" t="IncludeRecursive" />
<e p="$USER_HOME$/.Rider2019.1/system/resharper-host/local/Transient/ReSharperHost/v191/SolutionCaches/_DiscImageChef.-1491758497.00" t="ExcludeRecursive" /> <e p="$USER_HOME$/.Rider2019.1/system/resharper-host/local/Transient/ReSharperHost/v191/SolutionCaches/_DiscImageChef.-1491758497.00" t="ExcludeRecursive" />
<e p="$USER_HOME$/.config/git/ignore" t="IncludeRecursive" />
<e p="$USER_HOME$/.nuget/packages/sqlitepclraw.lib.e_sqlite3.linux/1.1.12/runtimes/linux-x64/native/libe_sqlite3.so" t="Include" /> <e p="$USER_HOME$/.nuget/packages/sqlitepclraw.lib.e_sqlite3.linux/1.1.12/runtimes/linux-x64/native/libe_sqlite3.so" t="Include" />
<e p="$PROJECT_DIR$" t="IncludeFlat"> <e p="$PROJECT_DIR$" t="IncludeFlat">
<e p=".git/info/exclude" t="IncludeRecursive" /> <e p=".git/info/exclude" t="IncludeRecursive" />
@@ -1312,6 +1311,7 @@
<e p="File.cs" t="Include" /> <e p="File.cs" t="Include" />
<e p="ISO9660.cs" t="Include" /> <e p="ISO9660.cs" t="Include" />
<e p="Info.cs" t="Include" /> <e p="Info.cs" t="Include" />
<e p="PathTable.cs" t="Include" />
<e p="Structs" t="Include"> <e p="Structs" t="Include">
<e p="Amiga.cs" t="Include" /> <e p="Amiga.cs" t="Include" />
<e p="Apple.cs" t="Include" /> <e p="Apple.cs" t="Include" />

View File

@@ -75,6 +75,14 @@ namespace DiscImageChef.Filesystems.ISO9660
? DecodeHighSierraDirectory(directoryBuffer) ? DecodeHighSierraDirectory(directoryBuffer)
: DecodeIsoDirectory(directoryBuffer); : DecodeIsoDirectory(directoryBuffer);
if(usePathTable)
foreach(DecodedDirectoryEntry subDirectory in cdi
? GetSubdirsFromCdiPathTable(currentPath)
: highSierra
? GetSubdirsFromHighSierraPathTable(currentPath)
: GetSubdirsFromIsoPathTable(currentPath))
currentDirectory[subDirectory.Filename] = subDirectory;
directoryCache.Add(currentPath, currentDirectory); directoryCache.Add(currentPath, currentDirectory);
} }
@@ -142,6 +150,12 @@ namespace DiscImageChef.Filesystems.ISO9660
Timestamp = DecodeHighSierraDateTime(record.date) Timestamp = DecodeHighSierraDateTime(record.date)
}; };
if(entry.Flags.HasFlag(FileFlags.Directory) && usePathTable)
{
entryOff += record.length;
continue;
}
if(!entries.ContainsKey(entry.Filename)) entries.Add(entry.Filename, entry); if(!entries.ContainsKey(entry.Filename)) entries.Add(entry.Filename, entry);
entryOff += record.length; entryOff += record.length;
@@ -187,6 +201,12 @@ namespace DiscImageChef.Filesystems.ISO9660
Timestamp = DecodeIsoDateTime(record.date) Timestamp = DecodeIsoDateTime(record.date)
}; };
if(entry.Flags.HasFlag(FileFlags.Directory) && usePathTable)
{
entryOff += record.length;
continue;
}
// TODO: XA // TODO: XA
int systemAreaStart = entryOff + record.name_len + Marshal.SizeOf<DirectoryRecord>(); int systemAreaStart = entryOff + record.name_len + Marshal.SizeOf<DirectoryRecord>();
int systemAreaLength = record.length - record.name_len - Marshal.SizeOf<DirectoryRecord>(); int systemAreaLength = record.length - record.name_len - Marshal.SizeOf<DirectoryRecord>();
@@ -700,5 +720,117 @@ namespace DiscImageChef.Filesystems.ISO9660
} }
} }
} }
PathTableEntryInternal[] GetPathTableEntries(string path)
{
IEnumerable<PathTableEntryInternal> tableEntries = new PathTableEntryInternal[0];
List<PathTableEntryInternal> pathTableList = new List<PathTableEntryInternal>(pathTable);
if(path == "" || path == "/") tableEntries = pathTable.Where(p => p.Parent == 1 && p != pathTable[0]);
else
{
string cutPath = path.StartsWith("/", StringComparison.Ordinal)
? path.Substring(1).ToLower(CultureInfo.CurrentUICulture)
: path.ToLower(CultureInfo.CurrentUICulture);
string[] pieces = cutPath.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
int currentParent = 1;
int currentPiece = 0;
while(currentPiece < pieces.Length)
{
PathTableEntryInternal currentEntry = pathTable.FirstOrDefault(p => p.Parent == currentParent &&
p.Name.ToLower(CultureInfo
.CurrentUICulture) ==
pieces[currentPiece]);
if(currentEntry is null) break;
currentPiece++;
currentParent = pathTableList.IndexOf(currentEntry) + 1;
}
tableEntries = pathTable.Where(p => p.Parent == currentParent);
}
return tableEntries.ToArray();
}
DecodedDirectoryEntry[] GetSubdirsFromCdiPathTable(string path) => throw new NotImplementedException();
DecodedDirectoryEntry[] GetSubdirsFromIsoPathTable(string path)
{
PathTableEntryInternal[] tableEntries = GetPathTableEntries(path);
List<DecodedDirectoryEntry> entries = new List<DecodedDirectoryEntry>();
foreach(PathTableEntryInternal tEntry in tableEntries)
{
byte[] sector = image.ReadSector(tEntry.Extent);
DirectoryRecord record =
Marshal.ByteArrayToStructureLittleEndian<DirectoryRecord>(sector, 0,
Marshal.SizeOf<DirectoryRecord>());
if(record.length == 0) break;
DecodedDirectoryEntry entry = new DecodedDirectoryEntry
{
Extent = record.size == 0 ? 0 : record.extent,
Size = record.size,
Flags = record.flags,
Filename = tEntry.Name,
FileUnitSize = record.file_unit_size,
Interleave = record.interleave,
VolumeSequenceNumber = record.volume_sequence_number,
Timestamp = DecodeIsoDateTime(record.date)
};
// TODO: XA
int systemAreaStart = record.name_len + Marshal.SizeOf<DirectoryRecord>();
int systemAreaLength = record.length - record.name_len - Marshal.SizeOf<DirectoryRecord>();
if(systemAreaStart % 2 != 0)
{
systemAreaStart++;
systemAreaLength--;
}
DecodeSystemArea(sector, systemAreaStart, systemAreaStart + systemAreaLength, ref entry, out _);
entries.Add(entry);
}
return entries.ToArray();
}
DecodedDirectoryEntry[] GetSubdirsFromHighSierraPathTable(string path)
{
PathTableEntryInternal[] tableEntries = GetPathTableEntries(path);
List<DecodedDirectoryEntry> entries = new List<DecodedDirectoryEntry>();
foreach(PathTableEntryInternal tEntry in tableEntries)
{
byte[] sector = image.ReadSector(tEntry.Extent);
HighSierraDirectoryRecord record =
Marshal.ByteArrayToStructureLittleEndian<HighSierraDirectoryRecord>(sector, 0,
Marshal
.SizeOf<
HighSierraDirectoryRecord
>());
DecodedDirectoryEntry entry = new DecodedDirectoryEntry
{
Extent = record.size == 0 ? 0 : record.extent,
Size = record.size,
Flags = record.flags,
Filename = tEntry.Name,
Interleave = record.interleave,
VolumeSequenceNumber = record.volume_sequence_number,
Timestamp = DecodeHighSierraDateTime(record.date)
};
entries.Add(entry);
}
return entries.ToArray();
}
} }
} }

View File

@@ -52,6 +52,7 @@ namespace DiscImageChef.Filesystems.ISO9660
PathTableEntryInternal[] pathTable; PathTableEntryInternal[] pathTable;
Dictionary<string, DecodedDirectoryEntry> rootDirectoryCache; Dictionary<string, DecodedDirectoryEntry> rootDirectoryCache;
FileSystemInfo statfs; FileSystemInfo statfs;
bool usePathTable;
public FileSystemType XmlFsType { get; private set; } public FileSystemType XmlFsType { get; private set; }
public Encoding Encoding { get; private set; } public Encoding Encoding { get; private set; }
@@ -60,7 +61,10 @@ namespace DiscImageChef.Filesystems.ISO9660
public string Author => "Natalia Portillo"; public string Author => "Natalia Portillo";
public IEnumerable<(string name, Type type, string description)> SupportedOptions => public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
new (string name, Type type, string description)[] { }; new (string name, Type type, string description)[]
{
("use_path_table", typeof(bool), "Use path table for directory traversal")
};
public Dictionary<string, string> Namespaces => public Dictionary<string, string> Namespaces =>
new Dictionary<string, string> new Dictionary<string, string>

View File

@@ -22,6 +22,8 @@ namespace DiscImageChef.Filesystems.ISO9660
if(options == null) options = GetDefaultOptions(); if(options == null) options = GetDefaultOptions();
if(options.TryGetValue("debug", out string debugString)) bool.TryParse(debugString, out debug); if(options.TryGetValue("debug", out string debugString)) bool.TryParse(debugString, out debug);
if(options.TryGetValue("use_path_table", out string usePathTableString))
bool.TryParse(usePathTableString, out usePathTable);
// Default namespace // Default namespace
if(@namespace is null) @namespace = "joliet"; if(@namespace is null) @namespace = "joliet";
@@ -234,6 +236,8 @@ namespace DiscImageChef.Filesystems.ISO9660
Marshal.ByteArrayToStructureBigEndian<CdiDirectoryRecord>(firstRootSector); Marshal.ByteArrayToStructureBigEndian<CdiDirectoryRecord>(firstRootSector);
rootSize = rootEntry.size / fsvd.Value.logical_block_size; rootSize = rootEntry.size / fsvd.Value.logical_block_size;
if(rootEntry.size % fsvd.Value.logical_block_size > 0) rootSize++; if(rootEntry.size % fsvd.Value.logical_block_size > 0) rootSize++;
usePathTable = true;
} }
if(rootLocation + rootSize >= imagePlugin.Info.Sectors) return Errno.InvalidArgument; if(rootLocation + rootSize >= imagePlugin.Info.Sectors) return Errno.InvalidArgument;
@@ -248,6 +252,8 @@ namespace DiscImageChef.Filesystems.ISO9660
// TODO: Add IP.BIN to debug root directory // TODO: Add IP.BIN to debug root directory
// TODO: Add volume descriptors to debug root directory // TODO: Add volume descriptors to debug root directory
if(this.@namespace == Namespace.Joliet || this.@namespace == Namespace.Rrip) usePathTable = false;
if(this.@namespace != Namespace.Joliet) if(this.@namespace != Namespace.Joliet)
rootDirectoryCache = cdi rootDirectoryCache = cdi
? DecodeCdiDirectory(rootDir) ? DecodeCdiDirectory(rootDir)
@@ -382,6 +388,15 @@ namespace DiscImageChef.Filesystems.ISO9660
directoryCache = new Dictionary<string, Dictionary<string, DecodedDirectoryEntry>>(); directoryCache = new Dictionary<string, Dictionary<string, DecodedDirectoryEntry>>();
image = imagePlugin; image = imagePlugin;
if(usePathTable)
foreach(DecodedDirectoryEntry subDirectory in cdi
? GetSubdirsFromCdiPathTable("")
: highSierra
? GetSubdirsFromHighSierraPathTable("")
: GetSubdirsFromIsoPathTable(""))
rootDirectoryCache[subDirectory.Filename] = subDirectory;
mounted = true; mounted = true;
return Errno.NoError; return Errno.NoError;