@@ -0,0 +1,318 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : JFS.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Component
//
// --[ Description ] ----------------------------------------------------------
//
// Identifies the IBM JFS filesystem and shows information.
//
// --[ 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-2016 Natalia Portillo
// ****************************************************************************/
using System ;
using System.Collections.Generic ;
using System.Runtime.InteropServices ;
using System.Text ;
namespace DiscImageChef.Filesystems
{
class JFS : Filesystem
{
[Flags]
enum JFS_Flags : uint
{
Unicode = 0x00000001 ,
RemountRO = 0x00000002 ,
Continue = 0x00000004 ,
Panic = 0x00000008 ,
UserQuota = 0x00000010 ,
GroupQuota = 0x00000020 ,
NoJournal = 0x00000040 ,
Discard = 0x00000080 ,
GroupCommit = 0x00000100 ,
LazyCommit = 0x00000200 ,
Temporary = 0x00000400 ,
InlineLog = 0x00000800 ,
InlineMoving = 0x00001000 ,
BadSAIT = 0x00010000 ,
Sparse = 0x00020000 ,
DASDEnabled = 0x00040000 ,
DASDPrime = 0x00080000 ,
SwapBytes = 0x00100000 ,
DirIndex = 0x00200000 ,
Linux = 0x10000000 ,
DFS = 0x20000000 ,
OS2 = 0x40000000 ,
AIX = 0x80000000
}
[Flags]
enum JFS_State : uint
{
Clean = 0 ,
Mounted = 1 ,
Dirty = 2 ,
Logredo = 4 ,
Extendfs = 8
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct JFS_Extent
{
/// <summary>
/// Leftmost 24 bits are extent length, rest 8 bits are most significant for <see cref="addr2"/>
/// </summary>
public uint len_addr ;
public uint addr2 ;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct JFS_TimeStruct
{
public uint tv_sec ;
public uint tv_nsec ;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct JFS_SuperBlock
{
public uint s_magic ;
public uint s_version ;
public ulong s_size ;
public uint s_bsize ;
public ushort s_l2bsize ;
public ushort s_l2bfactor ;
public uint s_pbsize ;
public ushort s_l1pbsize ;
public ushort pad ;
public uint s_agsize ;
public JFS_Flags s_flags ;
public JFS_State s_state ;
public uint s_compress ;
public JFS_Extent s_ait2 ;
public JFS_Extent s_aim2 ;
public uint s_logdev ;
public uint s_logserial ;
public JFS_Extent s_logpxd ;
public JFS_Extent s_fsckpxd ;
public JFS_TimeStruct s_time ;
public uint s_fsckloglen ;
public sbyte s_fscklog ;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
public byte [ ] s_fpack ;
public ulong s_xsize ;
public JFS_Extent s_xfsckpxd ;
public JFS_Extent s_xlogpxd ;
public Guid s_uuid ;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte [ ] s_label ;
public Guid s_loguuid ;
}
const uint JFS_BootBlocksSize = 0x8000 ;
const uint JFS_Magic = 0x3153464A ;
public JFS ( )
{
Name = "JFS Plugin" ;
PluginUUID = new Guid ( "D3BE2A41-8F28-4055-94DC-BB6C72A0E9C4" ) ;
}
public JFS ( ImagePlugins . ImagePlugin imagePlugin , ulong partitionStart , ulong partitionEnd )
{
Name = "JFS Plugin" ;
PluginUUID = new Guid ( "D3BE2A41-8F28-4055-94DC-BB6C72A0E9C4" ) ;
}
public override bool Identify ( ImagePlugins . ImagePlugin imagePlugin , ulong partitionStart , ulong partitionEnd )
{
uint bootSectors = JFS_BootBlocksSize / imagePlugin . GetSectorSize ( ) ;
byte [ ] sector = imagePlugin . ReadSector ( partitionStart + bootSectors ) ;
if ( sector . Length < 512 )
return false ;
JFS_SuperBlock jfsSb = new JFS_SuperBlock ( ) ;
IntPtr sbPtr = Marshal . AllocHGlobal ( Marshal . SizeOf ( jfsSb ) ) ;
Marshal . Copy ( sector , 0 , sbPtr , Marshal . SizeOf ( jfsSb ) ) ;
jfsSb = ( JFS_SuperBlock ) Marshal . PtrToStructure ( sbPtr , typeof ( JFS_SuperBlock ) ) ;
Marshal . FreeHGlobal ( sbPtr ) ;
return jfsSb . s_magic = = JFS_Magic ;
}
public override void GetInformation ( ImagePlugins . ImagePlugin imagePlugin , ulong partitionStart , ulong partitionEnd , out string information )
{
information = "" ;
StringBuilder sb = new StringBuilder ( ) ;
uint bootSectors = JFS_BootBlocksSize / imagePlugin . GetSectorSize ( ) ;
byte [ ] sector = imagePlugin . ReadSector ( partitionStart + bootSectors ) ;
if ( sector . Length < 512 )
return ;
JFS_SuperBlock jfsSb = new JFS_SuperBlock ( ) ;
IntPtr sbPtr = Marshal . AllocHGlobal ( Marshal . SizeOf ( jfsSb ) ) ;
Marshal . Copy ( sector , 0 , sbPtr , Marshal . SizeOf ( jfsSb ) ) ;
jfsSb = ( JFS_SuperBlock ) Marshal . PtrToStructure ( sbPtr , typeof ( JFS_SuperBlock ) ) ;
Marshal . FreeHGlobal ( sbPtr ) ;
sb . AppendLine ( "JFS filesystem" ) ;
sb . AppendFormat ( "Version {0}" , jfsSb . s_version ) . AppendLine ( ) ;
sb . AppendFormat ( "{0} blocks of {1} bytes" , jfsSb . s_size , jfsSb . s_bsize ) . AppendLine ( ) ;
sb . AppendFormat ( "{0} blocks per allocation group" , jfsSb . s_agsize ) . AppendLine ( ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . Unicode ) )
sb . AppendLine ( "Volume uses Unicode for directory entries" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . RemountRO ) )
sb . AppendLine ( "Volume remounts read-only on error" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . Continue ) )
sb . AppendLine ( "Volume continues on error" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . Panic ) )
sb . AppendLine ( "Volume panics on error" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . UserQuota ) )
sb . AppendLine ( "Volume has user quotas enabled" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . GroupQuota ) )
sb . AppendLine ( "Volume has group quotas enabled" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . NoJournal ) )
sb . AppendLine ( "Volume is not using any journal" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . Discard ) )
sb . AppendLine ( "Volume sends TRIM/UNMAP commands to underlying device" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . GroupCommit ) )
sb . AppendLine ( "Volume commits in groups of 1" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . LazyCommit ) )
sb . AppendLine ( "Volume commits lazy" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . Temporary ) )
sb . AppendLine ( "Volume does not commit to log" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . InlineLog ) )
sb . AppendLine ( "Volume has log withing itself" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . InlineMoving ) )
sb . AppendLine ( "Volume has log withing itself and is moving it out" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . BadSAIT ) )
sb . AppendLine ( "Volume has bad current secondary ait" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . Sparse ) )
sb . AppendLine ( "Volume supports sparse files" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . DASDEnabled ) )
sb . AppendLine ( "Volume has DASD limits enabled" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . DASDPrime ) )
sb . AppendLine ( "Volume primes DASD on boot" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . SwapBytes ) )
sb . AppendLine ( "Volume is in a big-endian system" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . DirIndex ) )
sb . AppendLine ( "Volume has presistent indexes" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . Linux ) )
sb . AppendLine ( "Volume supports Linux" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . DFS ) )
sb . AppendLine ( "Volume supports DCE DFS LFS" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . OS2 ) )
sb . AppendLine ( "Volume supports OS/2, and is case insensitive" ) ;
if ( jfsSb . s_flags . HasFlag ( JFS_Flags . AIX ) )
sb . AppendLine ( "Volume supports AIX" ) ;
if ( jfsSb . s_state ! = 0 )
sb . AppendLine ( "Volume is dirty" ) ;
sb . AppendFormat ( "Volume was last updated on {0}" , DateHandlers . UNIXUnsignedToDateTime ( jfsSb . s_time . tv_sec , jfsSb . s_time . tv_nsec ) ) . AppendLine ( ) ;
if ( jfsSb . s_version = = 1 )
sb . AppendFormat ( "Volume name: {0}" , Encoding . ASCII . GetString ( jfsSb . s_fpack ) ) . AppendLine ( ) ;
else
sb . AppendFormat ( "Volume name: {0}" , Encoding . ASCII . GetString ( jfsSb . s_label ) ) . AppendLine ( ) ;
sb . AppendFormat ( "Volume UUID: {0}" , jfsSb . s_uuid ) . AppendLine ( ) ;
xmlFSType = new Schemas . FileSystemType ( ) ;
xmlFSType . Type = "JFS filesystem" ;
xmlFSType . Clusters = ( long ) jfsSb . s_size ;
xmlFSType . ClusterSize = ( int ) jfsSb . s_bsize ;
xmlFSType . Bootable = true ;
if ( jfsSb . s_version = = 1 )
xmlFSType . VolumeName = Encoding . ASCII . GetString ( jfsSb . s_fpack ) ;
else
xmlFSType . VolumeName = Encoding . ASCII . GetString ( jfsSb . s_label ) ;
xmlFSType . VolumeSerial = string . Format ( "{0}" , jfsSb . s_uuid ) ;
xmlFSType . ModificationDate = DateHandlers . UNIXUnsignedToDateTime ( jfsSb . s_time . tv_sec , jfsSb . s_time . tv_nsec ) ;
xmlFSType . ModificationDateSpecified = true ;
if ( jfsSb . s_state ! = 0 )
xmlFSType . Dirty = true ;
information = sb . ToString ( ) ;
return ;
}
public override Errno Mount ( )
{
return Errno . NotImplemented ;
}
public override Errno Mount ( bool debug )
{
return Errno . NotImplemented ;
}
public override Errno Unmount ( )
{
return Errno . NotImplemented ;
}
public override Errno MapBlock ( string path , long fileBlock , ref long deviceBlock )
{
return Errno . NotImplemented ;
}
public override Errno GetAttributes ( string path , ref FileAttributes attributes )
{
return Errno . NotImplemented ;
}
public override Errno ListXAttr ( string path , ref List < string > xattrs )
{
return Errno . NotImplemented ;
}
public override Errno GetXattr ( string path , string xattr , ref byte [ ] buf )
{
return Errno . NotImplemented ;
}
public override Errno Read ( string path , long offset , long size , ref byte [ ] buf )
{
return Errno . NotImplemented ;
}
public override Errno ReadDir ( string path , ref List < string > contents )
{
return Errno . NotImplemented ;
}
public override Errno StatFs ( ref FileSystemInfo stat )
{
return Errno . NotImplemented ;
}
public override Errno Stat ( string path , ref FileEntryInfo stat )
{
return Errno . NotImplemented ;
}
public override Errno ReadLink ( string path , ref string dest )
{
return Errno . NotImplemented ;
}
}
}