Finché non si sposta il file attraverso i bordi del file system, l'operazione dovrebbe essere sicura. Ciò è dovuto al meccanismo, come viene effettivamente fatto lo "spostamento".
Se mv
un file si trova sullo stesso file system, il file non viene effettivamente toccato, ma viene modificata solo la voce del file system.
$ mv foo bar
in realtà fa qualcosa di simile
$ ln foo bar
$ rm foo
Ciò creerebbe un forte legame (una seconda voce di directory) per il file (in realtà l'inode puntato dalla voce del file-system) foo
di nome bar
e rimuovere la foo
voce di. Da quando in fase di rimozione foo
, esiste una seconda voce del file system che punta foo
all'inode, la rimozione della voce precedente foo
non rimuove effettivamente alcun blocco appartenente all'inode.
Il tuo programma si accetterebbe comunque felicemente al file, poiché il suo handle di file aperto punta all'inode del file, non alla voce del file system.
Nota: se il programma chiude e riapre il file tra le scritture, si finirà per creare un nuovo file con la vecchia voce del file system!
Spostamenti incrociati del file system:
Se sposti il file attraverso i bordi del file system, le cose diventano brutte. In questo caso non puoi garantire che il tuo file rimanga coerente, dato che lo mv
farebbe davvero
- creare un nuovo file sul file system di destinazione
- copia il contenuto del vecchio file nel nuovo file
- rimuovere il vecchio file
o
$ cp /path/to/foo /path/to/bar
$ rm /path/to/foo
resp.
$ touch /path/to/bar
$ cat < /path/to/foo > /path/to/bar
$ rm /path/to/foo
A seconda che la copia raggiunga la fine del file durante una scrittura dell'applicazione, è possibile che nel nuovo file sia presente solo la metà di una riga.
Inoltre, se l'applicazione non si chiude e riapre il vecchio file, continuerebbe a scrivere nel vecchio file, anche se sembra essere eliminato: il kernel sa quali file sono aperti e sebbene eliminerebbe la voce del file system, non cancellerà l'inode del vecchio file e i blocchi associati fino a quando l'applicazione non chiuderà il suo handle di file aperto.
rename()
chiamata di sistema. Quindi la versione originale dimv
effettivamente ha chiamatolink()
per creare il collegamento reale, seguita daunlink()
per rimuovere il nome originale.rename()
è stato aggiunto in FreeBSD, per implementarlo atomicamente nel kernel.