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 }
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 #[br(temp)]
78 _reserved: u8,
79 #[bw(calc = 0)]
80 #[br(temp)]
81 _reserved2: u16,
82 #[bw(calc = 0)]
83 #[br(temp)]
84 _reserved3: u32,
85 /// A file handle for the root directory. For network operations, this value must be zero.
86 pub root_directory: u64,
87 #[bw(try_calc = file_name.size().try_into())]
88 _file_name_length: u32,
89 /// The new name for the file, including the full path.
90 #[br(args { size: SizedStringSize::bytes(_file_name_length) })]
91 pub file_name: SizedWideString,
92}
93
94/// Set the allocation size for a file.
95///
96/// The file system is passed a 64-bit signed integer containing the file allocation size, in bytes.
97/// The file system rounds the requested allocation size up to an integer multiple of the cluster size for nonresident files,
98/// or an implementation-defined multiple for resident files.
99/// All unused allocation (beyond EOF) is freed on the last handle close.
100///
101/// [MS-FSCC 2.4.4](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/0201c69b-50db-412d-bab3-dd97aeede13b>)
102#[binrw::binrw]
103#[derive(Debug, PartialEq, Eq)]
104pub struct FileAllocationInformation {
105 /// The new allocation size in bytes. Usually a multiple of the sector or cluster size of the underlying physical device.
106 pub allocation_size: u64,
107}
108
109/// Create a hard link to an existing file via the SMB Version 2 Protocol, as specified in [MS-SMB2].
110///
111/// WARNING: This operation is currently unstable and untested, and may lead to data loss or corruption if used improperly!
112///
113/// [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
114#[binrw::binrw]
115#[derive(Debug, PartialEq, Eq)]
116pub struct FileLinkInformation {
117 /// 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.
118 pub replace_if_exists: Boolean,
119 #[bw(calc = 0)]
120 #[br(temp)]
121 _reserved: u8,
122 #[bw(calc = 0)]
123 #[br(temp)]
124 _reserved2: u16,
125 #[bw(calc = 0)]
126 #[br(temp)]
127 _reserved3: u32,
128 /// A file handle for the root directory. For network operations, this value must be zero.
129 #[bw(calc = 0)]
130 #[br(assert(root_directory == 0))]
131 root_directory: u64,
132 #[bw(try_calc = file_name.size().try_into())]
133 _file_name_length: u32,
134 /// The name to be assigned to the newly created link.
135 #[br(args {size: SizedStringSize::bytes(_file_name_length)})]
136 pub file_name: SizedWideString,
137}
138
139/// change a file's short name.
140///
141/// If the supplied name is of zero length, the file's existing short name, if any,
142/// SHOULD be deleted.
143/// Otherwise, the supplied name MUST be a valid short name as specified in section 2.1.5.2.1
144/// and be unique among all file names and short names in the same directory as the file being operated on.
145/// A caller changing the file's short name MUST have SeRestorePrivilege.
146///
147/// [MS-FSCC 2.4.46](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/80cecad8-9172-4c42-af90-f890a84f2abc>)
148#[binrw::binrw]
149#[derive(Debug, PartialEq, Eq)]
150pub struct FileShortNameInformation {
151 /// The short name information, following the same structure as FileNameInformation.
152 inner: FileNameInformation,
153}
154
155impl Deref for FileShortNameInformation {
156 type Target = FileNameInformation;
157
158 fn deref(&self) -> &Self::Target {
159 &self.inner
160 }
161}
162
163/// set the valid data length information for a file.
164///
165/// A file's valid data length is the length, in bytes, of the data that has been written to the file.
166/// 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
167///
168/// [MS-FSCC 2.4.49](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/5c9f9d50-f0e0-40b1-9b84-0b78f59158b1>)
169#[binrw::binrw]
170#[derive(Debug, PartialEq, Eq)]
171pub struct FileValidDataLengthInformation {
172 /// The new valid data length for the file.
173 /// 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.
174 pub valid_data_length: u64,
175}
176
177#[cfg(test)]
178mod tests {
179 use crate::FileAttributes;
180
181 use super::*;
182 use smb_tests::*;
183 use time::macros::datetime;
184
185 test_binrw! {
186 struct FileAllocationInformation {
187 allocation_size: 500,
188 } => "f401000000000000"
189 }
190
191 test_binrw! {
192 struct FileEndOfFileInformation {
193 end_of_file: 777,
194 } => "0903000000000000"
195 }
196
197 test_binrw! {
198 struct FileDispositionInformation {
199 delete_pending: true.into(),
200 } => "01"
201 }
202
203 test_binrw_read! {
204 struct FileRenameInformation {
205 replace_if_exists: false.into(),
206 root_directory: 0,
207 file_name: SizedWideString::from("b.txt"),
208 } => "0002750062006c0000000000000000000a00000062002e00740078007400"
209 }
210
211 test_binrw_write! {
212 struct FileRenameInformation {
213 replace_if_exists: false.into(),
214 root_directory: 0,
215 file_name: SizedWideString::from("b.txt"),
216 } => "000000000000000000000000000000000a00000062002e00740078007400"
217 }
218
219 test_binrw! {
220 struct FileBasicInformation {
221 creation_time: FileTime::ZERO,
222 last_access_time: FileTime::ZERO,
223 last_write_time: datetime!(2025-04-11 17:24:47.489599300).into(),
224 change_time: datetime!(2025-04-11 17:24:47.489599300).into(),
225 file_attributes: FileAttributes::new(),
226 } => "00000000000000000000000000000000790eb19f06abdb01790eb19f06abdb010000000000000000"
227 }
228
229 test_binrw! {
230 struct FileValidDataLengthInformation {
231 valid_data_length: 0x123456789,
232 } => "8967452301000000"
233 }
234
235 test_binrw! {
236 struct FileShortNameInformation {
237 inner: FileNameInformation {
238 file_name: SizedWideString::from("SHORTN~1.TXT"),
239 },
240 } => "18000000530048004f00520054004e007e0031002e00540058005400"
241 }
242
243 // TODO: the following test is currently missing.
244 // pub Link = 11,
245}