/* This file is part of apfs-fuse, a read-only implementation of APFS (Apple File System) for FUSE. Copyright (C) 2017 Simon Gander Apfs-fuse is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Apfs-fuse 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 General Public License for more details. You should have received a copy of the GNU General Public License along with apfs-fuse. If not, see . */ #include #include #include "ApfsContainer.h" #include "ApfsVolume.h" #include "Util.h" #include "BlockDumper.h" #include "Global.h" int g_debug = 0; ApfsContainer::ApfsContainer(Disk &disk, uint64_t start, uint64_t len) : m_disk(disk), m_part_start(start), m_part_len(len), m_nodemap_vol(*this), m_nidmap_bt(*this), m_oldmgr_bt(*this), m_oldvol_bt(*this) { } ApfsContainer::~ApfsContainer() { } bool ApfsContainer::Init() { std::vector blk; blk.resize(0x1000); if (!m_disk.Read(blk.data(), m_part_start, 0x1000)) return false; memcpy(&m_sb, blk.data(), sizeof(APFS_Superblock_NXSB)); if (m_sb.signature != 0x4253584E) return false; if (m_sb.block_size != 0x1000) { blk.resize(m_sb.block_size); m_disk.Read(blk.data(), m_part_start, blk.size()); } if (!VerifyBlock(blk.data(), blk.size())) return false; memcpy(&m_sb, blk.data(), sizeof(APFS_Superblock_NXSB)); m_nodemap_vol.Init(m_sb.blockid_volhdr, m_sb.hdr.version); return true; } ApfsVolume * ApfsContainer::GetVolume(int index) { ApfsVolume *vol = nullptr; uint64_t nodeid; uint64_t blkid; if (index >= 100) return nullptr; nodeid = m_sb.nodeid_apsb[index]; if (nodeid == 0) return nullptr; blkid = m_nodemap_vol.GetBlockID(nodeid, m_sb.hdr.version); // std::cout << std::hex << "Loading Volume " << index << ", nodeid = " << nodeid << ", version = " << m_sb.hdr.version << ", blkid = " << blkid << std::endl; if (blkid == 0) return nullptr; vol = new ApfsVolume(*this); vol->Init(blkid); return vol; } int ApfsContainer::GetVolumeCnt() const { int k; for (k = 0; k < 100; k++) { if (m_sb.nodeid_apsb[k] == 0) break; } return k; } bool ApfsContainer::ReadBlocks(byte_t * data, uint64_t blkid, uint64_t blkcnt) const { uint64_t offs; uint64_t size; if ((blkid + blkcnt) > m_sb.block_count) return false; offs = m_sb.block_size * blkid; size = m_sb.block_size * blkcnt; return m_disk.Read(data, offs, size); } bool ApfsContainer::ReadAndVerifyHeaderBlock(byte_t * data, uint64_t blkid) const { if (!ReadBlocks(data, blkid)) return false; if (!VerifyBlock(data, m_sb.block_size)) return false; return true; } void ApfsContainer::dump(BlockDumper& bd) { std::vector blk; uint64_t blkid; blk.resize(GetBlocksize()); ReadAndVerifyHeaderBlock(blk.data(), 0); bd.DumpNode(blk.data(), 0); for (blkid = m_sb.blockid_sb_area_start; blkid < (m_sb.blockid_sb_area_start + m_sb.sb_area_cnt); blkid++) { ReadAndVerifyHeaderBlock(blk.data(), blkid); bd.DumpNode(blk.data(), blkid); } #if 0 for (blkid = m_sb.blockid_spaceman_area_start; blkid < (m_sb.blockid_spaceman_area_start + m_sb.spaceman_area_cnt); blkid++) { ReadAndVerifyHeaderBlock(blk.data(), blkid); bd.DumpNode(blk.data(), blkid); } #endif m_nodemap_vol.dump(bd); // m_nidmap_bt.dump(bd); // m_oldmgr_bt.dump(bd); // m_oldvol_bt.dump(bd); }