smb_fscc/set_file_info.rs
1//! File Information Classes for setting file information.
2//!
3//! This module exports [`SetFileInfo`] enum and all structs that can be used to set file information.
4//!
5//! [MS-FSCC 2.4](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/4718fc40-e539-4014-8e33-b675af74e3e1>)
6
7use std::ops::Deref;
8
9use crate::file_info_classes;
10
11use smb_dtyp::binrw_util::prelude::*;
12
13use super::{
14 FileBasicInformation, FileFullEaInformation, FileModeInformation, FileNameInformation,
15 FilePipeInformation, FilePositionInformation,
16};
17
18file_info_classes! {
19 /// Set file information classes.
20 pub SetFileInfo {
21 pub Allocation = 19,
22 pub Basic = 4,
23 pub Disposition = 13,
24 pub EndOfFile = 20,
25 pub FullEa = 15,
26 pub Link = 11,
27 pub Mode = 16,
28 pub Pipe = 23,
29 pub Position = 14,
30 pub Rename = 10,
31 pub ShortName = 40,
32 pub ValidDataLength = 39,
33 }, Write
34}
35
36/// Set end-of-file information for a file.
37///
38/// [MS-FSCC 2.4.14](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/75241cca-3167-472f-8058-a52d77c6bb17>)
39#[binrw::binrw]
40#[derive(Debug, PartialEq, Eq)]
41pub struct FileEndOfFileInformation {
42 /// The absolute new end of file position as a byte offset from the start of the file.
43 /// Specifies the offset from the beginning of the file of the byte following the last byte in the file.
44 /// That is, it is the offset from the beginning of the file at which new bytes appended to the file will be written.
45 /// The value of this field MUST be greater than or equal to 0.
46 pub end_of_file: u64,
47}
48
49/// Mark a file for deletion.
50///
51/// [MS-FSCC 2.4.11](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/12c3dd1c-14f6-4229-9d29-75fb2cb392f6>)
52#[binrw::binrw]
53#[derive(Debug, PartialEq, Eq)]
54pub struct FileDispositionInformation {
55 /// Set to TRUE to indicate that a file should be deleted when it is closed; set to FALSE otherwise.
56 /// **Note:** Default is TRUE
57 pub delete_pending: Boolean,
58}
59
60impl Default for FileDispositionInformation {
61 fn default() -> Self {
62 Self {
63 delete_pending: true.into(),
64 }
65 }
66}
67
68/// Rename a file within the SMB2 protocol.
69///
70/// [MS-FSCC 2.4.42.2](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/52aa0b70-8094-4971-862d-79793f41e6a8>) - FileRenameInformation for SMB2 protocol
71#[binrw::binrw]
72#[derive(Debug, PartialEq, Eq)]
73pub struct FileRenameInformation {
74 /// Set to TRUE to indicate that if a file with the given name already exists, it should be replaced with the given file. Set to FALSE if the rename operation should fail if a file with the given name already exists.
75 pub replace_if_exists: Boolean,
76 #[bw(calc = 0)]
77 _reserved: u8,
78 #[bw(calc = 0)]
79 _reserved2: u16,
80 #[bw(calc = 0)]
81 _reserved3: u32,
82 /// A file handle for the root directory. For network operations, this value must be zero.
83 pub root_directory: u64,
84 #[bw(try_calc = file_name.size().try_into())]
85 _file_name_length: u32,
86 /// The new name for the file, including the full path.
87 #[br(args { size: SizedStringSize::bytes(_file_name_length) })]
88 pub file_name: SizedWideString,
89}
90
91/// Set the allocation size for a file.
92///
93/// The file system is passed a 64-bit signed integer containing the file allocation size, in bytes.
94/// The file system rounds the requested allocation size up to an integer multiple of the cluster size for nonresident files,
95/// or an implementation-defined multiple for resident files.
96/// All unused allocation (beyond EOF) is freed on the last handle close.
97///
98/// [MS-FSCC 2.4.4](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/0201c69b-50db-412d-bab3-dd97aeede13b>)
99#[binrw::binrw]
100#[derive(Debug, PartialEq, Eq)]
101pub struct FileAllocationInformation {
102 /// The new allocation size in bytes. Usually a multiple of the sector or cluster size of the underlying physical device.
103 pub allocation_size: u64,
104}
105
106/// Create a hard link to an existing file via the SMB Version 2 Protocol, as specified in [MS-SMB2].
107///
108/// WARNING: This operation is currently unstable and untested, and may lead to data loss or corruption if used improperly!
109///
110/// [MS-FSCC 2.4.8.2](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/58f44021-120d-4662-bf2c-9905ed4940dc>) - FileLinkInformation for SMB2 protocol
111#[binrw::binrw]
112#[derive(Debug, PartialEq, Eq)]
113pub struct FileLinkInformation {
114 /// Set to TRUE to indicate that if a file with the given name already exists, it should be replaced with the given file. Set to FALSE if the link operation should fail if a file with the given name already exists.
115 pub replace_if_exists: Boolean,
116 #[bw(calc = 0)]
117 _reserved: u8,
118 #[bw(calc = 0)]
119 _reserved2: u16,
120 #[bw(calc = 0)]
121 _reserved3: u32,
122 /// A file handle for the root directory. For network operations, this value must be zero.
123 #[bw(calc = 0)]
124 #[br(assert(root_directory == 0))]
125 root_directory: u64,
126 #[bw(try_calc = file_name.size().try_into())]
127 _file_name_length: u32,
128 /// The name to be assigned to the newly created link.
129 #[br(args {size: SizedStringSize::bytes(_file_name_length)})]
130 pub file_name: SizedWideString,
131}
132
133/// change a file's short name.
134///
135/// If the supplied name is of zero length, the file's existing short name, if any,
136/// SHOULD be deleted.
137/// Otherwise, the supplied name MUST be a valid short name as specified in section 2.1.5.2.1
138/// and be unique among all file names and short names in the same directory as the file being operated on.
139/// A caller changing the file's short name MUST have SeRestorePrivilege.
140///
141/// [MS-FSCC 2.4.46](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/80cecad8-9172-4c42-af90-f890a84f2abc>)
142#[binrw::binrw]
143#[derive(Debug, PartialEq, Eq)]
144pub struct FileShortNameInformation {
145 /// The short name information, following the same structure as FileNameInformation.
146 inner: FileNameInformation,
147}
148
149impl Deref for FileShortNameInformation {
150 type Target = FileNameInformation;
151
152 fn deref(&self) -> &Self::Target {
153 &self.inner
154 }
155}
156
157/// set the valid data length information for a file.
158///
159/// A file's valid data length is the length, in bytes, of the data that has been written to the file.
160/// This valid data extends from the beginning of the file to the last byte in the file that has not been zeroed or left uninitialized
161///
162/// [MS-FSCC 2.4.49](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/5c9f9d50-f0e0-40b1-9b84-0b78f59158b1>)
163#[binrw::binrw]
164#[derive(Debug, PartialEq, Eq)]
165pub struct FileValidDataLengthInformation {
166 /// The new valid data length for the file.
167 /// This parameter must be a positive value that is greater than the current valid data length, but less than or equal to the current file size.
168 pub valid_data_length: u64,
169}
170
171#[cfg(test)]
172mod tests {
173 use crate::FileAttributes;
174
175 use super::*;
176 use smb_tests::{test_binrw, test_binrw_read, test_binrw_write};
177 use time::macros::datetime;
178
179 test_binrw! {
180 struct FileAllocationInformation {
181 allocation_size: 500,
182 } => "f401000000000000"
183 }
184
185 test_binrw! {
186 struct FileEndOfFileInformation {
187 end_of_file: 777,
188 } => "0903000000000000"
189 }
190
191 test_binrw! {
192 struct FileDispositionInformation {
193 delete_pending: true.into(),
194 } => "01"
195 }
196
197 test_binrw_read! {
198 struct FileRenameInformation {
199 replace_if_exists: false.into(),
200 root_directory: 0,
201 file_name: SizedWideString::from("b.txt"),
202 } => "0002750062006c0000000000000000000a00000062002e00740078007400"
203 }
204
205 test_binrw_write! {
206 struct FileRenameInformation {
207 replace_if_exists: false.into(),
208 root_directory: 0,
209 file_name: SizedWideString::from("b.txt"),
210 } => "000000000000000000000000000000000a00000062002e00740078007400"
211 }
212
213 test_binrw! {
214 struct FileBasicInformation {
215 creation_time: FileTime::ZERO,
216 last_access_time: FileTime::ZERO,
217 last_write_time: datetime!(2025-04-11 17:24:47.489599300).into(),
218 change_time: datetime!(2025-04-11 17:24:47.489599300).into(),
219 file_attributes: FileAttributes::new(),
220 } => "00000000000000000000000000000000790eb19f06abdb01790eb19f06abdb010000000000000000"
221 }
222
223 test_binrw! {
224 struct FileValidDataLengthInformation {
225 valid_data_length: 0x123456789,
226 } => "8967452301000000"
227 }
228
229 test_binrw! {
230 struct FileShortNameInformation {
231 inner: FileNameInformation {
232 file_name: SizedWideString::from("SHORTN~1.TXT"),
233 },
234 } => "18000000530048004f00520054004e007e0031002e00540058005400"
235 }
236
237 // TODO: the following test is currently missing.
238 // pub Link = 11,
239}