1

I have a Python program that applies or removes multiple layers of encryption from a file. In this case, I have to open a DMG to access the ZIP file inside. I have used hidutil to make the DMG, but I am stuck on how to open it and access the file -- any method that I've seen relies on mounting, accessing the mount point and unmounting, which I cannot do without intelligently searching for where it was mounted to.

How do I do this? It doesn't have to be in Python, a Bash solution is fine.

3 Answers3

5

You can list and extract the contents of a DMG file with 7zip - the website is here.

On macOS, 7zip can be installed with homebrew using:

brew install p7zip

Then if you have a DMG file, you can list the contents with:

7z l SomeDisk.dmg

Sample Output

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=utf8,Utf16=on,HugeFiles=on,64 bits,8 CPUs x64)

...
...

Modified = 2018-01-14 13:28:17

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2018-01-14 13:28:16 D....                            MyFunkyDMG
2018-01-14 13:28:16 D....                            MyFunkyDMG/.HFS+ Private Directory Data
2018-01-14 13:28:17 .....       524288       524288  MyFunkyDMG/.journal
2018-01-14 13:28:16 .....         4096         4096  MyFunkyDMG/.journal_info_block
2017-08-27 13:50:45 .....          255         4096  MyFunkyDMG/client.py
2017-08-27 13:49:22 .....          356         4096  MyFunkyDMG/server.py
2018-01-14 13:28:16 D....                            MyFunkyDMG/[HFS+ Private Data]
------------------- ----- ------------ ------------  ------------------------
2018-01-14 13:28:17             528995       536576  4 files, 3 folders

Then you can extract, say to a new directory called FRED with:

7z x -oFRED SomeDisk.dmg 

A benefit of using 7zip is that the disk doesn't suddenly flash up on your Desktop as being mounted.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • Is there a way to do this that is included already on macOS rather than get the user to download a different tool? –  Jan 16 '18 at 06:04
1

Here's a bash version which parses the hdiutil output to extract the mount point for zip file access and the dev entry for detaching afterwards:

#!/bin/bash

dmg_path="$1"

# use process redirection to capture the mount point and dev entry
IFS=$'\n' read -rd '\n' mount_point dev_entry < <(
    # mount the diskimage; leave out -readonly if making changes to the filesystem
    hdiutil attach -readonly -plist "$dmg_path" | \

    # convert output plist to json
    plutil -convert json - -o - | \

    # extract mount point and dev entry
    jq -r '
        .[] | .[] |
        select(."volume-kind" == "hfs") |
        ."mount-point" + "\n" + ."dev-entry"
    '
)

# work with the zip file
ls "$mount_point/*.zip"

# unmount the disk image
hdiutil detach "$dev_entry"
Cole Tierney
  • 9,571
  • 1
  • 27
  • 35
  • I get the error `./test.sh: line 12: jq: command not found` and from there `ls: /*.zip: No such file or directory` and `hdiutil: detach failed - No such file or directory`. This is on macOS, are these packages installed by default? –  Jan 15 '18 at 07:29
  • Sorry, I should've listed jq as a dependency. It's so handy, I'm beginning to take it for granted. It's like sed for json. It could be replaced with an xpath xml tool, if you want. – Cole Tierney Jan 15 '18 at 11:11
  • This example works, but only on every second run. The problem is "hdiutil attach -plist" will only return mount point details if run on already mounted dmg. So it fails once, but works when you run it again. You have to add one more "hdiutil attach" for this to work correctly. – Mirko Jan 17 '20 at 03:23
  • Thanks for the note! – Cole Tierney Jan 17 '20 at 16:13
  • You don’t need to go to all the trouble of parsing the output of `hdiutil` to find out where it’s mounted. Use the `-mountpoint` option to pick the location yourself. – Jim Nov 20 '21 at 06:10
0

Based on this answer you can use hdiutil info -plist to get the mount point for a dmg through Python. That way you can mount, find mount point, list contents, and unmount intelligently.

jcragun
  • 2,060
  • 10
  • 8