Как скопировать только атрибуты файла (метаданные) без фактического содержимого файла?

Я уже скопировал терабайты файлов с rsync но я забыл использовать --archive сохранить специальные атрибуты файлов.

Я пытался выполнить rsync снова на этот раз с --archive но это было намного медленнее, чем я ожидал. Есть ли простой способ сделать это быстрее, просто рекурсивно копируя метаданные?

5 ответов

Решение

Хорошо, вы можете скопировать владельца, группу, разрешение и метки времени, используя --reference параметр для chown, chmod, touch, Вот скрипт для этого

#!/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

Вы должны запустить его с sudo (чтобы разрешить chown) и с двумя параметрами: исходный и целевой каталог. Сценарий только повторяет, что он будет делать. Если удовлетворены, измените строку myecho=echo с myecho=,

Отвечая на вопрос как "rsync только копирует метаданные, так почему же он такой медленный и как я могу сделать это быстрее?":

rsync обычно использует одинаковые значения mtimes в качестве эвристики для обнаружения и пропуска неизмененных файлов. Без --archive (в частности, без --timesmtimes конечных файлов остаются установленными на время их повторной синхронизации, в то время как mtimes исходных файлов остаются нетронутыми (не обращая внимания на ручной обман). Без внешних гарантий от вас, что содержимое исходных файлов не изменилось, rsync должен предположить, что они могут иметься, и поэтому должен проверять их и / или снова копировать в место назначения. Это плюс тот факт, что --whole-file подразумевается для локальной-> локальной синхронизации, делает rsync без --times примерно эквивалентно cp для локальной синхронизации.

При условии, что обновление содержимого целевых файлов является приемлемым, или если исходные файлы не затронуты со времени оригинальной копии, вы должны найти rsync --archive --size-only быстрее, чем наивный rsync.

Если вы сомневаетесь в том, что rsync копирование, которое занимает так много времени, rsync --archive --dry-run --itemize-changes ... говорит вам в исчерпывающей, если кратко, подробно.

WARNING: Without special workarounds, GNU cp --attributes-only will truncate the destination files, at least in Precise. See the edit below.

Оригинал:

In this situation you probably want GNU cp's --attributes-only option, together with --archive, as it's tried and tested code, does all filesystem-agnostic attributes and doesn't follow symlinks (following them can be bad!):

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

As with files, cp является аддитивным с расширенными атрибутами: если и источник, и пункт назначения имеют расширенные атрибуты, он добавляет расширенные атрибуты источника к месту назначения (вместо того, чтобы сначала удалить все xattrs назначения). Хотя это отражает, как cp ведет себя, если вы копируете файлы в существующее дерево, это может не соответствовать вашим ожиданиям.

Также обратите внимание, что если вы не сохранили жесткие ссылки в первый раз с rsync но хочу сохранить их сейчас cp не исправлю это для вас; ты, наверное, лучше перезапускать rsync с правильными вариантами (см. мой другой ответ) и терпением.

Если вы нашли этот вопрос, пытаясь преднамеренно разделить и рекомбинировать содержимое метаданных / файлов, вы можете взглянуть на metastore, который находится в репозиториях Ubuntu.

Источник: руководство по GNU coreutils


Отредактировано, чтобы добавить:

cp из GNU coreutils > = 8.17 и выше будет работать как описано, но coreutils <= 8.16 будет обрезать файлы при восстановлении их метаданных. Если есть сомнения, не используйте cp в этой ситуации; использование rsync с правильными вариантами и / или будьте терпеливы.

Я не рекомендовал бы это, если вы не полностью понимаете, что делаете, но ранее GNU cp можно предотвратить усечение файлов с помощью трюка LD_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);
}

Мне пришлось сделать это удаленно на другой компьютер, чтобы я не мог использовать --reference

Я использовал это, чтобы сделать сценарий...

find -printf "touch -d \"%Tc\" \"%P\"\n" >/tmp/touch.sh

Но сначала убедитесь, что в них нет имен файлов с "...

find | grep '"'

Затем скопируйте файл touch.sh на удаленный компьютер и запустите...

cd <DestinationFolder>; sh /tmp/touch.sh

В find -printf также есть опции для печати пользователя, имени группы, если вы хотите скопировать их.

В локальных передачах, когда источник и назначение находятся в локально смонтированных файловых системах, rsync всегда будет копировать весь контент файлов. Чтобы избежать этого вы можете использовать

rsync -a --no-whole-file source dest
Другие вопросы по тегам