Saat mengembangkan proyek, menjadi perlu untuk menghapus file yang dibuat oleh aplikasi selama pelaksanaannya. Tetapi diharuskan bahwa file tidak dihapus pada akhir sesi, karya PC, tetapi atas permintaan pengguna.
Dan sepertinya tidak ada masalah. Pustaka standar Java memiliki metode delete () di kelas java.io.File untuk menghapus file.
File file = new File("path/to/file"); if (file.delete()) { System.out.println(file.getName() + " deleted"); } else { System.out.println(file.getName() + " not deleted"); }
Metode delete () di kelas java.io.File memanggil fungsi asli untuk menghapus file, tergantung pada OS. Dan sistem operasi modern tidak segera menghapus file saat menghapus file, tetapi hanya menghapus nama file. Isi file tetap ada, dan memori yang ditempati oleh file yang sudah dihapus dapat digunakan kembali di masa depan. Tetapi semua sama, untuk beberapa waktu tampaknya file yang sudah dihapus tersedia.
Dan jika Anda melihat Internet, ada banyak program untuk memulihkan file yang dihapus, misalnya
Recuva .
Tapi saya ingin file dihapus tanpa kemungkinan mengembalikannya di masa depan. Mulai mencari di internet, ternyata menghapus file tanpa mengembalikan (menimpa) bukanlah tugas yang sangat sepele. Dan ketika mengimplementasikan tugas seperti itu, diperlukan untuk mempertimbangkan fitur bekerja dengan file di OS tertentu. Dan dalam hal ini, Anda perlu menggunakan API asli yang ditulis secara manual atau semacam perpustakaan asli.
Karena aplikasi dikembangkan di Ubuntu, OS ini menyediakan banyak solusi siap pakai dalam bentuk utilitas baris perintah. Misalnya, utilitas hapus-aman, yang memungkinkan Anda menghapus file tanpa pemulihan menggunakan pendekatan berbeda.
$ srm -vz private/*
Aplikasi harus memeriksa apakah utilitas diinstal dan menampilkan kesalahan jika tidak menemukannya. Tetapi dalam hal menggunakan aplikasi untuk OS lain, Anda perlu menggunakan utilitas serupa.
Yang sangat tidak nyaman dan saya ingin keluar dari masalah ini. Jika Anda melihat kode sumber utilitas penghapus-aman, maka itu memungkinkan Anda untuk bekerja di bawah sistem operasi yang berbeda. Itu ditulis dalam C99 dan menggunakan sihir preprocessing berbeda dan API platform-spesifik. Mendebug kode asli tersebut jika terjadi kesalahan sangat sulit dan itu adalah tugas.
Jika Anda memahami cara kerja utilitas hapus-aman, maka langkah-langkah berikut dapat dibedakan.
- Pertama, ia memeriksa apakah file itu ada dan apakah haknya benar.
- tergantung pada algoritma yang ditentukan, menimpa konten file.
- mengurangi ukuran file menjadi nol byte.
- mengganti nama file urutan karakter acak.
- menghapus file.
secure-delete memungkinkan algoritme yang berbeda untuk menimpa konten file:
- Algoritma sederhana - menimpa dengan 1 pass 0x00 byte.
- Algoritma DOE - menimpa dengan 3 melewati acak, acak, "DoE".
- Algoritma RCMP - menimpa dengan 3 melewati 0x00, 0xFF, "RCMP".
- Algoritma OPENBSD - menimpa dengan 3 melewati 0xFF, 0x00, 0xFF byte.
- Algoritma DOD - menimpa 7 berlalu.
- Algoritma Gutmann - Menimpa 35 operan.
Saya ingin kode menjadi platform-independen dan bekerja di bawah sistem operasi yang berbeda. Jika Anda melihat C ++ modern, maka semua langkah yang dilakukan penghapusan aman untuk menimpa file dapat dilakukan.
Untuk memeriksa apakah suatu file ada dan apakah memiliki hak yang benar, Anda dapat menggunakan std :: filesystem, yang ditambahkan dalam C ++ 17.
Untuk versi standar sebelumnya, boost :: filesystem dapat digunakan.
namespace fs = std::filesystem; if (!fs::exists(file)) { env->ThrowNew(exception_class, "File doesn't exist"); } if (!fs::is_regular_file(file)) { env->ThrowNew(exception_class, "Path doesn't regular file or symlink"); } if (!eraser.check_permision(file, fs::status(file).permissions())) { env->ThrowNew(exception_class, "File hasn't enough permision (maybe not user)"); } bool kl::erase_content::check_permision(const fs::path& entry, fs::perms permision) { try { fs::permissions(entry, fs::perms::owner_read | fs::perms::owner_write, fs::perm_options::add); return true; } catch (fs::filesystem_error& e) { return false; } }
Untuk menimpa konten file, tergantung pada algoritma yang dipilih, Anda dapat membiarkan implementasi seperti dalam penghapusan aman.
bool kl::erase_content::overwrite() { switch (entry.get_mode()) { case kl::overwrite_mode::SIMPLE_MODE: if (!overwrite_byte(1, 0x00)) { return false; } break; case kl::overwrite_mode::DOE_MODE: if (!overwrite_random(1)) { return false; } if (!overwrite_random(2)) { return false; } if (!overwrite_bytes(3, "DoE")) { return false; } break; case kl::overwrite_mode::OPENBSD_MODE: break; case kl::overwrite_mode::RCMP_MODE: break; case kl::overwrite_mode::DOD_MODE: break; case kl::overwrite_mode::GUTMAN_MODE: break; default: std::cerr << "overwrite mode doesn't choose" << std::endl; } return true; }
Buffer ukuran tertentu diisi dengan set data tertentu, tergantung pada algoritme, dan tulis buffer ini ke file hingga mencapai akhir.
bool kl::erase_content::overwrite_byte(const int pass, const uint8_t byte) { const auto& [file_name, file_size, buffer_size, mode] = entry; this->buffer = std::make_unique<uint8_t[]>(buffer_size); std::memset(buffer.get(), byte, buffer_size); this->file = kl::fs_util::make_open_file(file_name, "r+b"); if (!overwrite_data(pass)) { return false; } return true; } bool kl::erase_content::overwrite_data(const int pass) { const auto& [file_name, file_size, buffer_size, mode] = entry; const size_t count = file_size / buffer_size; const size_t tail = file_size % buffer_size; size_t writted = 0; if (fseek(file.get(), 0, SEEK_SET) != 0) { std::cerr << "couldn't seek in file" << std::endl; return false; } writted = write_buffer(count, tail); if (writted != file_size) { std::cerr << "couldn't write buffer in file" << std::endl; return false; } fflush(file.get()); if (fseek(file.get(), 0, SEEK_SET) != 0) { std::cerr << "couldn't seek in file" << std::endl; return false; } file.reset(); return true; }
Kemudian kurangi ukuran file menjadi nol byte, menggunakan fungsi std :: filesystem :: resize_file () untuk ini.
try { fs::resize_file(file, 0); } catch (fs::filesystem_error& e) { env->ThrowNew(exception_class, "truncate file fail"); }
Langkah selanjutnya adalah mengubah nama file urutan karakter acak, menggunakan std :: random () dan std :: filesystem :: file :: replace_filename () untuk ini.
std::string parent_path = file.parent_path(); std::string file_name = file.filename(); fs::path copy_file = file; file_name = random_text(file_name.size()); copy_file.replace_filename(fs::path(file_name)); try { fs::rename(file, copy_file); } catch (fs::filesystem_error& e) { env->ThrowNew(exception_class, "can't rename file"); } return true;
Dan pada tahap akhir, Anda hanya perlu menghapus file menggunakan std :: filesystem :: remove () untuk ini.
try { fs::remove(copy_file); } catch (fs::filesystem_error& e) { env->ThrowNew(exception_class, "can't remove file"); }
Nah, untuk digunakan di Jawa Anda perlu mendeklarasikan metode asli.
public class EraseFS { static { System.loadLibrary("jefl"); } public static native boolean eraseFile(String path) throws EraseException; public static native boolean eraseFile(String path, OverwrideMode mode) throws EraseException; public static native boolean eraseFiles(String... paths) throws EraseException; public static native boolean eraseFiles(OverwrideMode mode, String... paths) throws EraseException; public static native boolean eraseDirectory(String path, boolean recursived) throws EraseException; public static native boolean eraseDirectory(String path, OverwrideMode mode, boolean recursived) throws EraseException; }
Implementasi asli hanya menggunakan pustaka C ++ standar, yang membuatnya mudah untuk port ke platform lain. Dan yang paling penting, tidak ada sihir makro preprosesor, yang tidak begitu mudah untuk di-debug jika terjadi kesalahan.
C ++ 17 standar sudah didukung oleh semua kompiler populer: MVSC, Dentang, GCC.
Kode sumber lengkap dapat dilihat di
kode github :.