// /*************************************************************************** // The Disc Image Chef // ---------------------------------------------------------------------------- // // Filename : BTRFS.cs // Author(s) : Natalia Portillo // // Component : B-tree file system plugin. // // --[ Description ] ---------------------------------------------------------- // // Identifies the B-tree file system 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 . // // ---------------------------------------------------------------------------- // Copyright © 2011-2016 Natalia Portillo // ****************************************************************************/ using System; using System.Runtime.InteropServices; using System.Text; using DiscImageChef.Console; using System.Collections.Generic; namespace DiscImageChef.Filesystems { class BTRFS : Filesystem { /// /// BTRFS magic "_BHRfS_M" /// const ulong magic = 0x4D5F53665248425F; public BTRFS() { Name = "B-tree file system"; PluginUUID = new Guid("C904CF15-5222-446B-B7DB-02EAC5D781B3"); } public BTRFS(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) { Name = "B-tree file system"; PluginUUID = new Guid("C904CF15-5222-446B-B7DB-02EAC5D781B3"); } [StructLayout(LayoutKind.Sequential, Pack = 1)] struct SuperBlock { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] public byte[] checksum; public Guid uuid; public ulong pba; public ulong flags; public ulong magic; public ulong generation; public ulong root_lba; public ulong chunk_lba; public ulong log_lba; public ulong log_root_transid; public ulong total_bytes; public ulong bytes_used; public ulong root_dir_objectid; public ulong num_devices; public uint sectorsize; public uint nodesize; public uint leafsize; public uint stripesize; public uint n; public ulong chunk_root_generation; public ulong compat_flags; public ulong compat_ro_flags; public ulong incompat_flags; public ushort csum_type; public byte root_level; public byte chunk_root_level; public byte log_root_level; public DevItem dev_item; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x100)] public string label; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x100)] public byte[] reserved; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x800)] public byte[] chunkpairs; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4D5)] public byte[] unused; } [StructLayout(LayoutKind.Sequential, Pack = 1)] struct DevItem { public ulong id; public ulong bytes; public ulong used; public uint optimal_align; public uint optimal_width; public uint minimal_size; public ulong type; public ulong generation; public ulong start_offset; public uint dev_group; public byte seek_speed; public byte bandwitdh; public Guid device_uuid; public Guid uuid; } public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) { if(partitionStart >= imagePlugin.GetSectors()) return false; ulong sbSectorOff = 0x10000 / imagePlugin.GetSectorSize(); uint sbSectorSize = 0x1000 / imagePlugin.GetSectorSize(); if((sbSectorOff + sbSectorSize) >= imagePlugin.GetSectors()) return false; byte[] sector = imagePlugin.ReadSectors(sbSectorOff + partitionStart, sbSectorSize); SuperBlock btrfsSb; try { GCHandle handle = GCHandle.Alloc(sector, GCHandleType.Pinned); btrfsSb = (SuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(SuperBlock)); handle.Free(); } catch { System.Console.WriteLine("Crash"); return false; } DicConsole.DebugWriteLine("BTRFS Plugin", "sbSectorOff = {0}", sbSectorOff); DicConsole.DebugWriteLine("BTRFS Plugin", "sbSectorSize = {0}", sbSectorSize); DicConsole.DebugWriteLine("BTRFS Plugin", "partitionStart = {0}", partitionStart); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.magic = 0x{0:X16}", btrfsSb.magic); return btrfsSb.magic == magic; } public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information) { StringBuilder sbInformation = new StringBuilder(); xmlFSType = new Schemas.FileSystemType(); information = ""; ulong sbSectorOff = 0x10000 / imagePlugin.GetSectorSize(); uint sbSectorSize = 0x1000 / imagePlugin.GetSectorSize(); byte[] sector = imagePlugin.ReadSectors(sbSectorOff + partitionStart, sbSectorSize); SuperBlock btrfsSb; GCHandle handle = GCHandle.Alloc(sector, GCHandleType.Pinned); btrfsSb = (SuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(SuperBlock)); handle.Free(); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.checksum = {0}", btrfsSb.checksum); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.uuid = {0}", btrfsSb.uuid); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.pba = {0}", btrfsSb.pba); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.flags = {0}", btrfsSb.flags); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.magic = {0}", btrfsSb.magic); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.generation = {0}", btrfsSb.generation); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.root_lba = {0}", btrfsSb.root_lba); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.chunk_lba = {0}", btrfsSb.chunk_lba); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.log_lba = {0}", btrfsSb.log_lba); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.log_root_transid = {0}", btrfsSb.log_root_transid); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.total_bytes = {0}", btrfsSb.total_bytes); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.bytes_used = {0}", btrfsSb.bytes_used); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.root_dir_objectid = {0}", btrfsSb.root_dir_objectid); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.num_devices = {0}", btrfsSb.num_devices); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.sectorsize = {0}", btrfsSb.sectorsize); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.nodesize = {0}", btrfsSb.nodesize); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.leafsize = {0}", btrfsSb.leafsize); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.stripesize = {0}", btrfsSb.stripesize); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.n = {0}", btrfsSb.n); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.chunk_root_generation = {0}", btrfsSb.chunk_root_generation); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.compat_flags = 0x{0:X16}", btrfsSb.compat_flags); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.compat_ro_flags = 0x{0:X16}", btrfsSb.compat_ro_flags); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.incompat_flags = 0x{0:X16}", btrfsSb.incompat_flags); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.csum_type = {0}", btrfsSb.csum_type); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.root_level = {0}", btrfsSb.root_level); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.chunk_root_level = {0}", btrfsSb.chunk_root_level); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.log_root_level = {0}", btrfsSb.log_root_level); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.id = 0x{0:X16}", btrfsSb.dev_item.id); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.bytes = {0}", btrfsSb.dev_item.bytes); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.used = {0}", btrfsSb.dev_item.used); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.optimal_align = {0}", btrfsSb.dev_item.optimal_align); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.optimal_width = {0}", btrfsSb.dev_item.optimal_width); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.minimal_size = {0}", btrfsSb.dev_item.minimal_size); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.type = {0}", btrfsSb.dev_item.type); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.generation = {0}", btrfsSb.dev_item.generation); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.start_offset = {0}", btrfsSb.dev_item.start_offset); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.dev_group = {0}", btrfsSb.dev_item.dev_group); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.seek_speed = {0}", btrfsSb.dev_item.seek_speed); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.bandwitdh = {0}", btrfsSb.dev_item.bandwitdh); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.device_uuid = {0}", btrfsSb.dev_item.device_uuid); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.uuid = {0}", btrfsSb.dev_item.uuid); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.label = {0}", btrfsSb.label); sbInformation.AppendLine("B-tree filesystem"); sbInformation.AppendFormat("UUID: {0}", btrfsSb.uuid); sbInformation.AppendFormat("This superblock resides on physical block {0}", btrfsSb.pba); sbInformation.AppendFormat("Root tree starts at LBA {0}", btrfsSb.root_lba); sbInformation.AppendFormat("Chunk tree starts at LBA {0}", btrfsSb.chunk_lba); sbInformation.AppendFormat("Log tree starts at LBA {0}", btrfsSb.log_lba); sbInformation.AppendFormat("Volume has {0} bytes spanned in {1} devices", btrfsSb.total_bytes, btrfsSb.num_devices); sbInformation.AppendFormat("Volume has {0} bytes used", btrfsSb.bytes_used); sbInformation.AppendFormat("{0} bytes/sector", btrfsSb.sectorsize); sbInformation.AppendFormat("{0} bytes/node", btrfsSb.nodesize); sbInformation.AppendFormat("{0} bytes/leaf", btrfsSb.leafsize); sbInformation.AppendFormat("{0} bytes/stripe", btrfsSb.stripesize); sbInformation.AppendFormat("Flags: 0x{0:X}", btrfsSb.flags); sbInformation.AppendFormat("Compatible flags: 0x{0:X}", btrfsSb.compat_flags); sbInformation.AppendFormat("Read-only compatible flags: 0x{0:X}", btrfsSb.compat_ro_flags); sbInformation.AppendFormat("Incompatible flags: 0x{0:X}", btrfsSb.incompat_flags); sbInformation.AppendFormat("Device's UUID: {0}", btrfsSb.dev_item.uuid); sbInformation.AppendFormat("Volume label: {0}", btrfsSb.label); information = sbInformation.ToString(); xmlFSType = new Schemas.FileSystemType(); xmlFSType.Clusters = (long)(btrfsSb.total_bytes / btrfsSb.sectorsize); xmlFSType.ClusterSize = (int)btrfsSb.sectorsize; xmlFSType.FreeClusters = xmlFSType.Clusters - (long)(btrfsSb.bytes_used / btrfsSb.sectorsize); xmlFSType.FreeClustersSpecified = true; xmlFSType.VolumeName = btrfsSb.label; xmlFSType.VolumeSerial = string.Format("{0}", btrfsSb.uuid); xmlFSType.VolumeSetIdentifier = string.Format("{0}", btrfsSb.dev_item.device_uuid); xmlFSType.Type = Name; } 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 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 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; } } }