Skip to content

Instantly share code, notes, and snippets.

@joevt
Last active August 28, 2025 07:03
Show Gist options
  • Save joevt/a99e3af71343d8242e0078ab4af39b6c to your computer and use it in GitHub Desktop.
Save joevt/a99e3af71343d8242e0078ab4af39b6c to your computer and use it in GitHub Desktop.

Revisions

  1. joevt revised this gist Aug 28, 2025. 1 changed file with 30 additions and 8 deletions.
    38 changes: 30 additions & 8 deletions dumpvols.sh
    Original file line number Diff line number Diff line change
    @@ -133,7 +133,11 @@ inodestring () {
    local thepath;
    thepath="$(inodetopath "$deviceid" "$inode")"
    printf "%d" "$inode"
    [[ -n $thepath ]] && printf " => \"%s\"" "$thepath"
    if [[ -n $thepath ]]; then
    printf " => \"%s\"" "$thepath"
    elif ((inode == 2)); then
    printf " => root directory of volume"
    fi
    }

    forkdatastring () {
    @@ -255,6 +259,8 @@ DRIVELIST="$(sed -n -E "
    for PARTDRIVE in $(echo $DRIVELIST); do
    DRIVE=$(expr "$PARTDRIVE" : '.*_\([^_]*\)')
    DTYPE=$(expr "$PARTDRIVE" : '\(.*\)_[^_]*')
    #echo "DRIVE = <<$DRIVE>>"
    #echo "DTYPE = <<$DTYPE>>"
    echo "==============================================================================="

    diskutiloutput="$(sed -nE '/\/dev\/'"$DRIVE"'( |$)/,/^$/ p' <<< "${disklist}")"
    @@ -267,25 +273,29 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    if [[ -z $BLOCKSIZE ]]; then
    BLOCKSIZE=512
    fi
    #echo "BLOCKSIZE = <<$BLOCKSIZE>>"

    TOTALSIZE=$((
    $(diskutil info -plist disk16 | perl -0777 -ne 'if (m|<key>TotalSize</key>\s*<integer>(\d+)</integer>|) { print $1 }')
    $(diskutil info -plist $DRIVE | perl -0777 -ne 'if (m|<key>TotalSize</key>\s*<integer>(\d+)</integer>|) { print $1 }')
    / BLOCKSIZE
    ))
    #echo "TOTALSIZE = <<$TOTALSIZE>>"

    MOUNTPOINTS=""
    if [[ -n $INPUTSLICE ]]; then
    DEVLIST="$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s${INPUTSLICE})$/s//\1/p")"
    SLICELIST="$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s${INPUTSLICE})$/s//\1/p")"
    else
    DEVLIST="$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s[0-9]+)$/s//\1/p")"
    SLICELIST="$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s[0-9]+)$/s//\1/p")"
    fi
    #echo "SLICELIST = <<$SLICELIST>>"

    for THEDEV in $(echo $DEVLIST); do
    for THESLICE in $(echo $SLICELIST); do
    echo "---------------------------------------------"
    partinfo="$(diskutil info "$THEDEV")"
    partinfo="$(diskutil info "$THESLICE")"
    echo "$partinfo"
    MOUNTPOINTS="${MOUNTPOINTS}${THEDEV}_$(sed -nE '/ *Mount Point: *(.*)/s//\1/p' <<< "$partinfo")"$'\n'
    MOUNTPOINTS="${MOUNTPOINTS}${THESLICE}_$(sed -nE '/ *Mount Point: *(.*)/s//\1/p' <<< "$partinfo")"$'\n'
    done
    echo "MOUNTPOINTS: $MOUNTPOINTS"
    echo "---------------------------------------------"

    PARTLIST=""
    @@ -408,17 +418,29 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    else
    DEVICEID=$(stat -f "%r" "/dev/${DRIVE}")
    fi
    #echo "PNUM = <<$PNUM>>"
    #echo "PSTART = <<$PSTART>>"
    #echo "PLENGTH = <<$PLENGTH>>"
    #echo "PTYPE = <<$PTYPE>>"
    #echo "DEVICEID = <<$DEVICEID>>"

    POFFSETS="_0"
    while [[ -n $POFFSETS ]]; do
    POFFSET=$( expr "$POFFSETS" : '_\([0-9]*\)')
    POFFSETS=$( expr "$POFFSETS" : '_[0-9]*\(_.*\)')
    #echo "POFFSET: <<$POFFSET>>"

    if (( POFFSET >= PLENGTH )); then
    continue
    fi

    blockbytes=$(dd if="/dev/$DRIVE" bs="$BLOCKSIZE" skip=$((PSTART + POFFSET)) count=1 2> /dev/null | xxd -p -c 9999)
    blockbytes=$(
    {
    dd if="/dev/$DRIVE" bs="$BLOCKSIZE" skip=$((PSTART + POFFSET)) count=1 2> /dev/null || \
    dd if="/dev/r$DRIVE" bs="$BLOCKSIZE" skip=$((PSTART + POFFSET)) count=1 2> /dev/null
    } | xxd -p -c 9999
    )
    #echo "blockbytes: <<$blockbytes>>"

    if [[ $PTYPE = "Apple_Patches" ]]; then

  2. joevt revised this gist Mar 20, 2025. 1 changed file with 92 additions and 6 deletions.
    98 changes: 92 additions & 6 deletions dumpvols.sh
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    #
    # Get Partition Info from all disks
    #
    # Written by joevt updated March 16, 2024
    # Written by joevt updated March 20, 2025
    # Patches marked "rgh" July, 2010, to dump information beyond the
    # four bios partitions
    #
    @@ -33,6 +33,9 @@ else
    fi
    [[ "${apfslist:0:4}" == "Disk" ]] && apfslist=""

    #echo "disklist = <<${disklist}>>"
    #echo "apfslist = <<${apfslist}>>"

    MBRHASHES="
    Windows_XP=d88d4f2dbc2c662db7d7d60ebf9e3e00
    Windows_Vista=12c9d7ff4914c88a7f9eadf9211b861b
    @@ -172,6 +175,7 @@ dumpencoding () {
    local encoding="$2"
    ((encoding)) && {
    printf "%s 0x%08x" "$message" "$encoding"
    # 656e63 = enc
    (( (encoding & 0x656e6300) == 0x656e6300 )) && {
    case $((encoding & 0xff)) in
    0) printf " = kTextEncodingMacRoman" ;;
    @@ -217,6 +221,9 @@ dumpencoding () {
    esac
    }
    printf "\n"
    } || {
    printf "%s 0x%08x" "$message" "$encoding"
    printf "\n"
    }
    }

    @@ -239,7 +246,11 @@ vsdbtouuid () {
    (( ALLDISKS )) && echo "$disklist"
    echo "$apfslist"

    DRIVELIST="$(sed -n -E "/^[ ]*0: [ ]{0,25}([A-Za-z_]+)[ ]*[+*][0-9.]+ [TGMK][iB][ ]+(disk[0-9]+)$/s//\1_\2/p;/^[ ]*0: [ ]{0,26} .* \*[0-9.]+ [TGMK][iB][ ]+(disk[0-9]+)$/s//whole_\1/p" <<< "$disklist")"
    DRIVELIST="$(sed -n -E "
    /^[ ]*0: [ ]{0,25}([A-Za-z_]+)[ ]*[+*][0-9.]+ [TGMK][iB][ ]+(disk[0-9]+)$/s//\1_\2/p;
    /^[ ]*0: [ ]{0,26} .* [*+][0-9.]+ [TGMK][iB][ ]+(disk[0-9]+)$/s//whole_\1/p
    " <<< "$disklist")"
    #echo "DRIVELIST = <<${DRIVELIST}>>"

    for PARTDRIVE in $(echo $DRIVELIST); do
    DRIVE=$(expr "$PARTDRIVE" : '.*_\([^_]*\)')
    @@ -257,6 +268,11 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    BLOCKSIZE=512
    fi

    TOTALSIZE=$((
    $(diskutil info -plist disk16 | perl -0777 -ne 'if (m|<key>TotalSize</key>\s*<integer>(\d+)</integer>|) { print $1 }')
    / BLOCKSIZE
    ))

    MOUNTPOINTS=""
    if [[ -n $INPUTSLICE ]]; then
    DEVLIST="$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s${INPUTSLICE})$/s//\1/p")"
    @@ -377,12 +393,21 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    PARTLIST="$(sed -nE "/^${INPUTSLICE}_/p" <<< "$PARTLIST")"
    fi

    if [[ -z $PARTLIST ]]; then
    PARTLIST="0_0_$TOTALSIZE"
    fi

    #echo "PARTLIST = <<${PARTLIST}>>"
    for THEPART in $(echo $PARTLIST); do
    PNUM=$( expr "$THEPART" : '\([0-9]*\)_')
    PSTART=$( expr "$THEPART" : '[0-9]*_\([0-9]*\)_[0-9]*')
    PLENGTH=$(expr "$THEPART" : '[0-9]*_[0-9]*_\([0-9]*\)')
    PTYPE=$( expr "$THEPART" : '[0-9]*_[0-9]*_[0-9]*_\(.*\)')
    DEVICEID=$(stat -f "%r" "/dev/${DRIVE}s$PNUM")
    if ((PNUM)); then
    DEVICEID=$(stat -f "%r" "/dev/${DRIVE}s$PNUM")
    else
    DEVICEID=$(stat -f "%r" "/dev/${DRIVE}")
    fi

    POFFSETS="_0"
    while [[ -n $POFFSETS ]]; do
    @@ -646,6 +671,67 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    #printf "queued first MDB after boot blocks: $POFFSETS\n"


    elif [[ ${blockbytes:0:4} == "D2D7" ]]; then # 'RW'+0x8080
    # Master Directory Blocks # https://developer.apple.com/library/archive/documentation/mac/pdf/Files/File_Manager.pdf

    # MDB
    #drSigWord=${blockbytes:0x000*2:4}
    drCrDate=$((0x${blockbytes:0x002*2:8}))
    drLsBkUp=$((0x${blockbytes:0x006*2:8}))
    drAtrb=$((0x${blockbytes:0x00a*2:4}))
    drNmFls=$((0x${blockbytes:0x00c*2:4}))
    drDirSt=$((0x${blockbytes:0x00e*2:4}))
    drBlLen=$((0x${blockbytes:0x010*2:4}))
    drNmAlBlks=$((0x${blockbytes:0x012*2:4}))
    drAlBlkSiz=$((0x${blockbytes:0x014*2:8}))
    drClpSiz=$((0x${blockbytes:0x018*2:8}))
    drAlBlSt=$((0x${blockbytes:0x01c*2:4}))
    drNxtfNum=$((0x${blockbytes:0x01e*2:8}))
    drFreeBks=$((0x${blockbytes:0x022*2:4}))
    drVN="$(pascalstring "${blockbytes:0x024*2:28*2}")"

    echo
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Master Directory Block contents"

    printf "000: drSigWord : 'RW'+0x8080 = kMFSSigWord\n"
    printf "002: drCrDate : %s\n" "$( ((drCrDate)) && date -r $((drCrDate-2082844800)))"
    printf "006: drLsBkUp : %s\n" "$( ((drLsBkUp )) && date -r $((drLsBkUp -2082844800)))"
    ((drAtrb)) && {
    attributestext=$(
    ((drAtrb & 0x0080)) && printf ",VolumeHardwareLock"
    ((drAtrb & 0x0100)) && printf ",VolumeUnmounted"
    ((drAtrb & 0x0200)) && printf ",VolumeSparedBlocks"
    ((drAtrb & 0x0400)) && printf ",VolumeNoCacheRequired"
    ((drAtrb & 0x0800)) && printf ",BootVolumeInconsistent"
    ((drAtrb & 0x1000)) && printf ",CatalogNodeIDsReused"
    ((drAtrb & 0x2000)) && printf ",VolumeJournaled"
    ((drAtrb & 0x4000)) && printf ",VolumeInconsistent"
    ((drAtrb & 0x8000)) && printf ",VolumeSoftwareLock"
    ((drAtrb & 0x007f)) && printf ",0x%04x?" $((drAtrb & 0x007f))
    )
    printf "00a: drAtrb : 0x%04x = %s\n" "$drAtrb" "${attributestext:1}"
    }

    printf "00c: drNmFls : %d\n" "$drNmFls"
    printf "00e: drDirSt : %d\n" "$drDirSt"
    printf "010: drBlLen : %d\n" "$drBlLen"
    printf "012: drNmAlBlks : %d\n" "$drNmAlBlks"
    printf "014: drAlBlkSiz : %d\n" "$drAlBlkSiz"
    printf "018: drClpSiz : %d\n" "$drClpSiz"
    printf "01c: drAlBlSt : %d\n" "$drAlBlSt"
    printf "01e: drNxtfNum : %d\n" "$drNxtfNum"
    printf "022: drFreeBks : %d\n" "$drFreeBks"
    printf "024: drVN : %s\n" "$drVN"

    echo
    xxd -p -r <<< "$blockbytes" | xxd -c 16

    if ((POFFSET < drNmAlBlks * (drAlBlkSiz / 512) - 2)); then
    # queue up location of alternate Master Directory Block
    POFFSETS="_$((PLENGTH-2))_$((PLENGTH-1))${POFFSETS}"
    #printf "queued 2alternate MDB: $POFFSETS \n"
    fi

    elif [[ ${blockbytes:0:4} == "4244" ]]; then # 'BD'
    # Master Directory Blocks # https://developer.apple.com/library/archive/documentation/mac/pdf/Files/File_Manager.pdf

    @@ -784,7 +870,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    checkedDate=$((0x${blockbytes:0x01c*2:8}))
    fileCount=$((0x${blockbytes:0x020*2:8}))
    folderCount=$((0x${blockbytes:0x024*2:8}))
    blockSize=$((0x${blockbytes:0x028*2:8}))
    mdbblockSize=$((0x${blockbytes:0x028*2:8}))
    totalBlocks=$((0x${blockbytes:0x02c*2:8}))
    freeBlocks=$((0x${blockbytes:0x030*2:8}))
    nextAllocation=$((0x${blockbytes:0x034*2:8}))
    @@ -844,7 +930,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    printf "01c: checkedDate : %s\n" "$( ((checkedDate)) && date -r $((checkedDate-2082844800)))"
    printf "020: fileCount : %d\n" "$fileCount"
    printf "024: folderCount : %d\n" "$folderCount"
    printf "028: blockSize : %d\n" "$blockSize"
    printf "028: blockSize : %d\n" "$mdbblockSize"
    printf "02c: totalBlocks : %d\n" "$totalBlocks"
    printf "030: freeBlocks : %d\n" "$freeBlocks"
    printf "034: nextAllocation : %d\n" "$nextAllocation"
    @@ -919,7 +1005,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    # queue up location of alternate HFS Plus Volume Header

    # HFS+ volume starts at POFFSET - 2
    endoffset=$((POFFSET - 2 + totalBlocks * (blockSize / 512)))
    endoffset=$((POFFSET - 2 + totalBlocks * (mdbblockSize / 512)))

    POFFSETS="_$((endoffset - 2))_$((endoffset - 1))${POFFSETS}"
    #printf "queued alternate HFS+ Header: $POFFSETS\n"
  3. joevt revised this gist Mar 16, 2024. 1 changed file with 23 additions and 24 deletions.
    47 changes: 23 additions & 24 deletions dumpvols.sh
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    #
    # Get Partition Info from all disks
    #
    # Written by joevt updated August 15, 2023
    # Written by joevt updated March 16, 2024
    # Patches marked "rgh" July, 2010, to dump information beyond the
    # four bios partitions
    #
    @@ -239,7 +239,7 @@ vsdbtouuid () {
    (( ALLDISKS )) && echo "$disklist"
    echo "$apfslist"

    DRIVELIST="$(sed -n -E "/^[ ]*0: [ ]{0,25}([A-Za-z_]+)[ ]*[+*][0-9.]+ [TGMK]B[ ]+(disk[0-9]+)$/s//\1_\2/p;/^[ ]*0: [ ]{0,26} .* \*[0-9.]+ [TGMK]B[ ]+(disk[0-9]+)$/s//whole_\1/p" <<< "$disklist")"
    DRIVELIST="$(sed -n -E "/^[ ]*0: [ ]{0,25}([A-Za-z_]+)[ ]*[+*][0-9.]+ [TGMK][iB][ ]+(disk[0-9]+)$/s//\1_\2/p;/^[ ]*0: [ ]{0,26} .* \*[0-9.]+ [TGMK][iB][ ]+(disk[0-9]+)$/s//whole_\1/p" <<< "$disklist")"

    for PARTDRIVE in $(echo $DRIVELIST); do
    DRIVE=$(expr "$PARTDRIVE" : '.*_\([^_]*\)')
    @@ -383,22 +383,22 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    PLENGTH=$(expr "$THEPART" : '[0-9]*_[0-9]*_\([0-9]*\)')
    PTYPE=$( expr "$THEPART" : '[0-9]*_[0-9]*_[0-9]*_\(.*\)')
    DEVICEID=$(stat -f "%r" "/dev/${DRIVE}s$PNUM")

    POFFSETS="_0"
    while [[ -n $POFFSETS ]]; do
    POFFSET=$( expr "$POFFSETS" : '_\([0-9]*\)')
    POFFSETS=$( expr "$POFFSETS" : '_[0-9]*\(_.*\)')

    if (( POFFSET >= PLENGTH )); then
    continue
    fi

    blockbytes=$(dd if="/dev/$DRIVE" bs="$BLOCKSIZE" skip=$((PSTART + POFFSET)) count=1 2> /dev/null | xxd -p -c 9999)

    if [[ $PTYPE = "Apple_Patches" ]]; then

    # Patches # https://developer.apple.com/library/archive/technotes/tn/tn1189.html#SecretsOfThePartitionMap

    echo
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Driver Patches"

    @@ -442,7 +442,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    printf "%03x: patchName : %s\n" $((byteoffset+28)) "$patchName"
    printf "%03x: patchVendor : %s\n" $((byteoffset+61)) "$patchVendor"
    [[ -n $patchPad ]] && printf "%03x: patchPad : %s\n" $((byteoffset+62+patchVendorLen)) "$patchPad"

    ((byteoffset+=patchDescriptorLen))
    done # for numPatches

    @@ -486,7 +486,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    printf " %10d @ %-10d" \
    "$pmPartBlkCnt" \
    "$pmPyPartStart"

    [[ $pmSig != 504d ]] && printf " Sig:0x%s?" "$pmSig"
    [[ -n $pmParType ]] && printf " Type:\"%s\"" "$pmParType"
    [[ -n $pmPartName ]] && printf " Name:\"%s\"" "$pmPartName"
    @@ -543,7 +543,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do

    elif [[ ${blockbytes:0:4} == "4c4b" ]]; then # 'LK'
    # Boot Blocks # https://developer.apple.com/library/archive/documentation/mac/pdf/Files/File_Manager.pdf

    # BootBlkHdr
    #bbID=$((0x${blockbytes:0:4}))
    bbEntry=$((0x${blockbytes:4:8}))
    @@ -564,7 +564,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    filler=$((0x${blockbytes:276:4}))
    bbSysHeapExtra=$((0x${blockbytes:280:8}))
    bbSysHeapFract=$((0x${blockbytes:288:8}))

    echo
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Boot Block Header contents"

    @@ -604,7 +604,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    }
    printf "\n"
    }

    ((bbPageFlags)) && {
    # https://developer.apple.com/library/archive/technotes/dv/dv_03.html#//apple_ref/doc/uid/DTS10002393
    printf "008: bbPageFlags : 0x%04x =" "$bbPageFlags"
    @@ -640,15 +640,15 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    echo
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): 2nd Boot Block contents"
    xxd -p -r <<< "$blockbytes" | xxd -c 16

    ((POFFSET++))
    POFFSETS="_${POFFSET}${POFFSETS}"
    #printf "queued first MDB after boot blocks: $POFFSETS\n"


    elif [[ ${blockbytes:0:4} == "4244" ]]; then # 'BD'
    # Master Directory Blocks # https://developer.apple.com/library/archive/documentation/mac/pdf/Files/File_Manager.pdf

    # MDB
    #drSigWord=${blockbytes:0x000*2:4}
    drCrDate=$((0x${blockbytes:0x002*2:8}))
    @@ -686,7 +686,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    drXTExtRec="${blockbytes:0x086*2:24}"
    drCTFlSize=$((0x${blockbytes:0x092*2:8}))
    drCTExtRec="${blockbytes:0x096*2:24}"

    echo
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Master Directory Block contents"

    @@ -708,7 +708,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    )
    printf "00a: drAtrb : 0x%04x = %s\n" "$drAtrb" "${attributestext:1}"
    }

    printf "00c: drNmFls : %d\n" "$drNmFls"
    printf "00e: drVBMSt : %d\n" "$drVBMSt"
    printf "010: drAllocPtr : %d\n" "$drAllocPtr"
    @@ -745,7 +745,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    printf "07e: drVBMCSize : %d\n" "$drVBMCSize"
    printf "080: drCtlCSize : %d\n" "$drCtlCSize"
    fi

    printf "082: drXTFlSize : %d\n" "$drXTFlSize"
    printf "086: drXTExtRec : %s\n" "$(extentstring "$drXTExtRec")"
    printf "092: drCTFlSize : %d\n" "$drCTFlSize"
    @@ -758,7 +758,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    # queue up location of alternate Master Directory Block
    POFFSETS="_$((PLENGTH-2))_$((PLENGTH-1))${POFFSETS}"
    #printf "queued 2alternate MDB: $POFFSETS \n"

    if (( drEmbedSigWord == 0x482b )); then
    # queue up location of wrapped HFS+ partition
    hfsplusblock=$(( drAlBlSt + drEmbedExtent_startBlock * (drAlBlkSiz / 512) ))
    @@ -769,7 +769,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do

    elif [[ ${blockbytes:0:4} == "482b" ]] || [[ ${blockbytes:0:4} == "4858" ]]; then # 'H+' or 'HX'
    # Master Directory Blocks # https://developer.apple.com/library/archive/documentation/mac/pdf/Files/File_Manager.pdf

    # HFS Plus Volume Header
    signature=$((0x${blockbytes:0x000*2:4}))
    signatureChars=$(sed -E 's/(00)+$//' <<< "${blockbytes:0x000*2:4}" | xxd -p -r | tr '\0' '.')
    @@ -807,7 +807,7 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    ((signature == 0x482b )) && printf " = kHFSPlusSigWord"
    ((signature == 0x4858 )) && printf " = kHFSXSigWord"
    printf "\n"

    printf "002: version : %d" "$version"
    ((version == 4 )) && printf " = kHFSPlusVersion"
    ((version == 5 )) && printf " = kHFSXVersion"
    @@ -917,10 +917,10 @@ for PARTDRIVE in $(echo $DRIVELIST); do

    if ((POFFSET < PLENGTH-4)); then
    # queue up location of alternate HFS Plus Volume Header

    # HFS+ volume starts at POFFSET - 2
    endoffset=$((POFFSET - 2 + totalBlocks * (blockSize / 512)))

    POFFSETS="_$((endoffset - 2))_$((endoffset - 1))${POFFSETS}"
    #printf "queued alternate HFS+ Header: $POFFSETS\n"
    fi
    @@ -935,10 +935,9 @@ for PARTDRIVE in $(echo $DRIVELIST); do
    ((POFFSET==0)) && printf "VBR "
    )contents" "$VBRHASHES" "$HASH"
    fi

    if [[ -n ${blockbytes//0/} ]]; then
    xxd -p -r <<< "$blockbytes" | xxd -c 16
    POFFSETS=""
    elif [[ -z $POFFSETS ]] && (( POFFSET < 2 )); then
    POFFSETS="_$((POFFSET+1))"
    #printf "queued after zero block: $POFFSETS\n"
    @@ -955,7 +954,7 @@ if [[ -n $INPUTDISK ]]; then
    ioreg -w 0 -c IOMedia | sed -n -E "/^[ \|]*\+\-o (.*) <class IOMedia[^a-zA-Z]/,/^[ \|]+ }$/p" | {
    sed -n -E "/^[ \|]*\+\-o (.*)/s//\1/p;/^[ \|]* \| (.*)/s//\1/p;"
    } | {
    perl -0777 -nE 'while (/(^.*? <class IOMedia.*\n\{\n( .*\n)*^ "BSD Name" = "('"$INPUTDISK"'[^\d]|'"${INPUTDISK/s[0-9]*/}"'").*\n( .*\n)*?^}\n)/mg) { printf "$1\n" }'
    perl -0777 -n -e 'while (/(^.*? <class IOMedia.*\n\{\n( .*\n)*^ "BSD Name" = "('"$INPUTDISK"'[^\d]|'"${INPUTDISK/s[0-9]*/}"'").*\n( .*\n)*?^}\n)/mg) { printf "$1\n" }'
    }
    echo "==============================================================================="
    else
  4. joevt revised this gist Aug 15, 2023. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion dumpvols.sh
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    #
    # Get Partition Info from all disks
    #
    # Written by joevt updated July 28, 2023
    # Written by joevt updated August 15, 2023
    # Patches marked "rgh" July, 2010, to dump information beyond the
    # four bios partitions
    #
    @@ -19,6 +19,7 @@ if [ ! "$USER" = "root" ]; then
    fi

    INPUTDISK="$1"
    INPUTDISK="${INPUTDISK#/dev/}"
    INPUTSLICE=$(expr "$INPUTDISK" : 'disk[0-9]*s\([0-9]*\)')

    if [[ -n $INPUTDISK ]]; then
  5. joevt revised this gist Jul 28, 2023. 1 changed file with 25 additions and 26 deletions.
    51 changes: 25 additions & 26 deletions dumpvols.sh
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    #
    # Get Partition Info from all disks
    #
    # Written by joevt updated May 20, 2023
    # Written by joevt updated July 28, 2023
    # Patches marked "rgh" July, 2010, to dump information beyond the
    # four bios partitions
    #
    @@ -22,7 +22,7 @@ INPUTDISK="$1"
    INPUTSLICE=$(expr "$INPUTDISK" : 'disk[0-9]*s\([0-9]*\)')

    if [[ -n $INPUTDISK ]]; then
    disklist="$(diskutil list "$1" | perl -p -e 's|^/|\n/|')"
    disklist="$(diskutil list "$INPUTDISK" | perl -p -e 's|^/|\n/|')"
    apfslist="$(diskutil apfs list | sed -nE "/^\|/s// /; /^ $/s///; /\+.*$1 /,/^$/ { /^$/d ; p ; }" 2> /dev/null)"
    ALLDISKS=0
    else
    @@ -219,7 +219,7 @@ dumpencoding () {
    }
    }

    command -V python > /dev/null && python=python || python=python3
    command -v python > /dev/null 2>&1 && python=python || python=python3
    vsdbtouuid0 () {
    "$python" -c '
    import uuid ; from hashlib import md5
    @@ -238,10 +238,9 @@ vsdbtouuid () {
    (( ALLDISKS )) && echo "$disklist"
    echo "$apfslist"

    DRIVELIST="$(sed -n -E "/^[ ]*0: [ ]{0,25}([A-Za-z_]+)[ ]*[+*][0-9.]+ [TGMK]B[ ]+(disk[0-9]+)$/s//\1_\2/p;/^[ ]*0: [ ]{0,26} .* \*[0-9.]+ [TGMK]B[ ]+(disk[0-9]+)$/s//whole_\1/p" <<< "$disklist")"

    DRIVELIST=$(sed -n -E "/^[ ]*0: [ ]{0,25}([A-Za-z_]+)[ ]*\*[0-9.]+ [TGMK]B[ ]+(disk[0-9]+)$/s//\1_\2/p;/^[ ]*0: [ ]{0,26} .* \*[0-9.]+ [TGMK]B[ ]+(disk[0-9]+)$/s//whole_\1/p" <<< "$disklist")
    for PARTDRIVE in $DRIVELIST;
    do
    for PARTDRIVE in $(echo $DRIVELIST); do
    DRIVE=$(expr "$PARTDRIVE" : '.*_\([^_]*\)')
    DTYPE=$(expr "$PARTDRIVE" : '\(.*\)_[^_]*')
    echo "==============================================================================="
    @@ -259,12 +258,12 @@ do

    MOUNTPOINTS=""
    if [[ -n $INPUTSLICE ]]; then
    DEVLIST=$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s${INPUTSLICE})$/s//\1/p")
    DEVLIST="$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s${INPUTSLICE})$/s//\1/p")"
    else
    DEVLIST=$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s[0-9]+)$/s//\1/p")
    DEVLIST="$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s[0-9]+)$/s//\1/p")"
    fi

    for THEDEV in $DEVLIST; do
    for THEDEV in $(echo $DEVLIST); do
    echo "---------------------------------------------"
    partinfo="$(diskutil info "$THEDEV")"
    echo "$partinfo"
    @@ -377,7 +376,7 @@ do
    PARTLIST="$(sed -nE "/^${INPUTSLICE}_/p" <<< "$PARTLIST")"
    fi

    for THEPART in $PARTLIST; do
    for THEPART in $(echo $PARTLIST); do
    PNUM=$( expr "$THEPART" : '\([0-9]*\)_')
    PSTART=$( expr "$THEPART" : '[0-9]*_\([0-9]*\)_[0-9]*')
    PLENGTH=$(expr "$THEPART" : '[0-9]*_[0-9]*_\([0-9]*\)')
    @@ -409,19 +408,19 @@ do
    byteoffset=4;
    for (( i=0; i < numPatches; i++ )); do
    printf "%03x: PatchDescriptor[%d]:\n" "$byteoffset" "$i"

    patchSig=$(sed -E 's/(00)+$//' <<< "${blockbytes:byteoffset*2:8}" | xxd -p -r | tr '\0' '.')
    majorVers=$((0x${blockbytes:byteoffset*2+8:4}));
    minorVers=$((0x${blockbytes:byteoffset*2+12:4}));
    flags=$((0x${blockbytes:byteoffset*2+16:8}));
    patchOffset=$((0x${blockbytes:byteoffset*2+24:8}));
    patchSize=$((0x${blockbytes:byteoffset*2+32:8}));
    patchCRC=$((0x${blockbytes:byteoffset*2+40:8}));
    patchDescriptorLen=$((0x${blockbytes:byteoffset*2+48:8}));
    patchName=$((0x${blockbytes:byteoffset*2+56:33*2}));
    patchVendorLen=$((0x${blockbytes:byteoffset*2+122:2}));
    patchVendor=$(pascalstring "${blockbytes:byteoffset*2+122:patchVendorLen*2+2}")
    patchPad="${blockbytes:byteoffset*2+124+patchVendorLen*2:patchDescriptorLen*2 - (124+patchVendorLen*2)}"
    patchSig=$(sed -E 's/(00)+$//' <<< "${blockbytes:$byteoffset*2:8}" | xxd -p -r | tr '\0' '.')
    majorVers=$((0x${blockbytes:$byteoffset*2+8:4}));
    minorVers=$((0x${blockbytes:$byteoffset*2+12:4}));
    flags=$((0x${blockbytes:$byteoffset*2+16:8}));
    patchOffset=$((0x${blockbytes:$byteoffset*2+24:8}));
    patchSize=$((0x${blockbytes:$byteoffset*2+32:8}));
    patchCRC=$((0x${blockbytes:$byteoffset*2+40:8}));
    patchDescriptorLen=$((0x${blockbytes:$byteoffset*2+48:8}));
    patchNameLen=$((0x${blockbytes:$byteoffset*2+56:2}));
    patchName=$(pascalstring "${blockbytes:$byteoffset*2+56:$patchNameLen*2+2}")
    patchVendorLen=$((0x${blockbytes:$byteoffset*2+122:2}));
    patchVendor=$(pascalstring "${blockbytes:$byteoffset*2+122:$patchVendorLen*2+2}")
    patchPad="${blockbytes:$byteoffset*2+124+$patchVendorLen*2:$patchDescriptorLen*2 - (124+$patchVendorLen*2)}"

    printf "%03x: patchSig : '%s'\n" $((byteoffset+ 0)) "$patchSig"
    printf "%03x: majorVers : %d\n" $((byteoffset+ 4)) "$majorVers"
    @@ -569,7 +568,7 @@ do
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Boot Block Header contents"

    CODESTART=$((0x94))
    printf "000: bbID : \'LK'\n"
    printf "000: bbID : 'LK'\n"
    printf "002: bbEntry : 0x%08x" "$bbEntry"
    if (( (bbEntry & 0xffff0000) == 0x60000000 )); then
    CODESTART=$(((bbEntry & 0xffff) + 4))
    @@ -893,7 +892,7 @@ do
    ((encodingsBitmap & (1<<38))) && printf ",MacRomanian"
    ((encodingsBitmap & (1<<48))) && printf ",MacUkrainian"
    ((encodingsBitmap & (1<<49))) && printf ",MacFarsi"
    ((encodingsBitmap & 0xfffcff8100000000)) && printf ",0x%016x?" $((encodingsBitmap & 0xfffcff8100000000))
    ((encodingsBitmap & (0xfffcff81 << 32))) && printf ",0x%016x?" $((encodingsBitmap & (0xfffcff81 << 32)))
    )
    printf "048: encodingsBitmap : 0x%016x = %s" "$encodingsBitmap" "${encodings:1}"
    }
    @@ -905,7 +904,7 @@ do
    printf "05c: Alternate OS blessed file/folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo:24: 8}))" )"
    dumpencoding "060: Text encoding :" "$((0x${finderInfo:32: 8}))"
    printf "064: OS X blessed folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo:40: 8}))" )"
    printf "068: 64-bit VSDB volume id : 0x%016X => Volume UUID: %s\n" $((0x${finderInfo:48:16})) "$(vsdbtouuid "${finderInfo:48:16}")"
    printf "068: 64-bit VSDB volume id : 0x%016X => Volume UUID: %s\n" $(((0x${finderInfo:48:8} << 32) | 0x${finderInfo:56:8} )) "$(vsdbtouuid "${finderInfo:48:16}")"
    printf "070: allocationFile : %s\n" "$(forkdatastring "$allocationFile" )"
    printf "0c0: extentsFile : %s\n" "$(forkdatastring "$extentsFile" )"
    printf "110: catalogFile : %s\n" "$(forkdatastring "$catalogFile" )"
  6. joevt revised this gist May 20, 2023. 1 changed file with 19 additions and 3 deletions.
    22 changes: 19 additions & 3 deletions dumpvols.sh
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    #
    # Get Partition Info from all disks
    #
    # Written by joevt updated Dec 2, 2022
    # Written by joevt updated May 20, 2023
    # Patches marked "rgh" July, 2010, to dump information beyond the
    # four bios partitions
    #
    @@ -219,6 +219,22 @@ dumpencoding () {
    }
    }

    command -V python > /dev/null && python=python || python=python3
    vsdbtouuid0 () {
    "$python" -c '
    import uuid ; from hashlib import md5
    kFSUUIDNamespaceSHA1 = uuid.UUID("b3e20f39-f292-11d6-97a4-00306543ecac")
    digest = md5(kFSUUIDNamespaceSHA1.bytes + bytes.fromhex("'"$1"'"), usedforsecurity=False).digest()
    print ("%s" % uuid.UUID(bytes=digest[:16], version=3))
    '
    }

    vsdbtouuid () {
    local theuuid=""
    theuuid=$(printf "b3e20f39f29211d697a400306543ecac%s" "$1" | xxd -p -r | md5 | tr "a-f" "A-F" )
    printf "%s" "${theuuid:0:8}-${theuuid:8:4}-3${theuuid:13:3}-$(printf "%X" $(((0x${theuuid:16:1} & 3) | 8)))${theuuid:17:3}-${theuuid:20:12}"
    }

    (( ALLDISKS )) && echo "$disklist"
    echo "$apfslist"

    @@ -718,7 +734,7 @@ do
    printf "068: Alternate OS blessed file/folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${drFndrInfo:24: 8}))" )"
    dumpencoding "06c: Text encoding :" "$((0x${drFndrInfo:32: 8}))"
    printf "070: OS X blessed folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${drFndrInfo:40: 8}))" )"
    printf "074: 64-bit VSDB volume id : 0x%016X\n" $((0x${drFndrInfo:48:16}))
    printf "074: 64-bit VSDB volume id : 0x%016X => Volume UUID: %s\n" $((0x${drFndrInfo:48:16})) "$(vsdbtouuid "${drFndrInfo:48:16}")"

    if (( drEmbedSigWord == 0x482b )); then
    printf "07c: drEmbedSigWord: %d = 'H+' = kHFSPlusSigWord\n" "$drEmbedSigWord"
    @@ -889,7 +905,7 @@ do
    printf "05c: Alternate OS blessed file/folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo:24: 8}))" )"
    dumpencoding "060: Text encoding :" "$((0x${finderInfo:32: 8}))"
    printf "064: OS X blessed folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo:40: 8}))" )"
    printf "068: 64-bit VSDB volume id : 0x%016X\n" $((0x${finderInfo:48:16}))
    printf "068: 64-bit VSDB volume id : 0x%016X => Volume UUID: %s\n" $((0x${finderInfo:48:16})) "$(vsdbtouuid "${finderInfo:48:16}")"
    printf "070: allocationFile : %s\n" "$(forkdatastring "$allocationFile" )"
    printf "0c0: extentsFile : %s\n" "$(forkdatastring "$extentsFile" )"
    printf "110: catalogFile : %s\n" "$(forkdatastring "$catalogFile" )"
  7. joevt revised this gist Dec 2, 2022. 1 changed file with 870 additions and 86 deletions.
    956 changes: 870 additions & 86 deletions dumpvols.sh
    Original file line number Diff line number Diff line change
    @@ -2,8 +2,8 @@
    #
    # Get Partition Info from all disks
    #
    # Written by joevt updated Dec 29. 2020
    # Patches marked "rgh" July, 2010, to dump information beyond the
    # Written by joevt updated Dec 2, 2022
    # Patches marked "rgh" July, 2010, to dump information beyond the
    # four bios partitions
    #
    # sudo ./dumpvols.sh > dumpvols_result.txt 2>&1
    @@ -18,46 +18,66 @@ if [ ! "$USER" = "root" ]; then
    exit
    fi

    MBRHASHES=\
    "Windows_XP=d88d4f2dbc2c662db7d7d60ebf9e3e00 "\
    "Windows_Vista=12c9d7ff4914c88a7f9eadf9211b861b "\
    "Windows_7=118eb70c44cb69284e5d8aa93096831e "\
    "None_all_zeros=4ebc676ce4896613a3a9df6e2a1c77ae "\
    ""\
    "MSDOS_or_FreeDOS_on_FreeDOS=93dd2ee87a995e36cbab0c2d5c2f041a "\
    ""\
    "Windows_XP_On_BootCamp2_with_AHCI_patch=c3fb54174bc479899d4ef6e45308dc18 "\
    "Windows_XP_On_BootCamp2=cb4dabdd862da0508083b05814e198b8 "\
    "Windows_Vista_on_XP_with_AHCI_patch=4979e1b9d70738759280f6962c2ad298 "\
    "Windows_7_on_XP=7db43c1425e9ff3077dd62b776a50419 "\
    "Windows_7_with_AHCI_patch=a243d3475531b0f6f0d7199043c2eb5c "\
    "Windows_7_on_XP_with_AHCI_patch=24977c27865adec9ac8298f1a8d214bf "\
    ""\
    "Apple_Partition_Map_Block0_Driver_Descriptor_Map_390721968_blocks_and_Tiger_OS_9_drivers=087f35e49a39d52a46e3a94882869f51 "\
    ""
    INPUTDISK="$1"
    INPUTSLICE=$(expr "$INPUTDISK" : 'disk[0-9]*s\([0-9]*\)')

    if [[ -n $INPUTDISK ]]; then
    disklist="$(diskutil list "$1" | perl -p -e 's|^/|\n/|')"
    apfslist="$(diskutil apfs list | sed -nE "/^\|/s// /; /^ $/s///; /\+.*$1 /,/^$/ { /^$/d ; p ; }" 2> /dev/null)"
    ALLDISKS=0
    else
    disklist="$(diskutil list | perl -p -e 's|^/|\n/|')"
    apfslist="$(diskutil apfs list 2> /dev/null)"
    ALLDISKS=1
    fi
    [[ "${apfslist:0:4}" == "Disk" ]] && apfslist=""

    MBRHASHES="
    Windows_XP=d88d4f2dbc2c662db7d7d60ebf9e3e00
    Windows_Vista=12c9d7ff4914c88a7f9eadf9211b861b
    Windows_7=118eb70c44cb69284e5d8aa93096831e
    None_all_zeros=4ebc676ce4896613a3a9df6e2a1c77ae
    MSDOS_or_FreeDOS_on_FreeDOS=93dd2ee87a995e36cbab0c2d5c2f041a
    Windows_XP_On_BootCamp2_with_AHCI_patch=c3fb54174bc479899d4ef6e45308dc18
    Windows_XP_On_BootCamp2=cb4dabdd862da0508083b05814e198b8
    Windows_Vista_on_XP_with_AHCI_patch=4979e1b9d70738759280f6962c2ad298
    Windows_7_on_XP=7db43c1425e9ff3077dd62b776a50419
    Windows_7_with_AHCI_patch=a243d3475531b0f6f0d7199043c2eb5c
    Windows_7_on_XP_with_AHCI_patch=24977c27865adec9ac8298f1a8d214bf
    Apple_Partition_Map_Block0_Driver_Descriptor_Map_390721968_blocks_and_Tiger_OS_9_drivers=087f35e49a39d52a46e3a94882869f51
    "


    #All VBR hashes use all the bytes starting from offset 0x60. It may be better to use a different range for each type of VBR...

    # GRUB2 hash was incorrectly named GRUB #rgh
    # added GRUB hash from observation of kununtu 9.04 #rgh
    # added Windows 8
    VBRHASHES=\
    "None_all_zeros=acf496fff71230daa6985a701f83ce49 "\
    "NTFS_No_Loader=3be27456483746abb85cd614381dac5e "\
    "NTFS_Windows_XP_NTLDR=dd1728a59343b9fa9458d80657f68771 "\
    "NTFS_Windows_Vista_BOOTMGR=d1c278b56eeea9536d0eb5898fe6a0b5 "\
    "NTFS_Windows_8_BOOTMGR=771df8b803f96296854316d3d5918812 "\
    "GRUB_from_Ubuntu=332469fa146db809f58d6392e2e0bdce "\
    "GRUB2_from_Ubuntu=9c249066e1eb9c842d8acdfe6d23a2e3 "\
    "FAT32_FRDOS4.1=98050815221ee147066f99f806c23203 "\
    "FAT32_FRDOS4.1_or_MSWIN4.1_BOOTMGR=aec608de8ac709d91e6f3340b643ab4d "\
    "FAT32_NTFS_NTLDR=d9c3d66e975d2b3b122353951a598b32 "\
    "FAT12_BSD_4.4_BOOTMGR=4cc92970d5a3350bc72d2b975e28b915 "\
    "FAT16_Non_system_disk=2a3d0f51ad246f115aa7d37891788857 "\
    "FAT32_Non_system_disk_or_EFI=34f2d1f3c3ecce5c00cae8f0b82c922b "\
    "HFS_boot_block_0=28f5bc1563fbaedeb8dabbd4ef9eb4c2 "\
    ""
    VBRHASHES="
    None_all_zeros=acf496fff71230daa6985a701f83ce49
    NTFS_No_Loader=3be27456483746abb85cd614381dac5e
    NTFS_Windows_XP_NTLDR=dd1728a59343b9fa9458d80657f68771
    NTFS_Windows_Vista_BOOTMGR=d1c278b56eeea9536d0eb5898fe6a0b5
    NTFS_Windows_8_BOOTMGR=771df8b803f96296854316d3d5918812
    GRUB_from_Ubuntu=332469fa146db809f58d6392e2e0bdce
    GRUB2_from_Ubuntu=9c249066e1eb9c842d8acdfe6d23a2e3
    FAT32_FRDOS4.1=98050815221ee147066f99f806c23203
    FAT32_FRDOS4.1_or_MSWIN4.1_BOOTMGR=aec608de8ac709d91e6f3340b643ab4d
    FAT32_NTFS_NTLDR=d9c3d66e975d2b3b122353951a598b32
    FAT12_BSD_4.4_BOOTMGR=4cc92970d5a3350bc72d2b975e28b915
    FAT16_Non_system_disk=2a3d0f51ad246f115aa7d37891788857
    FAT32_Non_system_disk_or_EFI=34f2d1f3c3ecce5c00cae8f0b82c922b
    HFS_boot_block_0=28f5bc1563fbaedeb8dabbd4ef9eb4c2
    APM_Driver_SCSI_patch=44dc8729f17b4de891fc93d8db04e393
    APM_Driver_SCSI_chained_real=f13d0837e944353d07121dcda47f01c0
    APM_Driver_ATA_patch=e1dd2732d4f0cfc3f79357f1bae992c7
    APM_Driver_ATA_chained_real=4ccc33e59537e50e7831fc499a8672a5
    "
    # APM drivers created by Leopard Install Mac OS 9 Drivers

    FindHash () {
    # $1: name of hashed contents
    @@ -80,93 +100,857 @@ FindHash () {
    fi
    }

    disklist="$(diskutil list)"
    echo "$disklist"
    echo
    diskutil apfs list
    pascalstring () {
    # $1 pascal string bytes
    local thebytes;
    local thechars;
    local thelen;
    thebytes="$1"
    thelen=$((0x${thebytes:0:2}))
    thechars=$(sed -E 's/(00)+$//' <<< "${thebytes:2}" | xxd -p -r | tr '\0' '.')
    if (( thelen != ${#thechars} )); then
    printf "len:%d? " "$thelen"
    fi
    printf "\"%s\"" "$thechars"
    }

    GetFileInfo="GetFileInfo"
    command -v GetFileInfo > /dev/null 2>&1 || {
    GetFileInfo="/Developer/Tools/GetFileInfo"
    }

    inodetopath () {
    "$GetFileInfo" -P "/.vol/$1/$2" 2> /dev/null | sed -nE '/^(file|directory): "(.*)"/s//\2/p'
    }

    inodestring () {
    local deviceid="$1"
    local inode="$2"
    local thepath;
    thepath="$(inodetopath "$deviceid" "$inode")"
    printf "%d" "$inode"
    [[ -n $thepath ]] && printf " => \"%s\"" "$thepath"
    }

    forkdatastring () {
    local forkdata="$1"
    local extentslist
    if [[ -n ${forkdata//0/} ]]; then
    extentslist=$(
    extents="${forkdata:32}"
    while [[ -n $extents ]]; do
    if ((0x${extents:0:16})); then
    printf "(%d,%d)," $((0x${extents:0:8})) $((0x${extents:8:8}))
    else
    printf ","
    fi
    extents="${extents:16}"
    done
    )
    printf "logicalSize:%d clumpSize:%d totalBlocks:%d extents:(%s)" $((0x${forkdata:0:16})) $((0x${forkdata:16:8})) $((0x${forkdata:24:8})) "${extentslist%"${extentslist##*[!,]}"}"
    fi
    }

    extentstring () {
    extents="$1"
    extentslist=$(
    while [[ -n $extents ]]; do
    if ((0x${extents:0:16})); then
    printf "(%d,%d)," $((0x${extents:0:4})) $((0x${extents:4:4}))
    else
    printf ","
    fi
    extents="${extents:8}"
    done
    )
    printf "(%s)" "${extentslist%"${extentslist##*[!,]}"}"
    }

    dumpencoding () {
    local message="$1"
    local encoding="$2"
    ((encoding)) && {
    printf "%s 0x%08x" "$message" "$encoding"
    (( (encoding & 0x656e6300) == 0x656e6300 )) && {
    case $((encoding & 0xff)) in
    0) printf " = kTextEncodingMacRoman" ;;
    1) printf " = kTextEncodingMacJapanese" ;;
    2) printf " = kTextEncodingMacChineseTrad" ;;
    3) printf " = kTextEncodingMacKorean" ;;
    4) printf " = kTextEncodingMacArabic" ;;
    5) printf " = kTextEncodingMacHebrew" ;;
    6) printf " = kTextEncodingMacGreek" ;;
    7) printf " = kTextEncodingMacCyrillic" ;;
    9) printf " = kTextEncodingMacDevanagari" ;;
    10) printf " = kTextEncodingMacGurmukhi" ;;
    11) printf " = kTextEncodingMacGujarati" ;;
    12) printf " = kTextEncodingMacOriya" ;;
    13) printf " = kTextEncodingMacBengali" ;;
    14) printf " = kTextEncodingMacTamil" ;;
    15) printf " = kTextEncodingMacTelugu" ;;
    16) printf " = kTextEncodingMacKannada" ;;
    17) printf " = kTextEncodingMacMalayalam" ;;
    18) printf " = kTextEncodingMacSinhalese" ;;
    19) printf " = kTextEncodingMacBurmese" ;;
    20) printf " = kTextEncodingMacKhmer" ;;
    21) printf " = kTextEncodingMacThai" ;;
    22) printf " = kTextEncodingMacLaotian" ;;
    23) printf " = kTextEncodingMacGeorgian" ;;
    24) printf " = kTextEncodingMacArmenian" ;;
    25) printf " = kTextEncodingMacChineseSimp" ;;
    26) printf " = kTextEncodingMacTibetan" ;;
    27) printf " = kTextEncodingMacMongolian" ;;
    28) printf " = kTextEncodingMacEthiopic" ;;
    29) printf " = kTextEncodingMacCentralEurRoman" ;;
    30) printf " = kTextEncodingMacVietnamese" ;;
    31) printf " = kTextEncodingMacExtArabic" ;;
    33) printf " = kTextEncodingMacSymbol" ;;
    34) printf " = kTextEncodingMacDingbats" ;;
    35) printf " = kTextEncodingMacTurkish" ;;
    36) printf " = kTextEncodingMacCroatian" ;;
    37) printf " = kTextEncodingMacIcelandic" ;;
    38) printf " = kTextEncodingMacRomanian" ;;
    39) printf " = kTextEncodingMacCeltic" ;;
    40) printf " = kTextEncodingMacGaelic" ;;
    41) printf " = kTextEncodingMacKeyboardGlyphs" ;;
    esac
    }
    printf "\n"
    }
    }

    (( ALLDISKS )) && echo "$disklist"
    echo "$apfslist"


    DRIVELIST=$(sed -n -E "/^[ ]*0: [ ]{0,25}([A-Za-z_]+)[ ]*\*[0-9.]+ [TGMK]B[ ]+(disk[0-9]+)$/s//\1_\2/p;/^[ ]*0: [ ]{0,26} .* \*[0-9.]+ [TGMK]B[ ]+(disk[0-9]+)$/s//whole_\1/p" <<< "$disklist")
    for PARTDRIVE in $DRIVELIST;
    do
    DRIVE=$(expr "$PARTDRIVE" : '.*_\([^_]*\)')
    PTYPE=$(expr "$PARTDRIVE" : '\(.*\)_[^_]*')
    DTYPE=$(expr "$PARTDRIVE" : '\(.*\)_[^_]*')
    echo "==============================================================================="

    diskutiloutput="$(sed -nE '/\/dev\/'$DRIVE' /,/^$/ p' <<< "${disklist}")"
    diskutiloutput="$(sed -nE '/\/dev\/'"$DRIVE"'( |$)/,/^$/ p' <<< "${disklist}")"
    echo "$diskutiloutput"

    echo "---------------------------------------------"
    diskinfo="$(diskutil info $DRIVE)"
    diskinfo="$(diskutil info "$DRIVE")"
    echo "$diskinfo"
    echo
    BLOCKSIZE=$(sed -nE '/^ *Device Block Size: +([0-9]+).*/s//\1/p' <<< "$diskinfo")
    if [[ -z $BLOCKSIZE ]]; then
    BLOCKSIZE=512
    fi

    DEVLIST=$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s[0-9]+)$/s//\1/p")
    MOUNTPOINTS=""
    if [[ -n $INPUTSLICE ]]; then
    DEVLIST=$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s${INPUTSLICE})$/s//\1/p")
    else
    DEVLIST=$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s[0-9]+)$/s//\1/p")
    fi

    for THEDEV in $DEVLIST; do
    echo "---------------------------------------------"
    diskutil info $THEDEV
    partinfo="$(diskutil info "$THEDEV")"
    echo "$partinfo"
    MOUNTPOINTS="${MOUNTPOINTS}${THEDEV}_$(sed -nE '/ *Mount Point: *(.*)/s//\1/p' <<< "$partinfo")"$'\n'
    done
    echo "---------------------------------------------"

    PARTLIST=""

    blockbytes=$(dd if="/dev/$DRIVE" bs=512 count=1 2> /dev/null | xxd -p -c 9999)

    if [ "$DTYPE" = "Apple_partition_scheme" ]; then

    pdiskoutput="$(pdisk -r -l "/dev/$DRIVE" 2>&1)"
    pdiskoutput2="$(pdisk -r -l -f "/dev/$DRIVE" 2>&1)"

    if [ "$PTYPE" = "Apple_partition_scheme" ]; then
    pdisk -r -l "/dev/$DRIVE"
    pdisk -r -l -f "/dev/$DRIVE"
    echo "$pdiskoutput"
    [[ "$pdiskoutput" != "$pdiskoutput2" ]] && echo "$pdiskoutput2"

    # use the same bytes as MBR hash even though Block0 contents are totally different
    HASH=$(dd if="/dev/$DRIVE" bs=1 count=446 2> /dev/null | xxd -p -l 440 | md5)
    FindHash "Block0 contents" "$MBRHASHES" "$HASH"
    dd if="/dev/$DRIVE" bs=1 count=512 2> /dev/null | xxd -c 16
    elif [ "$PTYPE" = "GUID_partition_scheme" -o "$PTYPE" = "FDisk_partition_scheme" ]; then
    i=0
    if [[ ${blockbytes:0:4} == "4552" ]]; then # 'ER'
    sbBlkSize=$((0x${blockbytes:4:4}))
    sbBlkCount=$((0x${blockbytes:8:8}))
    sbDevType=$((0x${blockbytes:16:4}))
    sbDevId=$((0x${blockbytes:20:4}))
    sbData=$((0x${blockbytes:24:8}))
    sbDrvrCount=$((0x${blockbytes:32:4}))

    gptoutput="$(gpt -r show $DRIVE 2>&1)"
    gptoutput2="$(gpt -r show -l $DRIVE 2>&1)"
    fdiskoutput="$(fdisk /dev/r$DRIVE)"
    echo
    echo "APM Block 0 contents"

    printf "000: sbSig : 'ER' = sbSIGWord\n"
    printf "002: sbBlkSize : %d\n" "$sbBlkSize"
    printf "004: sbBlkCount : %d = %d MB\n" "$sbBlkCount" $((sbBlkCount*sbBlkSize / 1000 / 1000))
    ((sbDevType != 0)) && printf "008: sbDevType : %d\n" "$sbDevType"
    ((sbDevId != 0)) && printf "00a: sbDevId : %d\n" "$sbDevId"
    ((sbData != 0)) && printf "00c: sbData : %d\n" "$sbData"
    ((sbDrvrCount > 10)) && printf "010: sbDrvrCount: %d\n" "$sbDrvrCount"
    for ((i=0; i < sbDrvrCount; i++)); do
    ddBlock=$((0x${blockbytes:36+i*16:8}))
    ddSize=$((0x${blockbytes:44+i*16:4}))
    ddType=$((0x${blockbytes:48+i*16:4}))
    printf "%03x: DDMap[%d]:%4d @ %-4d 0x%04x = %-27s\n" $((0x012 + i*8)) "$i" "$ddSize" "$ddBlock" "$ddType" "$(
    {
    ((ddType == 0x0001)) && printf "kDriverTypeMacSCSI" ; } ||
    {
    ((ddType == 0x0701)) && printf "kDriverTypeMacATA" ; } ||
    {
    ((ddType == 0xFFFF)) && printf "kDriverTypeMacSCSIChained"; } ||
    {
    ((ddType == 0xF8FF)) && printf "kDriverTypeMacATAChained" ; } ||
    printf "?"
    )"
    done
    ddPad="${blockbytes:52+i*16}"
    [[ -n ${ddPad//0/} ]] && printf "ddPad: %s\n" "$ddPad"
    echo
    xxd -p -r <<< "$blockbytes" | xxd -c 16
    else
    # use the same bytes as MBR hash even though Block0 contents are totally different
    HASH=$(xxd -p -r <<< "${blockbytes:0:440*2}" | xxd -p | md5)
    FindHash "Block0 contents" "$MBRHASHES" "$HASH"
    xxd -p -r <<< "$blockbytes" | xxd -c 16
    fi

    PARTTYPE="APM"
    PARTLIST=$(echo "$pdiskoutput" | sed -nE "/ *[0-9]+: +Apple_Free /d; /[0-9]+: +[0-9]+ @ [0-9]+, type=0x/d; / *([0-9]+): +([^ ]+) .* ([0-9]+) @ ([0-9]+).*/s//\1_\4_\3_\2/p")

    elif [ "$DTYPE" = "GUID_partition_scheme" ] || [ "$DTYPE" = "FDisk_partition_scheme" ]; then

    gptoutput="$(gpt -r show "$DRIVE" 2>&1)"
    gptoutput2="$(gpt -r show -l "$DRIVE" 2>&1)"
    fdiskoutput="$(fdisk "/dev/r$DRIVE")"

    echo
    echo "$gptoutput"
    echo "$gptoutput2"
    ! grep -q "illegal option -- l" <<< "$gptoutput2" && {
    echo
    echo "$gptoutput2"
    }
    echo
    echo "$fdiskoutput"

    HASH=$(dd if="/dev/$DRIVE" bs=1 count=446 2> /dev/null | xxd -p -l 440 | md5)
    HASH=$(xxd -p -r <<< "${blockbytes:0:440*2}" | xxd -p | md5)
    FindHash "MBR contents" "$MBRHASHES" "$HASH"
    dd if="/dev/$DRIVE" bs=1 count=512 2> /dev/null | xxd -c 16
    xxd -p -r <<< "$blockbytes" | xxd -c 16

    if [ "$PTYPE" = "FDisk_partition_scheme" ]; then
    PARTLIST=$(echo "$fdiskoutput" | sed -n -E "/^[ \*]+([0-9])\: .*\[[ ]*([0-9]+) \-[ ]+([1-9][0-9]*)\].*$/s//\1_\2_\3/p")
    if [ "$DTYPE" = "FDisk_partition_scheme" ]; then
    PARTLIST=$(echo "$fdiskoutput" | sed -n -E "/^[ \*]+([0-9])\: ([0-9A-F]{2}) .*\[[ ]*([0-9]+) \-[ ]+([1-9][0-9]*)\].*$/s//\1_\3_\4_\2/p")
    PARTTYPE="MBR"
    else
    HASH=$(dd if="/dev/$DRIVE" bs=1 skip=$((BLOCKSIZE + 96)) count=416 2> /dev/null | xxd -p -l 440 | md5)
    blockbytes=$(dd if="/dev/$DRIVE" bs="$BLOCKSIZE" skip=1 count=1 2> /dev/null | xxd -p -c 9999)
    HASH=$(xxd -p -r <<< "${blockbytes:96*2:416*2}" | xxd -p | md5)
    FindHash "GPT Header @ 1: GPT Header contents" "$VBRHASHES" "$HASH"
    dd if="/dev/$DRIVE" bs=1 skip=$BLOCKSIZE count=$BLOCKSIZE 2> /dev/null | xxd -c 16
    xxd -p -r <<< "$blockbytes" | xxd -c 16

    PARTLIST=$(echo "$gptoutput" | sed -n -E "/^[ ]+([0-9]+)[ ]+([0-9]+)[ ]+([0-9]+)[ ]+GPT part \-.*$/s//\3_\1_\2/p")
    PARTLIST=$(echo "$gptoutput" | sed -n -E "/^[ ]+([0-9]+)[ ]+([0-9]+)[ ]+([0-9]+)[ ]+GPT part \- (.*)$/s//\3_\1_\2_\4/p")
    PARTTYPE="GPT"
    fi

    for THEPART in $PARTLIST; do
    PNUM=$(expr "$THEPART" : '\([0-9]*\)_')
    PSTART=$(expr "$THEPART" : '[0-9]*_\([0-9]*\)_[0-9]*')
    PLENGTH=$(expr "$THEPART" : '[0-9]*_[0-9]*_\([0-9]*\)')

    HASH=$(dd if="/dev/$DRIVE" bs=1 skip=$((PSTART * BLOCKSIZE + 96)) count=416 2> /dev/null | xxd -p -l 440 | md5)
    FindHash "$PARTTYPE $PNUM @ $PSTART: VBR contents" "$VBRHASHES" "$HASH"
    dd if="/dev/$DRIVE" bs=1 skip=$((PSTART * BLOCKSIZE)) count=$BLOCKSIZE 2> /dev/null | xxd -c 16
    done
    elif [ "$PTYPE" = "whole" ]; then
    HASH=$(dd if="/dev/$DRIVE" bs=1 count=416 2> /dev/null | xxd -p -l 440 | md5)
    elif [ "$DTYPE" = "whole" ]; then
    HASH=$(xxd -p -r <<< "${blockbytes:0:416*2}" | xxd -p | md5)
    FindHash "0 @ 0: VBR contents" "$VBRHASHES" "$HASH"
    dd if="/dev/$DRIVE" bs=512 count=1 2> /dev/null | xxd -c 16
    xxd -p -r <<< "$blockbytes" | xxd -c 16
    else
    echo "Unknown partition scheme"
    fi

    if [[ -n $INPUTSLICE ]]; then
    PARTLIST="$(sed -nE "/^${INPUTSLICE}_/p" <<< "$PARTLIST")"
    fi

    for THEPART in $PARTLIST; do
    PNUM=$( expr "$THEPART" : '\([0-9]*\)_')
    PSTART=$( expr "$THEPART" : '[0-9]*_\([0-9]*\)_[0-9]*')
    PLENGTH=$(expr "$THEPART" : '[0-9]*_[0-9]*_\([0-9]*\)')
    PTYPE=$( expr "$THEPART" : '[0-9]*_[0-9]*_[0-9]*_\(.*\)')
    DEVICEID=$(stat -f "%r" "/dev/${DRIVE}s$PNUM")

    POFFSETS="_0"
    while [[ -n $POFFSETS ]]; do
    POFFSET=$( expr "$POFFSETS" : '_\([0-9]*\)')
    POFFSETS=$( expr "$POFFSETS" : '_[0-9]*\(_.*\)')

    if (( POFFSET >= PLENGTH )); then
    continue
    fi

    blockbytes=$(dd if="/dev/$DRIVE" bs="$BLOCKSIZE" skip=$((PSTART + POFFSET)) count=1 2> /dev/null | xxd -p -c 9999)

    if [[ $PTYPE = "Apple_Patches" ]]; then

    # Patches # https://developer.apple.com/library/archive/technotes/tn/tn1189.html#SecretsOfThePartitionMap

    echo
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Driver Patches"

    numPatchBlocks=$((0x${blockbytes:0:4}))
    numPatches=$((0x${blockbytes:4:4}))
    printf "000: numPatchBlocks: %d\n" "$numPatchBlocks"

    byteoffset=4;
    for (( i=0; i < numPatches; i++ )); do
    printf "%03x: PatchDescriptor[%d]:\n" "$byteoffset" "$i"

    patchSig=$(sed -E 's/(00)+$//' <<< "${blockbytes:byteoffset*2:8}" | xxd -p -r | tr '\0' '.')
    majorVers=$((0x${blockbytes:byteoffset*2+8:4}));
    minorVers=$((0x${blockbytes:byteoffset*2+12:4}));
    flags=$((0x${blockbytes:byteoffset*2+16:8}));
    patchOffset=$((0x${blockbytes:byteoffset*2+24:8}));
    patchSize=$((0x${blockbytes:byteoffset*2+32:8}));
    patchCRC=$((0x${blockbytes:byteoffset*2+40:8}));
    patchDescriptorLen=$((0x${blockbytes:byteoffset*2+48:8}));
    patchName=$((0x${blockbytes:byteoffset*2+56:33*2}));
    patchVendorLen=$((0x${blockbytes:byteoffset*2+122:2}));
    patchVendor=$(pascalstring "${blockbytes:byteoffset*2+122:patchVendorLen*2+2}")
    patchPad="${blockbytes:byteoffset*2+124+patchVendorLen*2:patchDescriptorLen*2 - (124+patchVendorLen*2)}"

    printf "%03x: patchSig : '%s'\n" $((byteoffset+ 0)) "$patchSig"
    printf "%03x: majorVers : %d\n" $((byteoffset+ 4)) "$majorVers"
    printf "%03x: minorVers : %d\n" $((byteoffset+ 6)) "$minorVers"
    printf "%03x: flags : 0x%08x" $((byteoffset+ 8)) "$flags"
    if (( flags )); then
    flagtext=$(
    ((flags & 1)) && printf ",kRequiredPatch"
    ((flags & ~1)) && printf ",0x%08x?" $((flags & ~1))
    )
    printf " = %s" "${flagtext:1}"
    fi
    printf "\n"
    printf "%03x: patchOffset : %d\n" $((byteoffset+12)) "$patchOffset"
    printf "%03x: patchSize : %d\n" $((byteoffset+16)) "$patchSize"
    printf "%03x: patchCRC : 0x%08x\n" $((byteoffset+20)) "$patchCRC"
    printf "%03x: patchDescriptorLen : %d\n" $((byteoffset+24)) "$patchDescriptorLen"
    printf "%03x: patchName : %s\n" $((byteoffset+28)) "$patchName"
    printf "%03x: patchVendor : %s\n" $((byteoffset+61)) "$patchVendor"
    [[ -n $patchPad ]] && printf "%03x: patchPad : %s\n" $((byteoffset+62+patchVendorLen)) "$patchPad"

    ((byteoffset+=patchDescriptorLen))
    done # for numPatches

    echo
    xxd -p -r <<< "$blockbytes" | xxd -c 16

    elif [[ ${blockbytes:0:4} == "504d" ]]; then # 'PM'

    first_pmMapBlkCnt=$((0x${blockbytes:8:8}))

    echo
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Partition Map contents (${first_pmMapBlkCnt} partitions)"
    for ((i=0;i<PLENGTH;i++)); do
    if (( i > 0 )); then
    blockbytes=$(dd if="/dev/$DRIVE" bs="$BLOCKSIZE" skip=$((PSTART + POFFSET + i)) count=1 2> /dev/null | xxd -p -c 9999)
    fi
    if [[ -n ${blockbytes//0/} ]]; then
    # Partition
    pmSig="${blockbytes:0:4}"
    pmSigPad=$((0x${blockbytes:4:4}))
    pmMapBlkCnt=$((0x${blockbytes:8:8}))
    pmPyPartStart=$((0x${blockbytes:16:8}))
    pmPartBlkCnt=$((0x${blockbytes:24:8}))
    pmPartName=$(sed -E 's/(00)+$//' <<< "${blockbytes:32:64}" | xxd -p -r | tr '\0' '.')
    pmParType=$(sed -E 's/(00)+$//' <<< "${blockbytes:96:64}" | xxd -p -r | tr '\0' '.')
    pmLgDataStart=$((0x${blockbytes:160:8}))
    pmDataCnt=$((0x${blockbytes:168:8}))
    pmPartStatus=$((0x${blockbytes:176:8}))
    pmLgBootStart=$((0x${blockbytes:184:8}))
    pmBootSize=$((0x${blockbytes:192:8}))
    pmBootAddr=$((0x${blockbytes:200:8}))
    pmBootAddr2=$((0x${blockbytes:208:8}))
    pmBootEntry=$((0x${blockbytes:216:8}))
    pmBootEntry2=$((0x${blockbytes:224:8}))
    pmBootCksum=$((0x${blockbytes:232:8}))
    pmProcessor=$(sed -E 's/(00)+$//' <<< "${blockbytes:240:32}" | xxd -p -r | tr '\0' '.')
    pmPad1="${blockbytes:272:256}"
    pmPad2=$(sed -E 's/(00)+$//' <<< "${blockbytes:528}")

    printf "%2d:" "$((i+1))"
    printf " %10d @ %-10d" \
    "$pmPartBlkCnt" \
    "$pmPyPartStart"

    [[ $pmSig != 504d ]] && printf " Sig:0x%s?" "$pmSig"
    [[ -n $pmParType ]] && printf " Type:\"%s\"" "$pmParType"
    [[ -n $pmPartName ]] && printf " Name:\"%s\"" "$pmPartName"
    (( pmSigPad )) && printf " SigPad:0x%04X" "$pmSigPad"
    (( pmMapBlkCnt != first_pmMapBlkCnt )) && printf " MapBlkCnt:%d" "$pmMapBlkCnt"
    (( pmLgDataStart )) && printf " LgDataStart:%d" "$pmLgDataStart"

    blockbytes2=${blockbytes:160}
    if [[ -n ${blockbytes2//0/} ]]; then

    (( pmDataCnt != pmPartBlkCnt )) && printf " DataCnt:%d" "$pmDataCnt"
    (( pmPartStatus )) && {
    statustext=$(
    (( pmPartStatus & 0x00000001 )) && printf ",Valid" # AUX
    (( pmPartStatus & 0x00000002 )) && printf ",Allocated" # AUX
    (( pmPartStatus & 0x00000004 )) && printf ",InUse" # AUX
    (( pmPartStatus & 0x00000008 )) && printf ",Bootable" # AUX
    (( pmPartStatus & 0x00000010 )) && printf ",Readable" # AUX
    (( pmPartStatus & 0x00000020 )) && printf ",Writeable" # AUX and Mac OS
    (( pmPartStatus & 0x00000040 )) && printf ",BootCodePositionIndependent" # AUX
    (( pmPartStatus & 0x00000080 )) && printf ",OSSpecific2" # ?
    (( pmPartStatus & 0x00000100 )) && printf ",ChainCompatible" # driver
    (( pmPartStatus & 0x00000200 )) && printf ",RealDeviceDriver" # driver
    (( pmPartStatus & 0x00000400 )) && printf ",CanChainToNext" # driver
    (( pmPartStatus & 0x40000000 )) && printf ",MountedAtStartup" # Mac OS
    (( pmPartStatus & 0x80000000 )) && printf ",Startup" # Mac OS
    (( pmPartStatus & 0x3FFFF800 )) && printf ",0x%x?" $((pmPartStatus & 0x3FFFF800))
    )
    printf " Status:%08X=%s" "$pmPartStatus" "${statustext:1}"
    }

    (( pmLgBootStart )) && printf " LgBootStart:%d" "$pmLgBootStart"
    (( pmBootSize )) && printf " BootSize:%d" "$pmBootSize"
    (( pmBootAddr )) && printf " BootAddr:0x%08X" "$pmBootAddr"
    (( pmBootAddr2 )) && printf " BootAddr2:0x%08X" "$pmBootAddr2"
    (( pmBootEntry )) && printf " BootEntry:0x%08X" "$pmBootEntry"
    (( pmBootEntry2 )) && printf " BootEntry2:0x%08X" "$pmBootEntry2"
    (( pmBootCksum )) && printf " BootCksum:0x%08X" "$pmBootCksum"
    [[ -n $pmProcessor ]] && printf " Processor:\"%s\"" "$pmProcessor"
    [[ -n ${pmPad1//0/} ]] && {
    printf " Pad1:%s" "$(sed -E 's/(00)+$//' <<< "${pmPad1}")"
    [ "${pmPad1:0:8}" = 70744452 ] && printf " = 'ptDR' = kPatchDriverSignature"
    [ "${pmPad1:0:8}" = 00010600 ] && printf "00 = kSCSIDriverSignature"
    [ "${pmPad1:0:8}" = 77696b69 ] && printf " = 'wiki' = kATADriverSignature"
    [ "${pmPad1:0:8}" = 43447672 ] && printf " = 'CDvr' = kSCSICDDriverSignature"
    [ "${pmPad1:0:8}" = 41545049 ] && printf " = 'ATPI' = kATAPIDriverSignature"
    [ "${pmPad1:0:8}" = 44535531 ] && printf " = 'DSU1' = kDriveSetupHFSSignature"
    }
    [[ -n $pmPad2 ]] && printf " Pad2:%s" "$pmPad2"
    fi
    printf "\n"
    fi
    done # for APM block

    elif [[ ${blockbytes:0:4} == "4c4b" ]]; then # 'LK'
    # Boot Blocks # https://developer.apple.com/library/archive/documentation/mac/pdf/Files/File_Manager.pdf

    # BootBlkHdr
    #bbID=$((0x${blockbytes:0:4}))
    bbEntry=$((0x${blockbytes:4:8}))
    bbVersion=$((0x${blockbytes:12:4}))
    bbPageFlags=$((0x${blockbytes:16:4}))
    bbSysName=$( pascalstring "${blockbytes:20:32}" )
    bbShellName=$( pascalstring "${blockbytes:52:32}" )
    bbDbg1Name=$( pascalstring "${blockbytes:84:32}" )
    bbDbg2Name=$( pascalstring "${blockbytes:116:32}" )
    bbScreenName=$(pascalstring "${blockbytes:148:32}" )
    bbHelloName=$( pascalstring "${blockbytes:180:32}" )
    bbScrapName=$( pascalstring "${blockbytes:212:32}" )
    bbCntFCBs=$((0x${blockbytes:244:4}))
    bbCntEvts=$((0x${blockbytes:248:4}))
    bb128KSHeap=$((0x${blockbytes:252:8}))
    bb256KSHeap=$((0x${blockbytes:260:8}))
    bbSysHeapSize=$((0x${blockbytes:268:8}))
    filler=$((0x${blockbytes:276:4}))
    bbSysHeapExtra=$((0x${blockbytes:280:8}))
    bbSysHeapFract=$((0x${blockbytes:288:8}))

    echo
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Boot Block Header contents"

    CODESTART=$((0x94))
    printf "000: bbID : \'LK'\n"
    printf "002: bbEntry : 0x%08x" "$bbEntry"
    if (( (bbEntry & 0xffff0000) == 0x60000000 )); then
    CODESTART=$(((bbEntry & 0xffff) + 4))
    printf " = BRA.S *+$%X to offset 0x%03x" $(( CODESTART - 2)) "$CODESTART"
    (( CODESTART - 2 == 0x8a )) && printf " (after old header)"
    (( CODESTART - 2 == 0x94 )) && printf " (after new header)"
    fi
    printf "\n"
    printf "006: bbVersion : 0x%04x" "$bbVersion"
    (( bbVersion )) && {
    printf " ="
    (( bbVersion & 0xff00 )) && {
    printf " flags:("
    if (( bbVersion & 0x8000 )); then
    printf "new header"
    (( bbVersion & 0x4000 )) && printf ", execute boot code"
    (( bbVersion & 0x2000 )) && printf ", use relative system heap - bbSysHeapExtra and bbSysHeapFract instead of bbSysHeapSize"
    (( bbVersion & 0x1f00 )) && printf ", 0x%02x?" $(( (bbVersion & 0x1f00) >> 8 ))
    else
    printf "old header"
    (( bbVersion & 0x7f00 )) && printf ", 0x%02x?" $(( (bbVersion & 0x7f00) >> 8 ))
    fi
    printf ")"
    }
    (( bbVersion & 0xff )) && {
    (( bbVersion & 0xff00 )) && printf ","
    printf " version:%d.%d:(" $(( (bbVersion >> 4) & 15 )) $(( bbVersion & 15 ))
    (( (bbVersion & 0xff) < 0x15 )) && printf "ignore bb128KSHeap and bb256KSHeap and use default of bbSysHeapSize"
    (( (bbVersion & 0xff) >= 0x15 )) && printf "use bbSysHeapSize" # How is this different than < 0x15? the documentation for this is bad
    (( (bbVersion & 0xff) == 0xD )) && printf ", don't execute boot code" # I don't know if this is correct; the documentation for this is bad
    printf ")"
    }
    printf "\n"
    }

    ((bbPageFlags)) && {
    # https://developer.apple.com/library/archive/technotes/dv/dv_03.html#//apple_ref/doc/uid/DTS10002393
    printf "008: bbPageFlags : 0x%04x =" "$bbPageFlags"
    if ((bbPageFlags & 0x8000)); then
    printf "allocate both video and sound buffers"
    else
    ((bbPageFlags > 0)) && printf "allocate only the secondary sound buffer"
    fi
    printf "\n"
    }
    printf "00a: bbSysName : %s\n" "$bbSysName"
    printf "01a: bbShellName : %s\n" "$bbShellName"
    printf "02a: bbDbg1Name : %s\n" "$bbDbg1Name"
    printf "03a: bbDbg2Name : %s\n" "$bbDbg2Name"
    printf "04a: bbScreenName : %s\n" "$bbScreenName"
    printf "05a: bbHelloName : %s\n" "$bbHelloName"
    printf "06a: bbScrapName : %s\n" "$bbScrapName"
    printf "07a: bbCntFCBs : %d\n" "$bbCntFCBs"
    printf "07c: bbCntEvts : %d\n" "$bbCntEvts"
    printf "07e: bb128KSHeap : %d\n" "$bb128KSHeap"
    printf "082: bb256KSHeap : %d\n" "$bb256KSHeap"
    printf "086: bbSysHeapSize : %d\n" "$bbSysHeapSize"
    ((CODESTART > 0x8a)) && printf "08a: filler : 0x%08x\n" "$filler"
    ((CODESTART > 0x8c)) && printf "08c: bbSysHeapExtra: 0x%08x\n" "$bbSysHeapExtra"
    ((CODESTART > 0x90)) && printf "090: bbSysHeapFract: 0x%08x\n" "$bbSysHeapFract"
    printf "%03x: boot code\n" "$CODESTART"

    echo
    xxd -p -r <<< "$blockbytes" | xxd -c 16

    ((POFFSET++))
    blockbytes=$(dd if="/dev/$DRIVE" bs="$BLOCKSIZE" skip=$((PSTART + POFFSET)) count=1 2> /dev/null | xxd -p -c 9999)
    echo
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): 2nd Boot Block contents"
    xxd -p -r <<< "$blockbytes" | xxd -c 16

    ((POFFSET++))
    POFFSETS="_${POFFSET}${POFFSETS}"
    #printf "queued first MDB after boot blocks: $POFFSETS\n"


    elif [[ ${blockbytes:0:4} == "4244" ]]; then # 'BD'
    # Master Directory Blocks # https://developer.apple.com/library/archive/documentation/mac/pdf/Files/File_Manager.pdf

    # MDB
    #drSigWord=${blockbytes:0x000*2:4}
    drCrDate=$((0x${blockbytes:0x002*2:8}))
    drLsMod=$((0x${blockbytes:0x006*2:8}))
    drAtrb=$((0x${blockbytes:0x00a*2:4}))
    drNmFls=$((0x${blockbytes:0x00c*2:4}))
    drVBMSt=$((0x${blockbytes:0x00e*2:4}))
    drAllocPtr=$((0x${blockbytes:0x010*2:4}))
    drNmAlBlks=$((0x${blockbytes:0x012*2:4}))
    drAlBlkSiz=$((0x${blockbytes:0x014*2:8}))
    drClpSiz=$((0x${blockbytes:0x018*2:8}))
    drAlBlSt=$((0x${blockbytes:0x01c*2:4}))
    drNxtCNID=$((0x${blockbytes:0x01e*2:8}))
    drFreeBks=$((0x${blockbytes:0x022*2:4}))
    drVN="$(pascalstring "${blockbytes:0x024*2:28*2}")"
    drVolBkUp=$((0x${blockbytes:0x040*2:8}))
    drVSeqNum=$((0x${blockbytes:0x044*2:4}))
    drWrCnt=$((0x${blockbytes:0x046*2:8}))
    drXTClpSiz=$((0x${blockbytes:0x04a*2:8}))
    drCTClpSiz=$((0x${blockbytes:0x04e*2:8}))
    drNmRtDirs=$((0x${blockbytes:0x052*2:4}))
    drFilCnt=$((0x${blockbytes:0x054*2:8}))
    drDirCnt=$((0x${blockbytes:0x058*2:8}))
    drFndrInfo="${blockbytes:0x05c*2:64}"

    drVCSize=$((0x${blockbytes:0x07c*2:4}))
    drVBMCSize=$((0x${blockbytes:0x07e*2:4}))
    drCtlCSize=$((0x${blockbytes:0x080*2:4}))

    drEmbedSigWord="$drVCSize"
    drEmbedExtent_startBlock="$drVBMCSize"
    drEmbedExtent_blockCount="$drCtlCSize"

    drXTFlSize=$((0x${blockbytes:0x082*2:8}))
    drXTExtRec="${blockbytes:0x086*2:24}"
    drCTFlSize=$((0x${blockbytes:0x092*2:8}))
    drCTExtRec="${blockbytes:0x096*2:24}"

    echo
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Master Directory Block contents"

    printf "000: drSigWord : 'BD' = kHFSSigWord\n"
    printf "002: drCrDate : %s\n" "$( ((drCrDate)) && date -r $((drCrDate-2082844800)))"
    printf "006: drLsMod : %s\n" "$( ((drLsMod )) && date -r $((drLsMod -2082844800)))"
    ((drAtrb)) && {
    attributestext=$(
    ((drAtrb & 0x0080)) && printf ",VolumeHardwareLock"
    ((drAtrb & 0x0100)) && printf ",VolumeUnmounted"
    ((drAtrb & 0x0200)) && printf ",VolumeSparedBlocks"
    ((drAtrb & 0x0400)) && printf ",VolumeNoCacheRequired"
    ((drAtrb & 0x0800)) && printf ",BootVolumeInconsistent"
    ((drAtrb & 0x1000)) && printf ",CatalogNodeIDsReused"
    ((drAtrb & 0x2000)) && printf ",VolumeJournaled"
    ((drAtrb & 0x4000)) && printf ",VolumeInconsistent"
    ((drAtrb & 0x8000)) && printf ",VolumeSoftwareLock"
    ((drAtrb & 0x007f)) && printf ",0x%04x?" $((drAtrb & 0x007f))
    )
    printf "00a: drAtrb : 0x%04x = %s\n" "$drAtrb" "${attributestext:1}"
    }

    printf "00c: drNmFls : %d\n" "$drNmFls"
    printf "00e: drVBMSt : %d\n" "$drVBMSt"
    printf "010: drAllocPtr : %d\n" "$drAllocPtr"
    printf "012: drNmAlBlks : %d\n" "$drNmAlBlks"
    printf "014: drAlBlkSiz : %d\n" "$drAlBlkSiz"
    printf "018: drClpSiz : %d\n" "$drClpSiz"
    printf "01c: drAlBlSt : %d\n" "$drAlBlSt"
    printf "01e: drNxtCNID : %d\n" "$drNxtCNID"
    printf "022: drFreeBks : %d\n" "$drFreeBks"
    printf "024: drVN : %s\n" "$drVN"
    printf "040: drVolBkUp : %s\n" "$( ((drVolBkUp)) && date -r $((drVolBkUp-2082844800)))"
    printf "044: drVSeqNum : %d\n" "$drVSeqNum"
    printf "046: drWrCnt : %d\n" "$drWrCnt"
    printf "04a: drXTClpSiz : %d\n" "$drXTClpSiz"
    printf "04e: drCTClpSiz : %d\n" "$drCTClpSiz"
    printf "052: drNmRtDirs : %d\n" "$drNmRtDirs"
    printf "054: drFilCnt : %d\n" "$drFilCnt"
    printf "058: drDirCnt : %d\n" "$drDirCnt"
    printf "05c: drFndrInfo:\n"
    printf "05c: Blessed System Folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${drFndrInfo: 0: 8}))" )"
    printf "060: Blessed System File : %s\n" "$(inodestring "$DEVICEID" "$((0x${drFndrInfo: 8: 8}))" )"
    printf "064: Open-folder linked list : %s\n" "$(inodestring "$DEVICEID" "$((0x${drFndrInfo:16: 8}))" )"
    printf "068: Alternate OS blessed file/folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${drFndrInfo:24: 8}))" )"
    dumpencoding "06c: Text encoding :" "$((0x${drFndrInfo:32: 8}))"
    printf "070: OS X blessed folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${drFndrInfo:40: 8}))" )"
    printf "074: 64-bit VSDB volume id : 0x%016X\n" $((0x${drFndrInfo:48:16}))

    if (( drEmbedSigWord == 0x482b )); then
    printf "07c: drEmbedSigWord: %d = 'H+' = kHFSPlusSigWord\n" "$drEmbedSigWord"
    printf "07e: drEmbedExtent.startBlock : %d\n" "$drEmbedExtent_startBlock"
    printf "080: drEmbedExtent.blockCount : %d\n" "$drEmbedExtent_blockCount"
    else
    printf "07c: drVCSize : %d\n" "$drVCSize"
    printf "07e: drVBMCSize : %d\n" "$drVBMCSize"
    printf "080: drCtlCSize : %d\n" "$drCtlCSize"
    fi

    printf "082: drXTFlSize : %d\n" "$drXTFlSize"
    printf "086: drXTExtRec : %s\n" "$(extentstring "$drXTExtRec")"
    printf "092: drCTFlSize : %d\n" "$drCTFlSize"
    printf "096: drCTExtRec : %s\n" "$(extentstring "$drCTExtRec")"

    echo
    xxd -p -r <<< "$blockbytes" | xxd -c 16

    if ((POFFSET < drNmAlBlks * (drAlBlkSiz / 512) - 2)); then
    # queue up location of alternate Master Directory Block
    POFFSETS="_$((PLENGTH-2))_$((PLENGTH-1))${POFFSETS}"
    #printf "queued 2alternate MDB: $POFFSETS \n"

    if (( drEmbedSigWord == 0x482b )); then
    # queue up location of wrapped HFS+ partition
    hfsplusblock=$(( drAlBlSt + drEmbedExtent_startBlock * (drAlBlkSiz / 512) ))
    POFFSETS="${POFFSETS}_$((hfsplusblock))_$((hfsplusblock+1))_$((hfsplusblock+2))"
    #printf "queued 3wrapped: $POFFSETS \n"
    fi
    fi

    elif [[ ${blockbytes:0:4} == "482b" ]] || [[ ${blockbytes:0:4} == "4858" ]]; then # 'H+' or 'HX'
    # Master Directory Blocks # https://developer.apple.com/library/archive/documentation/mac/pdf/Files/File_Manager.pdf

    # HFS Plus Volume Header
    signature=$((0x${blockbytes:0x000*2:4}))
    signatureChars=$(sed -E 's/(00)+$//' <<< "${blockbytes:0x000*2:4}" | xxd -p -r | tr '\0' '.')
    version=$((0x${blockbytes:0x002*2:4}))
    attributes=$((0x${blockbytes:0x004*2:8}))
    lastMountedVersion=$((0x${blockbytes:0x008*2:8}))
    lastMountedVersionChars=$(sed -E 's/(00)+$//' <<< "${blockbytes:0x008*2:8}" | xxd -p -r | tr '\0' '.')
    journalInfoBlock=$((0x${blockbytes:0x00c*2:8}))
    createDate=$((0x${blockbytes:0x010*2:8}))
    modifyDate=$((0x${blockbytes:0x014*2:8}))
    backupDate=$((0x${blockbytes:0x018*2:8}))
    checkedDate=$((0x${blockbytes:0x01c*2:8}))
    fileCount=$((0x${blockbytes:0x020*2:8}))
    folderCount=$((0x${blockbytes:0x024*2:8}))
    blockSize=$((0x${blockbytes:0x028*2:8}))
    totalBlocks=$((0x${blockbytes:0x02c*2:8}))
    freeBlocks=$((0x${blockbytes:0x030*2:8}))
    nextAllocation=$((0x${blockbytes:0x034*2:8}))
    rsrcClumpSize=$((0x${blockbytes:0x038*2:8}))
    dataClumpSize=$((0x${blockbytes:0x03c*2:8}))
    nextCatalogID=$((0x${blockbytes:0x040*2:8}))
    writeCount=$((0x${blockbytes:0x044*2:8}))
    encodingsBitmap=$((0x${blockbytes:0x048*2:16}))
    finderInfo="${blockbytes:0x050*2:64}"
    allocationFile="${blockbytes:0x070*2:160}"
    extentsFile="${blockbytes:0x0c0*2:160}"
    catalogFile="${blockbytes:0x110*2:160}"
    attributesFile="${blockbytes:0x160*2:160}"
    startupFile="${blockbytes:0x1b0*2:160}"

    echo
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): HFS Plus Volume Header contents"

    printf "000: signature : '%s'" "$signatureChars"
    ((signature == 0x482b )) && printf " = kHFSPlusSigWord"
    ((signature == 0x4858 )) && printf " = kHFSXSigWord"
    printf "\n"

    printf "002: version : %d" "$version"
    ((version == 4 )) && printf " = kHFSPlusVersion"
    ((version == 5 )) && printf " = kHFSXVersion"
    printf "\n"

    ((attributes)) && {
    attributestext=$(
    ((attributes & 0x00000080)) && printf ",VolumeHardwareLock"
    ((attributes & 0x00000100)) && printf ",VolumeUnmounted"
    ((attributes & 0x00000200)) && printf ",VolumeSparedBlocks"
    ((attributes & 0x00000400)) && printf ",VolumeNoCacheRequired"
    ((attributes & 0x00000800)) && printf ",BootVolumeInconsistent"
    ((attributes & 0x00001000)) && printf ",CatalogNodeIDsReused"
    ((attributes & 0x00002000)) && printf ",VolumeJournaled"
    ((attributes & 0x00004000)) && printf ",VolumeInconsistent"
    ((attributes & 0x00008000)) && printf ",VolumeSoftwareLock"
    ((attributes & 0x40000000)) && printf ",ContentProtection"
    ((attributes & 0x80000000)) && printf ",UnusedNodeFix"
    ((attributes & 0x3fff007f)) && printf ",0x%08x?" $((drAtrb & 0x3fff007f))
    )
    printf "004: attributes : 0x%08x = %s\n" "$attributes" "${attributestext:1}"
    }

    printf "008: lastMountedVersion : 0x%08x = '%s'" "$lastMountedVersion" "$lastMountedVersionChars"
    ((lastMountedVersion == 0x31302E30 )) && printf " = kHFSPlusMountVersion" # '10.0'; (Mac OS 8.1 to 9.2.2 is '8.10')
    ((lastMountedVersion == 0x4846534a )) && printf " = kHFSJMountVersion"
    ((lastMountedVersion == 0x46534b21 )) && printf " = kFSKMountVersion"
    printf "\n"

    ((journalInfoBlock || (attributes & 0x00002000) )) && printf "00c: journalInfoBlock : %d\n" "$journalInfoBlock"
    printf "010: createDate : %s\n" "$( ((createDate )) && date -r $((createDate -2082844800)))"
    printf "014: modifyDate : %s\n" "$( ((modifyDate )) && date -r $((modifyDate -2082844800)))"
    printf "018: backupDate : %s\n" "$( ((backupDate )) && date -r $((backupDate -2082844800)))"
    printf "01c: checkedDate : %s\n" "$( ((checkedDate)) && date -r $((checkedDate-2082844800)))"
    printf "020: fileCount : %d\n" "$fileCount"
    printf "024: folderCount : %d\n" "$folderCount"
    printf "028: blockSize : %d\n" "$blockSize"
    printf "02c: totalBlocks : %d\n" "$totalBlocks"
    printf "030: freeBlocks : %d\n" "$freeBlocks"
    printf "034: nextAllocation : %d\n" "$nextAllocation"
    printf "038: rsrcClumpSize : %d\n" "$rsrcClumpSize"
    printf "03c: dataClumpSize : %d\n" "$dataClumpSize"
    printf "040: nextCatalogID : %d\n" "$nextCatalogID"
    printf "044: writeCount : %d\n" "$writeCount"
    ((encodingsBitmap)) && {
    encodings=$(
    ((encodingsBitmap & (1<< 0))) && printf ",MacRoman"
    ((encodingsBitmap & (1<< 1))) && printf ",MacJapanese"
    ((encodingsBitmap & (1<< 2))) && printf ",MacChineseTrad"
    ((encodingsBitmap & (1<< 3))) && printf ",MacKorean"
    ((encodingsBitmap & (1<< 4))) && printf ",MacArabic"
    ((encodingsBitmap & (1<< 5))) && printf ",MacHebrew"
    ((encodingsBitmap & (1<< 6))) && printf ",MacGreek"
    ((encodingsBitmap & (1<< 7))) && printf ",MacCyrillic"
    ((encodingsBitmap & (1<< 9))) && printf ",MacDevanagari"
    ((encodingsBitmap & (1<<10))) && printf ",MacGurmukhi"
    ((encodingsBitmap & (1<<11))) && printf ",MacGujarati"
    ((encodingsBitmap & (1<<12))) && printf ",MacOriya"
    ((encodingsBitmap & (1<<13))) && printf ",MacBengali"
    ((encodingsBitmap & (1<<14))) && printf ",MacTamil"
    ((encodingsBitmap & (1<<15))) && printf ",MacTelugu"
    ((encodingsBitmap & (1<<16))) && printf ",MacKannada"
    ((encodingsBitmap & (1<<17))) && printf ",MacMalayalam"
    ((encodingsBitmap & (1<<18))) && printf ",MacSinhalese"
    ((encodingsBitmap & (1<<19))) && printf ",MacBurmese"
    ((encodingsBitmap & (1<<20))) && printf ",MacKhmer"
    ((encodingsBitmap & (1<<21))) && printf ",MacThai"
    ((encodingsBitmap & (1<<22))) && printf ",MacLaotian"
    ((encodingsBitmap & (1<<23))) && printf ",MacGeorgian"
    ((encodingsBitmap & (1<<24))) && printf ",MacArmenian"
    ((encodingsBitmap & (1<<25))) && printf ",MacChineseSimp"
    ((encodingsBitmap & (1<<26))) && printf ",MacTibetan"
    ((encodingsBitmap & (1<<27))) && printf ",MacMongolian"
    ((encodingsBitmap & (1<<28))) && printf ",MacEthiopic"
    ((encodingsBitmap & (1<<29))) && printf ",MacCentralEurRoman"
    ((encodingsBitmap & (1<<30))) && printf ",MacVietnamese"
    ((encodingsBitmap & (1<<31))) && printf ",MacExtArabic"
    ((encodingsBitmap & (1<<33))) && printf ",MacSymbol"
    ((encodingsBitmap & (1<<34))) && printf ",MacDingbats"
    ((encodingsBitmap & (1<<35))) && printf ",MacTurkish"
    ((encodingsBitmap & (1<<36))) && printf ",MacCroatian"
    ((encodingsBitmap & (1<<37))) && printf ",MacIcelandic"
    ((encodingsBitmap & (1<<38))) && printf ",MacRomanian"
    ((encodingsBitmap & (1<<48))) && printf ",MacUkrainian"
    ((encodingsBitmap & (1<<49))) && printf ",MacFarsi"
    ((encodingsBitmap & 0xfffcff8100000000)) && printf ",0x%016x?" $((encodingsBitmap & 0xfffcff8100000000))
    )
    printf "048: encodingsBitmap : 0x%016x = %s" "$encodingsBitmap" "${encodings:1}"
    }
    printf "\n"
    printf "050: finderInfo:\n"
    printf "050: Blessed System Folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo: 0: 8}))" )"
    printf "054: Blessed System File : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo: 8: 8}))" )"
    printf "058: Open-folder linked list : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo:16: 8}))" )"
    printf "05c: Alternate OS blessed file/folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo:24: 8}))" )"
    dumpencoding "060: Text encoding :" "$((0x${finderInfo:32: 8}))"
    printf "064: OS X blessed folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo:40: 8}))" )"
    printf "068: 64-bit VSDB volume id : 0x%016X\n" $((0x${finderInfo:48:16}))
    printf "070: allocationFile : %s\n" "$(forkdatastring "$allocationFile" )"
    printf "0c0: extentsFile : %s\n" "$(forkdatastring "$extentsFile" )"
    printf "110: catalogFile : %s\n" "$(forkdatastring "$catalogFile" )"
    printf "160: attributesFile : %s\n" "$(forkdatastring "$attributesFile" )"
    printf "1b0: startupFile : %s\n" "$(forkdatastring "$startupFile" )"

    echo
    xxd -p -r <<< "$blockbytes" | xxd -c 16

    if ((POFFSET < PLENGTH-4)); then
    # queue up location of alternate HFS Plus Volume Header

    # HFS+ volume starts at POFFSET - 2
    endoffset=$((POFFSET - 2 + totalBlocks * (blockSize / 512)))

    POFFSETS="_$((endoffset - 2))_$((endoffset - 1))${POFFSETS}"
    #printf "queued alternate HFS+ Header: $POFFSETS\n"
    fi

    else
    if (( 0x${blockbytes:0x20*2:8} == 0x4e585342 )); then # 'NXSB'
    echo
    echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): APFS Container contents"
    else
    HASH=$(xxd -p -r <<< "${blockbytes:96*2:416*2}" | xxd -p | md5)
    FindHash "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): $(
    ((POFFSET==0)) && printf "VBR "
    )contents" "$VBRHASHES" "$HASH"
    fi

    if [[ -n ${blockbytes//0/} ]]; then
    xxd -p -r <<< "$blockbytes" | xxd -c 16
    POFFSETS=""
    elif [[ -z $POFFSETS ]] && (( POFFSET < 2 )); then
    POFFSETS="_$((POFFSET+1))"
    #printf "queued after zero block: $POFFSETS\n"
    fi
    fi
    done # while POFFSETS
    done # while THEPART

    done
    echo "==============================================================================="
    ioreg -rw 0 -c IOMedia | sed -n -E "/^[ \|]*\+\-o (.*) <class IOMedia[^a-zA-Z]/,/^[ \|]+ }$/p" | sed -n -E "/^[ \|]*\+\-o (.*)/s//\1/p;/^[ \|]* \| (.*)/s//\1/p;"
    echo "==============================================================================="
    bless --verbose --getboot
    echo "==============================================================================="
    bless --verbose --info
    echo "==============================================================================="
    ioreg -rw 0 -n AppleEFINVRAM | sed -n -E "/^[ \|]+[ ]+(\".*)$/s//\1/p;"
    echo "==============================================================================="
    #exit

    if [[ -n $INPUTDISK ]]; then
    echo "==============================================================================="
    ioreg -w 0 -c IOMedia | sed -n -E "/^[ \|]*\+\-o (.*) <class IOMedia[^a-zA-Z]/,/^[ \|]+ }$/p" | {
    sed -n -E "/^[ \|]*\+\-o (.*)/s//\1/p;/^[ \|]* \| (.*)/s//\1/p;"
    } | {
    perl -0777 -nE 'while (/(^.*? <class IOMedia.*\n\{\n( .*\n)*^ "BSD Name" = "('"$INPUTDISK"'[^\d]|'"${INPUTDISK/s[0-9]*/}"'").*\n( .*\n)*?^}\n)/mg) { printf "$1\n" }'
    }
    echo "==============================================================================="
    else
    echo "==============================================================================="
    ioreg -w 0 -c IOMedia | sed -n -E "/^[ \|]*\+\-o (.*) <class IOMedia[^a-zA-Z]/,/^[ \|]+ }$/p" | sed -n -E "/^[ \|]*\+\-o (.*)/s//\1/p;/^[ \|]* \| (.*)/s//\1/p;"
    echo "==============================================================================="
    bless --verbose --getBoot
    echo "==============================================================================="
    bless --verbose --info
    echo "==============================================================================="
    #ioreg -rw 0 -n AppleEFINVRAM 2> /dev/null | sed -n -E "/^[ \|]+[ ]+(\".*)$/s//\1/p;"
    ioreg -lw0 -p IODeviceTree 2> /dev/null | sed -nE '/o chosen/,/}$/p ; /o option/,/}$/p ; /o aliases/,/}$/p ' | sed -nE "/^[ \|]+[ ]+(\".*)$/s// \1/p; / +\+\-o (.*) +<class ([^,]+).*/s//\1 <\2>/p"
    echo "==============================================================================="
    fi
  8. joevt created this gist Jan 16, 2021.
    172 changes: 172 additions & 0 deletions dumpvols.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,172 @@
    #!/bin/bash
    #
    # Get Partition Info from all disks
    #
    # Written by joevt updated Dec 29. 2020
    # Patches marked "rgh" July, 2010, to dump information beyond the
    # four bios partitions
    #
    # sudo ./dumpvols.sh > dumpvols_result.txt 2>&1
    #
    # Based on johnsock's AHCI Master Boot Record Patch.
    #
    # This script is freely distributable.
    #

    if [ ! "$USER" = "root" ]; then
    echo WARNING: This script must be run as root.
    exit
    fi

    MBRHASHES=\
    "Windows_XP=d88d4f2dbc2c662db7d7d60ebf9e3e00 "\
    "Windows_Vista=12c9d7ff4914c88a7f9eadf9211b861b "\
    "Windows_7=118eb70c44cb69284e5d8aa93096831e "\
    "None_all_zeros=4ebc676ce4896613a3a9df6e2a1c77ae "\
    ""\
    "MSDOS_or_FreeDOS_on_FreeDOS=93dd2ee87a995e36cbab0c2d5c2f041a "\
    ""\
    "Windows_XP_On_BootCamp2_with_AHCI_patch=c3fb54174bc479899d4ef6e45308dc18 "\
    "Windows_XP_On_BootCamp2=cb4dabdd862da0508083b05814e198b8 "\
    "Windows_Vista_on_XP_with_AHCI_patch=4979e1b9d70738759280f6962c2ad298 "\
    "Windows_7_on_XP=7db43c1425e9ff3077dd62b776a50419 "\
    "Windows_7_with_AHCI_patch=a243d3475531b0f6f0d7199043c2eb5c "\
    "Windows_7_on_XP_with_AHCI_patch=24977c27865adec9ac8298f1a8d214bf "\
    ""\
    "Apple_Partition_Map_Block0_Driver_Descriptor_Map_390721968_blocks_and_Tiger_OS_9_drivers=087f35e49a39d52a46e3a94882869f51 "\
    ""


    #All VBR hashes use all the bytes starting from offset 0x60. It may be better to use a different range for each type of VBR...

    # GRUB2 hash was incorrectly named GRUB #rgh
    # added GRUB hash from observation of kununtu 9.04 #rgh
    # added Windows 8
    VBRHASHES=\
    "None_all_zeros=acf496fff71230daa6985a701f83ce49 "\
    "NTFS_No_Loader=3be27456483746abb85cd614381dac5e "\
    "NTFS_Windows_XP_NTLDR=dd1728a59343b9fa9458d80657f68771 "\
    "NTFS_Windows_Vista_BOOTMGR=d1c278b56eeea9536d0eb5898fe6a0b5 "\
    "NTFS_Windows_8_BOOTMGR=771df8b803f96296854316d3d5918812 "\
    "GRUB_from_Ubuntu=332469fa146db809f58d6392e2e0bdce "\
    "GRUB2_from_Ubuntu=9c249066e1eb9c842d8acdfe6d23a2e3 "\
    "FAT32_FRDOS4.1=98050815221ee147066f99f806c23203 "\
    "FAT32_FRDOS4.1_or_MSWIN4.1_BOOTMGR=aec608de8ac709d91e6f3340b643ab4d "\
    "FAT32_NTFS_NTLDR=d9c3d66e975d2b3b122353951a598b32 "\
    "FAT12_BSD_4.4_BOOTMGR=4cc92970d5a3350bc72d2b975e28b915 "\
    "FAT16_Non_system_disk=2a3d0f51ad246f115aa7d37891788857 "\
    "FAT32_Non_system_disk_or_EFI=34f2d1f3c3ecce5c00cae8f0b82c922b "\
    "HFS_boot_block_0=28f5bc1563fbaedeb8dabbd4ef9eb4c2 "\
    ""

    FindHash () {
    # $1: name of hashed contents
    # $2: list of known hashes
    # $3: the hash to search for
    DIDFIND=0
    for CURHASH in $2; do
    THEHASH=$(expr "$CURHASH" : '[^=]*=\(.*\)')
    THEOS=$(expr "$CURHASH" : '^\([^=]*\)=')
    if [ "$3" = "$THEHASH" ]; then
    DIDFIND=1
    break
    fi
    done
    echo ""
    if [ $DIDFIND = 1 ]; then
    echo "$1: $THEOS"
    else
    echo "$1: Unrecognized (hash=$3)"
    fi
    }

    disklist="$(diskutil list)"
    echo "$disklist"
    echo
    diskutil apfs list

    DRIVELIST=$(sed -n -E "/^[ ]*0: [ ]{0,25}([A-Za-z_]+)[ ]*\*[0-9.]+ [TGMK]B[ ]+(disk[0-9]+)$/s//\1_\2/p;/^[ ]*0: [ ]{0,26} .* \*[0-9.]+ [TGMK]B[ ]+(disk[0-9]+)$/s//whole_\1/p" <<< "$disklist")
    for PARTDRIVE in $DRIVELIST;
    do
    DRIVE=$(expr "$PARTDRIVE" : '.*_\([^_]*\)')
    PTYPE=$(expr "$PARTDRIVE" : '\(.*\)_[^_]*')
    echo "==============================================================================="

    diskutiloutput="$(sed -nE '/\/dev\/'$DRIVE' /,/^$/ p' <<< "${disklist}")"
    echo "$diskutiloutput"

    echo "---------------------------------------------"
    diskinfo="$(diskutil info $DRIVE)"
    echo "$diskinfo"
    echo
    BLOCKSIZE=$(sed -nE '/^ *Device Block Size: +([0-9]+).*/s//\1/p' <<< "$diskinfo")
    if [[ -z $BLOCKSIZE ]]; then
    BLOCKSIZE=512
    fi

    DEVLIST=$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s[0-9]+)$/s//\1/p")
    for THEDEV in $DEVLIST; do
    echo "---------------------------------------------"
    diskutil info $THEDEV
    done

    if [ "$PTYPE" = "Apple_partition_scheme" ]; then
    pdisk -r -l "/dev/$DRIVE"
    pdisk -r -l -f "/dev/$DRIVE"

    # use the same bytes as MBR hash even though Block0 contents are totally different
    HASH=$(dd if="/dev/$DRIVE" bs=1 count=446 2> /dev/null | xxd -p -l 440 | md5)
    FindHash "Block0 contents" "$MBRHASHES" "$HASH"
    dd if="/dev/$DRIVE" bs=1 count=512 2> /dev/null | xxd -c 16
    elif [ "$PTYPE" = "GUID_partition_scheme" -o "$PTYPE" = "FDisk_partition_scheme" ]; then

    gptoutput="$(gpt -r show $DRIVE 2>&1)"
    gptoutput2="$(gpt -r show -l $DRIVE 2>&1)"
    fdiskoutput="$(fdisk /dev/r$DRIVE)"

    echo "$gptoutput"
    echo "$gptoutput2"
    echo "$fdiskoutput"

    HASH=$(dd if="/dev/$DRIVE" bs=1 count=446 2> /dev/null | xxd -p -l 440 | md5)
    FindHash "MBR contents" "$MBRHASHES" "$HASH"
    dd if="/dev/$DRIVE" bs=1 count=512 2> /dev/null | xxd -c 16

    if [ "$PTYPE" = "FDisk_partition_scheme" ]; then
    PARTLIST=$(echo "$fdiskoutput" | sed -n -E "/^[ \*]+([0-9])\: .*\[[ ]*([0-9]+) \-[ ]+([1-9][0-9]*)\].*$/s//\1_\2_\3/p")
    PARTTYPE="MBR"
    else
    HASH=$(dd if="/dev/$DRIVE" bs=1 skip=$((BLOCKSIZE + 96)) count=416 2> /dev/null | xxd -p -l 440 | md5)
    FindHash "GPT Header @ 1: GPT Header contents" "$VBRHASHES" "$HASH"
    dd if="/dev/$DRIVE" bs=1 skip=$BLOCKSIZE count=$BLOCKSIZE 2> /dev/null | xxd -c 16

    PARTLIST=$(echo "$gptoutput" | sed -n -E "/^[ ]+([0-9]+)[ ]+([0-9]+)[ ]+([0-9]+)[ ]+GPT part \-.*$/s//\3_\1_\2/p")
    PARTTYPE="GPT"
    fi

    for THEPART in $PARTLIST; do
    PNUM=$(expr "$THEPART" : '\([0-9]*\)_')
    PSTART=$(expr "$THEPART" : '[0-9]*_\([0-9]*\)_[0-9]*')
    PLENGTH=$(expr "$THEPART" : '[0-9]*_[0-9]*_\([0-9]*\)')

    HASH=$(dd if="/dev/$DRIVE" bs=1 skip=$((PSTART * BLOCKSIZE + 96)) count=416 2> /dev/null | xxd -p -l 440 | md5)
    FindHash "$PARTTYPE $PNUM @ $PSTART: VBR contents" "$VBRHASHES" "$HASH"
    dd if="/dev/$DRIVE" bs=1 skip=$((PSTART * BLOCKSIZE)) count=$BLOCKSIZE 2> /dev/null | xxd -c 16
    done
    elif [ "$PTYPE" = "whole" ]; then
    HASH=$(dd if="/dev/$DRIVE" bs=1 count=416 2> /dev/null | xxd -p -l 440 | md5)
    FindHash "0 @ 0: VBR contents" "$VBRHASHES" "$HASH"
    dd if="/dev/$DRIVE" bs=512 count=1 2> /dev/null | xxd -c 16
    else
    echo "Unknown partition scheme"
    fi
    done
    echo "==============================================================================="
    ioreg -rw 0 -c IOMedia | sed -n -E "/^[ \|]*\+\-o (.*) <class IOMedia[^a-zA-Z]/,/^[ \|]+ }$/p" | sed -n -E "/^[ \|]*\+\-o (.*)/s//\1/p;/^[ \|]* \| (.*)/s//\1/p;"
    echo "==============================================================================="
    bless --verbose --getboot
    echo "==============================================================================="
    bless --verbose --info
    echo "==============================================================================="
    ioreg -rw 0 -n AppleEFINVRAM | sed -n -E "/^[ \|]+[ ]+(\".*)$/s//\1/p;"
    echo "==============================================================================="