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

21

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

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

Мохаммад
источник
Под «метаданными» вы подразумеваете права доступа к файлам и владение файлами или более сложные вещи, такие как расширенные атрибуты файла?
Марсель Стимберг
Файловая система, в которой находятся исходные файлы, монтируется локально или нет?
энзотиб
под метаданными я имею в виду разрешения и метки времени. отметки времени особенно важны для меня.
Мохаммед
файловая система как в источнике, так и в месте назначения смонтирована локально.
Мохаммед

Ответы:

17

Хорошо, вы можете скопировать владельца, группу, разрешение и временные метки с помощью --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=.

enzotib
источник
1
Да, это то, что мне нужно: - ссылка в chmod. Спасибо. И я действительно ценю, если кто-нибудь может представить что-то вроде chmod --reference для копирования меток времени.
Мухаммед
1
@ Мохаммед: для этого вы можете использовать touch --reference=otherfile file. Обновленный ответ
enzotib
Замечательно. На самом деле я только что читал руководство по сенсорному управлению ;-)
Мохаммед
Просто примечание: touchпо дизайну изменяется только время модификации и доступа, на время «создания» это не влияет. (Я думаю, что ext2 / 3 в любом случае не поддерживает изменение ctime, но это может иметь значение, если вы используете NTFS или тому подобное).
Amro
Если вы хотите изменить только метаданные существующих файлов и не хотите гарантировать существование файлов, добавьте -cпереключатель в touchкоманду, чтобы она не создавала пустые файлы в $dst_path.
Синхро
5

ВНИМАНИЕ: Без специальных обходных путей GNU cp --attributes-onlyбудет обрезать конечные файлы, по крайней мере, в Precise. Смотрите редактирование ниже.

Оригинал:

В этой ситуации вы, вероятно, захотите, чтобы --attributes-onlyопция GNU cp , вместе с --archiveпроверенным и протестированным кодом, выполняла все атрибуты, независимые от файловой системы, и не следовала по символическим ссылкам (следовать им может быть плохо!):

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

Как и в случае с файлами, 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);
}
ZakW
источник
errornoдолжно быть errno, верно?
энзотиб
Быстрое удаление теста, похоже, сработало, так что, я думаю, я увековечил избыточность / ошибку в оригинале , но все равно теперь будут использовать более новые coreutils.
ZakW
но то, что вы называете rsyncс правильными вариантами, является ответом на другой вопрос ...
Жан Поль
5

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

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

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

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

ZakW
источник
1
Очень полезная информация --archive --size-only - отличная комбинация. Он не только предотвращает повторное копирование файлов, которые уже существуют в месте назначения, но также обновляет их метаданные. Это было неожиданно для меня, потому что на справочной странице rsync --size-only описывается как «пропуск» файлов, размеры которых совпадают. Оказывается, он просто пропускает копию, но все равно синхронизирует метаданные. Идеально.
Чад фон Нау
2

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

rsync -a --no-whole-file source dest
enzotib
источник
Я попытался rsync с --no-whole-file и --progress, и я все еще вижу прогресс копирования (около 30 МБ / с); так что я думаю, это еще не достаточно быстро. Я теряю надежду на rsync ...
Мухаммед
Эта опция используется, чтобы rsyncзапретить использование ярлыка, когда файлы находятся по локальному пути, но это не препятствует rsyncкопированию содержимого.
Жан Поль
2

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

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

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

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

find | grep '"'

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

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

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

niknah
источник
Спасибо за идеи а) «просто использовать скрипт оболочки» и б) для генерации указанного скрипта с использованием find. Я был в такой же ситуации - забыл скопировать атрибуты, диски источника и назначения уже были в разных машинах и не были на самом деле хотят отменить это.
i336_