Briser un lien dur en place?


13

Je garde mes fichiers dot sous contrôle de version et le script qui les déploie crée des liens durs. J'utilise également etckeeperpour mettre mon /etccontrôle de version sous. Récemment, j'ai reçu des avertissements comme celui-ci:

warning: hard-linked files could cause problems with bzr

Une simple copie ( cp filename.ext filename.ext) ne fonctionnera pas:

cp: `filename.ext' and `filename.ext' are the same file

Renommer / déplacer un fichier - sauf sur plusieurs volumes - ne rompt pas non plus le lien dur.

Ma question est donc la suivante: existe-t-il un moyen de rompre un lien dur vers un fichier sans avoir à savoir où se trouvent / sont les autres liens durs vers ce fichier?


2
La commande "rm" rompt les liens durs.
Johan

Réponses:


14
cp -p filename filename.tmp
mv -f filename.tmp filename

Rendre scriptable:

dir=$(dirname -- "$filename")
tmp=$(TMPDIR=$dir mktemp)
cp -p -- "$filename" "$tmp"
mv -f -- "$tmp" "$filename"

Faire la copie d'abord, puis la déplacer, a l'avantage que le fichier passe atomiquement d'un lien dur à une copie distincte (il n'y a aucun moment où il filenameest partiel ou manquant).


7

Vous voulez probablement dire que vous souhaitez diviser le lien physique en un fichier séparé et indépendant.

mv hardlink tempname && cp tempname hardlink && rm tempname

Un lien physique est la connexion entre une entrée dans le répertoire et le bloc inode sur le disque.

les inodes stockent les métadonnées des fichiers, et pour les petits fichiers, certains systèmes de fichiers stockent les données dans l'inode, sinon pointeurs vers les blocs de données, et pour les très gros fichiers, listes indirectes et doubles-indirectes de pointeurs vers les unités d'allocation de disque.

Quoi qu'il en soit, la connexion entre le nom de fichier (qui est ce que produit la commande ls) et le bloc inode qui stocke ces métadonnées, est appelée un lien dur.

Avoir plusieurs liens durs vers un seul fichier signifie le même inode référencé par plusieurs entrées de répertoire, éventuellement dans des répertoires différents (sur un seul système de fichiers)

rm supprime l'entrée du nom de fichier du répertoire. Une fois qu'un inode n'est plus référencé par aucun fichier, son espace est libéré pour être utilisé par d'autres fichiers.


En effet. C'est ce que le cpet les mvexemples impliquaient. Donc, je ne vois aucun moyen d'utiliser un fichier temporaire.
0xC0000022L

@ 0xC0000022L, Non, les inodes ne contiennent pas de pointeurs vers d'autres inodes. Juste aux blocs de données (ou ils peuvent doubler en tant qu'espace de données si l'objet est petit).
vonbrand

4
Assurez-vous que les autorisations et autres données sont préservées lors de la copie, c'est-à-dire. utiliser cp -a(au moins GNU coreutils).
vonbrand

@ 0xC0000022L, si vous regardez attentivement, il n'y a qu'un nom temporaire pour le fichier d'origine, un nouveau fichier n'est créé qu'à la dernière étape.
vonbrand

@vonbrand Ils peuvent en effet, selon le système de fichiers utilisé.
Johan

4

Mettez-le à la fin de votre fichier ~ / .bashrc.

delink () { tmpfile="$1$(date)"; cp -a "$1" "$tmpfile"; mv "$tmpfile" "$1"; }

Exécutez-le comme ça

delink filename

3

La meilleure façon de le faire avec un script bash serait quelque chose comme ceci:

if [ -f "$1" ] ; then
dir="$(dirname -- "$1")"
tmpfile="$(mktemp --tmpdir="$dir")"
cp --preserve=all -f -- "$1" "$tmpfile"
mv -f -- "$tmpfile" "$1"
fi

points à noter:

  • vérifier si le fichier est un fichier normal avant d'essayer de le copier
  • garder l'ancien fichier en place jusqu'à ce que la copie soit prête
  • utiliser mktemppour générer un fichier dont il est garanti qu'il n'existe pas
  • utiliser -fpour forcer l'écrasement et --preserve=allpour garder les métadonnées aussi similaires que possible au fichier d'origine
  • utiliser --et "pour citer des chemins contenant des espaces et / ou commençant par-

Faire le remplacement sans créer de fichier temporaire n'est pas possible avec les appels système Linux actuels (3.16): bien qu'il soit possible d'écraser un fichier atomiquement (c'est-à-dire de supprimer l'ancien fichier et de le remplacer par un nouveau en une seule opération), il n'est pas possible de le faire avec un fichier qui n'a pas de nom sur le système de fichiers (c'est-à-dire un fichier temporaire créé en utilisant l' O_TMPFILEindicateur de openfonction) car la renamefonction nécessite un nom de fichier en entrée (il n'y a pas de version renamequi prend en entrée un descripteur de fichier - voir ici pour plus de détails)


1
Notez que vous n'avez pas cité le nom dans vos appels dirnameet mktemp. Correction de cela pour vous ...
derobert

@derobert oh merci, mais cela ne fonctionnera pas car il y a des guillemets imbriqués ... besoin d'un autre correctif! Kinda hate bash
pqnet

3
Il va travailler en raison de la $( ... )substitution de commande de style. Une raison pour laquelle c'est plus agréable que le ` ... `style.
derobert

@derobert nice, je ne le savais pas. De plus, comment pouvez-vous utiliser `l'intérieur des balises de code en ligne?
pqnet

Vous pouvez leur échapper avec des barres obliques inverses. Donc, pour `vous mettre `\``dedans : (bien sûr, j'ai double-échappé pour le faire vous montrer ce que vous tapez).
derobert

-1

La commande que vous recherchez est unlink


Peut-être que ma question n'était pas claire, mais par "sur place" et les exemples avec cpet mvje voulais dire clairement que je souhaite que le fichier existe par la suite.
0xC0000022L

Ah, je n'ai pas trouvé cela clair, non. Vous devriez donc suivre la réponse de Johan.
Jenny D

1
La commande "unlink" supprime simplement le fichier (ce que fait l'appel système unlink ()).
Raúl Salinas-Monteagudo

-1

Si vous recherchez tous les noms de fichiers liés en dur à ce fichier, vous pouvez utiliser:

find -samefile myknowhardlinkfile

aussi ls -il myknowhardlinkfilevous montrer le nombre de nom de fichier au même lien fixe inode (troisième champ).

101612442 -rw-rw-r--. 2 me me 0 Aug  5 07:07 myknowhardlinkfile

Cela ne répond pas réellement à la question, bien que cela puisse être utile.
Flimm
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.