Como "reverter" rsync -L?

2

Nos documentos do rsync ' -L flag:

-L, --copy-links    transform symlink into referent file/dir

Esta questão é sobre como "reverter" uma transferência que foi feita originalmente usando rsync -L ... .

É mais fácil para mim explicar o que quero dizer aqui "invertendo" com um simples exemplo concreto.

A configuração

Suponha que eu tenha diretórios /tmp/SOURCE/ e /tmp/TARGET/ , conforme mostrado abaixo:

$ /usr/bin/tree -aF /tmp/SOURCE/ /tmp/TARGET/
/tmp/SOURCE/
├── A.d/
│   ├── w
│   └── x
├── B.d/
│   └── z
├── C.d/
│   ├── w -> ../A.d/w
│   └── y -> ../A.d/x
└── D.l -> B.d/
/tmp/TARGET/

Em particular, observe os seguintes detalhes:

  • o conteúdo de /tmp/SOURCE/C.d são links simbólicos relativos a arquivos regulares em /tmp/SOURCE/A.d ;
    • os nomes básicos de symlink /tmp/SOURCE/C.d/w e de seus referentes são os mesmos;
    • os nomes básicos de symlink /tmp/SOURCE/C.d/y (a saber, y ) e de seu referente (a saber, x ) são diferentes;
  • /tmp/SOURCE/D.l é um link simbólico relativo para /tmp/SOURCE/B.d ;
  • /tmp/TARGET/ está vazio no momento.

A partir desse estado inicial, eu executo o tipo de comando mencionado no título deste post, o tipo de comando que eu quero "reverter" (como explicado abaixo):

$ rsync -L -a /tmp/SOURCE/C.d /tmp/SOURCE/D.l /tmp/TARGET

Depois que eu executar este comando, /tmp/TARGET/ ficará assim:

$ /usr/bin/tree -aF /tmp/TARGET/
/tmp/TARGET/
├── C.d/
│   ├── w
│   └── y
└── D.l/
    └── z

Note em particular que, embora sob /tmp/SOURCE e /tmp/TARGET os caminhos relativos

C.d/w
C.d/y
D.l/z

existe, somente aqueles sob /tmp/TARGET são caminhos "reais". Por um "caminho real" $P , quero dizer que, grosso modo, a saída de readlink -f $P é novamente $P (ou, mais precisamente, ${P:a} ). Por exemplo,

$ readlink -f /tmp/TARGET/C.d/w
/tmp/TARGET/C.d/w

mas

$ readlink -f /tmp/SOURCE/C.d/w
/tmp/SOURCE/A.d/w

O problema

No contexto atual, o que quero dizer com "inverter" o comando rsync -L anterior é basicamente copiar os arquivos regulares em /tmp/TARGET/ para seus originais em /tmp/SOURCE , deixando o < em> estrutura de /tmp/SOURCE inalterado.

Em particular, após essa "transferência reversa", os links simbólicos em /tmp/SOURCE devem permanecer links simbólicos e devem apontar para exatamente os mesmos referentes que antes.

Estou procurando uma maneira de realizar tal "reversão" que seja comparável em complexidade / dificuldade ao comando rsync -aL usado para realizar a transferência "para frente" em primeiro lugar.

Uma desvantagem deste exemplo simples é que é tão simples que alguém é tentado a resolver o problema com força bruta. Por exemplo,

$ rsync /tmp/TARGET/C.d/w /tmp/SOURCE/A.d
$ rsync /tmp/TARGET/C.d/y /tmp/SOURCE/A.d/x
$ rsync /tmp/TARGET/D.l/z /tmp/SOURCE/B.d

IOW, em uma situação tão simples, essa abordagem de força bruta não é muito mais difícil do que executar a transferência rsync -L original. Em geral, no entanto, a estratégia de força bruta pode ser muito mais difícil de realizar, quando comparada à transferência original.

Este exemplo é simplificado demais porque os hosts de origem e de destino são os mesmos. Em geral, eles não serão, então evite soluções que dependam desse recurso do exemplo.

FWIW, o script a seguir cria a configuração do exemplo de brinquedo acima.

BASEDIR=/tmp/test1

# uncomment the following line before running this script a second time
# rm -rf $BASEDIR/SOURCE $BASEDIR/TARGET

mkdir -p $BASEDIR/SOURCE/{A,B,C}.d $BASEDIR/TARGET
touch $BASEDIR/SOURCE/{A.d/{w,x},B.d/z}
ln -s ../A.d/w $BASEDIR/SOURCE/C.d/w
ln -s ../A.d/x $BASEDIR/SOURCE/C.d/y
ln -s B.d $BASEDIR/SOURCE/D.l
    
por kjo 23.06.2017 / 17:03

2 respostas

1

Existem opções para permitir que o rsync não perturbe links simbólicos no controle remoto quando eles se referem a diretórios, mas não parece ter a opção de não substituir links simbólicos por arquivos reais.

Então, o que você pode fazer é preservar os links simbólicos para os arquivos no SOURCE de alguma forma, por exemplo, renomeando-os ou listando-os em um arquivo, então faça os links simbólicos do diretório de preservação rsync, então restaure os links simbólicos do arquivo, copiando os dados do arquivo real para o link simbólico restaurado e, em seguida, removendo o arquivo real. Aqui está um script em potencial:

find /tmp/SOURCE -type l ! -xtype d -exec mv {} {}.lnk \;
cd /tmp/TARGET || exit
rsync -a -R --no-implied-dirs --keep-dirlinks . /tmp/SOURCE/
find /tmp/SOURCE -type l ! -xtype d |
while read fname
do base=${fname%.lnk}
   cp "$base" "$fname" 
   mv "$fname" "$base"
done

Deixo você para lidar com nomes de arquivos estranhos corretamente. Não tenho certeza se o -R --no-implied-dirs é necessário, mas vou deixar você experimentar com isso.

    
por 25.06.2017 / 16:37
1

Eu não acho que você possa fazer isso diretamente em rsync . A opção --keep-dirlinks ( -K ) manterá os diretórios com links simbólicos intactos, mas os arquivos com links simbólicos ainda serão sobrescritos.

A solução mais próxima que posso encontrar para isso é um pequeno script ( bash )

( cd TARGET && find . -type f -print0 | sed 's!^./!!' ) |
    while IFS= read -d $'
( cd TARGET && find . -type f -print0 | sed 's!^./!!' ) |
    while IFS= read -d $'%pre%' -r f
    do
        s=$(readlink -f SOURCE/"$f")
        rsync -a TARGET/"$f" "${s:-f}"
    done
' -r f do s=$(readlink -f SOURCE/"$f") rsync -a TARGET/"$f" "${s:-f}" done

Isso leva cada arquivo em TARGET , um de cada vez, procura um destino de link simbólico em SOURCE e aplica rsync diretamente a isso.

    
por 23.06.2017 / 18:15

Tags