Skip to content

How to find deleted files using the NTFS crate? #35

@stolen-programmer

Description

@stolen-programmer

I'm trying to recover deleted files from an NTFS partition using the ntfs crate, but I can't see deleted files in my implementation. Here's my code snippet:

fn main() -> binrw::BinResult<()> {
    let name = r"\\.\PhysicalDrive0";
    let mut wname: Vec<_> = name.encode_utf16().collect();
    wname.push(0);
    // let cname = ffi::CString::new("t").unwrap();
    let mut file = fs::File::open(r"\\.\D:").unwrap();

    let h = file.as_raw_handle() as *mut winapi::ctypes::c_void;

    // 2. 获取磁盘扇区大小
    let mut geometry = [0u8; 256]; // 足够容纳 DISK_GEOMETRY 结构
    let mut bytes_returned = 0;

    let _result = unsafe {
        ioapiset::DeviceIoControl(
            h,
            winioctl::IOCTL_DISK_GET_DRIVE_GEOMETRY,
            std::ptr::null_mut(),
            0,
            geometry.as_mut_ptr() as *mut _,
            geometry.len() as u32,
            &mut bytes_returned,
            std::ptr::null_mut(),
        )
    };

    let g = geometry.as_ptr() as *const winioctl::DISK_GEOMETRY;
    let g = unsafe { g.as_ref() }.unwrap();

    let mut data = vec![0u8; g.BytesPerSector as usize * 200];
    file.read_exact(&mut data)?;
    // let mut r = Cursor::new(data);
    let mut r = AlignedAccess::new(&mut file, g.BytesPerSector as _)?;

    let ntfs = Ntfs::new(&mut r).unwrap();
    let root = ntfs.root_directory(&mut r).unwrap();
    let index = root.directory_index(&mut r).unwrap();

    let mut stack = vec![root.clone()];

    let mut curr = BTreeMap::new();

    loop {
        let bindings = stack.last().unwrap().directory_index(&mut r).unwrap();
        let mut iter = bindings.entries();

        while let Some(Ok(entry)) = iter.next(&mut r) {
            let pos = entry.position();
            // ntfs.file(&mut r, pos);
            // ntfs::NtfsFile::new(
            //     &ntfs,
            //     &mut r,
            //     pos.value().unwrap(),
            //     entry.file_reference().file_record_number(),
            // );

            let key = entry.key().unwrap().unwrap();
            let name: Vec<u16> = key
                .name()
                .0
                .chunks(2)
                .map(|x| u16::from_le_bytes(x.try_into().unwrap()))
                .collect();

            let name = String::from_utf16(&name).unwrap();

            let file = ntfs
                .file(&mut r, entry.file_reference().file_record_number())
                .unwrap();
            file.is_directory();
            // println!(
            //     "[{}] {} 0b{:b}",
            //     name,
            //     file.is_directory(),
            //     file.flags().bits()
            // );
            curr.insert(name.to_owned(), file);
            println!("insert [{name}]");
        }

        let mut line = String::new();
        std::io::stdin().lock().read_line(&mut line).unwrap();

        // println!("------- {:?}", curr.get(line.trim()));
        if let Some(file) = curr.get(line.trim()) {
            println!("cd {line}");
            stack.push(file.to_owned());
        }
    }
    Ok(())
}

Problem:
The current implementation only lists active files. How can I:

Access deleted files' metadata (timestamps, original size)

Recover file entries marked as deleted

Scan unallocated MFT entries?

Additional Questions:

Does the ntfs crate support working with deleted file records?

Are there any examples for low-level MFT parsing?

How to detect files marked with FILE_RECORD_SEGMENT_IN_USE flag cleared?

Environment:

Windows 10

rustc 1.88.0-nightly (4824c2bb7 2025-05-02)
rustup 1.28.1 (f9edccde0 2025-03-05)

ntfs crate 0.4.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions