GNU/Linux >> Linux Esercitazione >  >> Linux

Spostamento atomico di una directory

Da Linux 3.15, il nuovo renameat2 la chiamata di sistema può scambiare atomicamente due percorsi sullo stesso file system. Tuttavia, non esiste ancora nemmeno un wrapper glibc per esso, per non parlare di un modo coreutils per accedervi. Quindi sarebbe simile a questo:

int dirfd = open(".../base", O_PATH | O_DIRECTORY | O_CLOEXEC);
syscall(SYS_renameat2, dirfd, "alpha", dirfd, "bravo", RENAME_EXCHANGE);
close(dirfd);
system("rm -rf alpha");

(Naturalmente, dovresti eseguire una corretta gestione degli errori ecc. – vedi questo riassunto per un renameat2 più sofisticato involucro.)

Detto questo, la soluzione del collegamento simbolico menzionata da altri è sia più semplice che portabile, quindi a meno che bravo esiste già e devi aggiornalo atomicamente, vai invece con il link simbolico.

Aggiornamento 2020:un wrapper glibc per questa chiamata di sistema è disponibile a partire da glibc 2.28, rilasciato il 01-08-2018 (Debian Stretch, Fedora 29). Tuttavia, non è ancora accessibile tramite coreutils.

int dirfd = open(".../base", O_PATH | O_DIRECTORY | O_CLOEXEC);
renameat2(dirfd, "alpha", dirfd, "bravo", RENAME_EXCHANGE);
close(dirfd);
system("rm -rf alpha");

La soluzione finale è combinare l'approccio symlink e rinomina:

mkdir alpha_real
ln -s alpha_real alpha

# now use "alpha"

mkdir beta_real
ln -s beta_real tmp 

# atomically rename "tmp" to "alpha"
# use -T to actually replace "alpha" instead of moving *into* "alpha"
mv -T tmp alpha

Naturalmente, l'applicazione che accede ad alpha deve essere in grado di gestire i collegamenti simbolici che cambiano nel percorso.


Riprendendo la soluzione di David qui, che è completamente atomica... l'unico problema che potresti incontrare è che il -T opzione per mv non è POSIX, quindi alcuni sistemi operativi POSIX potrebbero non supportarlo (FreeBSD, Solaris, ecc. ... http://pubs.opengroup.org/onlinepubs/9699919799/utilities/mv.html). Con una leggera modifica, questo approccio può essere modificato per essere completamente atomico e portabile su tutti i sistemi operativi POSIX:

mkdir -p tmp/real_dir1 tmp/real_dir2
touch tmp/real_dir1/a tmp/real_dir2/a
# start with ./target_dir pointing to tmp/real_dir1
ln -s tmp/real_dir1 target_dir
# create a symlink named target_dir in tmp, pointing to real_dir2
ln -sf tmp/real_dir2 tmp/target_dir
# atomically mv it into ./ replacing ./target_dir
mv tmp/target_dir ./

esempio tramite:http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/


Puoi farlo se usi i collegamenti simbolici:

Diciamo che alpha è un collegamento simbolico alla directory alpha_1 e si desidera cambiare il collegamento simbolico in modo che punti a alpha_2. Ecco come appare prima del passaggio:

$ ls -l
lrwxrwxrwx alpha -> alpha_1
drwxr-xr-x alpha_1
drwxr-xr-x alpha_2

Per fare in modo che alpha si riferisca ad alpha_2, usa ln -nsf:

$ ln -nsf alpha_2 alpha
$ ls -l
lrwxrwxrwx alpha -> alpha_2
drwxr-xr-x alpha_1
drwxr-xr-x alpha_2

Ora puoi rimuovere la vecchia directory:

$ rm -rf alpha_1

Si noti che questa NON è in realtà un'operazione completamente atomica, ma avviene molto rapidamente poiché il comando "ln" scollega entrambi e quindi ricrea immediatamente il collegamento simbolico. Puoi verificare questo comportamento con strace:

$ strace ln -nsf alpha_2 alpha
...
symlink("alpha_2", "alpha")             = -1 EEXIST (File exists)
unlink("alpha")                         = 0
symlink("alpha_2", "alpha")             = 0
...

È possibile ripetere questa procedura come desiderato:ad es. quando hai una nuova versione, alpha_3:

$ ln -nsf alpha_3 alpha
$ rm -rf alpha_2

Linux
  1. PWD senza collegamenti simbolici?

  2. Rinominare i file nella directory?

  3. CD in una directory con nome sconosciuto in un percorso noto?

  4. Simulazione di un collegamento fisico a una directory?

  5. Creazione di una nuova directory in C

Comando Cd in Linux (Cambia directory)

Du comando in Linux

Comando mv in Linux

Come copiare la directory su Linux

Linux:aggiungi una directory a PATH

directory rsync in modo che tutte le modifiche vengano visualizzate in modo atomico