次のような構造があるとしましょう。
$ mkdir d1
$ mkdir d1/d2
$ touch d1/f1
$ touch d1/d2/f2
$ chmod u-w d1/d2
削除しようとするとd1
書き込み権限がないため削除できませんd1/d2
。しかし、まだ削除されますd1/f1
。
$ rm -rf d1
rm: cannot remove 'd1/d2/f2': Permission denied
$ ls d1
d2 # f1 has been deleted
原子ツールを実装する方法はありますかrm
?たとえば、すべてのアイテムを削除できない場合、何も削除されません。
ベストアンサー1
私はツリーのハードリンクバックアップを作成する方法でこのプログラムを作成します。その後、操作が失敗した場合は、削除されたファイルをバックアップから復元します。ジョブが成功すると、ハードリンクバックアップは削除されます。
もちろん、これは「いつでも電源コードを抜くことができる」という意味では原子的ではなく、論理的に原子的であるだけです。もちろん、追加のロジックと起動時に実行されるいくつかのフックを使用してソートすることもできます。
2回のパス(1つは権限確認用、もう1つは削除用)を作成するのは難しいです。拡張属性を含むすべての権限を確認するには、ロジックを徹底する必要があります。たとえば、これを行うと、通常のUnix権限が大丈夫に見えても、書き込みsudo chattr +i file
可能file
なディレクトリは削除できなくなります。 「このファイルを削除できますか?」の最高のリトマステストは、実際に試してみることです。
rsync
これは、ハードリンクベースのバックアップとリカバリの概念証明として特定のテストを受けた概念的なプロトタイプです。スクリプト名は次のとおりですatomic-rm.sh
。
#!/bin/sh
set -eu
if [ $# -ne 1 ] ; then
echo "specify directory to remove"
exit 1
fi
ar_src=$(realpath "$1")
ar_tmp=$(mktemp -d "$(dirname "$ar_src")/tmp-XXXXXX")
if [ $? -ne 0 ] ; then
echo "unable to create temporary directory"
exit 1
fi
cleanup()
{
find "$ar_tmp" -type d -print0 | xargs -0 chmod +w
if ! rm -rf "$ar_tmp" ; then
echo "removal of temporary directory $ar_tmp failed"
exit 2 # 2 indicates dirty failure
fi
}
trap cleanup EXIT
if ! rsync -ar --link-dest="$ar_src" "$ar_src"/ "$ar_tmp"/ ; then
echo "unable to create hard-linked backup of $ar_src in $ar_tmp"
exit 1
fi
if ! rm -rf "$ar_src" ; then
if ! rsync -ar --link-dest="$ar_tmp" "$ar_tmp"/ "$ar_src"/ ; then
echo "removal of $ar_src failed; unfortunately, so did the rollback"
exit 2 # 2 indicates dirty failure
fi
exit 1
fi
exit 0
追加の努力をすれば、起動時にリカバリスクリプトが緩い一時ディレクトリをクリーンアップするために使用できる場所にいくつかの情報を保存できます。一時ディレクトリは削除されるディレクトリの兄弟として作成され、同じファイルシステムに存在します/tmp
。
削除が失敗してロールバックが実行されると、ディレクトリが混乱して修正タイムスタンプが変更されたため、ツリーの正確な状態を絶対に復元できません。
では、ディレクトリを書き込み可能にするためにディレクトリをcleanup
巡回する必要があります。find
これは、ディレクトリに書き込むことができず、削除が失敗した場合、そのディレクトリrsync
権限がコピーされるため、バックアップコピーでも同じように失敗するためです。