Sejak Linux 3.15, renameat2
baru system call secara atomik dapat bertukar dua jalur pada sistem file yang sama. Namun, belum ada pembungkus glibc untuk itu, apalagi cara coreutils untuk mengaksesnya. Jadi akan terlihat seperti ini:
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");
(Tentu saja, Anda harus melakukan penanganan kesalahan yang benar, dll. – lihat intisari ini untuk renameat2
yang lebih canggih pembungkus.)
Yang mengatakan - solusi symlink yang disebutkan oleh orang lain lebih mudah dan portabel, jadi kecuali bravo
sudah ada dan Anda harus perbarui secara atomik, alih-alih gunakan symlink.
Pembaruan 2020:pembungkus glibc untuk panggilan sistem ini tersedia sejak glibc 2.28, dirilis 01-08-2018 (Debian Stretch, Fedora 29). Itu masih tidak dapat diakses melalui coreutils.
int dirfd = open(".../base", O_PATH | O_DIRECTORY | O_CLOEXEC);
renameat2(dirfd, "alpha", dirfd, "bravo", RENAME_EXCHANGE);
close(dirfd);
system("rm -rf alpha");
Solusi terakhir adalah menggabungkan symlink- dan pendekatan rename:
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
Tentu saja, aplikasi yang mengakses alfa harus dapat menangani perubahan symlink di jalur.
Mengambil solusi David di sini, yang sepenuhnya atom ... satu-satunya masalah yang Anda temui adalah -T
opsi untuk mv
adalah non-POSIX, dan OS POSIX tertentu mungkin tidak mendukungnya (FreeBSD, Solaris, dll. ... http://pubs.opengroup.org/onlinepubs/9699919799/utilities/mv.html). Dengan sedikit modifikasi, pendekatan ini dapat diubah menjadi sepenuhnya atomik, dan portabel di semua OS 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 ./
contohnya melalui:http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/
Anda dapat melakukan ini jika menggunakan symlink:
Katakanlah alpha adalah symlink ke direktori alpha_1, dan Anda ingin mengalihkan symlink untuk menunjuk ke alpha_2. Inilah tampilannya sebelum beralih:
$ ls -l
lrwxrwxrwx alpha -> alpha_1
drwxr-xr-x alpha_1
drwxr-xr-x alpha_2
Untuk membuat alpha merujuk ke alpha_2, gunakan ln -nsf:
$ ln -nsf alpha_2 alpha
$ ls -l
lrwxrwxrwx alpha -> alpha_2
drwxr-xr-x alpha_1
drwxr-xr-x alpha_2
Sekarang Anda dapat menghapus direktori lama:
$ rm -rf alpha_1
Perhatikan bahwa ini BUKAN sebenarnya operasi yang sepenuhnya atomik, tetapi ini terjadi dengan sangat cepat karena perintah "ln" membatalkan tautan dan kemudian segera membuat ulang symlink. Anda dapat memverifikasi perilaku ini dengan strace:
$ strace ln -nsf alpha_2 alpha
...
symlink("alpha_2", "alpha") = -1 EEXIST (File exists)
unlink("alpha") = 0
symlink("alpha_2", "alpha") = 0
...
Anda dapat mengulangi prosedur ini sesuai keinginan:mis. ketika Anda memiliki versi baru, alpha_3:
$ ln -nsf alpha_3 alpha
$ rm -rf alpha_2