smb_fscc/
query_file_info.rs

1//! File Information Classes for getting file information.
2//!
3//! This module mostly exports [QueryFileInfo] enum, and all structs that can be used with it.
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 binrw::{NullString, io::TakeSeekExt, prelude::*};
10
11use super::{
12    ChainedItemList, FileAccessMask, FileAttributes, FileBasicInformation, FileFullEaInformation,
13    FileModeInformation, FileNameInformation, FilePipeInformation, FilePositionInformation,
14};
15use crate::{ReparseTag, file_info_classes};
16use smb_dtyp::binrw_util::prelude::*;
17
18file_info_classes! {
19    /// Query file information classes.
20    pub QueryFileInfo {
21        pub Access = 8,
22        pub Alignment = 17,
23        pub All = 18,
24        pub AlternateName = 21,
25        pub AttributeTag = 35,
26        pub Basic = 4,
27        pub Compression = 28,
28        pub Ea = 7,
29        pub FullEa = 15,
30        pub Id = 59,
31        pub Internal = 6,
32        pub Mode = 16,
33        pub NetworkOpen = 34,
34        pub NormalizedName = 48,
35        pub Pipe = 23,
36        pub PipeLocal = 24,
37        pub PipeRemote  = 25,
38        pub Position = 14,
39        pub Standard = 5,
40        pub Stream = 22,
41    }, Read
42}
43
44pub type QueryFileFullEaInformation = FileFullEaInformation;
45
46pub type FileStreamInformation = ChainedItemList<FileStreamInformationInner, 8>;
47
48/// Query the access rights of a file that were granted when the file was opened.
49///
50/// [MS-FSCC 2.4.1](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/01cf43d2-deb3-40d3-a39b-9e68693d7c90>)
51#[binrw::binrw]
52#[derive(Debug, PartialEq, Eq)]
53pub struct FileAccessInformation {
54    /// Contains values that specify the access rights that were granted when the file was opened.
55    pub access_flags: FileAccessMask,
56}
57
58/// Query a collection of file information structures.
59///
60/// [MS-FSCC 2.4.2](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/95f3056a-ebc1-4f5d-b938-3f68a44677a6>)
61#[binrw::binrw]
62#[derive(Debug, PartialEq, Eq)]
63pub struct FileAllInformation {
64    /// Basic file information including timestamps and attributes.
65    pub basic: FileBasicInformation,
66    /// Standard file information about allocation size and file size.
67    pub standard: FileStandardInformation,
68    /// Internal file information including the file index number.
69    pub internal: FileInternalInformation,
70    /// Extended attribute information for the file.
71    pub ea: FileEaInformation,
72    /// Access rights information for the file.
73    pub access: FileAccessInformation,
74    /// Current file position information.
75    pub position: FilePositionInformation,
76    /// File mode information.
77    pub mode: FileModeInformation,
78    /// Buffer alignment requirements for the underlying device.
79    pub alignment: FileAlignmentInformation,
80    /// File name information.
81    pub name: FileNameInformation,
82}
83
84/// Query the buffer alignment required by the underlying device.
85///
86/// [MS-FSCC 2.4.3](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/9b0b9971-85aa-4651-8438-f1c4298bcb0d>)
87#[binrw::binrw]
88#[derive(Debug, PartialEq, Eq)]
89#[brw(repr(u32))]
90pub enum FileAlignmentInformation {
91    /// Specifies that there are no alignment requirements for the device.
92    Byte = 0,
93    /// Specifies that data must be aligned on a 2-byte boundary.
94    Word = 1,
95    /// Specifies that data must be aligned on a 4-byte boundary.
96    Long = 3,
97    /// Specifies that data must be aligned on an 8-byte boundary.
98    Quad = 7,
99    /// Specifies that data must be aligned on a 16-byte boundary.
100    Octa = 0xf,
101    /// Specifies that data must be aligned on a 32-byte boundary.
102    _32Byte = 0x1f,
103    /// Specifies that data must be aligned on a 64-byte boundary.
104    _64Byte = 0x3f,
105    /// Specifies that data must be aligned on a 128-byte boundary.
106    _128Byte = 0x7f,
107    /// Specifies that data must be aligned on a 256-byte boundary.
108    _256Byte = 0xff,
109    /// Specifies that data must be aligned on a 512-byte boundary.
110    _512Byte = 0x1ff,
111}
112
113/// Query the alternate name (8.3 short name) of a file.
114///
115/// [MS-FSCC 2.4.5](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/cb90d9e0-695d-4418-8d89-a29e2ba9faf8>)
116#[binrw::binrw]
117#[derive(Debug, PartialEq, Eq)]
118pub struct FileAlternateNameInformation {
119    /// The alternate name information, following the same structure as FileNameInformation.
120    inner: FileNameInformation,
121}
122
123impl Deref for FileAlternateNameInformation {
124    type Target = FileNameInformation;
125
126    fn deref(&self) -> &Self::Target {
127        &self.inner
128    }
129}
130
131impl From<&str> for FileAlternateNameInformation {
132    fn from(value: &str) -> Self {
133        Self {
134            inner: FileNameInformation::from(value),
135        }
136    }
137}
138
139/// Query file attribute and reparse tag information for a file.
140///
141/// [MS-FSCC 2.4.6](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d295752f-ce89-4b98-8553-266d37c84f0e>)
142#[binrw::binrw]
143#[derive(Debug, PartialEq, Eq)]
144pub struct FileAttributeTagInformation {
145    /// File attributes as a bitmask of flags.
146    pub file_attributes: FileAttributes,
147    /// The reparse point tag value. If the file is not a reparse point, this value is undefined and should not be used.
148    pub reparse_tag: ReparseTag,
149}
150
151/// Query compression information for a file.
152///
153/// [MS-FSCC 2.4.9](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/0a7e50c4-2839-438e-aa6c-0da7d681a5a7>)
154#[binrw::binrw]
155#[derive(Debug, PartialEq, Eq)]
156pub struct FileCompressionInformation {
157    /// The size of the compressed file in bytes.
158    pub compressed_file_size: u64,
159    /// The compression format used for the file.
160    pub compression_format: FileCompressionFormat,
161    /// The compression unit size in bytes as a power of 2.
162    pub compression_unit: u8,
163    /// The compression chunk size in bytes as a power of 2.
164    pub chunk_shift: u8,
165    /// The cluster size in bytes as a power of 2.
166    pub cluster_shift: u8,
167
168    #[bw(calc = [0; 3])]
169    _reserved: [u8; 3],
170}
171
172/// Compression format values for file compression.
173#[binrw::binrw]
174#[derive(Debug, PartialEq, Eq)]
175#[brw(repr(u16))]
176pub enum FileCompressionFormat {
177    /// The file is not compressed.
178    None = 0,
179    /// The file is compressed using the LZNT1 compression algorithm.
180    Lznt1 = 2,
181}
182
183/// Query the size of the extended attributes (EA) for a file.
184///
185/// [MS-FSCC 2.4.13](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/db6cf109-ead8-441a-b29e-cb2032778b0f>)
186#[binrw::binrw]
187#[derive(Debug, PartialEq, Eq)]
188pub struct FileEaInformation {
189    /// The size in bytes of the extended attributes for the file.
190    pub ea_size: u32,
191}
192
193/// Query the file system's 8-byte file reference number for a file.
194///
195/// [MS-FSCC 2.4.26](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/e4185a8a-ed8d-4f98-ab55-ca34dc8916e6>)
196#[binrw::binrw]
197#[derive(Debug, PartialEq, Eq)]
198pub struct FileIdInformation {
199    /// The serial number of the volume containing the file.
200    pub volume_serial_number: u64,
201    /// A 128-bit file identifier that uniquely identifies a file within the file system.
202    pub file_id: u128,
203}
204
205/// Query the file system's 8-byte file reference number for a file.
206///
207/// [MS-FSCC 2.4.27](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/7d796611-2fa5-41ac-8178-b6fea3a017b3>)
208#[binrw::binrw]
209#[derive(Debug, PartialEq, Eq)]
210pub struct FileInternalInformation {
211    /// An 8-byte file reference number for the file. This number is generated and assigned to the file by the file system.
212    pub index_number: u64,
213}
214
215/// Query network file open information for a file.
216///
217/// [MS-FSCC 2.4.34](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/26d261db-58d1-4513-a548-074448cbb146>)
218#[binrw::binrw]
219#[derive(Debug, PartialEq, Eq)]
220pub struct FileNetworkOpenInformation {
221    /// The time when the file was created.
222    pub creation_time: FileTime,
223    /// The time when the file was last accessed.
224    pub last_access_time: FileTime,
225    /// The time when data was last written to the file.
226    pub last_write_time: FileTime,
227    /// The time when the file was last changed.
228    pub change_time: FileTime,
229    /// The number of bytes that are allocated for the file.
230    pub allocation_size: u64,
231    /// The end of file location as a byte offset from the start of the file.
232    pub end_of_file: u64,
233    /// The file attributes.
234    pub file_attributes: FileAttributes,
235    #[bw(calc = 0)]
236    _reserved: u32,
237}
238
239/// Query the normalized name of a file.
240///
241/// A normalized name is an absolute pathname where each short name component has been replaced with the corresponding long name component,
242/// and each name component uses the exact letter casing stored on disk
243///
244/// [MS-FSCC 2.4.36](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/20bcadba-808c-4880-b757-4af93e41edf6>)
245#[binrw::binrw]
246#[derive(Debug, PartialEq, Eq)]
247pub struct FileNormalizedNameInformation {
248    /// The normalized name information, following the same structure as FileNameInformation.
249    inner: FileNameInformation,
250}
251
252impl Deref for FileNormalizedNameInformation {
253    type Target = FileNameInformation;
254
255    fn deref(&self) -> &Self::Target {
256        &self.inner
257    }
258}
259
260impl From<&str> for FileNormalizedNameInformation {
261    fn from(value: &str) -> Self {
262        Self {
263            inner: FileNameInformation::from(value),
264        }
265    }
266}
267
268/// Query information associated with a named pipe that is not specific to one end of the pipe or another.
269///
270/// [MS-FSCC 2.4.38](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/de9abdc7-b974-4ec3-a4dc-42853777f412>)
271#[binrw::binrw]
272#[derive(Debug, PartialEq, Eq)]
273pub struct FilePipeLocalInformation {
274    /// The type of named pipe.
275    pub named_pipe_type: NamedPipeType,
276    /// The named pipe configuration.
277    pub named_pipe_configuration: NamedPipeConfiguration,
278    /// The maximum number of instances that can be created for this pipe.
279    pub maximum_instances: u32,
280    /// The number of current named pipe instances.
281    pub current_instances: u32,
282    /// The inbound quota in bytes.
283    pub inbound_quota: u32,
284    /// Bytes of data available to be read from the named pipe.
285    pub read_data_available: u32,
286    /// The outbound quota in bytes.
287    pub outbound_quota: u32,
288    /// The write quota in bytes.
289    pub write_quota_available: u32,
290    /// The named pipe state.
291    pub named_pipe_state: NamedPipeState,
292    /// Specifies whether the named pipe handle is for the client or server end of a named pipe.
293    pub named_pipe_end: NamedPipeEnd,
294}
295
296/// Named pipe type values.
297#[binrw::binrw]
298#[derive(Debug, PartialEq, Eq)]
299#[brw(repr(u32))]
300pub enum NamedPipeType {
301    /// The pipe is a byte-stream pipe.
302    ByteStream = 0,
303    /// The pipe is a message pipe.
304    Message = 1,
305}
306
307/// Named pipe configuration values.
308#[binrw::binrw]
309#[derive(Debug, PartialEq, Eq)]
310#[brw(repr(u32))]
311pub enum NamedPipeConfiguration {
312    /// The flow of data in the pipe goes from client to server only.
313    Inbound = 0,
314    /// The flow of data in the pipe goes from server to client only.
315    Outbound = 1,
316    /// The pipe is bidirectional; both server and client can read from and write to the pipe.
317    FullDuplex = 2,
318}
319
320/// Named pipe state values.
321#[binrw::binrw]
322#[derive(Debug, PartialEq, Eq)]
323#[brw(repr(u32))]
324pub enum NamedPipeState {
325    /// The pipe is disconnected.
326    Disconnected = 1,
327    /// The pipe is waiting for a client to connect.
328    Listening = 2,
329    /// The pipe is connected to a client.
330    Connected = 3,
331    /// The pipe is in the process of being closed.
332    Closing = 4,
333}
334
335/// Named pipe end values.
336#[binrw::binrw]
337#[derive(Debug, PartialEq, Eq)]
338#[brw(repr(u32))]
339pub enum NamedPipeEnd {
340    /// The handle is for the client end of the named pipe.
341    Client = 0,
342    /// The handle is for the server end of the named pipe.
343    Server = 1,
344}
345
346/// Query information that is associated with the remote end of a named pipe.
347///
348/// [MS-FSCC 2.4.39](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/4319b135-4472-482f-a0a3-6cc3a856c6b6>)
349#[binrw::binrw]
350#[derive(Debug, PartialEq, Eq)]
351pub struct FilePipeRemoteInformation {
352    /// The time at which the data is collected.
353    pub collect_data_time: FileTime,
354    /// The maximum size, in bytes, of data that will be collected before transmission to the remote end of the named pipe.
355    pub maximum_collection_count: u32,
356}
357
358/// Query standard information for a file.
359///
360/// [MS-FSCC 2.4.47](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/5afa7f66-619c-48f3-955f-68c4ece704ae>)
361#[binrw::binrw]
362#[derive(Debug, PartialEq, Eq)]
363pub struct FileStandardInformation {
364    /// The number of bytes that are allocated for the file.
365    pub allocation_size: u64,
366    /// The end of file location as a byte offset from the start of the file.
367    pub end_of_file: u64,
368    /// The number of non-deleted hard links to this file.
369    pub number_of_links: u32,
370    /// Set to TRUE if the file has been marked for deletion.
371    pub delete_pending: Boolean,
372    /// Set to TRUE if the file is a directory.
373    pub directory: Boolean,
374    #[bw(calc = 0)]
375    #[br(assert(reserved == 0))]
376    reserved: u16,
377}
378
379/// Enumerate the data streams for a file.
380///
381/// [MS-FSCC 2.4.49](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/f8762be6-3ab9-411e-a7d6-5cc68f70c78d>)
382#[binrw::binrw]
383#[derive(Debug, PartialEq, Eq)]
384pub struct FileStreamInformationInner {
385    #[bw(try_calc = stream_name.size().try_into())]
386    stream_name_length: u32,
387    /// The size, in bytes, of the stream.
388    pub stream_size: u64,
389    /// The number of bytes that are allocated for the stream.
390    pub stream_allocation_size: u64,
391    /// The name of the stream in Unicode.
392    #[br(args { size: SizedStringSize::bytes(stream_name_length)})]
393    pub stream_name: SizedWideString,
394}
395
396/// Query extended attributes for a file.
397#[binrw::binrw]
398#[derive(Debug, PartialEq, Eq)]
399#[bw(import(has_next: bool))]
400pub struct FileGetEaInformation {
401    #[bw(try_calc = ea_name.len().try_into())]
402    ea_name_length: u8,
403    /// The name of the extended attribute.
404    #[br(map_stream = |s| s.take_seek(ea_name_length as u64))]
405    pub ea_name: NullString,
406}
407
408impl FileGetEaInformation {
409    pub fn new<S: Into<String>>(name: S) -> Self {
410        Self {
411            ea_name: NullString::from(name.into()),
412        }
413    }
414}
415
416#[cfg(test)]
417mod tests {
418    use super::*;
419    use smb_tests::test_binrw;
420    use time::macros::datetime;
421
422    fn get_file_access_information_for_test() -> FileAccessInformation {
423        FileAccessInformation {
424            access_flags: FileAccessMask::new()
425                .with_file_read_data(true)
426                .with_file_write_data(true)
427                .with_file_append_data(true)
428                .with_file_read_ea(true)
429                .with_file_write_ea(true)
430                .with_file_execute(true)
431                .with_file_delete_child(true)
432                .with_file_read_attributes(true)
433                .with_file_write_attributes(true)
434                .with_delete(true)
435                .with_read_control(true)
436                .with_write_dacl(true)
437                .with_write_owner(true)
438                .with_synchronize(true),
439        }
440    }
441    const FILE_ACCESS_INFORMATION_FOR_TEST_STRING: &str = "ff011f00";
442    test_binrw! {
443        FileAccessInformation: get_file_access_information_for_test() => FILE_ACCESS_INFORMATION_FOR_TEST_STRING
444    }
445
446    fn get_file_alignment_information_for_test() -> FileAlignmentInformation {
447        FileAlignmentInformation::Byte
448    }
449    const FILE_ALIGNMENT_INFORMATION_FOR_TEST_STRING: &str = "00000000";
450    test_binrw! {
451        FileAlignmentInformation: get_file_alignment_information_for_test() => FILE_ALIGNMENT_INFORMATION_FOR_TEST_STRING
452    }
453
454    test_binrw! {
455        FileAlternateNameInformation: FileAlternateNameInformation::from("query_info_o") => "18000000710075006500720079005f0069006e0066006f005f006f00"
456    }
457
458    test_binrw! {
459        // TODO: DFS reparse tag here can be cool
460        struct FileAttributeTagInformation {
461            file_attributes: FileAttributes::new()
462                .with_archive(true),
463            reparse_tag: ReparseTag::ReservedZero,
464        } => "2000000000000000"
465    }
466
467    fn get_file_basic_information_for_test() -> FileBasicInformation {
468        FileBasicInformation {
469            creation_time: datetime!(2025-10-17 10:35:07.801764000).into(),
470            last_access_time: datetime!(2025-10-17 10:35:07.801764000).into(),
471            last_write_time: datetime!(2025-10-17 10:35:07.801764000).into(),
472            change_time: datetime!(2025-10-17 10:35:07.801764000).into(),
473            file_attributes: FileAttributes::new().with_archive(true),
474        }
475    }
476    const FILE_BASIC_INFORMATION_FOR_TEST_STRING: &str =
477        "681621b5513fdc01681621b5513fdc01681621b5513fdc01681621b5513fdc012000000000000000";
478
479    test_binrw! {
480        FileBasicInformation: get_file_basic_information_for_test() => FILE_BASIC_INFORMATION_FOR_TEST_STRING
481    }
482
483    test_binrw! {
484        // TODO: something with actual compression
485        struct FileCompressionInformation => no {
486            compressed_file_size: 13,
487            compression_format: FileCompressionFormat::None,
488            compression_unit: 0,
489            chunk_shift: 0,
490            cluster_shift: 0,
491        } => "0d000000000000000000000000000000"
492    }
493
494    fn get_internal_information_for_test() -> FileInternalInformation {
495        FileInternalInformation {
496            index_number: 0x33b16,
497        }
498    }
499    const FILE_INTERNAL_INFORMATION_FOR_TEST_STRING: &str = "163b030000000000";
500
501    test_binrw! {
502         FileInternalInformation: get_internal_information_for_test() => FILE_INTERNAL_INFORMATION_FOR_TEST_STRING
503    }
504
505    fn get_file_mode_information_for_test() -> FileModeInformation {
506        FileModeInformation::new().with_synchronous_io_non_alert(true)
507    }
508
509    const FILE_MODE_INFORMATION_FOR_TEST_STRING: &str = "20000000";
510
511    test_binrw! {
512        FileModeInformation: get_file_mode_information_for_test() => FILE_MODE_INFORMATION_FOR_TEST_STRING
513    }
514
515    test_binrw! {
516        struct FileNetworkOpenInformation {
517            creation_time: datetime!(2025-10-17 12:44:04.747034).into(),
518            last_access_time: datetime!(2025-10-17 12:44:04.747034).into(),
519            last_write_time: datetime!(2025-10-17 12:44:04.747034).into(),
520            change_time: datetime!(2025-10-17 12:44:04.747034).into(),
521            allocation_size: 4096,
522            end_of_file: 13,
523            file_attributes: FileAttributes::new().with_archive(true),
524        } => "043fb5b8633fdc01043fb5b8633fdc01043fb5b8633fdc01043fb5b8633fdc0100100000000000000d000000000000002000000000000000"
525    }
526
527    test_binrw! {
528        FileNormalizedNameInformation: FileNormalizedNameInformation::from("query_info_on.txt") => "22000000710075006500720079005f0069006e0066006f005f006f006e002e00740078007400"
529    }
530
531    fn get_file_position_information_for_test() -> FilePositionInformation {
532        FilePositionInformation {
533            current_byte_offset: 1024,
534        }
535    }
536    const FILE_POSITION_INFORMATION_FOR_TEST_STRING: &str = "0004000000000000";
537
538    test_binrw! {
539        FilePositionInformation: get_file_position_information_for_test() => FILE_POSITION_INFORMATION_FOR_TEST_STRING
540    }
541
542    fn get_standard_information_for_test() -> FileStandardInformation {
543        FileStandardInformation {
544            allocation_size: 4096,
545            end_of_file: 13,
546            number_of_links: 0,
547            delete_pending: true.into(),
548            directory: false.into(),
549        }
550    }
551    const FILE_STANDARD_INFORMATION_FOR_TEST_STRING: &str =
552        "00100000000000000d000000000000000000000001000000";
553
554    test_binrw! {FileStandardInformation: get_standard_information_for_test() => FILE_STANDARD_INFORMATION_FOR_TEST_STRING}
555
556    fn get_file_name_information_for_test() -> FileNameInformation {
557        FileNameInformation::from("File_Name.txt")
558    }
559    const FILE_NAME_INFORMATION_FOR_TEST_STRING: &str =
560        "1a000000460069006c0065005f004e0061006d0065002e00740078007400";
561    test_binrw!(
562        FileNameInformation: get_file_name_information_for_test() =>
563        FILE_NAME_INFORMATION_FOR_TEST_STRING
564    );
565
566    fn get_file_ea_information_for_test() -> FileEaInformation {
567        FileEaInformation { ea_size: 208 }
568    }
569    const FILE_EA_INFORMATION_FOR_TEST_STRING: &str = "d0000000";
570    test_binrw!(
571        FileEaInformation: get_file_ea_information_for_test() =>
572        FILE_EA_INFORMATION_FOR_TEST_STRING
573    );
574
575    const FILE_ALL_INFORMATION_FOR_TEST_STRING: &str = const_format::concatcp!(
576        FILE_BASIC_INFORMATION_FOR_TEST_STRING,
577        FILE_STANDARD_INFORMATION_FOR_TEST_STRING,
578        FILE_INTERNAL_INFORMATION_FOR_TEST_STRING,
579        FILE_EA_INFORMATION_FOR_TEST_STRING,
580        FILE_ACCESS_INFORMATION_FOR_TEST_STRING,
581        FILE_POSITION_INFORMATION_FOR_TEST_STRING,
582        FILE_MODE_INFORMATION_FOR_TEST_STRING,
583        FILE_ALIGNMENT_INFORMATION_FOR_TEST_STRING,
584        FILE_NAME_INFORMATION_FOR_TEST_STRING
585    );
586    test_binrw! {
587        FileAllInformation: FileAllInformation {basic:get_file_basic_information_for_test(),
588            standard:get_standard_information_for_test(),
589            internal: get_internal_information_for_test(),
590            ea: get_file_ea_information_for_test(),
591            access: get_file_access_information_for_test(),
592            position: get_file_position_information_for_test(),
593            mode: get_file_mode_information_for_test(),
594            alignment: get_file_alignment_information_for_test(),
595            name: get_file_name_information_for_test(),
596        }
597        => FILE_ALL_INFORMATION_FOR_TEST_STRING
598    }
599
600    test_binrw! {
601        FileStreamInformation: FileStreamInformation::from(
602            vec![
603                FileStreamInformationInner { stream_size: 1096224, stream_allocation_size: 720896, stream_name: "::$DATA".into() },
604                FileStreamInformationInner { stream_size: 7, stream_allocation_size: 8, stream_name: ":SmartScreen:$DATA".into() },
605                FileStreamInformationInner { stream_size: 63, stream_allocation_size: 64, stream_name: ":Zone.Identifier:$DATA".into() },
606            ]
607        ) => "280000000e00000020ba10000000000000000b00000000003a003a002400440041005400410000004000000024000000070000000000000008000000000000003a0053006d00610072007400530063007200650065006e003a002400440041005400410000000000000000002c0000003f0000000000000040000000000000003a005a006f006e0065002e004900640065006e007400690066006900650072003a0024004400410054004100"
608    }
609
610    test_binrw! {
611        struct FileIdInformation {
612            volume_serial_number: 0xc86ef7996ef77f0e,
613            file_id: 0x0000000000000000006a00000000cd5a,
614        } => "0e7ff76e99f76ec85acd000000006a000000000000000000"
615    }
616
617    test_binrw! {
618        struct FilePipeLocalInformation {
619            named_pipe_type: NamedPipeType::Message,
620            named_pipe_configuration: NamedPipeConfiguration::FullDuplex,
621            maximum_instances: 0xffffffff,
622            current_instances: 4,
623            inbound_quota: 2048,
624            read_data_available: 0,
625            outbound_quota: 2048,
626            write_quota_available: 1024,
627            named_pipe_state: NamedPipeState::Connected,
628            named_pipe_end: NamedPipeEnd::Client,
629        } => "0100000002000000ffffffff04000000000800000000000000080000000400000300000000000000"
630    }
631
632    // Querying this is both no trivial, and also probably passes tests.
633    // test_binrw! {
634    //     struct FilePipeRemoteInformation {
635    //     } => ""
636    // }
637}