Jak skopiować tylko atrybuty pliku (metadane) bez faktycznej zawartości pliku?

21

Skopiowałem już terabajty plików, rsyncale zapomniałem użyć, --archiveaby zachować specjalne atrybuty plików.

rsyncTym razem próbowałem wykonać ponownie, --archiveale było to o wiele wolniejsze niż się spodziewałem. Czy jest jakiś prosty sposób, aby zrobić to szybciej, po prostu kopiując rekurencyjnie metadane?

Mohammad
źródło
Z „metadanymi” rozumiesz uprawnienia do plików i prawa własności do plików lub bardziej skomplikowane rzeczy, takie jak rozszerzone atrybuty plików?
Marcel Stimberg,
System plików, w którym znajdują się pliki źródłowe, jest montowany lokalnie czy nie?
enzotib,
przez metadane mam na myśli uprawnienia i znaczniki czasu. znaczniki czasu są dla mnie szczególnie ważne.
Mohammad,
system plików zarówno źródłowy, jak i docelowy jest montowany lokalnie.
Mohammad,

Odpowiedzi:

17

Ok, można skopiować właściciela, grupy i uprawnienia znaczników czasu za pomocą --referenceparametru na chown, chmod, touch. Oto skrypt, aby to zrobić

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

Powinieneś go uruchomić z sudo(aby umożliwić przeglądanie) i dwoma parametrami: katalog źródłowy i docelowy. Skrypt odzwierciedla tylko to, co by zrobił. Jeśli jesteś zadowolony, zmień linię za myecho=echopomocą myecho=.

enzotib
źródło
1
Tak, właśnie tego potrzebuję: - odwołanie do chmod. Dziękuję Ci. Naprawdę doceniam to, jeśli ktoś mógłby wprowadzić coś takiego jak chmod - odniesienie do kopiowania znaczników czasu.
Mohammad,
1
@Mohammad: do tego możesz użyć touch --reference=otherfile file. Zaktualizowano odpowiedź
enzotib,
To wspaniale. Właściwie właśnie czytałem teraz instrukcję dotykową ;-)
Mohammad,
Uwaga: touchz założenia zmienia tylko czasy modyfikacji i dostępu, czas „tworzenia” nie ma wpływu. (Myślę, że ext2 / 3 i tak nie obsługuje zmiany ctime, ale może mieć znaczenie, jeśli używasz NTFS lub podobnego).
Amro,
Jeśli chcesz zmienić tylko metadane istniejących plików i nie musisz zapewniać istnienia plików, dodaj -cprzełącznik do touchpolecenia, aby zatrzymać tworzenie pustych plików w pliku $dst_path.
Synchro,
5

OSTRZEŻENIE: Bez specjalnych obejść GNU cp --attributes-onlyobetnie pliki docelowe, przynajmniej w Precise. Zobacz edycję poniżej.

Oryginalny:

W tej sytuacji prawdopodobnie chcesz opcji GNU cp --attributes-only, wraz z --archivewypróbowanym i przetestowanym kodem, robi wszystkie atrybuty niezależne od systemu plików i nie podąża za dowiązaniami symbolicznymi (podążanie za nimi może być złe!):

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

Podobnie jak w przypadku plików, cpjest addytywny z rozszerzonymi atrybutami: jeśli zarówno źródło, jak i miejsce docelowe mają atrybuty rozszerzone, dodaje rozszerzone atrybuty źródła do miejsca docelowego (zamiast najpierw usuwać wszystkie xattry miejsca docelowego). Chociaż odzwierciedla to cpzachowanie w przypadku kopiowania plików do istniejącego drzewa, może nie być to oczekiwane.

Zauważ też, że jeśli nie zachowałeś twardych linków za pierwszym razem, rsyncale chcesz je teraz zachować, to cp nie naprawisz tego za ciebie; prawdopodobnie najlepiej będzie, rsyncjeśli ponownie uruchomisz z odpowiednimi opcjami (patrz moja inna odpowiedź ) i będziesz cierpliwy.

Jeśli znalazłeś to pytanie podczas celowego rozdzielania i ponownego łączenia zawartości metadanych / plików, możesz rzucić okiem na metastore, który znajduje się w repozytoriach Ubuntu.

Źródło: Podręcznik GNU coreutils


Edytowano, aby dodać:

cpod GNU coreutils> = 8.17 i nowszych będzie działać zgodnie z opisem, ale coreutils <= 8.16 obetnie pliki podczas przywracania ich metadanych. W razie wątpliwości nie używaj cpw tej sytuacji; używaj rsyncz odpowiednimi opcjami i / lub bądź cierpliwy.

Nie poleciłbym tego, chyba że w pełni rozumiesz, co robisz, ale wcześniejszym GNU cpmożna zapobiec obcinaniu plików za pomocą sztuczki 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
źródło
errornopowinno być errno, prawda?
enzotib
Szybki test na usunięcie wydaje się działać, więc wydaje mi się, że utrwaliłem redundancję / błąd w oryginale , ale i tak wszyscy już będą na nowszych coreutils.
ZakW
ale to, co nazywasz rsyncodpowiednimi opcjami, jest odpowiedzią na inne pytanie ...
Jean Paul
5

Traktując to pytanie jako „rsync ma tylko metadane do skopiowania, więc dlaczego jest tak wolny i jak mogę go przyspieszyć?”:

rsynczwykle używa równych czasów jako heurystyki do wykrywania i pomijania niezmienionych plików. Bez --archive(konkretnie bez --times) mity plików docelowych pozostają ustawione na czas, kiedy je synchronizujesz, podczas gdy mity plików źródłowych pozostają nienaruszone (ignorując twoje ręczne oszustwo). Bez zewnętrznych gwarancji od ciebie, że zawartość plików źródłowych nie uległa zmianie, rsync musi założyć, że tak się stało, i dlatego musi je zsumować i / lub ponownie skopiować do miejsca docelowego. To plus fakt, który --whole-filejest sugerowany dla lokalnych-> lokalnych synchronizacji, czyni rsyncbez w --timesprzybliżeniu równoważnym cpdla lokalnych synchronizacji.

Pod warunkiem, że aktualizacja zawartości plików docelowych jest akceptowalna lub jeśli pliki źródłowe są nietknięte od oryginalnej kopii, powinieneś znaleźć rsync --archive --size-onlyszybciej niż naiwny rsync.

W razie wątpliwości co do tego, co rsynctrwa tak długo, rsync --archive --dry-run --itemize-changes ...powiedzą Ci wyczerpujące, jeśli zwięzłe, szczegóły.

ZakW
źródło
1
Bardzo przydatne informacje. --archive --size-only to świetne połączenie. Nie tylko zapobiega kopiowaniu plików, które już istnieją w miejscu docelowym, ale także aktualizuje ich metadane. Było to dla mnie nieoczekiwane, ponieważ strona man rsync opisuje --size-only jako „pomijanie” plików, których rozmiary są zgodne. Okazuje się, że po prostu pomija kopię, ale nadal synchronizuje metadane. Ideał.
Chad von Nau
2

W transferach lokalnych, gdy źródło i miejsce docelowe znajdują się w lokalnie zamontowanych systemach plików, rsynczawsze będą kopiować całą zawartość plików. Aby tego uniknąć, możesz użyć

rsync -a --no-whole-file source dest
enzotib
źródło
Próbowałem rsync z --no-Whole-file i --progress i nadal widzę postęp kopiowania (około 30 MB / s); więc chyba nie jest jeszcze wystarczająco szybki. Tracę nadzieję na rsync ...
Mohammad,
Ta opcja jest używana, aby powiedzieć, aby rsyncnie używać skrótu, gdy oba pliki znajdują się w ścieżce lokalnej, ale nie zapobiega rsynckopiowaniu zawartości.
Jean Paul
2

Musiałem to zrobić zdalnie na innym komputerze, więc nie mogłem użyć - odniesienia

Użyłem tego, aby skrypt ...

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

Ale najpierw upewnij się, że nie ma w nich żadnych nazw plików z „…

find | grep '"'

Następnie skopiuj touch.sh na komputer zdalny i uruchom ...

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

Istnieją również opcje w find -printf, aby wydrukować użytkownika, nazwę grupy, jeśli chcesz je skopiować.

niknah
źródło
Dzięki za pomysły, aby a) „po prostu użyć skryptu powłoki” ib) wygenerować wspomniany skrypt za pomocą find. Byłem w tej samej sytuacji - zapomniałem skopiować atrybuty, dyski źródłowy i docelowy były już na różnych komputerach i tak naprawdę nie chciałem tego odwracać.
i336_