2017-07-26 03:08:29 +01:00
// /***************************************************************************
2020-02-27 12:31:25 +00:00
// Aaru Data Preservation Suite
2017-07-26 03:08:29 +01:00
// ----------------------------------------------------------------------------
//
2017-12-19 03:50:57 +00:00
// Filename : Atheos.cs
2017-07-26 03:08:29 +01:00
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
2017-12-19 03:50:57 +00:00
// Component : Atheos filesystem plugin.
2017-07-26 03:08:29 +01:00
//
// --[ Description ] ----------------------------------------------------------
//
2017-12-19 03:50:57 +00:00
// Identifies the Atheos filesystem and shows information.
2017-07-26 03:08:29 +01:00
//
// --[ 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/>.
//
// ----------------------------------------------------------------------------
2020-01-03 17:51:30 +00:00
// Copyright © 2011-2020 Natalia Portillo
2017-07-26 03:08:29 +01:00
// ****************************************************************************/
using System ;
2020-07-20 07:47:12 +01:00
using System.Diagnostics.CodeAnalysis ;
2017-07-26 03:08:29 +01:00
using System.Runtime.InteropServices ;
using System.Text ;
2020-02-27 00:33:26 +00:00
using Aaru.CommonTypes ;
using Aaru.CommonTypes.Interfaces ;
2017-12-21 14:30:38 +00:00
using Schemas ;
2020-02-27 00:33:26 +00:00
using Marshal = Aaru . Helpers . Marshal ;
2017-07-26 03:08:29 +01:00
2020-02-27 00:33:26 +00:00
namespace Aaru.Filesystems
2017-07-26 03:08:29 +01:00
{
2020-07-20 07:47:12 +01:00
[SuppressMessage("ReSharper", "UnusedMember.Local")]
2017-12-26 06:05:12 +00:00
public class AtheOS : IFilesystem
2017-07-26 03:08:29 +01:00
{
// Little endian constants (that is, as read by .NET :p)
const uint AFS_MAGIC1 = 0x41465331 ;
const uint AFS_MAGIC2 = 0xDD121031 ;
const uint AFS_MAGIC3 = 0x15B6830E ;
2020-02-29 18:03:35 +00:00
2017-07-26 03:08:29 +01:00
// Common constants
const uint AFS_SUPERBLOCK_SIZE = 1024 ;
2018-06-22 08:08:38 +01:00
const uint AFS_BOOTBLOCK_SIZE = AFS_SUPERBLOCK_SIZE ;
2017-07-26 03:08:29 +01:00
2017-12-26 08:01:40 +00:00
public FileSystemType XmlFsType { get ; private set ; }
2018-06-22 08:08:38 +01:00
public Encoding Encoding { get ; private set ; }
public string Name = > "AtheOS Filesystem" ;
public Guid Id = > new Guid ( "AAB2C4F1-DC07-49EE-A948-576CC51B58C5" ) ;
2018-08-29 22:15:43 +01:00
public string Author = > "Natalia Portillo" ;
2017-07-26 03:08:29 +01:00
2017-12-26 07:28:40 +00:00
public bool Identify ( IMediaImage imagePlugin , Partition partition )
2017-07-26 03:08:29 +01:00
{
2017-12-26 06:05:12 +00:00
ulong sector = AFS_BOOTBLOCK_SIZE / imagePlugin . Info . SectorSize ;
2018-06-22 08:08:38 +01:00
uint offset = AFS_BOOTBLOCK_SIZE % imagePlugin . Info . SectorSize ;
uint run = 1 ;
2017-07-26 03:08:29 +01:00
2017-12-26 06:05:12 +00:00
if ( imagePlugin . Info . SectorSize < AFS_SUPERBLOCK_SIZE )
run = AFS_SUPERBLOCK_SIZE / imagePlugin . Info . SectorSize ;
2017-07-26 03:08:29 +01:00
2020-02-29 18:03:35 +00:00
if ( sector + partition . Start > = partition . End )
return false ;
2017-07-26 03:08:29 +01:00
2018-06-22 08:08:38 +01:00
byte [ ] tmp = imagePlugin . ReadSectors ( sector + partition . Start , run ) ;
2017-12-22 08:43:22 +00:00
byte [ ] sbSector = new byte [ AFS_SUPERBLOCK_SIZE ] ;
2019-05-06 20:09:25 +01:00
2020-02-29 18:03:35 +00:00
if ( offset + AFS_SUPERBLOCK_SIZE > tmp . Length )
return false ;
2019-05-06 20:09:25 +01:00
2017-12-22 08:43:22 +00:00
Array . Copy ( tmp , offset , sbSector , 0 , AFS_SUPERBLOCK_SIZE ) ;
2017-07-26 03:08:29 +01:00
2018-06-20 22:22:21 +01:00
uint magic = BitConverter . ToUInt32 ( sbSector , 0x20 ) ;
2017-07-26 03:08:29 +01:00
return magic = = AFS_MAGIC1 ;
}
2017-12-26 07:28:40 +00:00
public void GetInformation ( IMediaImage imagePlugin , Partition partition , out string information ,
2020-02-29 18:03:35 +00:00
Encoding encoding )
2017-07-26 03:08:29 +01:00
{
2018-06-22 08:08:38 +01:00
Encoding = encoding ? ? Encoding . GetEncoding ( "iso-8859-15" ) ;
2017-07-26 03:08:29 +01:00
information = "" ;
2020-02-29 18:03:35 +00:00
var sb = new StringBuilder ( ) ;
2017-07-26 03:08:29 +01:00
2017-12-26 06:05:12 +00:00
ulong sector = AFS_BOOTBLOCK_SIZE / imagePlugin . Info . SectorSize ;
2018-06-22 08:08:38 +01:00
uint offset = AFS_BOOTBLOCK_SIZE % imagePlugin . Info . SectorSize ;
uint run = 1 ;
2017-07-26 03:08:29 +01:00
2017-12-26 06:05:12 +00:00
if ( imagePlugin . Info . SectorSize < AFS_SUPERBLOCK_SIZE )
run = AFS_SUPERBLOCK_SIZE / imagePlugin . Info . SectorSize ;
2017-07-26 03:08:29 +01:00
2018-06-22 08:08:38 +01:00
byte [ ] tmp = imagePlugin . ReadSectors ( sector + partition . Start , run ) ;
2017-12-22 08:43:22 +00:00
byte [ ] sbSector = new byte [ AFS_SUPERBLOCK_SIZE ] ;
Array . Copy ( tmp , offset , sbSector , 0 , AFS_SUPERBLOCK_SIZE ) ;
2017-07-26 03:08:29 +01:00
2019-03-01 07:35:22 +00:00
AtheosSuperBlock afsSb = Marshal . ByteArrayToStructureLittleEndian < AtheosSuperBlock > ( sbSector ) ;
2017-07-26 03:08:29 +01:00
sb . AppendLine ( "Atheos filesystem" ) ;
2020-02-29 18:03:35 +00:00
if ( afsSb . flags = = 1 )
sb . AppendLine ( "Filesystem is read-only" ) ;
2017-07-26 03:08:29 +01:00
2017-12-26 08:01:40 +00:00
sb . AppendFormat ( "Volume name: {0}" , StringHandlers . CToString ( afsSb . name , Encoding ) ) . AppendLine ( ) ;
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} bytes per block" , afsSb . block_size ) . AppendLine ( ) ;
2020-02-29 18:03:35 +00:00
sb . AppendFormat ( "{0} blocks in volume ({1} bytes)" , afsSb . num_blocks , afsSb . num_blocks * afsSb . block_size ) .
AppendLine ( ) ;
sb . AppendFormat ( "{0} used blocks ({1} bytes)" , afsSb . used_blocks , afsSb . used_blocks * afsSb . block_size ) .
AppendLine ( ) ;
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} bytes per i-node" , afsSb . inode_size ) . AppendLine ( ) ;
2020-02-29 18:03:35 +00:00
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} blocks per allocation group ({1} bytes)" , afsSb . blocks_per_ag ,
afsSb . blocks_per_ag * afsSb . block_size ) . AppendLine ( ) ;
2020-02-29 18:03:35 +00:00
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} allocation groups in volume" , afsSb . num_ags ) . AppendLine ( ) ;
2020-02-29 18:03:35 +00:00
2017-12-19 20:33:03 +00:00
sb . AppendFormat ( "Journal resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)" ,
2017-12-22 08:43:22 +00:00
afsSb . log_blocks_start , afsSb . log_blocks_ag , afsSb . log_blocks_len ,
afsSb . log_blocks_len * afsSb . block_size ) . AppendLine ( ) ;
2020-02-29 18:03:35 +00:00
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "Journal starts in byte {0} and has {1} bytes in {2} blocks" , afsSb . log_start ,
afsSb . log_size , afsSb . log_valid_blocks ) . AppendLine ( ) ;
2020-02-29 18:03:35 +00:00
sb .
AppendFormat ( "Root folder's i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)" ,
2018-06-22 08:08:38 +01:00
afsSb . root_dir_start , afsSb . root_dir_ag , afsSb . root_dir_len ,
afsSb . root_dir_len * afsSb . block_size ) . AppendLine ( ) ;
2020-02-29 18:03:35 +00:00
sb .
AppendFormat ( "Directory containing files scheduled for deletion's i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)" ,
2018-06-22 08:08:38 +01:00
afsSb . deleted_start , afsSb . deleted_ag , afsSb . deleted_len ,
afsSb . deleted_len * afsSb . block_size ) . AppendLine ( ) ;
2020-02-29 18:03:35 +00:00
sb .
AppendFormat ( "Indices' i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)" ,
2018-06-22 08:08:38 +01:00
afsSb . indices_start , afsSb . indices_ag , afsSb . indices_len ,
afsSb . indices_len * afsSb . block_size ) . AppendLine ( ) ;
2020-02-29 18:03:35 +00:00
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} blocks for bootloader ({1} bytes)" , afsSb . boot_size ,
afsSb . boot_size * afsSb . block_size ) . AppendLine ( ) ;
2017-07-26 03:08:29 +01:00
information = sb . ToString ( ) ;
2017-12-26 08:01:40 +00:00
XmlFsType = new FileSystemType
2017-07-26 03:08:29 +01:00
{
2020-07-20 04:34:16 +01:00
Clusters = ( ulong ) afsSb . num_blocks ,
ClusterSize = afsSb . block_size ,
Dirty = false ,
FreeClusters = ( ulong ) ( afsSb . num_blocks - afsSb . used_blocks ) ,
FreeClustersSpecified = true ,
Type = "AtheOS filesystem" ,
VolumeName = StringHandlers . CToString ( afsSb . name , Encoding )
2017-07-26 03:08:29 +01:00
} ;
}
2020-02-29 18:03:35 +00:00
/// <summary>Be superblock</summary>
2017-07-26 03:08:29 +01:00
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct AtheosSuperBlock
{
/// <summary>0x000, Volume name, 32 bytes</summary>
2018-06-22 08:08:38 +01:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
2019-04-23 01:38:33 +01:00
public readonly byte [ ] name ;
2017-07-26 03:08:29 +01:00
/// <summary>0x020, "AFS1", 0x41465331</summary>
2019-04-23 01:38:33 +01:00
public readonly uint magic1 ;
2017-07-26 03:08:29 +01:00
/// <summary>0x024, "BIGE", 0x42494745</summary>
2019-04-23 01:38:33 +01:00
public readonly uint fs_byte_order ;
2017-07-26 03:08:29 +01:00
/// <summary>0x028, Bytes per block</summary>
2019-04-23 01:38:33 +01:00
public readonly uint block_size ;
2017-07-26 03:08:29 +01:00
/// <summary>0x02C, 1 << block_shift == block_size</summary>
2019-04-23 01:38:33 +01:00
public readonly uint block_shift ;
2017-07-26 03:08:29 +01:00
/// <summary>0x030, Blocks in volume</summary>
2019-04-23 01:38:33 +01:00
public readonly long num_blocks ;
2017-07-26 03:08:29 +01:00
/// <summary>0x038, Used blocks in volume</summary>
2019-04-23 01:38:33 +01:00
public readonly long used_blocks ;
2017-07-26 03:08:29 +01:00
/// <summary>0x040, Bytes per inode</summary>
2019-04-23 01:38:33 +01:00
public readonly int inode_size ;
2017-07-26 03:08:29 +01:00
/// <summary>0x044, 0xDD121031</summary>
2019-04-23 01:38:33 +01:00
public readonly uint magic2 ;
2017-07-26 03:08:29 +01:00
/// <summary>0x048, Blocks per allocation group</summary>
2019-04-23 01:38:33 +01:00
public readonly int blocks_per_ag ;
2017-07-26 03:08:29 +01:00
/// <summary>0x04C, 1 << ag_shift == blocks_per_ag</summary>
2019-04-23 01:38:33 +01:00
public readonly int ag_shift ;
2017-07-26 03:08:29 +01:00
/// <summary>0x050, Allocation groups in volume</summary>
2019-04-23 01:38:33 +01:00
public readonly int num_ags ;
2017-07-26 03:08:29 +01:00
/// <summary>0x054, 0x434c454e if clean, 0x44495254 if dirty</summary>
2019-04-23 01:38:33 +01:00
public readonly uint flags ;
2017-07-26 03:08:29 +01:00
/// <summary>0x058, Allocation group of journal</summary>
2019-04-23 01:38:33 +01:00
public readonly int log_blocks_ag ;
2017-07-26 03:08:29 +01:00
/// <summary>0x05C, Start block of journal, inside ag</summary>
2019-04-23 01:38:33 +01:00
public readonly ushort log_blocks_start ;
2017-07-26 03:08:29 +01:00
/// <summary>0x05E, Length in blocks of journal, inside ag</summary>
2019-04-23 01:38:33 +01:00
public readonly ushort log_blocks_len ;
2017-07-26 03:08:29 +01:00
/// <summary>0x060, Start of journal</summary>
2019-04-23 01:38:33 +01:00
public readonly long log_start ;
2017-07-26 03:08:29 +01:00
/// <summary>0x068, Valid block logs</summary>
2019-04-23 01:38:33 +01:00
public readonly int log_valid_blocks ;
2017-07-26 03:08:29 +01:00
/// <summary>0x06C, Log size</summary>
2019-04-23 01:38:33 +01:00
public readonly int log_size ;
2017-07-26 03:08:29 +01:00
/// <summary>0x070, 0x15B6830E</summary>
2019-04-23 01:38:33 +01:00
public readonly uint magic3 ;
2017-07-26 03:08:29 +01:00
/// <summary>0x074, Allocation group where root folder's i-node resides</summary>
2019-04-23 01:38:33 +01:00
public readonly int root_dir_ag ;
2017-07-26 03:08:29 +01:00
/// <summary>0x078, Start in ag of root folder's i-node</summary>
2019-04-23 01:38:33 +01:00
public readonly ushort root_dir_start ;
2017-07-26 03:08:29 +01:00
/// <summary>0x07A, As this is part of inode_addr, this is 1</summary>
2019-04-23 01:38:33 +01:00
public readonly ushort root_dir_len ;
2017-07-26 03:08:29 +01:00
/// <summary>0x07C, Allocation group where pending-delete-files' i-node resides</summary>
2019-04-23 01:38:33 +01:00
public readonly int deleted_ag ;
2017-07-26 03:08:29 +01:00
/// <summary>0x080, Start in ag of pending-delete-files' i-node</summary>
2019-04-23 01:38:33 +01:00
public readonly ushort deleted_start ;
2017-07-26 03:08:29 +01:00
/// <summary>0x082, As this is part of inode_addr, this is 1</summary>
2019-04-23 01:38:33 +01:00
public readonly ushort deleted_len ;
2017-07-26 03:08:29 +01:00
/// <summary>0x084, Allocation group where indices' i-node resides</summary>
2019-04-23 01:38:33 +01:00
public readonly int indices_ag ;
2017-07-26 03:08:29 +01:00
/// <summary>0x088, Start in ag of indices' i-node</summary>
2019-04-23 01:38:33 +01:00
public readonly ushort indices_start ;
2017-07-26 03:08:29 +01:00
/// <summary>0x08A, As this is part of inode_addr, this is 1</summary>
2019-04-23 01:38:33 +01:00
public readonly ushort indices_len ;
2017-07-26 03:08:29 +01:00
/// <summary>0x08C, Size of bootloader</summary>
2019-04-23 01:38:33 +01:00
public readonly int boot_size ;
2017-07-26 03:08:29 +01:00
}
}
}