I know it is/was experimental, but I'm having trouble reading the contents of a .dmg file...

Dec 5, 2013 at 8:11 PM
Edited Dec 5, 2013 at 8:16 PM
Hi Ken,

Although you're not actively developing DiscUtils any more, I appreciate that you seem to take the time to address questions about it.

I would love to be able to read/extract the contents of an un-encrypted .dmg file.

Pardon all the using statements, but my test/P.O.C. code seems to hang when I attempt to create the new HfsPlusFileSystem using the contents of the Dmg.Disk read in from my file.

It doesn't throw an exception or spike memory, but rather just sits there. I will attempt to build the libraries from source so that I can step into the HfsPlusFileSystem constructor, but I am curious to know if something immediately comes to mind.
using (FileStream dmgStream = File.Open(@"C:\Test.dmg", FileMode.Open))
{
  using (DiscUtils.Dmg.Disk disk = new DiscUtils.Dmg.Disk(dmgStream, Ownership.Dispose))
  {
      DiscUtils.SparseStream content = disk.Content;
      using (DiscUtils.HfsPlus.HfsPlusFileSystem fs = new DiscUtils.HfsPlus.HfsPlusFileSystem(content))
      {
        // this line never gets touched.
      }
    }
  }
}
// neither does this line, or anything in between.
I did toggle the Ownership between Dispose and None with no apparent change. The content object has an appropriate-looking length, but the bus seems to stop rolling there.

Thanks for all of your hard work!

-William
Dec 6, 2013 at 10:10 PM
Edited Dec 6, 2013 at 10:10 PM
So, I've made some progress with DiscUtils reading the contents of a .dmg using a VirtualDisk and GetLogicalVolume()[0].Open() to obtain the correct stream for passing into the HfsPlusFileSystem() initializer.

Here is my updated code:
try
{
  VirtualDisk dmgDisk = new DiscUtils.Dmg.Disk(new FileStream(@"C:\Test.dmg", FileMode.Open, FileAccess.Read), Ownership.Dispose);

  VolumeManager vm = new VolumeManager(dmgDisk);

  Stream lvs = vm.GetLogicalVolumes()[0].Open();

  using (DiscUtils.DiscFileSystem dfs = new DiscUtils.HfsPlus.HfsPlusFileSystem(lvs))
  {
    // do something with dfs.  woohoo!
  }
}
catch (Exception e)
{
  // do something with e;
}
Interestingly enough, when I use the pre-compiled DiscUtils.dll as my project reference, this works! When I reference the source project from the same release, the code is different and throws a null reference exception from here in the HfsPlusFileSystemImpl( Stream s ):
FileBuffer extentsBuffer = new FileBuffer(Context, hdr.ExtentsFile, CatalogNodeId.ExtentsFileId);
Context.ExtentsOverflow = new BTree<ExtentKey>(extentsBuffer);
specifically, the exception occurs here with nodeData being the null reference.:
internal BTreeKeyedNode<TKey> GetKeyedNode(uint nodeId)
{
  byte[] nodeData = Utilities.ReadFully(_data, (int)nodeId * _header.NodeSize, _header.NodeSize);

  BTreeKeyedNode<TKey> node = BTreeNode.ReadNode<TKey>(this, nodeData, 0) as BTreeKeyedNode<TKey>;
  node.ReadFrom(nodeData, 0);
  return node;
}
When I looked at the pre-compiled assembly in ILSpy, it shows that it does not contain these two lines:
FileBuffer extentsBuffer = new FileBuffer(Context, hdr.ExtentsFile, CatalogNodeId.ExtentsFileId);
Context.ExtentsOverflow = new BTree<ExtentKey>(extentsBuffer);
So, I just commented them out and everything seems to be working beautifully, I am getting back all of my files now! Beautiful! Maybe you could comment on the role of the Context.ExtentsOverflow and help me understand why it's not working for me?

Thanks so much,
William
Coordinator
Dec 7, 2013 at 10:41 AM
Hi William,

I'm not sure why the binaries and source don't line up. In general, would recommend working from the latest source - lots of fixes that haven't been pushed to a proper release. I've some notion I want to get the VHDX support finished before I do another release - but finding the time to do that has been tricky.

I think I've found the problem with the HFS+ code, and checked in a change (cafa70c896af).


Thanks,

Ken