-
Star
(113)
You must be signed in to star a gist -
Fork
(21)
You must be signed in to fork a gist
-
-
Save vjt/5183305 to your computer and use it in GitHub Desktop.
| #!/bin/bash | |
| # | |
| # 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] | |
| # | |
| 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 | |
| sysname="$(echo -ne '.HFS+ Private Directory Data\r')" | |
| hfsd=$source | |
| while [ "$hfsd" != "/" -a ! -d "$hfsd/$sysname" ]; do | |
| 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/$sysname" | |
| 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 -van "$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 |
Scritp does not work either if the source is a Time-Machine hard link. My fork https://gist.github.com/magicoli/283785bdf21ebafd2202 fixes that too.
I am getting a lot of the following errors:
stat: cannot stat ‘/xxxx’: Cannot allocate memory
Is there any way to fix this?
You saved my life, lol! Thanks!
Is it intended behavior that my Backups.backupdb folder is now empty? How can I use this with a mac again?
Thank you very much for making this script available!
@shushugah's comment worried me, but if you read through the script you can see that no files are deleted or modified in any way in the source folder. I can see all the files in my Backups.backupdb folder after extracting everything I needed.
Thank you :)
This was so useful I created a python clone here:
https://gist.github.com/alexcthomas/6df11f8a7b10a40a1dbc6adf7440995f
Hey Guys ,
I'm a complete noob when it comes to programming. I have written small C programms for school but other than that, I'm useless hahah.
I wanted to ask how exactly to I proceed with this? I copied the code to my atom editor (but the version with the "unset LANG" at the beginning of the code) saved it as tmbackup.sh and compiled with chmod +x.
Then i tried to run the programm by typing ./tmbackup.sh /dev/sdb2/ desktop. This means my source is the /dev/sdb2/ and i wanted to test out if it works, so i used the desktop as my target (was that ok or completely wrong??) .
After executing that last line, i get the following error:*** HFS Private Directory Data not found in /dev/sdb2/, is it an HFS filesystem? ***
I would be very thankful for any advice, and excuse my lacking skills ^^
Copied the script into a repo and updated it with some improvements from others forks. This also should help to better manage issues (thus having a more "clear" snapshot of the status quo in the README).
I do this because @vjt's script is a really good thing, but I had some issues (which I solved myself recognizing belatedly that others already solved them, too.)
@sepaepa try to use the mount point of mounted devices, not devices themselves, i.e. not /dev/sdb2.
Wow, thank you! This just saved my life ahah.
@stanfrbd haha I am super glad to hear that! that’s what OSS is for :-) and luckily these internals rarely change over time :D cheers!
damn, this script keeps on giving! Life-saving 10 years after its release — thank you @vjt !
damn, this script keeps on giving! Life-saving 10 years after its release — thank you @vjt !
glad it’s useful! enjoy
Nothing happens when your locale is set to something else than english.
Add
unset LANG
or
export LANG=C
at the beginning of the script and it will fix it.
I made a fork including this fix:
https://gist.github.com/magicoli/283785bdf21ebafd2202