Bagaimana cara menyalin hanya atribut file (metadata) tanpa konten file yang sebenarnya?

21

Saya sudah menyalin file terabyte rsynctetapi saya lupa menggunakan --archiveuntuk mempertahankan atribut khusus file.

Saya mencoba mengeksekusi rsynclagi kali ini dengan --archivetetapi itu jauh lebih lambat dari apa yang saya harapkan. Apakah ada cara mudah untuk melakukan ini lebih cepat hanya dengan menyalin metadata secara rekursif?

Mohammad
sumber
Dengan "metadata" yang Anda maksud izin file dan kepemilikan file atau hal-hal yang lebih rumit seperti atribut file yang diperluas?
Marcel Stimberg
Sistem file tempat file sumber berada dipasang secara lokal atau tidak?
enzotib
maksud saya dengan metadata adalah izin dan cap waktu. cap waktu sangat penting bagi saya.
Mohammad
sistem fils baik dalam sumber dan tujuan dipasang secara lokal.
Mohammad

Jawaban:

17

Ok, Anda dapat menyalin pemilik, grup, izin dan cap waktu menggunakan --referenceparameter untuk chown, chmod, touch. Berikut ini skrip untuk melakukannya

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

Anda harus menjalankannya dengan sudo(untuk mengizinkan chown) dan dengan dua parameter: direktori sumber dan tujuan. Script hanya menggemakan apa yang akan dilakukan. Jika puas ganti baris myecho=echodengan myecho=.

enzotib
sumber
1
Ya, itulah yang saya butuhkan: - referensi di chmod. Terima kasih. Dan saya sangat menghargai jika ada yang bisa memperkenalkan sesuatu seperti chmod - referensi untuk menyalin cap waktu.
Mohammad
1
@Mohammad: untuk itu Anda bisa menggunakan touch --reference=otherfile file. Diperbarui jawabannya
enzotib
Itu keren. Sebenarnya saya baru saja membaca manual sentuh ;-)
Mohammad
Hanya sebuah catatan: touchsecara desain hanya mengubah waktu modifikasi dan akses, waktu "pembuatan" tidak terpengaruh. (Saya pikir ext2 / 3 tidak mendukung perubahan waktu, tetapi mungkin masalah jika Anda menggunakan NTFS atau sejenisnya).
Amro
Jika Anda hanya ingin mengubah metadata file yang sudah ada dan tidak perlu memastikan keberadaan file, tambahkan -cperalihan ke touchperintah untuk menghentikannya membuat file kosong di $dst_path.
Sinkronisasi
5

PERINGATAN: Tanpa solusi khusus, GNU cp --attributes-onlyakan memotong file tujuan, setidaknya dalam Precise. Lihat hasil edit di bawah.

Asli:

Dalam situasi ini, Anda mungkin menginginkan --attributes-onlyopsi GNU cp , bersama dengan --archive, ketika kode ini dicoba dan diuji, apakah semua atribut filesystem-agnostik dan tidak mengikuti symlink (mengikutinya bisa buruk!):

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

Seperti halnya file, cpaditif dengan atribut yang diperluas: jika kedua sumber dan tujuan memiliki atribut yang diperluas, ia menambahkan atribut yang diperluas sumber ke tujuan (daripada menghapus semua xattrs tujuan terlebih dahulu). Meskipun ini mencerminkan bagaimana cpperilaku jika Anda menyalin file ke pohon yang ada, itu mungkin tidak seperti yang Anda harapkan.

Perhatikan juga bahwa jika Anda tidak menyimpan tautan keras pertama kali rsynctetapi ingin mempertahankannya sekarang cp tidak akan memperbaikinya untuk Anda; Anda mungkin terbaik menjalankan kembali rsyncdengan opsi yang tepat (lihat jawaban saya yang lain ) dan bersabar.

Jika Anda menemukan pertanyaan ini sambil berusaha memisahkan dan menggabungkan kembali konten metadata / file dengan sengaja maka Anda mungkin ingin melihat metastore yang ada di dalam repositori Ubuntu.

Sumber: manual GNU coreutils


Diedit untuk menambahkan:

cpdari GNU coreutils> = 8.17 dan di atas akan berfungsi seperti yang dijelaskan, tetapi coreutils <= 8.16 akan memotong file ketika memulihkan metadata mereka. Jika ragu, jangan gunakan cpdalam situasi ini; gunakan rsyncdengan opsi yang tepat dan / atau bersabarlah.

Saya tidak akan merekomendasikan hal ini kecuali jika Anda sepenuhnya memahami apa yang Anda lakukan, tetapi GNU sebelumnya cpdapat dicegah memotong file menggunakan trik 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
sumber
errornoseharusnya errno, kan?
enzotib
Sebuah tes cepat untuk menghapusnya sepertinya berhasil, jadi saya kira saya mengabadikan redundansi / kesalahan dalam versi aslinya , tetapi bagaimanapun juga semua orang akan menggunakan coreutils yang lebih baru.
ZakW
tetapi apa yang Anda panggil rsyncdengan opsi yang tepat adalah jawaban untuk pertanyaan lain ...
Jean Paul
5

Memperlakukan pertanyaan sebagai "rsync hanya memiliki metadata untuk disalin, jadi mengapa begitu lambat, dan bagaimana saya bisa membuatnya lebih cepat?":

rsyncbiasanya menggunakan mtimes yang sama sebagai heuristik untuk mendeteksi dan melewati file yang tidak berubah. Tanpa --archive(khusus, tanpa --times) mtimes file tujuan tetap disetel ke waktu Anda rsync-ed mereka, sementara mtimes file sumber tetap utuh (mengabaikan tipu daya manual oleh Anda). Tanpa jaminan eksternal dari Anda bahwa konten file sumber tidak berubah, rsync harus berasumsi bahwa mereka mungkin memilikinya dan karenanya harus melakukan checksum dan / atau menyalinnya ke tujuan lagi. Ini, ditambah fakta yang --whole-filetersirat untuk sinkronisasi lokal-> lokal, membuat rsynctanpa --timeskira - kira setara dengan cpuntuk sinkronisasi lokal.

Asalkan memperbarui konten file tujuan dapat diterima, atau jika file sumber tidak tersentuh sejak salinan asli, Anda harus menemukan rsync --archive --size-onlylebih cepat daripada rsync naif.

Jika ragu-ragu untuk rsyncmenyalin apa yang memakan waktu begitu lama, rsync --archive --dry-run --itemize-changes ...memberi tahu Anda secara lengkap, jika singkat, detail.

ZakW
sumber
1
Info yang sangat berguna. --archive --size-only adalah kombo yang bagus. Tidak hanya mencegah penyalinan ulang file yang sudah ada di tujuan, tetapi juga memperbarui metadata mereka. Ini tidak terduga bagi saya, karena halaman manual rsync menggambarkan --size-only sebagai "melewatkan" file yang ukurannya cocok. Ternyata itu hanya melewatkan salinan, tetapi masih akan menyinkronkan metadata. Ideal.
Chad von Nau
2

Dalam transfer lokal, ketika sumber dan tujuan berada pada sistem file yang dipasang secara lokal, rsyncakan selalu menyalin seluruh isi file. Untuk menghindarinya bisa Anda gunakan

rsync -a --no-whole-file source dest
enzotib
sumber
Saya mencoba rsync dengan --no-whole-file dan --progress dan saya masih bisa melihat kemajuan penyalinan (sekitar 30 MB / s); jadi saya kira itu belum cukup cepat. Saya kehilangan harapan saya pada rsync ...
Mohammad
Opsi ini digunakan untuk memberi tahu agar rsynctidak menggunakan pintasan ketika file keduanya berada di jalur lokal, tetapi itu tidak mencegah rsyncdari menyalin konten.
Jean Paul
1

Saya harus melakukan ini dari jarak jauh ke komputer lain sehingga saya tidak bisa menggunakan --referensi

Saya menggunakan ini untuk membuat skrip ...

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

Tapi pastikan tidak ada nama file dengan "di dalamnya dulu ...

find | grep '"'

Kemudian salin touch.sh ke komputer jarak jauh Anda, dan jalankan ...

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

Ada juga opsi di -printf untuk mencetak pengguna, nama grup jika Anda ingin menyalinnya.

niknah
sumber
Terima kasih atas ide untuk a) "cukup gunakan skrip shell" dan b) untuk menghasilkan skrip tersebut menggunakan find. Saya berada dalam situasi yang sama - lupa menyalin atribut, disk sumber dan tujuan sudah ada di mesin yang berbeda dan tidak benar - benar ingin membalikkan itu.
i336_