Selama Anda tidak memindahkan file melintasi batas sistem file, operasi harus aman. Ini karena mekanisme, bagaimana »bergerak« sebenarnya dilakukan.
Jika Anda mv
file pada sistem file yang sama, file tersebut tidak benar-benar disentuh, tetapi hanya entri sistem file yang diubah.
$ mv foo bar
sebenarnya melakukan sesuatu seperti
$ ln foo bar
$ rm foo
Ini akan membuat tautan keras (entri direktori kedua) untuk file (sebenarnya inode yang ditunjuk oleh entri sistem file) foo
bernama bar
dan menghapus foo
entri. Karena sekarang ketika menghapus foo
, ada entri sistem file kedua yang menunjuk ke foo
inode, menghapus entri lama foo
tidak benar-benar menghapus blok milik inode.
Program Anda akan dengan senang hati menambahkan file, karena file-handle yang terbuka menunjuk ke inode file, bukan entri sistem file.
Catatan: Jika program Anda menutup dan membuka kembali file di antara waktu menulis, Anda akhirnya akan membuat file baru dengan entri sistem file lama!
Pemindahan lintas sistem file:
Jika Anda memindahkan file melintasi batas sistem file, segalanya menjadi jelek. Dalam hal ini Anda tidak dapat menjamin agar file Anda tetap konsisten, karena mv
sebenarnya
- buat file baru di sistem file target
- salin isi dari file lama ke file baru
- hapus file lama
atau
$ 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
Bergantung pada apakah penyalinan mencapai akhir file selama penulisan aplikasi Anda, bisa jadi Anda hanya memiliki setengah baris dalam file baru.
Selain itu, jika aplikasi Anda tidak menutup dan membuka kembali file lama, itu akan terus menulis ke file lama, bahkan jika itu tampaknya dihapus: kernel tahu file mana yang terbuka dan meskipun itu akan menghapus entri sistem file, itu tidak akan menghapus inode file lama dan blok terkait sampai aplikasi Anda menutup pegangan file yang terbuka.
rename()
panggilan sistem. Jadi versi asli darimv
panggilan sebenarnyalink()
untuk membuat tautan keras, diikuti olehunlink()
untuk menghapus nama asli.rename()
ditambahkan di FreeBSD, untuk mengimplementasikannya secara atomik di kernel.file-system borders
?Karena Anda mengatakan Anda menggunakan node.js, saya menganggap Anda akan menggunakan
fs.rename()
(ataufs.renameSync()
) untuk mengubah nama file. Metode node.js ini didokumentasikan untuk menggunakan rename (2) system call, yang tidak menyentuh file itu sendiri dengan cara apa pun, tetapi hanya mengubah nama yang terdaftar dalam sistem file:Secara khusus, perhatikan kalimat terakhir yang dikutip di atas, yang mengatakan bahwa setiap deskriptor file terbuka (seperti program Anda akan digunakan untuk menulis ke file) akan terus menunjukkannya bahkan setelah diubah namanya. Dengan demikian, tidak akan ada kehilangan data atau kerusakan bahkan jika file diganti namanya saat sedang ditulis secara bersamaan.
Seperti Andreas Weise catat dalam jawabannya , rename (2) system call (dan dengan demikian
fs.rename()
dalam node.js) tidak akan bekerja melintasi batas filesystem. Dengan demikian, upaya untuk memindahkan file ke sistem file yang berbeda dengan cara ini akan gagal.mv
Perintah Unix mencoba untuk menyembunyikan batasan ini dengan mendeteksi kesalahan dan, sebaliknya, memindahkan file dengan menyalin kontennya ke file baru dan menghapus yang asli. Sayangnya, memindahkan file seperti ini tidak menghilangkan data risiko jika file dipindahkan saat sedang ditulis. Jadi, jika Anda ingin mengganti nama file yang dapat ditulis secara simultan secara aman, Anda tidak boleh menggunakanmv
(atau, setidaknya, Anda harus benar-benar memastikan bahwa jalur baru dan lama berada di sistem file yang sama).sumber