* DiscImageChef/Main.cs:

* DiscImageChef/Options.cs:
	* DiscImageChef/DiscImageChef.csproj:
	* DiscImageChef/Commands/ExtractFiles.cs:
	  Added command to extract all files from a filesystem.

	* DiscImageChef.Filesystems/LisaFS/Consts.cs:
	  Corrected comments.
	Added ftype known values.

	* DiscImageChef.Filesystems/LisaFS/Dir.cs:
	  Changed field name.

	* DiscImageChef.Filesystems/LisaFS/Extent.cs:
	* DiscImageChef.Filesystems/LisaFS/Structs.cs:
	  Reverse engineered new fields from ExtentsFile

	* DiscImageChef.Filesystems/LisaFS/File.cs:
	  Added support for reading tags.
	Added flags and ftype fields from ExtentsFile.

	* DiscImageChef.Filesystems/LisaFS/Xattr.cs:
	  Changed how serial number is returned.
	Allow to get tags in debug mode as an xattr.

	* DiscImageChef.Filesystems/Structs.cs:
	  Added PIPE attribute.
This commit is contained in:
2016-07-27 02:35:29 +01:00
parent 6c50cccacd
commit f1d2130d80
11 changed files with 641 additions and 71 deletions

View File

@@ -44,20 +44,40 @@ namespace DiscImageChef.Filesystems.LisaFS
const byte LisaFSv1 = 0x0E;
const byte LisaFSv2 = 0x0F;
const byte LisaFSv3 = 0x11;
/// <summary>Maximum string size in LisaFS</summary>
const uint E_NAME = 32;
// Maximum string size in LisaFS
const UInt16 FILEID_FREE = 0x0000;
const UInt16 FILEID_BOOT = 0xAAAA;
const UInt16 FILEID_LOADER = 0xBBBB;
const UInt16 FILEID_MDDF = 0x0001;
const UInt16 FILEID_BITMAP = 0x0002;
const UInt16 FILEID_SRECORD = 0x0003;
/// <summary>"Catalog file"</summary>
const UInt16 FILEID_DIRECTORY = 0x0004;
const Int16 FILEID_BOOT_SIGNED = -21846;
const Int16 FILEID_LOADER_SIGNED = -17477;
// "Catalog file"
const UInt16 FILEID_ERASED = 0x7FFF;
const UInt16 FILEID_MAX = FILEID_ERASED;
enum FileType : byte
{
Undefined = 0,
MDDFile = 1,
RootCat = 2,
FreeList = 3,
BadBlocks = 4,
SysData = 5,
Spool = 6,
Exec = 7,
UserCat = 8,
Pipe = 9,
BootFile = 10,
SwapData = 11,
SwapCode = 12,
RamAP = 13,
UserFile = 14,
KilledObject = 15
}
}
}

View File

@@ -147,7 +147,7 @@ namespace DiscImageChef.Filesystems.LisaFS
entry.zero = BigEndianBitConverter.ToUInt16(buf, offset + 0x01);
entry.filename = new byte[E_NAME];
Array.Copy(buf, offset + 0x03, entry.filename, 0, E_NAME);
entry.padding = buf[offset + 0x23];
entry.terminator = buf[offset + 0x23];
entry.fileType = buf[offset + 0x24];
entry.unknown = buf[offset + 0x25];
entry.fileID = BigEndianBitConverter.ToInt16(buf, offset + 0x26);

View File

@@ -88,27 +88,43 @@ namespace DiscImageChef.Filesystems.LisaFS
file.filenameLen = sector[0];
file.filename = new byte[file.filenameLen];
Array.Copy(sector, 0x01, file.filename, 0, file.filenameLen);
file.timestamp = BigEndianBitConverter.ToUInt32(sector, 0x20);
file.unknown1 = new byte[3];
Array.Copy(sector, 0x24, file.unknown1, 0, 3);
file.serial = new byte[3];
Array.Copy(sector, 0x27, file.serial, 0, 3);
file.unknown2 = BigEndianBitConverter.ToUInt32(sector, 0x2A);
file.unknown1 = BigEndianBitConverter.ToUInt16(sector, 0x20);
file.file_uid = BigEndianBitConverter.ToUInt64(sector, 0x22);
file.unknown2 = sector[0x2A];
file.etype = sector[0x2B];
file.ftype = (FileType)sector[0x2C];
file.unknown3 = sector[0x2D];
file.dtc = BigEndianBitConverter.ToUInt32(sector, 0x2E);
file.dta = BigEndianBitConverter.ToUInt32(sector, 0x32);
file.dtm = BigEndianBitConverter.ToUInt32(sector, 0x36);
file.dtb = BigEndianBitConverter.ToUInt32(sector, 0x3A);
file.dts = BigEndianBitConverter.ToUInt32(sector, 0x3E);
file.unknown3 = new byte[32];
Array.Copy(sector, 0x42, file.unknown3, 0, 32);
file.flags = sector[0x62];
file.serial = BigEndianBitConverter.ToUInt32(sector, 0x42);
file.unknown4 = sector[0x46];
file.locked = sector[0x47];
file.protect = sector[0x48];
file.master = sector[0x49];
file.scavenged = sector[0x4A];
file.closed = sector[0x4B];
file.open = sector[0x4C];
file.unknown5 = new byte[11];
Array.Copy(sector, 0x4D, file.unknown5, 0, 11);
file.release = BigEndianBitConverter.ToUInt16(sector, 0x58);
file.build = BigEndianBitConverter.ToUInt16(sector, 0x5A);
file.compatibility = BigEndianBitConverter.ToUInt16(sector, 0x5C);
file.revision = BigEndianBitConverter.ToUInt16(sector, 0x5E);
file.unknown6 = BigEndianBitConverter.ToUInt16(sector, 0x60);
file.password_valid = sector[0x62];
file.password = new byte[8];
Array.Copy(sector, 0x63, file.password, 0, 8);
file.unknown4 = new byte[21];
Array.Copy(sector, 0x6B, file.unknown4, 0, 21);
file.unknown7 = new byte[3];
Array.Copy(sector, 0x6B, file.unknown7, 0, 3);
file.overhead = BigEndianBitConverter.ToUInt16(sector, 0x6E);
file.unknown8 = new byte[16];
Array.Copy(sector, 0x70, file.unknown8, 0, 16);
file.length = BigEndianBitConverter.ToInt32(sector, 0x80);
file.unknown5 = BigEndianBitConverter.ToInt32(sector, 0x84);
file.unknown6 = BigEndianBitConverter.ToInt16(sector, 0x17E);
file.unknown9 = BigEndianBitConverter.ToInt32(sector, 0x84);
file.unknown10 = BigEndianBitConverter.ToInt16(sector, 0x17E);
file.LisaInfo = new byte[128];
Array.Copy(sector, 0x180, file.LisaInfo, 0, 128);

View File

@@ -41,6 +41,7 @@ using DiscImageChef.ImagePlugins;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using DiscImageChef.Console;
using System.IO;
namespace DiscImageChef.Filesystems.LisaFS
{
@@ -143,16 +144,44 @@ namespace DiscImageChef.Filesystems.LisaFS
return error;
attributes = new FileAttributes();
// TODO: Subcatalogs
attributes = FileAttributes.File;
attributes |= FileAttributes.Extents;
if((extFile.flags & 0x08) == 0x08)
switch(extFile.ftype)
{
case FileType.Spool:
attributes |= FileAttributes.CharDevice;
break;
case FileType.UserCat:
case FileType.RootCat:
attributes |= FileAttributes.Directory;
break;
case FileType.Pipe:
attributes |= FileAttributes.Pipe;
break;
case FileType.Undefined:
break;
default:
attributes |= FileAttributes.File;
// Subcatalogs use extents?
attributes |= FileAttributes.Extents;
break;
}
if(extFile.protect > 0)
attributes |= FileAttributes.Immutable;
if(extFile.locked > 0)
attributes |= FileAttributes.ReadOnly;
if(extFile.password_valid > 0)
attributes |= FileAttributes.Password;
return Errno.NoError;
}
Errno ReadSystemFile(Int16 fileId, out byte[] buf)
{
return ReadSystemFile(fileId, out buf, false);
}
Errno ReadSystemFile(Int16 fileId, out byte[] buf, bool tags)
{
buf = null;
if(!mounted || !debug)
@@ -164,7 +193,7 @@ namespace DiscImageChef.Filesystems.LisaFS
return Errno.InvalidArgument;
}
if(systemFileCache.TryGetValue(fileId, out buf))
if(systemFileCache.TryGetValue(fileId, out buf) && !tags)
return Errno.NoError;
int count = 0;
@@ -182,7 +211,10 @@ namespace DiscImageChef.Filesystems.LisaFS
if(count == 0)
return Errno.NoSuchFile;
buf = new byte[count * device.GetSectorSize()];
if(!tags)
buf = new byte[count * device.GetSectorSize()];
else
buf = new byte[count * 12];
// Should be enough to check 100 sectors?
for(ulong i = 0; i < 100; i++)
@@ -193,12 +225,20 @@ namespace DiscImageChef.Filesystems.LisaFS
if(id == fileId)
{
UInt16 pos = BigEndianBitConverter.ToUInt16(tag, 0x06);
byte[] sector = device.ReadSector(i);
byte[] sector;
if(!tags)
sector = device.ReadSector(i);
else
sector = device.ReadSectorTag(i, SectorTagType.AppleSectorTag);
Array.Copy(sector, 0, buf, sector.Length * pos, sector.Length);
}
}
systemFileCache.Add(fileId, buf);
if(!tags)
systemFileCache.Add(fileId, buf);
return Errno.NoError;
}
@@ -233,7 +273,6 @@ namespace DiscImageChef.Filesystems.LisaFS
stat.CreationTime = DateHandlers.LisaToDateTime(file.dtc);
stat.AccessTime = DateHandlers.LisaToDateTime(file.dta);
stat.StatusChangeTime = DateHandlers.LisaToDateTime(file.timestamp);
stat.BackupTime = DateHandlers.LisaToDateTime(file.dtb);
stat.LastWriteTime = DateHandlers.LisaToDateTime(file.dtm);
@@ -294,7 +333,6 @@ namespace DiscImageChef.Filesystems.LisaFS
stat.CreationTime = DateHandlers.LisaToDateTime(file.dtc);
stat.AccessTime = DateHandlers.LisaToDateTime(file.dta);
stat.StatusChangeTime = DateHandlers.LisaToDateTime(file.timestamp);
stat.BackupTime = DateHandlers.LisaToDateTime(file.dtb);
stat.LastWriteTime = DateHandlers.LisaToDateTime(file.dtm);
@@ -316,15 +354,22 @@ namespace DiscImageChef.Filesystems.LisaFS
}
Errno ReadFile(Int16 fileId, out byte[] buf)
{
return ReadFile(fileId, out buf, false);
}
Errno ReadFile(Int16 fileId, out byte[] buf, bool tags)
{
buf = null;
if(!mounted)
return Errno.AccessDenied;
tags &= debug;
if(fileId <= 4)
return Errno.InvalidArgument;
if(fileCache.TryGetValue(fileId, out buf))
if(!tags && fileCache.TryGetValue(fileId, out buf))
return Errno.NoError;
Errno error;
@@ -334,27 +379,44 @@ namespace DiscImageChef.Filesystems.LisaFS
if(error != Errno.NoError)
return error;
byte[] temp = new byte[file.length * (int)device.GetSectors()];
int sectorSize;
if(tags)
sectorSize = 12;
else
sectorSize = (int)device.GetSectorSize();
byte[] temp = new byte[file.length * sectorSize];
int offset = 0;
for(int i = 0; i < file.extents.Length; i++)
{
byte[] sector = device.ReadSectors((ulong)(file.extents[i].start + mddf.mddf_block), (uint)file.extents[i].length);
byte[] sector;
if(!tags)
sector = device.ReadSectors((ulong)(file.extents[i].start + mddf.mddf_block), (uint)file.extents[i].length);
else
sector = device.ReadSectorsTag((ulong)(file.extents[i].start + mddf.mddf_block), (uint)file.extents[i].length, SectorTagType.AppleSectorTag);
Array.Copy(sector, 0, temp, offset, sector.Length);
offset += sector.Length;
}
int realSize;
if(fileSizeCache.TryGetValue(fileId, out realSize))
if(!tags)
{
buf = new byte[realSize];
Array.Copy(temp, 0, buf, 0, realSize);
int realSize;
if(fileSizeCache.TryGetValue(fileId, out realSize))
{
buf = new byte[realSize];
Array.Copy(temp, 0, buf, 0, realSize);
}
else
buf = temp;
fileCache.Add(fileId, buf);
}
else
buf = temp;
fileCache.Add(fileId, buf);
return Errno.NoError;
}

View File

@@ -229,8 +229,8 @@ namespace DiscImageChef.Filesystems.LisaFS
public ushort zero;
/// <summary>0x03, filename, 32-bytes, null-padded</summary>
public byte[] filename;
/// <summary>0x23, seems to be always zero</summary>
public byte padding;
/// <summary>0x23, null-termination</summary>
public byte terminator;
/// <summary>
/// At 0x24
/// 0x03 here for entries 64 bytes long
@@ -267,14 +267,18 @@ namespace DiscImageChef.Filesystems.LisaFS
public byte filenameLen;
/// <summary>0x01, filename</summary>
public byte[] filename;
/// <summary>0x20, unknown timestamp</summary>
public UInt32 timestamp;
/// <summary>0x24, 3 bytes, unknown</summary>
public byte[] unknown1;
/// <summary>0x27, 3 bytes, machine serial number</summary>
public byte[] serial;
/// <summary>0x2A, 4 bytes, unknown</summary>
public uint unknown2;
/// <summary>0x20, unknown</summary>
public ushort unknown1;
/// <summary>0x22, 8 bytes</summary>
public UInt64 file_uid;
/// <summary>0x2A, unknown</summary>
public byte unknown2;
/// <summary>0x2B, entry type? gets modified</summary>
public byte etype;
/// <summary>0x2C, file type</summary>
public FileType ftype;
/// <summary>0x2D, unknown</summary>
public byte unknown3;
/// <summary>0x2E, creation time</summary>
public UInt32 dtc;
/// <summary>0x32, last access time</summary>
@@ -285,22 +289,52 @@ namespace DiscImageChef.Filesystems.LisaFS
public UInt32 dtb;
/// <summary>0x3E, scavenge time</summary>
public UInt32 dts;
/// <summary>0x42, unknown, 32 bytes</summary>
public byte[] unknown3;
/// <summary>0x62, flags?, 0x08 set if password is valid</summary>
public byte flags;
/// <summary>0x42, machine serial number</summary>
public UInt32 serial;
/// <summary>0x46, unknown</summary>
public byte unknown4;
/// <summary>0x47, locked file</summary>
public byte locked;
/// <summary>0x48, protected file</summary>
public byte protect;
/// <summary>0x49, master file</summary>
public byte master;
/// <summary>0x4A, scavenged file</summary>
public byte scavenged;
/// <summary>0x4B, file closed by os</summary>
public byte closed;
/// <summary>0x4C, file left open</summary>
public byte open;
/// <summary>0x4D, 11 bytes, unknown</summary>
public byte[] unknown5;
/// <summary>0x58, Release number</summary>
public UInt16 release;
/// <summary>0x5A, Build number</summary>
public UInt16 build;
/// <summary>0x5C, Compatibility level</summary>
public UInt16 compatibility;
/// <summary>0x5E, Revision level</summary>
public UInt16 revision;
/// <summary>0x60, unknown</summary>
public ushort unknown6;
/// <summary>0x62, 0x08 set if password is valid</summary>
public byte password_valid;
/// <summary>0x63, 8 bytes, scrambled password</summary>
public byte[] password;
/// <summary>0x6B, 21 bytes, unknown</summary>
public byte[] unknown4;
/// <summary>0x6B, 3 bytes, unknown</summary>
public byte[] unknown7;
/// <summary>0x6E, filesystem overhead</summary>
public ushort overhead;
/// <summary>0x70, 16 bytes, unknown</summary>
public byte[] unknown8;
/// <summary>0x80, file length in blocks</summary>
public Int32 length;
/// <summary>0x84, unknown</summary>
public Int32 unknown5;
public Int32 unknown9;
/// <summary>0x88, extents, can contain up to 41 extents, dunno LisaOS maximum (never seen more than 3)</summary>
public Extent[] extents;
/// <summary>0x17E, unknown, empty, padding?</summary>
public short unknown6;
public short unknown10;
/// <summary>0x180, 128 bytes</summary>
public byte[] LisaInfo;
}

View File

@@ -38,6 +38,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
namespace DiscImageChef.Filesystems.LisaFS
{
@@ -79,29 +80,40 @@ namespace DiscImageChef.Filesystems.LisaFS
if(fileId == FILEID_MDDF)
xattrs.Add("com.apple.lisa.password");
}
else
{
return Errno.NoError;
ExtentFile file;
Errno error = ReadExtentsFile(fileId, out file);
if(error != Errno.NoError)
return error;
xattrs = new List<string>();
if(file.password_valid > 0)
xattrs.Add("com.apple.lisa.password");
xattrs.Add("com.apple.lisa.serial");
if(!ArrayHelpers.ArrayIsNullOrEmpty(file.LisaInfo))
xattrs.Add("com.apple.lisa.label");
}
ExtentFile file;
if(debug)
xattrs.Add("com.apple.lisa.tags");
Errno error = ReadExtentsFile(fileId, out file);
if(error != Errno.NoError)
return error;
xattrs = new List<string>();
if((file.flags & 0x08) == 0x08)
xattrs.Add("com.apple.lisa.password");
xattrs.Add("com.apple.lisa.serial");
if(!ArrayHelpers.ArrayIsNullOrEmpty(file.LisaInfo))
xattrs.Add("com.apple.lisa.label");
xattrs.Sort();
return Errno.NoError;
}
Errno GetXattr(Int16 fileId, string xattr, out byte[] buf)
{
return GetXattr(fileId, xattr, out buf, false);
}
Errno GetXattr(Int16 fileId, string xattr, out byte[] buf, bool tags)
{
buf = null;
@@ -122,6 +134,9 @@ namespace DiscImageChef.Filesystems.LisaFS
}
}
if(debug && xattr == "com.apple.lisa.tags")
return ReadSystemFile(fileId, out buf, true);
return Errno.NoSuchExtendedAttribute;
}
@@ -132,7 +147,7 @@ namespace DiscImageChef.Filesystems.LisaFS
if(error != Errno.NoError)
return error;
if(xattr == "com.apple.lisa.password" && (file.flags & 0x08) == 0x08)
if(xattr == "com.apple.lisa.password" && file.password_valid > 0)
{
buf = new byte[8];
Array.Copy(file.password, 0, buf, 0, 8);
@@ -141,8 +156,7 @@ namespace DiscImageChef.Filesystems.LisaFS
if(xattr == "com.apple.lisa.serial")
{
buf = new byte[3];
Array.Copy(file.serial, 0, buf, 0, 3);
buf = Encoding.ASCII.GetBytes(file.serial.ToString());
return Errno.NoError;
}
@@ -153,6 +167,9 @@ namespace DiscImageChef.Filesystems.LisaFS
return Errno.NoError;
}
if(debug && xattr == "com.apple.lisa.tags")
return ReadFile(fileId, out buf, true);
return Errno.NoSuchExtendedAttribute;
}
}