Comment copier uniquement les attributs de fichier (métadonnées) sans le contenu réel du fichier?

21

J'ai déjà copié des téraoctets de fichiers avec rsyncmais j'ai oublié d'utiliser --archivepour conserver les attributs spéciaux des fichiers.

J'ai essayé d'exécuter à rsyncnouveau cette fois avec --archivemais c'était beaucoup plus lent que ce à quoi je m'attendais. Existe-t-il un moyen simple de le faire plus rapidement en copiant simplement les métadonnées de manière récursive?

Mohammad
la source
Avec "métadonnées", vous voulez dire les autorisations de fichiers et la propriété des fichiers ou des choses plus compliquées comme les attributs de fichiers étendus?
Marcel Stimberg
Le système de fichiers où résident les fichiers source est monté localement ou non?
enzotib
par métadonnées, j'entends les autorisations et les horodatages. les horodatages sont particulièrement importants pour moi.
Mohammad
le système fils en source et en destination est monté localement.
Mohammad

Réponses:

17

Ok, vous pouvez copier le propriétaire, le groupe, l' autorisation et horodatages à l' aide du --referenceparamètre chown, chmod, touch. Voici un script pour le faire

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

Vous devez l'exécuter avec sudo(pour autoriser chown) et avec deux paramètres: répertoire source et destination. Le script ne fait que répéter ce qu'il ferait. Si vous êtes satisfait, changez la ligne myecho=echoavec myecho=.

enzotib
la source
1
Oui, c'est ce dont j'ai besoin: - référence dans chmod. Merci. Et j'apprécie vraiment que quelqu'un puisse introduire quelque chose comme chmod - référence pour copier des horodatages.
Mohammad
1
@Mohammad: pour cela, vous pouvez utiliser touch --reference=otherfile file. Mise à jour de la réponse
enzotib
C'est génial. En fait, je lisais le manuel tactile tout à l'heure ;-)
Mohammad
Juste une note: touchpar conception, seuls les temps de modification et d'accès sont modifiés, le temps de "création" n'est pas affecté. (Je pense que ext2 / 3 ne prend pas en charge la modification de ctime de toute façon, mais cela peut être important si vous utilisez NTFS ou similaire).
Amro
Dans le cas où vous ne souhaitez modifier que les métadonnées des fichiers existants et n'avez pas besoin d'assurer l'existence de fichiers, ajoutez un -ccommutateur à la touchcommande pour l'empêcher de créer des fichiers vides dans le $dst_path.
Synchro
5

AVERTISSEMENT: Sans solutions de contournement spéciales, GNU cp --attributes-onlytronquera les fichiers de destination, au moins en Précise. Voir l'édition ci-dessous.

Original:

Dans cette situation, vous voulez probablement l' --attributes-onlyoption de GNU cp , ainsi que --archive, comme c'est du code éprouvé, fait tous les attributs agnostiques du système de fichiers et ne suit pas les liens symboliques (les suivre peut être mauvais!):

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

Comme pour les fichiers, cpest additif avec des attributs étendus: si la source et la destination ont des attributs étendus, ils ajoutent les attributs étendus de la source à la destination (plutôt que de supprimer tous les xattrs de la destination en premier). Bien que cela reflète comment cpse comporte si vous copiez des fichiers dans une arborescence existante, ce n'est peut-être pas ce que vous attendez.

Notez également que si vous n'avez pas conservé les liens durs la première fois avec rsyncmais que vous souhaitez les conserver maintenant, cp cela ne résoudra pas cela pour vous; il vaut probablement mieux relancer rsyncavec les bonnes options (voir mon autre réponse ) et être patient.

Si vous avez trouvé cette question en cherchant à séparer et à recombiner délibérément le contenu des métadonnées / fichiers, vous voudrez peut-être jeter un œil au métastore qui se trouve dans les référentiels Ubuntu.

Source: manuel GNU coreutils


Modifié pour ajouter:

cpdepuis GNU coreutils> = 8.17 et supérieur fonctionnera comme décrit, mais coreutils <= 8.16 tronquera les fichiers lors de la restauration de leurs métadonnées. En cas de doute, ne l'utilisez pas cpdans cette situation; utiliser rsyncavec les bonnes options et / ou être patient.

Je ne recommanderais pas cela à moins que vous compreniez parfaitement ce que vous faites, mais GNU antérieur cppeut être empêché de tronquer les fichiers en utilisant l' astuce 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
la source
errornodevrait être errno, non?
enzotib
Un test rapide pour le supprimer semble fonctionner, donc je suppose que j'ai perpétué une redondance / erreur dans l'original , mais tout le monde sera désormais sur des coreutils plus récents.
ZakW
mais ce que vous appelez rsyncavec les bonnes options est une réponse à une autre question ...
Jean Paul
5

Traiter la question comme "rsync n'a que des métadonnées à copier, alors pourquoi est-ce si lent et comment puis-je le faire plus rapidement?":

rsyncutilise généralement des temps égaux comme heuristique pour détecter et ignorer les fichiers inchangés. Sans --archive(spécifiquement, sans --times), les mtimes des fichiers de destination restent définis au moment où vous les avez synchronisés, tandis que les mtimes des fichiers source restent intacts (en ignorant la supercherie manuelle de votre part). Sans garantie externe de votre part que le contenu des fichiers source n'a pas changé, rsync doit supposer qu'ils pourraient avoir et doit donc les contrôler et / ou les copier à nouveau vers la destination. Ceci, plus le fait --whole-fileimplicite pour les synchronisations locales-> locales, rend rsyncsans --timesapproximativement l'équivalent cppour les synchronisations locales.

Pourvu que la mise à jour du contenu des fichiers de destination soit acceptable, ou si les fichiers source sont intacts depuis la copie originale, vous devriez trouver rsync --archive --size-onlyplus rapide qu'un rsync naïf.

En cas de doute sur la rsynccopie qui prend si longtemps, rsync --archive --dry-run --itemize-changes ...vous le dit en détail, même si elle est laconique.

ZakW
la source
1
Info très utile. --archive --size-only est un excellent combo. Non seulement cela empêche de recopier les fichiers qui existent déjà dans la destination, mais il mettra également à jour leurs métadonnées. C'était inattendu pour moi, car la page de manuel de rsync décrit --size-only comme "ignorant" les fichiers dont les tailles correspondent. Il s'avère qu'il saute simplement la copie, mais synchronisera toujours les métadonnées. Idéal.
Chad von Nau
2

Dans les transferts locaux, lorsque la source et la destination se trouvent sur des systèmes de fichiers montés localement, rsynccopiera toujours le contenu des fichiers entiers. Pour éviter cela, vous pouvez utiliser

rsync -a --no-whole-file source dest
enzotib
la source
J'ai essayé rsync avec --no-whole-file et --progress et je peux toujours voir la progression de la copie (environ 30 Mo / s); donc je suppose que ce n'est pas encore assez rapide. Je perds espoir sur rsync ...
Mohammad
Cette option est utilisée pour indiquer de rsyncne pas utiliser le raccourci lorsque les fichiers sont tous les deux dans le chemin local, mais elle n'empêche pas rsyncde copier le contenu.
Jean Paul
2

J'ai dû le faire à distance sur un autre ordinateur, donc je ne pouvais pas utiliser - référence

Je l'ai utilisé pour faire le script ...

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

Mais assurez-vous qu'il n'y a pas de noms de fichiers avec "en premier" ...

find | grep '"'

Copiez ensuite touch.sh sur votre ordinateur distant et exécutez ...

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

Il existe également des options dans find -printf pour imprimer l'utilisateur, le nom du groupe si vous souhaitez les copier.

niknah
la source
Merci pour les idées a) "utilisez simplement un script shell" et b) pour générer ledit script en utilisant find. J'étais dans la même situation - j'ai oublié de copier les attributs, les disques source et de destination étaient déjà sur des machines différentes et je ne voulais pas vraiment inverser cela.
i336_