Skip to content

Instantly share code, notes, and snippets.

@Mart-Bogdan
Created November 19, 2022 01:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Mart-Bogdan/bda2995621911254f73f80d157f07622 to your computer and use it in GitHub Desktop.
Save Mart-Bogdan/bda2995621911254f73f80d157f07622 to your computer and use it in GitHub Desktop.
windows file size experiments

This is scratch of getting data about file sizes.

But to compile it we need to add features impl-debug to crate winapi and change it's sources by adding debug to some structs.

It's bit tricky.

#![allow(unused_imports, unused)]
use std::error::Error;
use std::ffi::c_void;
use std::fs::{File, OpenOptions};
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::path::Path;
use std::process::exit;
use std::{io, mem};
use winapi::shared::minwindef::{DWORD, ULONG};
use winapi::shared::ntdef::ULONGLONG;
use winapi::shared::winerror::NO_ERROR;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::fileapi::{
GetCompressedFileSizeW, FILE_BASIC_INFO, FILE_COMPRESSION_INFO, FILE_STORAGE_INFO, FILE_ID_INFO
};
use winapi::um::fileapi::{FILE_STANDARD_INFO, INVALID_FILE_SIZE};
use winapi::um::minwinbase::{
FileBasicInfo, FileCompressionInfo, FileStandardInfo, FileStorageInfo,
FILE_INFO_BY_HANDLE_CLASS, FileIdInfo,
};
use winapi::um::winbase::{FILE_FLAG_BACKUP_SEMANTICS, GetFileInformationByHandleEx};
use winapi::um::winnt::{FILE_ATTRIBUTE_DIRECTORY, FILE_ID_128};
use winapi_util::{AsHandleRef, Handle};
#[path = "ffi.rs"]
mod ffi;
pub(crate) fn run() {
print_file_info("test-data\\text1_c.txt");
print_file_info("test-data\\text1.txt");
println!();
print_file_info("test-data\\text2_c.txt");
print_file_info("test-data\\text2.txt");
println!();
print_file_info("test-data\\b23_rand_c");
print_file_info("test-data\\b23_rand");
println!();
print_file_info("test-data\\b4000_rand_c");
print_file_info("test-data\\b4000_rand");
println!();
print_file_info("test-data\\b4096_rand_c");
print_file_info("test-data\\b4096_rand");
println!();
//
// print_file_info("test-data\\b23_zero_c");
// print_file_info("test-data\\b23_zero");
// println!();
//
print_file_info("test-data\\b512_zero_c");
print_file_info("test-data\\b512_zero");
// println!();
print_file_info("test-data\\alt_ds_512");
// print_file_info("C:\\tmp");
//exit(0);
}
fn print_file_info(file_name: &str) {
let std_info = get_file_info::<FILE_STANDARD_INFO>(file_name).unwrap();
let mut comp_info: FILE_COMPRESSION_INFO = get_file_info(file_name).unwrap();
let comp_size = ffi::compressed_size(Path::new(file_name)).unwrap();
let stor_info: FILE_STORAGE_INFO = get_file_info(file_name).unwrap();
let id_info: FILE_ID_INFO = get_file_info(file_name).unwrap();
unsafe {
// println!("File: {}\n SDT.AllocationSize: {} STD.EndOfFile: {} COMP.CompressedFileSize: {} COMP.CompressionFormat: {} GetCompressedFileSizeW: {} \
// COMP.ChunkShift {:?} COMP.ClusterShift: {:?}",
// file_name, std_info.AllocationSize.QuadPart(), std_info.EndOfFile.QuadPart(), comp_info.CompressedFileSize.QuadPart(), comp_info.CompressionFormat,comp_size,
// comp_info.ChunkShift, comp_info.ClusterShift
// );
println!("File: {}\n {:?}\n {:?}\n GetCompressedFileSizeW: {:?}\n {:?}\n {:?}\n",
file_name, &std_info, &comp_info, comp_size, &stor_info, &id_info
);
// println!("Storage info:
// LogicalBytesPerSector: {}
// PhysicalBytesPerSectorForAtomicity: {}
// PhysicalBytesPerSectorForPerformance: {}
// FileSystemEffectivePhysicalBytesPerSectorForAtomicity: {}
// Flags: {}
// ByteOffsetForSectorAlignment: {}
// ByteOffsetForPartitionAlignment: {}\n",
// stor_info.LogicalBytesPerSector,
// stor_info.PhysicalBytesPerSectorForAtomicity,
// stor_info.PhysicalBytesPerSectorForPerformance,
// stor_info.FileSystemEffectivePhysicalBytesPerSectorForAtomicity,
// stor_info.Flags,
// stor_info.ByteOffsetForSectorAlignment,
// stor_info.ByteOffsetForPartitionAlignment,
// );
}
}
#[inline(never)]
fn get_file_info<T: FileInfoTrait>(name: &str) -> Result<T, io::Error> {
use std::os::windows::fs::MetadataExt;
use std::os::windows::fs::OpenOptionsExt;
let file_path = Path::new(name);
let metadata = file_path.metadata()?;
let file = File::options()
.access_mode(0)//neither read or write: metadata access. This increases chance that we gain access due to security ACL.
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS)
.open(file_path)?;
let handle = Handle::from_file(file);
let mut file_std_info = get_file_information_by_handle_ex2(&handle)?;
return Result::Ok(file_std_info);
}
fn get_file_information_by_handle_ex<T: Default>(
handle: &Handle,
info_class: FILE_INFO_BY_HANDLE_CLASS,
) -> Result<T, io::Error> {
let mut buf = T::default();
let foo = "";
let res = unsafe {
GetFileInformationByHandleEx(
handle.as_raw(),
info_class,
&mut buf as *mut _ as *mut c_void,
mem::size_of_val(&buf) as DWORD,
)
};
if res != 0 {
Result::Ok(buf)
} else {
Result::Err(io::Error::last_os_error())
}
}
trait FileInfoTrait: Default + Sized {
const CLASS: FILE_INFO_BY_HANDLE_CLASS;
}
impl FileInfoTrait for FILE_STANDARD_INFO {
const CLASS: FILE_INFO_BY_HANDLE_CLASS = FileStandardInfo;
}
impl FileInfoTrait for FILE_COMPRESSION_INFO {
const CLASS: FILE_INFO_BY_HANDLE_CLASS = FileCompressionInfo;
}
impl FileInfoTrait for FILE_STORAGE_INFO {
const CLASS: FILE_INFO_BY_HANDLE_CLASS = FileStorageInfo;
}
impl FileInfoTrait for FILE_ID_INFO {
const CLASS: FILE_INFO_BY_HANDLE_CLASS = FileIdInfo ;
}
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntquerydirectoryfile
// https://www.winehq.org/pipermail/wine-cvs/2015-May/106715.html
// https://github.com/MicrosoftDocs/sdk-api/blob/docs/sdk-api-src/content/minwinbase/ne-minwinbase-file_info_by_handle_class.md#-field-fileidbothdirectoryinfo
// **RestartInfo -- restarts enumeration
fn get_file_information_by_handle_ex2<T: FileInfoTrait>(handle: &Handle) -> Result<T, io::Error> {
let mut buf = T::default();
let res = unsafe {
GetFileInformationByHandleEx(
handle.as_raw(),
T::CLASS,
&mut buf as *mut _ as *mut c_void,
mem::size_of_val(&buf) as DWORD,
)
};
if res != 0 {
Result::Ok(buf)
} else {
Result::Err(io::Error::last_os_error())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment