use std::ops::Deref;
use crate::file_info_classes;
use smb_dtyp::binrw_util::prelude::*;
use super::{
FileBasicInformation, FileFullEaInformation, FileModeInformation, FileNameInformation,
FilePipeInformation, FilePositionInformation,
};
file_info_classes! {
pub SetFileInfo {
pub Allocation = 19,
pub Basic = 4,
pub Disposition = 13,
pub EndOfFile = 20,
pub FullEa = 15,
pub Link = 11,
pub Mode = 16,
pub Pipe = 23,
pub Position = 14,
pub Rename = 10,
pub ShortName = 40,
pub ValidDataLength = 39,
}
}
#[binrw::binrw]
#[derive(Debug, PartialEq, Eq)]
pub struct FileEndOfFileInformation {
pub end_of_file: u64,
}
#[binrw::binrw]
#[derive(Debug, PartialEq, Eq)]
pub struct FileDispositionInformation {
pub delete_pending: Boolean,
}
impl Default for FileDispositionInformation {
fn default() -> Self {
Self {
delete_pending: true.into(),
}
}
}
#[binrw::binrw]
#[derive(Debug, PartialEq, Eq)]
pub struct FileRenameInformation {
pub replace_if_exists: Boolean,
#[bw(calc = 0)]
#[br(temp)]
_reserved: u8,
#[bw(calc = 0)]
#[br(temp)]
_reserved2: u16,
#[bw(calc = 0)]
#[br(temp)]
_reserved3: u32,
pub root_directory: u64,
#[bw(try_calc = file_name.size().try_into())]
_file_name_length: u32,
#[br(args { size: SizedStringSize::bytes(_file_name_length) })]
pub file_name: SizedWideString,
}
#[binrw::binrw]
#[derive(Debug, PartialEq, Eq)]
pub struct FileAllocationInformation {
pub allocation_size: u64,
}
#[binrw::binrw]
#[derive(Debug, PartialEq, Eq)]
pub struct FileLinkInformation {
pub replace_if_exists: Boolean,
#[bw(calc = 0)]
#[br(temp)]
_reserved: u8,
#[bw(calc = 0)]
#[br(temp)]
_reserved2: u16,
#[bw(calc = 0)]
#[br(temp)]
_reserved3: u32,
#[bw(calc = 0)]
#[br(assert(root_directory == 0))]
root_directory: u64,
#[bw(try_calc = file_name.size().try_into())]
_file_name_length: u32,
#[br(args {size: SizedStringSize::bytes(_file_name_length)})]
pub file_name: SizedWideString,
}
#[binrw::binrw]
#[derive(Debug, PartialEq, Eq)]
pub struct FileShortNameInformation {
inner: FileNameInformation,
}
impl Deref for FileShortNameInformation {
type Target = FileNameInformation;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[binrw::binrw]
#[derive(Debug, PartialEq, Eq)]
pub struct FileValidDataLengthInformation {
pub valid_data_length: u64,
}
#[cfg(test)]
mod tests {
use crate::FileAttributes;
use super::*;
use smb_tests::*;
use time::macros::datetime;
test_binrw! {
struct FileAllocationInformation {
allocation_size: 500,
} => "f401000000000000"
}
test_binrw! {
struct FileEndOfFileInformation {
end_of_file: 777,
} => "0903000000000000"
}
test_binrw! {
struct FileDispositionInformation {
delete_pending: true.into(),
} => "01"
}
test_binrw_read! {
struct FileRenameInformation {
replace_if_exists: false.into(),
root_directory: 0,
file_name: SizedWideString::from("b.txt"),
} => "0002750062006c0000000000000000000a00000062002e00740078007400"
}
test_binrw_write! {
struct FileRenameInformation {
replace_if_exists: false.into(),
root_directory: 0,
file_name: SizedWideString::from("b.txt"),
} => "000000000000000000000000000000000a00000062002e00740078007400"
}
test_binrw! {
struct FileBasicInformation {
creation_time: FileTime::ZERO,
last_access_time: FileTime::ZERO,
last_write_time: datetime!(2025-04-11 17:24:47.489599300).into(),
change_time: datetime!(2025-04-11 17:24:47.489599300).into(),
file_attributes: FileAttributes::new(),
} => "00000000000000000000000000000000790eb19f06abdb01790eb19f06abdb010000000000000000"
}
test_binrw! {
struct FileValidDataLengthInformation {
valid_data_length: 0x123456789,
} => "8967452301000000"
}
test_binrw! {
struct FileShortNameInformation {
inner: FileNameInformation {
file_name: SizedWideString::from("SHORTN~1.TXT"),
},
} => "18000000530048004f00520054004e007e0031002e00540058005400"
}
}