ハードリンクをコピーしたい。
ハードリンクが貼ってあるファイルがあるフォルダがあります。 ハードリンクを保ったまますべてコピーするにはどうしたらいいでしょうか? 具体的に申し上げますと、rsyncを利用したバックアップがあるのですが、新しいボリュームにそのまま移したいのです。 両方共hfs+ジャーナリングです。 できればターミナルで処理したいです。
MacBook Air, Mac OS X v10.7.1 Lion
ハードリンクが貼ってあるファイルがあるフォルダがあります。 ハードリンクを保ったまますべてコピーするにはどうしたらいいでしょうか? 具体的に申し上げますと、rsyncを利用したバックアップがあるのですが、新しいボリュームにそのまま移したいのです。 両方共hfs+ジャーナリングです。 できればターミナルで処理したいです。
MacBook Air, Mac OS X v10.7.1 Lion
pax(1) を使えばよいです。
pax -rw src dst
例えば、
#!/bin/bash cd ~/desktop/test || exit mkdir -p src/{x,y}/{a,b} touch src/x/{a,b}/{1,2}.txt ln -f src/x/a/{1,2}.txt src/y/a ln -f src/x/b/{1,2}.txt src/y/b mkdir -p dst pax -rw src dst ls -R -ialF .
追記
しかし、そもそも rsync で取ったのなら、rsync で戻すのが一番よいのではないかな。
当方の環境 (Snow Leopard / rsync 2.6.9) だと -H オプションがちゃんと動かないようです。Lion 以降に入ってる rsync は大丈夫なのでしょうかね。ちょっと心配。
rsync 3.1.1 をソースからコンパイルすれば -H オプションでハードリンクのコピーも出来るようになります。-N オプションでファイルの作成日もコピー可能となるのでお薦めしたいところですが、導入へのハードルがちょっと高いのが難点です。pax で良いような気もします。
ちなみに rsync3 だとこんな感じでしょうか。
$ rsync3 -aNEXAH -v "src/" "dst/"
実のところ私も 10.6.8 なので、rsync 3.1.1 をコンパイルして使っています。
http://www.opensource.apple.com/
で見た限りでは、10.7 はおろか 10.10 でも、rsync のバージョンは 2.6.9 のままのようですね。
10.6.8
http://www.opensource.apple.com/tarballs/rsync/rsync-40.tar.gz
10.7-10.9
http://www.opensource.apple.com/tarballs/rsync/rsync-42.tar.gz
10.10
http://www.opensource.apple.com/tarballs/rsync/rsync-45.tar.gz
10.7 以降に標準で含まれる rsync 2.6.9 でハードリンクを正しく保存できるのかどうかは知りません。
質問者のアポロさんがどのバージョンの rsync を使っているのか判りませんが、そのバージョンで作ったというバックアップでハードリンクが保存されているのなら、そのバージョンで大丈夫なのかな。しかし最新版でないなら最新版を使った方がよいかと思う。
---
アポロさんへ。
参考までに、rsync 3.1.1 のソースをダウンロード、コンパイル、インストールするスクリプトを載せておきます。正常に終われば、所産として、
/usr/local/bin/rsync /usr/local/share/man/man1/rsync.1 /usr/local/share/man/man5/rsyncd.conf.5
がインストールされます。
#!/bin/bash RSYNC_VERSION=3.1.1 SRC=https://rsync.samba.org/ftp/rsync/src DIR=~/desktop/build_rsync-${RSYNC_VERSION} mkdir "$DIR" && cd "$DIR" || exit # get sources curl -O ${SRC}/rsync-${RSYNC_VERSION}.tar.gz curl -O ${SRC}/rsync-patches-${RSYNC_VERSION}.tar.gz # expand sources tar xvzf rsync-${RSYNC_VERSION}.tar.gz tar xvzf rsync-patches-${RSYNC_VERSION}.tar.gz cd rsync-${RSYNC_VERSION} || exit # apply patches for Mac OS X specific features patch -p1 <patches/fileflags.diff patch -p1 <patches/crtimes.diff patch -p1 <patches/hfs-compression.diff # configure, make, install ./prepare-source ./configure make sudo make install exit 0
そうですね。 rsyncといってもrsyncを利用したアプリケーションで行ったのでうまく動いてくれる自信がありませんでした。 すこしフォルダ構造が深くなってしまいましたが何とか動いています。 ありがとうございました。
> http://www.opensource.apple.com/
> で見た限りでは、10.7 はおろか 10.10 でも、rsync のバージョンは 2.6.9 のままのようですね。
10.6.8 用 ~ 10.10 用の三つともビルドして試してみましたが、-H オプションを使うと、拡張属性付きファイルのコピーがうまく行かないようです。# rsync のバージョンは同一も、ソースがちょっとだけ異なるんですね...。
例えば以下のシェルスクリプト。標準装備の rsync 2.6.9 では dst/old にファイルが作成されません。コピー元のファイルに拡張属性が含まれているとダメなようです。拡張属性が付いてなければハードリンクが正しく作成されます。また、rsync 3.1.1 ならどちらでも問題ありません。
#!/bin/bash workdir="$HOME/Desktop/test2" cd "$workdir" || exit 1 mkdir -p "$workdir/src/org" touch "src/org/a.txt" # 拡張属性を適当に設定 xattr -w com.apple.TextEncoding 'UTF-8;134217984' "src/org/a.txt" rsync -aE --delete "src/org/" "src/old/" # rsync 2.6.9: src/new に a.txt (ハードリンク) が作成される rsync -aE --delete --link-dest="../old/" "src/org/" "src/new/" # rsync 2.6.9: dst/old が空っぽ... rsync -aEH -v "src/" "dst/" # rsync 3.1.1: dst/old に a.txt (ハードリンク) が作成される # rsync3 -aXH -v "src/" "dst/" ls -liR
問題は解決されたとのことなので不要かもしれませんが一応情報ということで。
実際にビルドして試されたのですね。脱帽です。:)
拡張属性がハードリンクの落とし穴になるとは思いもしませんでした。
rsync 2.6.9 の出力を見ると、このバージョンでは拡張属性を持つファイルについて一時的に ._ ファイルを作っているようで、どうもハードリンクがあった場合に、._ ファイルの統合に失敗しているように見えますね。rsync 3.1.1 では ._ ファイルを使わずに拡張属性を直接扱っているので問題ないということかな。
結局、OS X 10.10 までに標準搭載されている rsync 2.6.9 には重大な欠陥があるということは間違いないですね。
勉強になりました。ありがとうございました。
フォルダ構造が深くなったというのは、src が dst/src にコピーされてしまったということでしょうか。もしそうなら、それはコマンドの呼び方次第で変えられますよ。
rsync 3.1.1 の場合は、Hiro.S さんが既に示されている通り、
/usr/local/bin/rsync -aNEXAH -v src/ dst
のように、src の最後に / を付ければ、src 自体ではなく、src の中身がコピーされます。
pax の場合は、
#!/bin/bash cd src shopt -s dotglob pax -rw * /path/to/dst shopt -u dotglob
のようにすれば、src の中身をコピーできます。dotglob をセットするのは . で始まる不可視ファイルが * のパス名展開に含まれるようにするためです。これは、次のようにしても同じです。
#!/bin/bash cd src pax -rw .* * /path/to/dst
ハードリンクをコピーしたい。