Quebrar todos os hardlinks dentro de uma pasta

10

Eu tenho uma pasta que contém um certo número de arquivos que possuem links físicos (na mesma pasta ou em outro lugar) e quero desassociá-los, para que eles se tornem independentes e as alterações no conteúdo não afetem outro arquivo (a contagem de links se torna 1).

Abaixo, dou uma solução que basicamente copia cada link físico para outro local e depois o move novamente.

No entanto, esse método parece bastante grosseiro e propenso a erros, então eu gostaria de saber se existe algum comando que elimine o link de um arquivo para mim.

Resposta bruta:

Encontre arquivos com links físicos ( Editar : para também encontrar soquetes etc. que tenham links físicos, use find -not -type d -links +1):

find      -type f -links +1 # files only
find -not -type d -links +1 # files, sockets etc.

Um método simples para desassociar um arquivo (copie-o para outro local e mova-o de volta): Editar: Como o Celada disse, é melhor fazer um cp -p abaixo, para evitar a perda de carimbos de data e hora e permissões. Editar: Crie um diretório temporário e copie para um arquivo abaixo dele, em vez de sobrescrever um arquivo temporário, minimiza o risco de sobrescrever alguns dados, embora o mvcomando ainda seja arriscado (obrigado @Tobu). Editar: tente criar o diretório temporário no mesmo sistema de arquivos (@MikkoRantalainen).

# This is unhardlink.sh
set -e
for i in "$@"; do
  temp="$(mktemp -d -- "${i%/*}/hardlnk-XXXXXXXX")"
  [ -e "$temp" ] && cp -ip "$i" "$temp/tempcopy" && mv "$temp/tempcopy" "$i" && rmdir "$temp"
done

Portanto, para desassociar todos os links físicos ( Editar : alterado -type fpara -not -type d, veja acima):

find -not -type d -links +1 -print0 | xargs -0 unhardlink.sh
Suzanne Dupéron
fonte
Eu não consideraria isso "bruto". A única maneira de obter isso mais rápido é provavelmente fazer alguns truques com a chamada do sistema sendfile () e desvincular o arquivo de código aberto e reescrever o destino no local. Francamente, não vale a pena o esforço.
Matthew Ife
Por 'bruto', quero dizer que, por exemplo, quando executei esse comando usando a cp -iopção, ele cuspiu algumas mensagens perguntando se deveria substituir ./fileXXXXXX(o $temparquivo), mesmo que tmpfile deva dar nomes de arquivo exclusivos, portanto, é necessário seja algum tipo de condição de corrida ou o que seja, e com isso o risco de perder alguns dados.
Suzanne Dupéron
1
É normal que o arquivo exista, você apenas o criou com tempfile (obs: obsoleto em favor do mktemp, mas não foi isso que causou o seu problema).
31412 Tobu
1
Você unhardlink.shdeve criar um diretório temporário dentro do mesmo diretório que contém o arquivo que precisa ser desvinculado. Caso contrário, sua chamada recursiva poderá se repetir dentro de outro sistema de arquivos e você acabará movendo as coisas além dos limites do sistema de arquivos porque seu diretório temporário está no diretório de trabalho atual. Eu acho que você poderia passar "$(dirname "$i")/hardlink-XXXXXX"como argumento para mktemp.
Mikko Rantalainen 6/01/19
1
@MikkoRantalainen Muito obrigado, atualizado! Observe que, se o sistema de arquivos for algum tipo de unionfs ou um fusesistema de arquivos, ele poderá realmente ser enviado path/to/hardlink-XXXpara uma mídia de armazenamento físico diferente path/to/original-file, mas não há muito o que fazer sobre isso.
Suzanne Dupéron 08/02/19

Respostas:

9

Há espaço para melhorias em seu script, por exemplo, adicionando uma -popção ao cpcomando para que as permissões e os carimbos de data e hora sejam preservados em toda a operação de desarticulação, e você pode adicionar algum tratamento de erros para que o arquivo temporário seja excluído em caso de erro, mas a idéia básica da sua solução é a única que funcionará. Para desvincular um arquivo, você deve copiá-lo e, em seguida, mover a cópia novamente sobre o nome original. Não há solução "menos grosseira", e essa solução tem condições de corrida, caso outro processo esteja acessando o arquivo ao mesmo tempo.

Celada
fonte
Na verdade, eu sempre uso cp -a ao copiar coisas, para preservar tudo, recursar e copiar links simbólicos como links simbólicos. Não sei por que me esqueci dessa vez, mas depois de ver sua resposta, entendi que havia estragado todos os meus carimbos de data e hora e tive que (um pouco dolorosamente) recuperá-los de um backup.
Suzanne Dupéron
5

Se você deseja economizar espaço em disco e possui uma versão relativamente moderna tar(por exemplo, o que está no Ubuntu 10.04 e CentOS 6), pode jogar com a --hard-dereferenceopção

Algo como:

$ cd /path/to/directory
$ ls -l *
bar:
total 12
-rw-rw-r-- 2 cjc cjc 2 May  6 19:07 1
-rw-rw-r-- 2 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 3

foo:
total 12
-rw-rw-r-- 2 cjc cjc 3 May  6 19:07 1
-rw-rw-r-- 2 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 4

(onde eu corri ln foo/[12] bar)

$ tar cvf /tmp/dereferencing.tar --hard-dereference .
$ tar xvf /tmp/dereferencing.tar
$ ls -l *
bar:
total 12
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 1
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 3

foo:
total 12
-rw-rw-r-- 1 cjc cjc 3 May  6 19:07 1
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 4

Na página do manual:

   --hard-dereference
          follow hard links; archive and dump the files they refer to
cjc
fonte
Eu suspeito que há pouco alcatrão não pode fazer. Boa correção.
Joseph Kern
Esqueci de mencionar que não tinha espaço em disco suficiente para copiar tudo. Basicamente, seu método é o mesmo que cp -a --no-preserve=links /path/to/folder /path/to/copy && rm -rf /path/to/folder && mv /path/to/copy /path/to/folder, se não me engano. Eu acho que seu método seria mais eficiente, no entanto, porque o tar envolveria menos buscas de disco e, portanto, menos problemas. Pode-se conseguir o mesmo com o rsync, com desempenho ainda menor que o método cp :).
Suzanne Dupéron
1
Para evitar o uso de muito disco extra, pode ser possível executar algo parecido, tar cvf - --hard-dereference . | tar xf -mas pode haver uma condição de corrida que fará com que as coisas explodam. Eu não tentei e estou meio que desanimado em fazê-lo no momento.
cjc