Jadi, bagian yang cukup sederhana dari program untuk Windows. Ada file yang berisi beberapa entri. Dan mereka perlu disaring dengan cara tertentu.
Solusinya cukup sederhana - buka file, baca catatan satu per satu, kami menulis yang diperlukan untuk file sementara. Tutup file. Kami menghapusnya. Ganti nama sementara menjadi yang asli. Semuanya sangat sederhana sehingga saya bahkan tidak akan memberikan kode. Apakah ini alasan yang cukup untuk artikel ini?
Sementara semuanya bekerja, sebenarnya tidak ada alasan untuk menulis tentang itu. Tapi kemudian tiba-tiba suatu hari "semuanya jatuh", karena penggantian nama tidak terjadi karena kesalahan Akses ditolak. Ini sangat jarang terjadi, tetapi masih jauh lebih sering untuk mencurigai sinar kosmik.
Kami memulai penggalian. Petunjuk pertama yang ditemukan: dalam proses penggalian, kutipan dari dokumentasi Microsoft ini mengingatkan:
Fungsi DeleteFile menandai file untuk dihapus saat ditutup. Oleh karena itu, penghapusan file tidak terjadi sampai pegangan terakhir ke file ditutup. Panggilan selanjutnya ke CreateFile untuk membuka file gagal dengan ERROR_ACCESS_DENIED.
Dalam hal gejala, ini sangat mirip, tetapi dari mana "penangan lain" ini berasal, jika, selain kita, tidak ada yang melakukan dan tidak boleh melakukan apa pun dengan file ini? Dan kami tidak memiliki utas lain dengan utas yang akan melakukan sesuatu dengan file ini?
Pelakunya ditemukan berkat SysInternals dan ProcessMonitor mereka. Kami meluncurkannya, memasang filter pada file lama kami dan mencoba mereproduksinya untuk waktu yang lama dan persisten. Kami mereproduksi. Kami melihat. Dan apa yang kita lihat di sana?
01.2: 30: 28.3162097 PM our_prog.exe 1288 CreateFile our.file SUKSES Akses Yang Diinginkan: Generic Baca / Tulis
02.2: 25: 28.3164513 PM our_prog.exe 1288 WriteFile our.file SUKSES Offset: 0, Panjang: 898, Prioritas: Normal
...
34.2: 25: 28.3173405 PM our_prog.exe 1288 WriteFile our.file SUKSES Offset: 35.290, Panjang: 1.113
35.2: 25: 28.3173493 PM our_prog.exe 1288 WriteFile our.file SUKSES Offset: 36.403, Panjang: 1.128
36.2: 25: 28.3173736 PM our_prog.exe 1288 FlushBuffersFile our.file SUKSES
37.2: 25: 28.3174212 PM our_prog.exe 1288 WriteFile our.file SUKSES Offset: 0, Panjang: 40.960,
38.2: 25: 28.3175927 PM Explorer.EXE 1884 QueryBasicInformationFile our.file SUCCESS
39.2: 25: 28.3176144 PM Explorer.EXE 1884 CloseFile SUKSES kami.file
40.2: 25: 28.3263642 PM Explorer.EXE 1884 CreateFile our.file SUKSES Akses Yang Diinginkan: Baca Atribut,
41.2: 25: 28.3294990 PM our_prog.exe 1288 CloseFile our.file SUKSES
42.2: 25: 28.3351356 PM our_prog.exe 1288 CreateFile our.file SUKSES Akses Yang Diinginkan: Baca Atribut, Hapus,
43.2: 25: 28.3351856 PM our_prog.exe 1288 QueryAttributeTagFile our.file SUKSES Atribut: A, ReparseTag: 0x0
44.2: 25: 28.3352020 PM our_prog.exe 1288 SetDispositionInformationFile our.file SUKSES Hapus: Benar
45.2: 25: 28.3352218 PM our_prog.exe 1288 CloseFile SUKSES kami.file
46.2: 25: 28.3358275 PM our_prog.exe 1288 CreateFile our.file DELETE PENDING Akses yang Diinginkan: Generic Read / Write,
47.2: 25: 28.3362207 PM our_prog.exe 1288 CreateFile our.file DELETE PENDING Akses yang Diinginkan: Generic Read / Write,
48.2: 25: 28.3367696 PM Explorer.EXE 1884 QueryBasicInformationFile our.file SUCCESS
49.2: 25: 28.4279152 PM Explorer.EXE 1884 CloseFile SUKSES kami.file
50.2: 25: 28.4282859 PM Explorer.EXE 1884 CreateFile our.file NAMA TIDAK DITEMUKAN Akses yang Diinginkan: Baca Atribut,
...
83.2: 25: 29.3497760 PM our_prog.exe 1288 CreateFile our.file SUKSES Akses Yang Diinginkan: Generic Read / Write,
Dan kami melihat yang berikut di sana (data tambahan telah dihapus agar tidak berantakan). Baris 1 hingga 36 - kami membuat file, menulis padanya, membuat flush. Yang paling menarik dimulai pada baris 38-40. Explorer.exe muncul entah dari mana dan mulai membaca file kami.
Pada baris 41 kami menutup file kami. Sejalan 42 - hapus. Dan karena explorer.exe masih membacanya, file tersebut tidak dihapus. Apa yang dapat kita lihat pada baris 46 dan 47 ketika kita mencoba mengubah nama file sementara kita menjadi yang utama (HAPUS status PENDING alih-alih SUKSES).
Explorer.exe selesai membaca hanya pada baris 49. Hanya pada saat itu file tersebut dihapus secara fisik (seperti baris 50 memberitahu kita secara tidak langsung, di mana explorer.exe persisten kami lagi mencoba membuka file untuk dibaca, tetapi gagal karena file tersebut tidak lagi).
Apa yang mengikuti dari ini? Berkat Microsoft Windows, bahkan operasi penghapusan file sederhana sekarang perlu dilakukan dalam gaya pemrograman paranoid. Mereka memanggil fungsi hapus, memastikan bahwa ia kembali OK, dan memasuki siklus tunggu "sampai file tersebut dihapus secara fisik." Baik dan ya, tanpa mengetahui bahwa "dia memiliki neon di dalam," hampir tidak ada yang bisa dilakukan ...
Tetapi sekarang keraguan menggerogoti saya bahwa pendekatan semacam itu adalah praktik yang diterima secara umum. Untuk diingat selama bekerja dengan file di Windows bahwa OS setiap saat memutuskan untuk melakukan sesuatu dengan file tanpa sepengetahuan Anda, dan menulis kode yang tahan terhadap ini. Dalam hubungan ini, survei lebih rendah.