Skip to content

Instantly share code, notes, and snippets.

@vjt
Last active May 18, 2025 18:13

Revisions

  1. vjt revised this gist Nov 20, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion copy-from-time-machine.sh
    Original file line number Diff line number Diff line change
    @@ -46,7 +46,7 @@ if [ -z "$hfsd" ]; then
    sysname="$(echo -ne '.HFS+ Private Directory Data\r')"
    hfsd=$source
    while [ "$hfsd" != "/" -a ! -d "$hfsd/$sysname" ]; do
    hfsd=`dirname $hfsd`;
    hfsd=`dirname "$hfsd"`;
    done

    if [ "$hfsd" = '/' ]; then
  2. vjt revised this gist Mar 17, 2013. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions copy-from-time-machine.sh
    100644 → 100755
    Original file line number Diff line number Diff line change
    @@ -64,7 +64,7 @@ find "$source" -mindepth 1 -maxdepth 1 -and -not -name . -and -not -name .. | wh

    case $type in
    'regular file'|'symbolic link')
    cp -va "$entry" "$dest"
    cp -van "$entry" "$dest"
    ;;

    'directory')
    @@ -82,4 +82,4 @@ find "$source" -mindepth 1 -maxdepth 1 -and -not -name . -and -not -name .. | wh
    ;;
    esac

    done
    done
  3. vjt revised this gist Mar 17, 2013. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions copy-from-time-machine.sh
    Original file line number Diff line number Diff line change
    @@ -43,8 +43,9 @@ fi

    if [ -z "$hfsd" ]; then
    # Look for HFS Private directory data
    sysname="$(echo -ne '.HFS+ Private Directory Data\r')"
    hfsd=$source
    " ]; do [ "$hfsd" != "/" -a ! -d "$hfsd/.HFS+ Private Directory Data
    while [ "$hfsd" != "/" -a ! -d "$hfsd/$sysname" ]; do
    hfsd=`dirname $hfsd`;
    done

    @@ -53,7 +54,7 @@ if [ -z "$hfsd" ]; then
    exit -2
    else
    echo "HFS Private Directory Data found in '$hfsd'"
    " hfsd="$hfsd/.HFS+ Private Directory Data
    hfsd="$hfsd/$sysname"
    fi
    fi

  4. vjt revised this gist Mar 17, 2013. 1 changed file with 20 additions and 0 deletions.
    20 changes: 20 additions & 0 deletions copy-from-time-machine.sh
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,26 @@
    #
    # Copy data from a Time Machine volume mounted on a Linux box.
    #
    # Usage: copy-from-time-machine.sh <source> <target>
    #
    # source: the source directory inside a time machine backup
    # target: the target directory in which to copy the reconstructed
    # directory trees. Created if it does not exists.
    #
    # Details:
    #
    # Time machine implements directory hard links by creating an
    # empty file in place of the directory and storing in its
    # "number of hard links" metadata attribute a pointer to a
    # real directory in "/.HFS Private directory data^M" named
    # "dir_$number".
    #
    # This script reconstructs a plain directory tree from this
    # really ugly apple hack. Tested on a 650GB backup from OSX
    # 10.6 mounted on a Linux 3.2.0-38 Ubuntu box. YMMV.
    #
    # MIT License.
    #
    # - [email protected]
    #

  5. vjt created this gist Mar 17, 2013.
    64 changes: 64 additions & 0 deletions copy-from-time-machine.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,64 @@
    #!/bin/bash
    #
    # Copy data from a Time Machine volume mounted on a Linux box.
    #
    # - [email protected]
    #

    self="$0"
    source="$1"
    target="$2"
    hfsd="$3"

    set -e

    if [ -z "$source" -o -z "$target" ]; then
    echo "Usage: $self <source> <target>"
    exit -1
    fi

    if [ ! -d "$target" ]; then
    mkdir -p "$target"
    fi

    if [ -z "$hfsd" ]; then
    # Look for HFS Private directory data
    hfsd=$source
    " ]; do [ "$hfsd" != "/" -a ! -d "$hfsd/.HFS+ Private Directory Data
    hfsd=`dirname $hfsd`;
    done

    if [ "$hfsd" = '/' ]; then
    echo "HFS Private Directory Data not found in $source, is it an HFS filesystem?"
    exit -2
    else
    echo "HFS Private Directory Data found in '$hfsd'"
    " hfsd="$hfsd/.HFS+ Private Directory Data
    fi
    fi

    find "$source" -mindepth 1 -maxdepth 1 -and -not -name . -and -not -name .. | while read entry; do
    dest="$target/`basename "$entry"`"
    read hlnum type <<<$(stat -c '%h %F' "$entry")

    case $type in
    'regular file'|'symbolic link')
    cp -va "$entry" "$dest"
    ;;

    'directory')
    # Recurse
    $self "$entry" "$dest" "$hfsd"
    ;;

    'regular empty file')
    if [ -d "$hfsd/dir_$hlnum" ]; then
    # Recurse
    $self "$hfsd/dir_$hlnum" "$dest" "$hfsd"
    else
    echo "Skipping empty file $entry"
    fi
    ;;
    esac

    done