mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
829 lines
36 KiB
C#
829 lines
36 KiB
C#
// /***************************************************************************
|
|
// Aaru Data Preservation Suite
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// Filename : Info.cs
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
//
|
|
// Component : UNIX System V filesystem plugin.
|
|
//
|
|
// --[ 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-2025 Natalia Portillo
|
|
// ****************************************************************************/
|
|
|
|
// ReSharper disable NotAccessedField.Local
|
|
|
|
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Aaru.CommonTypes.AaruMetadata;
|
|
using Aaru.CommonTypes.Enums;
|
|
using Aaru.CommonTypes.Interfaces;
|
|
using Aaru.Helpers;
|
|
using Partition = Aaru.CommonTypes.Partition;
|
|
|
|
namespace Aaru.Filesystems;
|
|
|
|
// Information from the Linux kernel
|
|
/// <inheritdoc />
|
|
/// <summary>Implements detection of the UNIX System V filesystem</summary>
|
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
|
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
|
[SuppressMessage("ReSharper", "UnusedType.Local")]
|
|
public sealed partial class SysVfs
|
|
{
|
|
#region IFilesystem Members
|
|
|
|
/// <inheritdoc />
|
|
public bool Identify(IMediaImage imagePlugin, Partition partition)
|
|
{
|
|
if(2 + partition.Start >= partition.End) return false;
|
|
|
|
byte sb_size_in_sectors;
|
|
|
|
if(imagePlugin.Info.SectorSize <=
|
|
0x400) // Check if underlying device sector size is smaller than SuperBlock size
|
|
sb_size_in_sectors = (byte)(0x400 / imagePlugin.Info.SectorSize);
|
|
else
|
|
sb_size_in_sectors = 1; // If not a single sector can store it
|
|
|
|
if(partition.End <=
|
|
partition.Start +
|
|
4 * (ulong)sb_size_in_sectors +
|
|
sb_size_in_sectors) // Device must be bigger than SB location + SB size + offset
|
|
return false;
|
|
|
|
// Sectors in a cylinder
|
|
var spc = (int)(imagePlugin.Info.Heads * imagePlugin.Info.SectorsPerTrack);
|
|
|
|
// Superblock can start on 0x000, 0x200, 0x600 and 0x800, not aligned, so we assume 16 (128 bytes/sector) sectors as a safe value
|
|
int[] locations =
|
|
[
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
|
|
// Superblock can also skip one cylinder (for boot)
|
|
spc
|
|
];
|
|
|
|
foreach(int i in locations.TakeWhile(i => (ulong)i + partition.Start + sb_size_in_sectors <
|
|
imagePlugin.Info.Sectors))
|
|
{
|
|
ErrorNumber errno = imagePlugin.ReadSectors((ulong)i + partition.Start,
|
|
false,
|
|
sb_size_in_sectors,
|
|
out byte[] sb_sector,
|
|
out _);
|
|
|
|
if(errno != ErrorNumber.NoError || sb_sector.Length < 0x400) continue;
|
|
|
|
var magic = BitConverter.ToUInt32(sb_sector, 0x3F8);
|
|
|
|
if(magic is XENIX_MAGIC or XENIX_CIGAM or SYSV_MAGIC or SYSV_CIGAM) return true;
|
|
|
|
magic = BitConverter.ToUInt32(sb_sector, 0x1F8); // System V magic location
|
|
|
|
if(magic is SYSV_MAGIC or SYSV_CIGAM) return true;
|
|
|
|
magic = BitConverter.ToUInt32(sb_sector, 0x1F0); // XENIX 3 magic location
|
|
|
|
if(magic is XENIX_MAGIC or XENIX_CIGAM) return true;
|
|
|
|
var coherent_string = new byte[6];
|
|
Array.Copy(sb_sector, 0x1E4, coherent_string, 0, 6); // Coherent UNIX s_fname location
|
|
string s_fname = StringHandlers.CToString(coherent_string);
|
|
Array.Copy(sb_sector, 0x1EA, coherent_string, 0, 6); // Coherent UNIX s_fpack location
|
|
string s_fpack = StringHandlers.CToString(coherent_string);
|
|
|
|
if(s_fname == COH_FNAME && s_fpack == COH_FPACK ||
|
|
s_fname == COH_XXXXX && s_fpack == COH_XXXXX ||
|
|
s_fname == COH_XXXXS && s_fpack == COH_XXXXN)
|
|
return true;
|
|
|
|
// Now try to identify 7th edition
|
|
var s_fsize = BitConverter.ToUInt32(sb_sector, 0x002);
|
|
var s_nfree = BitConverter.ToUInt16(sb_sector, 0x006);
|
|
var s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0);
|
|
|
|
if(s_fsize is <= 0 or >= 0xFFFFFFFF || s_nfree is <= 0 or >= 0xFFFF || s_ninode is <= 0 or >= 0xFFFF)
|
|
continue;
|
|
|
|
if((s_fsize & 0xFF) == 0x00 && (s_nfree & 0xFF) == 0x00 && (s_ninode & 0xFF) == 0x00)
|
|
{
|
|
// Byteswap
|
|
s_fsize = ((s_fsize & 0xFF) << 24) +
|
|
((s_fsize & 0xFF00) << 8) +
|
|
((s_fsize & 0xFF0000) >> 8) +
|
|
((s_fsize & 0xFF000000) >> 24);
|
|
|
|
s_nfree = (ushort)(s_nfree >> 8);
|
|
s_ninode = (ushort)(s_ninode >> 8);
|
|
}
|
|
|
|
if((s_fsize & 0xFF000000) != 0x00 || (s_nfree & 0xFF00) != 0x00 || (s_ninode & 0xFF00) != 0x00) continue;
|
|
|
|
if(s_fsize >= V7_MAXSIZE || s_nfree >= V7_NICFREE || s_ninode >= V7_NICINOD) continue;
|
|
|
|
if(s_fsize * 1024 == (partition.End - partition.Start) * imagePlugin.Info.SectorSize ||
|
|
s_fsize * 512 == (partition.End - partition.Start) * imagePlugin.Info.SectorSize)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information,
|
|
out FileSystem metadata)
|
|
{
|
|
encoding ??= Encoding.GetEncoding("iso-8859-15");
|
|
information = "";
|
|
metadata = new FileSystem();
|
|
|
|
var sb = new StringBuilder();
|
|
var bigEndian = false; // Start in little endian until we know what are we handling here
|
|
var start = 0;
|
|
var xenix = false;
|
|
var sysv = false;
|
|
var sys7th = false;
|
|
var coherent = false;
|
|
var xenix3 = false;
|
|
byte[] sb_sector;
|
|
byte sb_size_in_sectors;
|
|
var offset = 0;
|
|
|
|
if(imagePlugin.Info.SectorSize <=
|
|
0x400) // Check if underlying device sector size is smaller than SuperBlock size
|
|
sb_size_in_sectors = (byte)(0x400 / imagePlugin.Info.SectorSize);
|
|
else
|
|
sb_size_in_sectors = 1; // If not a single sector can store it
|
|
|
|
// Sectors in a cylinder
|
|
var spc = (int)(imagePlugin.Info.Heads * imagePlugin.Info.SectorsPerTrack);
|
|
|
|
// Superblock can start on 0x000, 0x200, 0x600 and 0x800, not aligned, so we assume 16 (128 bytes/sector) sectors as a safe value
|
|
int[] locations =
|
|
[
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
|
|
// Superblock can also skip one cylinder (for boot)
|
|
spc
|
|
];
|
|
|
|
ErrorNumber errno;
|
|
|
|
foreach(int i in locations)
|
|
{
|
|
errno = imagePlugin.ReadSectors((ulong)i + partition.Start,
|
|
false,
|
|
sb_size_in_sectors,
|
|
out sb_sector,
|
|
out _);
|
|
|
|
if(errno != ErrorNumber.NoError) continue;
|
|
|
|
var magic = BitConverter.ToUInt32(sb_sector, 0x3F8);
|
|
|
|
if(magic is XENIX_MAGIC or SYSV_MAGIC)
|
|
{
|
|
if(magic == SYSV_MAGIC)
|
|
{
|
|
sysv = true;
|
|
offset = 0x200;
|
|
}
|
|
else
|
|
xenix = true;
|
|
|
|
start = i;
|
|
|
|
break;
|
|
}
|
|
|
|
if(magic is XENIX_CIGAM or SYSV_CIGAM)
|
|
{
|
|
bigEndian = true; // Big endian
|
|
|
|
if(magic == SYSV_CIGAM)
|
|
{
|
|
sysv = true;
|
|
offset = 0x200;
|
|
}
|
|
else
|
|
xenix = true;
|
|
|
|
start = i;
|
|
|
|
break;
|
|
}
|
|
|
|
magic = BitConverter.ToUInt32(sb_sector, 0x1F0); // XENIX 3 magic location
|
|
|
|
if(magic == XENIX_MAGIC)
|
|
{
|
|
xenix3 = true;
|
|
start = i;
|
|
|
|
break;
|
|
}
|
|
|
|
if(magic == XENIX_CIGAM)
|
|
{
|
|
bigEndian = true; // Big endian
|
|
xenix3 = true;
|
|
start = i;
|
|
|
|
break;
|
|
}
|
|
|
|
magic = BitConverter.ToUInt32(sb_sector, 0x1F8); // XENIX magic location
|
|
|
|
if(magic == SYSV_MAGIC)
|
|
{
|
|
sysv = true;
|
|
start = i;
|
|
|
|
break;
|
|
}
|
|
|
|
if(magic == SYSV_CIGAM)
|
|
{
|
|
bigEndian = true; // Big endian
|
|
sysv = true;
|
|
start = i;
|
|
|
|
break;
|
|
}
|
|
|
|
var coherent_string = new byte[6];
|
|
Array.Copy(sb_sector, 0x1E4, coherent_string, 0, 6); // Coherent UNIX s_fname location
|
|
string s_fname = StringHandlers.CToString(coherent_string, encoding);
|
|
Array.Copy(sb_sector, 0x1EA, coherent_string, 0, 6); // Coherent UNIX s_fpack location
|
|
string s_fpack = StringHandlers.CToString(coherent_string, encoding);
|
|
|
|
if(s_fname == COH_FNAME && s_fpack == COH_FPACK ||
|
|
s_fname == COH_XXXXX && s_fpack == COH_XXXXX ||
|
|
s_fname == COH_XXXXS && s_fpack == COH_XXXXN)
|
|
{
|
|
coherent = true;
|
|
start = i;
|
|
|
|
break;
|
|
}
|
|
|
|
// Now try to identify 7th edition
|
|
var s_fsize = BitConverter.ToUInt32(sb_sector, 0x002);
|
|
var s_nfree = BitConverter.ToUInt16(sb_sector, 0x006);
|
|
var s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0);
|
|
|
|
if(s_fsize is <= 0 or >= 0xFFFFFFFF || s_nfree is <= 0 or >= 0xFFFF || s_ninode is <= 0 or >= 0xFFFF)
|
|
continue;
|
|
|
|
if((s_fsize & 0xFF) == 0x00 && (s_nfree & 0xFF) == 0x00 && (s_ninode & 0xFF) == 0x00)
|
|
{
|
|
// Byteswap
|
|
s_fsize = ((s_fsize & 0xFF) << 24) +
|
|
((s_fsize & 0xFF00) << 8) +
|
|
((s_fsize & 0xFF0000) >> 8) +
|
|
((s_fsize & 0xFF000000) >> 24);
|
|
|
|
s_nfree = (ushort)(s_nfree >> 8);
|
|
s_ninode = (ushort)(s_ninode >> 8);
|
|
}
|
|
|
|
if((s_fsize & 0xFF000000) != 0x00 || (s_nfree & 0xFF00) != 0x00 || (s_ninode & 0xFF00) != 0x00) continue;
|
|
|
|
if(s_fsize >= V7_MAXSIZE || s_nfree >= V7_NICFREE || s_ninode >= V7_NICINOD) continue;
|
|
|
|
if(s_fsize * 1024 != (partition.End - partition.Start) * imagePlugin.Info.SectorSize &&
|
|
s_fsize * 512 != (partition.End - partition.Start) * imagePlugin.Info.SectorSize)
|
|
continue;
|
|
|
|
sys7th = true;
|
|
start = i;
|
|
|
|
break;
|
|
}
|
|
|
|
if(!sys7th && !sysv && !coherent && !xenix && !xenix3) return;
|
|
|
|
metadata = new FileSystem();
|
|
|
|
if(xenix || xenix3)
|
|
{
|
|
var xenix_strings = new byte[6];
|
|
var xnx_sb = new XenixSuperBlock();
|
|
|
|
errno = imagePlugin.ReadSectors((ulong)start + partition.Start,
|
|
false,
|
|
sb_size_in_sectors,
|
|
out sb_sector,
|
|
out _);
|
|
|
|
if(errno != ErrorNumber.NoError) return;
|
|
|
|
if(xenix3)
|
|
{
|
|
xnx_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000);
|
|
xnx_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002);
|
|
xnx_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006);
|
|
xnx_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0);
|
|
xnx_sb.s_flock = sb_sector[0x19A];
|
|
xnx_sb.s_ilock = sb_sector[0x19B];
|
|
xnx_sb.s_fmod = sb_sector[0x19C];
|
|
xnx_sb.s_ronly = sb_sector[0x19D];
|
|
xnx_sb.s_time = BitConverter.ToInt32(sb_sector, 0x19E);
|
|
xnx_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x1A2);
|
|
xnx_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1A6);
|
|
xnx_sb.s_cylblks = BitConverter.ToUInt16(sb_sector, 0x1A8);
|
|
xnx_sb.s_gapblks = BitConverter.ToUInt16(sb_sector, 0x1AA);
|
|
xnx_sb.s_dinfo0 = BitConverter.ToUInt16(sb_sector, 0x1AC);
|
|
xnx_sb.s_dinfo1 = BitConverter.ToUInt16(sb_sector, 0x1AE);
|
|
Array.Copy(sb_sector, 0x1B0, xenix_strings, 0, 6);
|
|
xnx_sb.s_fname = StringHandlers.CToString(xenix_strings, encoding);
|
|
Array.Copy(sb_sector, 0x1B6, xenix_strings, 0, 6);
|
|
xnx_sb.s_fpack = StringHandlers.CToString(xenix_strings, encoding);
|
|
xnx_sb.s_clean = sb_sector[0x1BC];
|
|
xnx_sb.s_magic = BitConverter.ToUInt32(sb_sector, 0x1F0);
|
|
xnx_sb.s_type = BitConverter.ToUInt32(sb_sector, 0x1F4);
|
|
}
|
|
else
|
|
{
|
|
xnx_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000);
|
|
xnx_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002);
|
|
xnx_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006);
|
|
xnx_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x198);
|
|
xnx_sb.s_flock = sb_sector[0x262];
|
|
xnx_sb.s_ilock = sb_sector[0x263];
|
|
xnx_sb.s_fmod = sb_sector[0x264];
|
|
xnx_sb.s_ronly = sb_sector[0x265];
|
|
xnx_sb.s_time = BitConverter.ToInt32(sb_sector, 0x266);
|
|
xnx_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x26A);
|
|
xnx_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x26E);
|
|
xnx_sb.s_cylblks = BitConverter.ToUInt16(sb_sector, 0x270);
|
|
xnx_sb.s_gapblks = BitConverter.ToUInt16(sb_sector, 0x272);
|
|
xnx_sb.s_dinfo0 = BitConverter.ToUInt16(sb_sector, 0x274);
|
|
xnx_sb.s_dinfo1 = BitConverter.ToUInt16(sb_sector, 0x276);
|
|
Array.Copy(sb_sector, 0x278, xenix_strings, 0, 6);
|
|
xnx_sb.s_fname = StringHandlers.CToString(xenix_strings, encoding);
|
|
Array.Copy(sb_sector, 0x27E, xenix_strings, 0, 6);
|
|
xnx_sb.s_fpack = StringHandlers.CToString(xenix_strings, encoding);
|
|
xnx_sb.s_clean = sb_sector[0x284];
|
|
xnx_sb.s_magic = BitConverter.ToUInt32(sb_sector, 0x3F8);
|
|
xnx_sb.s_type = BitConverter.ToUInt32(sb_sector, 0x3FC);
|
|
}
|
|
|
|
if(bigEndian)
|
|
{
|
|
xnx_sb.s_isize = Swapping.Swap(xnx_sb.s_isize);
|
|
xnx_sb.s_fsize = Swapping.Swap(xnx_sb.s_fsize);
|
|
xnx_sb.s_nfree = Swapping.Swap(xnx_sb.s_nfree);
|
|
xnx_sb.s_ninode = Swapping.Swap(xnx_sb.s_ninode);
|
|
xnx_sb.s_time = Swapping.Swap(xnx_sb.s_time);
|
|
xnx_sb.s_tfree = Swapping.Swap(xnx_sb.s_tfree);
|
|
xnx_sb.s_tinode = Swapping.Swap(xnx_sb.s_tinode);
|
|
xnx_sb.s_cylblks = Swapping.Swap(xnx_sb.s_cylblks);
|
|
xnx_sb.s_gapblks = Swapping.Swap(xnx_sb.s_gapblks);
|
|
xnx_sb.s_dinfo0 = Swapping.Swap(xnx_sb.s_dinfo0);
|
|
xnx_sb.s_dinfo1 = Swapping.Swap(xnx_sb.s_dinfo1);
|
|
xnx_sb.s_magic = Swapping.Swap(xnx_sb.s_magic);
|
|
xnx_sb.s_type = Swapping.Swap(xnx_sb.s_type);
|
|
}
|
|
|
|
uint bs = 512;
|
|
sb.AppendLine(Localization.XENIX_filesystem);
|
|
metadata.Type = FS_TYPE_XENIX;
|
|
|
|
switch(xnx_sb.s_type)
|
|
{
|
|
case 1:
|
|
sb.AppendLine(Localization._512_bytes_per_block);
|
|
metadata.ClusterSize = 512;
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine(Localization._1024_bytes_per_block);
|
|
bs = 1024;
|
|
metadata.ClusterSize = 1024;
|
|
|
|
break;
|
|
case 3:
|
|
sb.AppendLine(Localization._2048_bytes_per_block);
|
|
bs = 2048;
|
|
metadata.ClusterSize = 2048;
|
|
|
|
break;
|
|
default:
|
|
sb.AppendFormat(Localization.Unknown_s_type_value_0, xnx_sb.s_type).AppendLine();
|
|
|
|
break;
|
|
}
|
|
|
|
if(imagePlugin.Info.SectorSize is 2336 or 2352 or 2448)
|
|
{
|
|
if(bs != 2048)
|
|
{
|
|
sb.AppendFormat(Localization
|
|
.WARNING_Filesystem_indicates_0_bytes_block_while_device_indicates_1_bytes_block,
|
|
bs,
|
|
2048)
|
|
.AppendLine();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(bs != imagePlugin.Info.SectorSize)
|
|
{
|
|
sb.AppendFormat(Localization
|
|
.WARNING_Filesystem_indicates_0_bytes_block_while_device_indicates_1_bytes_block,
|
|
bs,
|
|
imagePlugin.Info.SectorSize)
|
|
.AppendLine();
|
|
}
|
|
}
|
|
|
|
sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, xnx_sb.s_fsize, xnx_sb.s_fsize * bs).AppendLine();
|
|
|
|
sb.AppendFormat(Localization._0_free_zones_on_volume_1_bytes, xnx_sb.s_tfree, xnx_sb.s_tfree * bs)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization._0_free_blocks_on_list_1_bytes, xnx_sb.s_nfree, xnx_sb.s_nfree * bs)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization._0_blocks_per_cylinder_1_bytes, xnx_sb.s_cylblks, xnx_sb.s_cylblks * bs)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization._0_blocks_per_gap_1_bytes, xnx_sb.s_gapblks, xnx_sb.s_gapblks * bs)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization.First_data_zone_0, xnx_sb.s_isize).AppendLine();
|
|
sb.AppendFormat(Localization._0_free_inodes_on_volume, xnx_sb.s_tinode).AppendLine();
|
|
sb.AppendFormat(Localization._0_free_inodes_on_list, xnx_sb.s_ninode).AppendLine();
|
|
|
|
if(xnx_sb.s_flock > 0) sb.AppendLine(Localization.Free_block_list_is_locked);
|
|
|
|
if(xnx_sb.s_ilock > 0) sb.AppendLine(Localization.inode_cache_is_locked);
|
|
|
|
if(xnx_sb.s_fmod > 0) sb.AppendLine(Localization.Superblock_is_being_modified);
|
|
|
|
if(xnx_sb.s_ronly > 0) sb.AppendLine(Localization.Volume_is_mounted_read_only);
|
|
|
|
sb.AppendFormat(Localization.Superblock_last_updated_on_0, DateHandlers.UnixToDateTime(xnx_sb.s_time))
|
|
.AppendLine();
|
|
|
|
if(xnx_sb.s_time != 0) metadata.ModificationDate = DateHandlers.UnixToDateTime(xnx_sb.s_time);
|
|
|
|
sb.AppendFormat(Localization.Volume_name_0, xnx_sb.s_fname).AppendLine();
|
|
metadata.VolumeName = xnx_sb.s_fname;
|
|
sb.AppendFormat(Localization.Pack_name_0, xnx_sb.s_fpack).AppendLine();
|
|
|
|
if(xnx_sb.s_clean == 0x46)
|
|
sb.AppendLine(Localization.Volume_is_clean);
|
|
else
|
|
{
|
|
sb.AppendLine(Localization.Volume_is_dirty);
|
|
metadata.Dirty = true;
|
|
}
|
|
}
|
|
|
|
if(sysv)
|
|
{
|
|
errno = imagePlugin.ReadSectors((ulong)start + partition.Start,
|
|
false,
|
|
sb_size_in_sectors,
|
|
out sb_sector,
|
|
out _);
|
|
|
|
if(errno != ErrorNumber.NoError) return;
|
|
|
|
var sysv_strings = new byte[6];
|
|
|
|
var sysv_sb = new SystemVRelease4SuperBlock
|
|
{
|
|
s_type = BitConverter.ToUInt32(sb_sector, 0x1FC + offset)
|
|
};
|
|
|
|
if(bigEndian) sysv_sb.s_type = Swapping.Swap(sysv_sb.s_type);
|
|
|
|
uint bs = 512;
|
|
|
|
switch(sysv_sb.s_type)
|
|
{
|
|
case 1:
|
|
metadata.ClusterSize = 512;
|
|
|
|
break;
|
|
case 2:
|
|
bs = 1024;
|
|
metadata.ClusterSize = 1024;
|
|
|
|
break;
|
|
case 3:
|
|
bs = 2048;
|
|
metadata.ClusterSize = 2048;
|
|
|
|
break;
|
|
default:
|
|
sb.AppendFormat(Localization.Unknown_s_type_value_0, sysv_sb.s_type).AppendLine();
|
|
|
|
break;
|
|
}
|
|
|
|
sysv_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002 + offset);
|
|
|
|
if(bigEndian) sysv_sb.s_fsize = Swapping.Swap(sysv_sb.s_fsize);
|
|
|
|
bool sysvr4 = sysv_sb.s_fsize * bs <= 0 || sysv_sb.s_fsize * bs != partition.Size;
|
|
|
|
if(sysvr4)
|
|
{
|
|
sysv_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000 + offset);
|
|
sysv_sb.s_state = BitConverter.ToUInt32(sb_sector, 0x1F4 + offset);
|
|
sysv_sb.s_magic = BitConverter.ToUInt32(sb_sector, 0x1F8 + offset);
|
|
sysv_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x004 + offset);
|
|
sysv_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x008 + offset);
|
|
sysv_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D4 + offset);
|
|
sysv_sb.s_flock = sb_sector[0x1A0 + offset];
|
|
sysv_sb.s_ilock = sb_sector[0x1A1 + offset];
|
|
sysv_sb.s_fmod = sb_sector[0x1A2 + offset];
|
|
sysv_sb.s_ronly = sb_sector[0x1A3 + offset];
|
|
sysv_sb.s_time = BitConverter.ToUInt32(sb_sector, 0x1A4 + offset);
|
|
sysv_sb.s_cylblks = BitConverter.ToUInt16(sb_sector, 0x1A8 + offset);
|
|
sysv_sb.s_gapblks = BitConverter.ToUInt16(sb_sector, 0x1AA + offset);
|
|
sysv_sb.s_dinfo0 = BitConverter.ToUInt16(sb_sector, 0x1AC + offset);
|
|
sysv_sb.s_dinfo1 = BitConverter.ToUInt16(sb_sector, 0x1AE + offset);
|
|
sysv_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x1B0 + offset);
|
|
sysv_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1B4 + offset);
|
|
Array.Copy(sb_sector, 0x1B6 + offset, sysv_strings, 0, 6);
|
|
sysv_sb.s_fname = StringHandlers.CToString(sysv_strings, encoding);
|
|
Array.Copy(sb_sector, 0x1BC + offset, sysv_strings, 0, 6);
|
|
sysv_sb.s_fpack = StringHandlers.CToString(sysv_strings, encoding);
|
|
sb.AppendLine(Localization.System_V_Release_4_filesystem);
|
|
metadata.Type = FS_TYPE_SVR4;
|
|
}
|
|
else
|
|
{
|
|
sysv_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000 + offset);
|
|
sysv_sb.s_state = BitConverter.ToUInt32(sb_sector, 0x1F4 + offset);
|
|
sysv_sb.s_magic = BitConverter.ToUInt32(sb_sector, 0x1F8 + offset);
|
|
sysv_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002 + offset);
|
|
sysv_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006 + offset);
|
|
sysv_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0 + offset);
|
|
sysv_sb.s_flock = sb_sector[0x19A + offset];
|
|
sysv_sb.s_ilock = sb_sector[0x19B + offset];
|
|
sysv_sb.s_fmod = sb_sector[0x19C + offset];
|
|
sysv_sb.s_ronly = sb_sector[0x19D + offset];
|
|
sysv_sb.s_time = BitConverter.ToUInt32(sb_sector, 0x19E + offset);
|
|
sysv_sb.s_cylblks = BitConverter.ToUInt16(sb_sector, 0x1A2 + offset);
|
|
sysv_sb.s_gapblks = BitConverter.ToUInt16(sb_sector, 0x1A4 + offset);
|
|
sysv_sb.s_dinfo0 = BitConverter.ToUInt16(sb_sector, 0x1A6 + offset);
|
|
sysv_sb.s_dinfo1 = BitConverter.ToUInt16(sb_sector, 0x1A8 + offset);
|
|
sysv_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x1AA + offset);
|
|
sysv_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1AE + offset);
|
|
Array.Copy(sb_sector, 0x1B0 + offset, sysv_strings, 0, 6);
|
|
sysv_sb.s_fname = StringHandlers.CToString(sysv_strings, encoding);
|
|
Array.Copy(sb_sector, 0x1B6 + offset, sysv_strings, 0, 6);
|
|
sysv_sb.s_fpack = StringHandlers.CToString(sysv_strings, encoding);
|
|
sb.AppendLine(Localization.System_V_Release_2_filesystem);
|
|
metadata.Type = FS_TYPE_SVR2;
|
|
}
|
|
|
|
if(bigEndian)
|
|
{
|
|
sysv_sb.s_isize = Swapping.Swap(sysv_sb.s_isize);
|
|
sysv_sb.s_state = Swapping.Swap(sysv_sb.s_state);
|
|
sysv_sb.s_magic = Swapping.Swap(sysv_sb.s_magic);
|
|
sysv_sb.s_fsize = Swapping.Swap(sysv_sb.s_fsize);
|
|
sysv_sb.s_nfree = Swapping.Swap(sysv_sb.s_nfree);
|
|
sysv_sb.s_ninode = Swapping.Swap(sysv_sb.s_ninode);
|
|
sysv_sb.s_time = Swapping.Swap(sysv_sb.s_time);
|
|
sysv_sb.s_cylblks = Swapping.Swap(sysv_sb.s_cylblks);
|
|
sysv_sb.s_gapblks = Swapping.Swap(sysv_sb.s_gapblks);
|
|
sysv_sb.s_dinfo0 = Swapping.Swap(sysv_sb.s_dinfo0);
|
|
sysv_sb.s_dinfo1 = Swapping.Swap(sysv_sb.s_dinfo1);
|
|
sysv_sb.s_tfree = Swapping.Swap(sysv_sb.s_tfree);
|
|
sysv_sb.s_tinode = Swapping.Swap(sysv_sb.s_tinode);
|
|
}
|
|
|
|
sb.AppendFormat(Localization._0_bytes_per_block, bs).AppendLine();
|
|
|
|
metadata.Clusters = sysv_sb.s_fsize;
|
|
|
|
sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, sysv_sb.s_fsize, sysv_sb.s_fsize * bs)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization._0_free_zones_on_volume_1_bytes, sysv_sb.s_tfree, sysv_sb.s_tfree * bs)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization._0_free_blocks_on_list_1_bytes, sysv_sb.s_nfree, sysv_sb.s_nfree * bs)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization._0_blocks_per_cylinder_1_bytes, sysv_sb.s_cylblks, sysv_sb.s_cylblks * bs)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization._0_blocks_per_gap_1_bytes, sysv_sb.s_gapblks, sysv_sb.s_gapblks * bs)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization.First_data_zone_0, sysv_sb.s_isize).AppendLine();
|
|
sb.AppendFormat(Localization._0_free_inodes_on_volume, sysv_sb.s_tinode).AppendLine();
|
|
sb.AppendFormat(Localization._0_free_inodes_on_list, sysv_sb.s_ninode).AppendLine();
|
|
|
|
if(sysv_sb.s_flock > 0) sb.AppendLine(Localization.Free_block_list_is_locked);
|
|
|
|
if(sysv_sb.s_ilock > 0) sb.AppendLine(Localization.inode_cache_is_locked);
|
|
|
|
if(sysv_sb.s_fmod > 0) sb.AppendLine(Localization.Superblock_is_being_modified);
|
|
|
|
if(sysv_sb.s_ronly > 0) sb.AppendLine(Localization.Volume_is_mounted_read_only);
|
|
|
|
sb.AppendFormat(Localization.Superblock_last_updated_on_0,
|
|
DateHandlers.UnixUnsignedToDateTime(sysv_sb.s_time))
|
|
.AppendLine();
|
|
|
|
if(sysv_sb.s_time != 0) metadata.ModificationDate = DateHandlers.UnixUnsignedToDateTime(sysv_sb.s_time);
|
|
|
|
sb.AppendFormat(Localization.Volume_name_0, sysv_sb.s_fname).AppendLine();
|
|
metadata.VolumeName = sysv_sb.s_fname;
|
|
sb.AppendFormat(Localization.Pack_name_0, sysv_sb.s_fpack).AppendLine();
|
|
|
|
if(sysv_sb.s_state == 0x7C269D38 - sysv_sb.s_time)
|
|
sb.AppendLine(Localization.Volume_is_clean);
|
|
else
|
|
{
|
|
sb.AppendLine(Localization.Volume_is_dirty);
|
|
metadata.Dirty = true;
|
|
}
|
|
}
|
|
|
|
if(coherent)
|
|
{
|
|
errno = imagePlugin.ReadSectors((ulong)start + partition.Start,
|
|
false,
|
|
sb_size_in_sectors,
|
|
out sb_sector,
|
|
out _);
|
|
|
|
if(errno != ErrorNumber.NoError) return;
|
|
|
|
var coh_sb = new CoherentSuperBlock();
|
|
var coh_strings = new byte[6];
|
|
|
|
coh_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000);
|
|
coh_sb.s_fsize = Swapping.PDPFromLittleEndian(BitConverter.ToUInt32(sb_sector, 0x002));
|
|
coh_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006);
|
|
coh_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x108);
|
|
coh_sb.s_flock = sb_sector[0x1D2];
|
|
coh_sb.s_ilock = sb_sector[0x1D3];
|
|
coh_sb.s_fmod = sb_sector[0x1D4];
|
|
coh_sb.s_ronly = sb_sector[0x1D5];
|
|
coh_sb.s_time = Swapping.PDPFromLittleEndian(BitConverter.ToUInt32(sb_sector, 0x1D6));
|
|
coh_sb.s_tfree = Swapping.PDPFromLittleEndian(BitConverter.ToUInt32(sb_sector, 0x1DA));
|
|
coh_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1DE);
|
|
coh_sb.s_int_m = BitConverter.ToUInt16(sb_sector, 0x1E0);
|
|
coh_sb.s_int_n = BitConverter.ToUInt16(sb_sector, 0x1E2);
|
|
Array.Copy(sb_sector, 0x1E4, coh_strings, 0, 6);
|
|
coh_sb.s_fname = StringHandlers.CToString(coh_strings, encoding);
|
|
Array.Copy(sb_sector, 0x1EA, coh_strings, 0, 6);
|
|
coh_sb.s_fpack = StringHandlers.CToString(coh_strings, encoding);
|
|
|
|
metadata.Type = FS_TYPE_COHERENT;
|
|
metadata.ClusterSize = 512;
|
|
metadata.Clusters = coh_sb.s_fsize;
|
|
|
|
sb.AppendLine(Localization.Coherent_UNIX_filesystem);
|
|
|
|
if(imagePlugin.Info.SectorSize != 512)
|
|
{
|
|
sb.AppendFormat(Localization
|
|
.WARNING_Filesystem_indicates_0_bytes_block_while_device_indicates_1_bytes_block,
|
|
512,
|
|
2048)
|
|
.AppendLine();
|
|
}
|
|
|
|
sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, coh_sb.s_fsize, coh_sb.s_fsize * 512).AppendLine();
|
|
|
|
sb.AppendFormat(Localization._0_free_zones_on_volume_1_bytes, coh_sb.s_tfree, coh_sb.s_tfree * 512)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization._0_free_blocks_on_list_1_bytes, coh_sb.s_nfree, coh_sb.s_nfree * 512)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization.First_data_zone_0, coh_sb.s_isize).AppendLine();
|
|
sb.AppendFormat(Localization._0_free_inodes_on_volume, coh_sb.s_tinode).AppendLine();
|
|
sb.AppendFormat(Localization._0_free_inodes_on_list, coh_sb.s_ninode).AppendLine();
|
|
|
|
if(coh_sb.s_flock > 0) sb.AppendLine(Localization.Free_block_list_is_locked);
|
|
|
|
if(coh_sb.s_ilock > 0) sb.AppendLine(Localization.inode_cache_is_locked);
|
|
|
|
if(coh_sb.s_fmod > 0) sb.AppendLine(Localization.Superblock_is_being_modified);
|
|
|
|
if(coh_sb.s_ronly > 0) sb.AppendLine(Localization.Volume_is_mounted_read_only);
|
|
|
|
sb.AppendFormat(Localization.Superblock_last_updated_on_0,
|
|
DateHandlers.UnixUnsignedToDateTime(coh_sb.s_time))
|
|
.AppendLine();
|
|
|
|
if(coh_sb.s_time != 0) metadata.ModificationDate = DateHandlers.UnixUnsignedToDateTime(coh_sb.s_time);
|
|
|
|
sb.AppendFormat(Localization.Volume_name_0, coh_sb.s_fname).AppendLine();
|
|
metadata.VolumeName = coh_sb.s_fname;
|
|
sb.AppendFormat(Localization.Pack_name_0, coh_sb.s_fpack).AppendLine();
|
|
}
|
|
|
|
if(sys7th)
|
|
{
|
|
errno = imagePlugin.ReadSectors((ulong)start + partition.Start,
|
|
false,
|
|
sb_size_in_sectors,
|
|
out sb_sector,
|
|
out _);
|
|
|
|
if(errno != ErrorNumber.NoError) return;
|
|
|
|
var v7_sb = new UNIX7thEditionSuperBlock();
|
|
var sys7_strings = new byte[6];
|
|
|
|
v7_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000);
|
|
v7_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002);
|
|
v7_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006);
|
|
v7_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0);
|
|
v7_sb.s_flock = sb_sector[0x19A];
|
|
v7_sb.s_ilock = sb_sector[0x19B];
|
|
v7_sb.s_fmod = sb_sector[0x19C];
|
|
v7_sb.s_ronly = sb_sector[0x19D];
|
|
v7_sb.s_time = BitConverter.ToUInt32(sb_sector, 0x19E);
|
|
v7_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x1A2);
|
|
v7_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1A6);
|
|
v7_sb.s_int_m = BitConverter.ToUInt16(sb_sector, 0x1A8);
|
|
v7_sb.s_int_n = BitConverter.ToUInt16(sb_sector, 0x1AA);
|
|
Array.Copy(sb_sector, 0x1AC, sys7_strings, 0, 6);
|
|
v7_sb.s_fname = StringHandlers.CToString(sys7_strings, encoding);
|
|
Array.Copy(sb_sector, 0x1B2, sys7_strings, 0, 6);
|
|
v7_sb.s_fpack = StringHandlers.CToString(sys7_strings, encoding);
|
|
|
|
metadata.Type = FS_TYPE_UNIX7;
|
|
metadata.ClusterSize = 512;
|
|
metadata.Clusters = v7_sb.s_fsize;
|
|
sb.AppendLine(Localization.UNIX_7th_Edition_filesystem);
|
|
|
|
if(imagePlugin.Info.SectorSize != 512)
|
|
{
|
|
sb.AppendFormat(Localization
|
|
.WARNING_Filesystem_indicates_0_bytes_block_while_device_indicates_1_bytes_block,
|
|
512,
|
|
2048)
|
|
.AppendLine();
|
|
}
|
|
|
|
sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, v7_sb.s_fsize, v7_sb.s_fsize * 512).AppendLine();
|
|
|
|
sb.AppendFormat(Localization._0_free_zones_on_volume_1_bytes, v7_sb.s_tfree, v7_sb.s_tfree * 512)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization._0_free_blocks_on_list_1_bytes, v7_sb.s_nfree, v7_sb.s_nfree * 512)
|
|
.AppendLine();
|
|
|
|
sb.AppendFormat(Localization.First_data_zone_0, v7_sb.s_isize).AppendLine();
|
|
sb.AppendFormat(Localization._0_free_inodes_on_volume, v7_sb.s_tinode).AppendLine();
|
|
sb.AppendFormat(Localization._0_free_inodes_on_list, v7_sb.s_ninode).AppendLine();
|
|
|
|
if(v7_sb.s_flock > 0) sb.AppendLine(Localization.Free_block_list_is_locked);
|
|
|
|
if(v7_sb.s_ilock > 0) sb.AppendLine(Localization.inode_cache_is_locked);
|
|
|
|
if(v7_sb.s_fmod > 0) sb.AppendLine(Localization.Superblock_is_being_modified);
|
|
|
|
if(v7_sb.s_ronly > 0) sb.AppendLine(Localization.Volume_is_mounted_read_only);
|
|
|
|
sb.AppendFormat(Localization.Superblock_last_updated_on_0,
|
|
DateHandlers.UnixUnsignedToDateTime(v7_sb.s_time))
|
|
.AppendLine();
|
|
|
|
if(v7_sb.s_time != 0) metadata.ModificationDate = DateHandlers.UnixUnsignedToDateTime(v7_sb.s_time);
|
|
|
|
sb.AppendFormat(Localization.Volume_name_0, v7_sb.s_fname).AppendLine();
|
|
metadata.VolumeName = v7_sb.s_fname;
|
|
sb.AppendFormat(Localization.Pack_name_0, v7_sb.s_fpack).AppendLine();
|
|
}
|
|
|
|
information = sb.ToString();
|
|
}
|
|
|
|
#endregion
|
|
} |