ファイルの実際の内容なしでファイル属性 (メタデータ) のみをコピーするにはどうすればよいですか?

ファイルの実際の内容なしでファイル属性 (メタデータ) のみをコピーするにはどうすればよいですか?

すでにテラバイト単位のファイルを でコピーしましたが、ファイルの特殊な属性を保持するためにrsyncを使用するのを忘れました。--archive

rsync今回、再度実行してみました--archiveが、予想よりもずっと遅かったです。メタデータを再帰的にコピーするだけで、これをより速く行う簡単な方法はありますか?

答え1

--referenceパラメータを使用してchown、所有者、グループ、権限、タイムスタンプをコピーできますchmodtouchこれを行うためのスクリプトは次のとおりです。

#!/bin/bash
# Filename: cp-metadata

myecho=echo
src_path="$1"
dst_path="$2"

find "$src_path" |
  while read src_file; do
    dst_file="$dst_path${src_file#$src_path}"
    $myecho chmod --reference="$src_file" "$dst_file"
    $myecho chown --reference="$src_file" "$dst_file"
    $myecho touch --reference="$src_file" "$dst_file"
  done

(chown を許可するため) と 2 つのパラメータ (ソース ディレクトリと宛先ディレクトリ) を指定して実行する必要があります。スクリプトは実行する内容のみをエコーし​​ます。満足できる場合は、でsudo行を変更します。myecho=echomyecho=

答え2

「rsync にはコピーするメタデータしかないのに、なぜこんなに遅いのか、どうすればもっと速くできるのか」という質問を扱うと、次のようになります。

rsync通常、 は、変更されていないファイルを検出してスキップするためのヒューリスティックとして、等しい mtimes を使用します。 なし--archive(具体的には なし--times) の場合、宛先ファイルの mtimes は rsync を実行した時間に設定されたままになりますが、ソース ファイルの mtimes は変更されません (ユーザーによる手動のトリックは無視されます)。ソース ファイルの内容が変更されていないという外部保証がない場合、rsync は変更されている可能性があると想定する必要があり、そのためチェックサムを計算したり、宛先に再度コピーしたりする必要があります。これと、--whole-fileローカル -> ローカル同期の場合に が暗黙的に適用されるという事実により、rsyncなし はローカル同期の場合--timesとほぼ同等になりますcp

宛先ファイルの内容の更新が許容される場合、またはソース ファイルが元のコピー以降変更されていない場合は、rsync --archive --size-only単純な rsync よりも高速になるはずです。

rsync何のコピーに時間がかかっているのか疑問に思う場合は、rsync --archive --dry-run --itemize-changes ...簡潔ではありますが詳細を徹底的に説明します。

答え3

警告: 特別な回避策がなければ、cp --attributes-only少なくとも Precise では、GNU は宛先ファイルを切り捨てます。以下の編集を参照してください。

オリジナル:

このような状況では、おそらく GNU cp の--attributes-onlyオプションを と一緒に使用する必要があります--archive。これは、試行錯誤されたコードであり、ファイルシステムに依存しないすべての属性を実行し、シンボリック リンクをたどりません (シンボリック リンクをたどると問題が発生する可能性があります)。

cp --archive --attributes-only /source/of/failed/backup/. /destination/

ファイルと同様に、cp拡張属性が追加されます。ソースと宛先の両方に拡張属性がある場合は、追加ソースの拡張属性を宛先にコピーします (最初に宛先の xattrs をすべて削除するのではなく)。これは、cpファイルを既存のツリーにコピーする場合の動作を反映していますが、期待どおりにならない可能性があります。

また、最初にハードリンクを保存しなかったがrsync、今保存したい場合は、cp しません修正してください。rsync正しいオプションで再度実行したほうが良いでしょう(私のその他の回答) と忍耐力が必要です。

もしあなたがこの質問を見つけたのなら故意にメタデータ/ファイルコンテンツを分離して再結合したい場合は、メタストアUbuntu リポジトリにあります。

ソース:GNU coreutils マニュアル


追加編集:

cpGNU coreutils>= 8.17 以降では説明どおりに動作しますが、coreutils <= 8.16 ではメタデータを復元するときにファイルが切り捨てられます。疑わしい場合は、cpこの状況ではrsync使用しないでください。正しい選択肢そして/または忍耐強くいてください。

自分が何をしているのかを完全に理解していない限り、これをお勧めしませんが、以前のGNUではcpLD_PRELOAD トリック:

/*
 * File: no_trunc.c
 * Author: D.J. Capelis with minor changes by Zak Wilcox
 *
 * Compile:
 * gcc -fPIC -c -o no_trunc.o no_trunc.c
 * gcc -shared -o no_trunc.so no_trunc.o -ldl
 *
 * Use:
 * LD_PRELOAD="./no_trunc.so" cp --archive --attributes-only <src...> <dest>
 */

#define _GNU_SOURCE
#include <dlfcn.h>
#define _FCNTL_H
#include <bits/fcntl.h>

extern int errorno;

int (*_open)(const char *pathname, int flags, ...);
int (*_open64)(const char *pathname, int flags, ...);

int open(const char *pathname, int flags, mode_t mode) {
        _open = (int (*)(const char *pathname, int flags, ...)) dlsym(RTLD_NEXT, "open");
        flags &= ~(O_TRUNC);
        return _open(pathname, flags, mode);
}

int open64(const char *pathname, int flags, mode_t mode) {
        _open64 = (int (*)(const char *pathname, int flags, ...)) dlsym(RTLD_NEXT, "open64");
        flags &= ~(O_TRUNC);
        return _open64(pathname, flags, mode);
}

答え4

ローカル転送では、ソースと宛先がローカルにマウントされたファイルシステム上にある場合、rsync常にファイルの内容全体がコピーされます。これを回避するには、

rsync -a --no-whole-file source dest

関連情報