¿Cómo copiar solo atributos de archivo (metadatos) sin contenido real del archivo?

21

Ya he copiado terabytes de archivos rsyncpero olvidé usarlos --archivepara preservar los atributos especiales de los archivos.

Intenté ejecutar rsyncnuevamente esta vez con --archivepero fue mucho más lento de lo que esperaba. ¿Hay alguna manera fácil de hacer esto más rápido simplemente copiando metadatos de forma recursiva?

Mohammad
fuente
Con "metadatos" te refieres a los permisos de archivos y la propiedad de archivos o cosas más complicadas como los atributos de archivos extendidos.
Marcel Stimberg
¿El sistema de archivos donde residen los archivos fuente está montado localmente o no?
enzotib
por metadatos me refiero a permisos y marcas de tiempo. Las marcas de tiempo son particularmente importantes para mí.
Mohammad el
El sistema de archivos tanto en origen como en destino se monta localmente.
Mohammad

Respuestas:

17

Ok, puede copiar el propietario, grupo, permiso y marcas de tiempo utilizando el --referenceparámetro a chown, chmod, touch. Aquí hay un guión para hacerlo

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

Debe ejecutarlo con sudo(para permitir chown) y con dos parámetros: directorio de origen y de destino. El guión solo hace eco de lo que haría. Si está satisfecho, cambie la línea myecho=echocon myecho=.

enzotib
fuente
1
Sí, eso es lo que necesito: - referencia en chmod. Gracias. Y realmente agradezco que alguien pueda introducir algo como chmod, referencia para copiar marcas de tiempo.
Mohammad el
1
@Mohammad: para eso puedes usar touch --reference=otherfile file. Se actualizó la respuesta
enzotib
Eso es genial. En realidad estaba leyendo el manual táctil en este momento ;-)
Mohammad
Solo una nota: touchpor diseño solo cambia los tiempos de modificación y acceso, el tiempo de "creación" no se ve afectado. (Creo que ext2 / 3 no admite el cambio de ctime de todos modos, pero podría importar si está utilizando NTFS o similar).
Amro
En caso de que solo desee cambiar los metadatos de los archivos existentes y no necesite asegurar la existencia de los archivos, agregue un -cinterruptor al touchcomando para detener la creación de archivos vacíos en el $dst_path.
Sincronización
5

ADVERTENCIA: Sin soluciones especiales, GNU cp --attributes-onlytruncará los archivos de destino, al menos en Precise. Vea la edición a continuación.

Original:

En esta situación, es probable que desee la --attributes-onlyopción GNU cp , junto con --archive, ya que es un código probado y probado, que hace todos los atributos independientes del sistema de archivos y no sigue los enlaces simbólicos (¡seguirlos puede ser malo!):

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

Al igual que con los archivos, cpes aditivo con atributos extendidos: si tanto el origen como el destino tienen atributos extendidos, agrega los atributos extendidos del origen al destino (en lugar de eliminar todos los xattrs del destino primero). Si bien esto refleja cómo se cpcomporta si copia archivos en un árbol existente, puede que no sea lo que espera.

También tenga en cuenta que si no conservó los enlaces duros la primera vez rsyncpero desea conservarlos ahora, entonces cp no lo solucionará por usted; probablemente sea mejor volver a ejecutar rsynccon las opciones correctas (ver mi otra respuesta ) y ser paciente.

Si encontró esta pregunta mientras buscaba separar y recombinar deliberadamente el contenido de metadatos / archivos, entonces puede echar un vistazo a metastore que se encuentra en los repositorios de Ubuntu.

Fuente: manual de GNU coreutils


Editado para agregar:

cpdesde GNU coreutils> = 8.17 y superior funcionará como se describe, pero coreutils <= 8.16 truncará los archivos al restaurar sus metadatos. En caso de duda, no lo use cpen esta situación; usar rsynccon las opciones correctas y / o ser paciente.

No recomendaría esto a menos que entiendas completamente lo que estás haciendo, pero antes cpse puede evitar que GNU trunque archivos usando el truco 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
fuente
errornodebería ser errno, ¿verdad?
enzotib
Una prueba rápida para eliminarlo parece funcionar, así que supongo que perpetué una redundancia / error en el original , pero de todos modos todos estarán en coreutils más nuevos.
ZakW
pero lo que llamas rsynccon las opciones correctas es una respuesta a otra pregunta ...
Jean Paul
5

Tratando la pregunta como "rsync solo tiene metadatos para copiar, entonces ¿por qué es tan lento y cómo puedo hacerlo más rápido?":

rsyncusualmente usa mtimes iguales como heurística para detectar y omitir archivos sin cambios. Sin --archive(específicamente, sin --times) los tiempos de los archivos de destino permanecen configurados en el momento en que los sincronizó, mientras que los tiempos de los archivos de origen permanecen intactos (ignorando el truco manual por usted). Sin garantías externas de su parte de que el contenido de los archivos de origen no ha cambiado, rsync debe asumir que podrían haberlo hecho y, por lo tanto, debe sumarlos y / o copiarlos nuevamente en el destino. Esto, más el hecho de que --whole-fileestá implícito para las sincronizaciones locales-> locales, lo hace rsyncsin --timesaproximadamente equivalente a cplas sincronizaciones locales.

Siempre que la actualización del contenido de los archivos de destino sea aceptable, o si los archivos de origen no se han tocado desde la copia original, debería encontrarlo rsync --archive --size-onlymás rápido que un rsync ingenuo.

Si tiene dudas sobre lo rsyncque está tardando tanto en copiarse, rsync --archive --dry-run --itemize-changes ...le informa en detalle exhaustivo, aunque conciso.

ZakW
fuente
1
Información muy útil --archive --size-only es un gran combo. No solo evita volver a copiar archivos que ya existen en el destino, sino que también actualizará sus metadatos. Esto fue inesperado para mí, porque la página de manual de rsync describe --size-only como archivos "omitidos" cuyos tamaños coinciden. Resulta que simplemente omite la copia, pero aún sincronizará los metadatos. Ideal.
Chad von Nau
2

En las transferencias locales, cuando el origen y el destino están en sistemas de archivos montados localmente, rsyncsiempre copiará el contenido de los archivos completos. Para evitar esto puedes usar

rsync -a --no-whole-file source dest
enzotib
fuente
Intenté rsync con --no-full-file y --progress y aún puedo ver el progreso de la copia (aproximadamente 30 MB / s); así que supongo que aún no es lo suficientemente rápido. Estoy perdiendo la esperanza en rsync ...
Mohammad
Esta opción se usa para indicar que rsyncno use el acceso directo cuando los archivos están en la ruta local, pero no impide rsynccopiar el contenido.
Jean Paul
2

Tuve que hacer esto de forma remota a otra computadora para que no pudiera usar - referencia

Usé esto para hacer el guión ...

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

Pero asegúrese de que no haya ningún nombre de archivo con "en ellos primero ...

find | grep '"'

Luego copie touch.sh a su computadora remota y ejecute ...

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

También hay opciones en find -printf para imprimir usuario, nombre de grupo si desea copiarlos.

niknah
fuente
Gracias por las ideas para a) "simplemente usar un script de shell" yb) para generar dicho script usando find. Estaba en la misma situación: olvidé copiar atributos, los discos de origen y de destino ya estaban en máquinas diferentes y realmente no quería revertir eso.
i336_