Skip to main content

sys_shred/core/
metadata.rs

1//! # Metadata & Filename Obfuscation
2//!
3//! Handles the transformation of file metadata to prevent path-based recovery
4//! and information leakage through filenames.
5
6use crate::error::ShredResult;
7use rand::{distributions::Alphanumeric, Rng};
8use std::fs;
9use std::path::{Path, PathBuf};
10
11#[cfg(unix)]
12use std::os::unix::io::AsRawFd;
13
14/// A utility for scrubbing and randomizing file metadata.
15///
16/// This component focuses on the anti-forensic aspects of shredding that go
17/// beyond raw data destruction.
18pub struct MetadataHandler;
19
20impl MetadataHandler {
21    /// Renames a file to a randomly generated alphanumeric string.
22    pub fn obfuscate_filename(path: &Path) -> ShredResult<PathBuf> {
23        let parent = path.parent().unwrap_or_else(|| Path::new("."));
24
25        // Generate a 16-character random alphanumeric string
26        let random_name: String = rand::thread_rng()
27            .sample_iter(&Alphanumeric)
28            .take(16)
29            .map(char::from)
30            .collect();
31
32        let new_path = parent.join(random_name);
33        fs::rename(path, &new_path)?;
34
35        Ok(new_path)
36    }
37
38    /// Truncates a file to zero bytes and flushes the change.
39    pub fn truncate(path: &Path) -> ShredResult<()> {
40        let file = fs::OpenOptions::new().write(true).open(path)?;
41        file.set_len(0)?;
42        file.sync_all()?;
43        Ok(())
44    }
45
46    /// Informs the OS/Hardware to discard the file's blocks (TRIM).
47    ///
48    /// On Linux, this uses `fallocate` with `FALLOC_FL_PUNCH_HOLE`.
49    /// On Windows, it uses `FSCTL_SET_ZERO_DATA`.
50    pub fn trim(path: &Path) -> ShredResult<()> {
51        let file = fs::OpenOptions::new().write(true).open(path)?;
52        let len = file.metadata()?.len();
53        if len == 0 {
54            return Ok(());
55        }
56
57        #[cfg(target_os = "linux")]
58        {
59            let fd = file.as_raw_fd();
60            unsafe {
61                // FALLOC_FL_PUNCH_HOLE (0x02) | FALLOC_FL_KEEP_SIZE (0x01)
62                libc::fallocate(fd, 0x01 | 0x02, 0, len as libc::off_t);
63            }
64        }
65
66        #[cfg(windows)]
67        {
68            use std::os::windows::io::AsRawHandle;
69            use windows_sys::Win32::Foundation::HANDLE;
70            use windows_sys::Win32::Storage::FileSystem::{
71                FILE_SET_ZERO_DATA_INFORMATION, FSCTL_SET_ZERO_DATA,
72            };
73            use windows_sys::Win32::System::IO::DeviceIoControl;
74
75            let handle = file.as_raw_handle() as HANDLE;
76            let mut info = FILE_SET_ZERO_DATA_INFORMATION {
77                FileOffset: 0,
78                BeyondFinalZero: len as i64,
79            };
80            let mut bytes_returned = 0;
81
82            unsafe {
83                DeviceIoControl(
84                    handle,
85                    FSCTL_SET_ZERO_DATA,
86                    &mut info as *mut _ as *mut _,
87                    std::mem::size_of::<FILE_SET_ZERO_DATA_INFORMATION>() as u32,
88                    std::ptr::null_mut(),
89                    0,
90                    &mut bytes_returned,
91                    std::ptr::null_mut(),
92                );
93            }
94        }
95
96        file.sync_all()?;
97        Ok(())
98    }
99}