smb_fscc/
filesystem_info.rs

1//! File System Information Classes
2//!
3//! This module defined [`QueryFileSystemInfo`] and [`SetFileSystemInfo`] enums,
4//! and all the information structs in those.
5//!
6//! [MS-FSCC 2.5](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/ee12042a-9352-46e3-9f67-c094b75fe6c3>)
7
8use crate::file_info_classes;
9use binrw::prelude::*;
10use modular_bitfield::prelude::*;
11use smb_dtyp::{Guid, binrw_util::prelude::*};
12
13file_info_classes! {
14    /// Query file system information classes.
15    pub QueryFileSystemInfo {
16        pub FsAttribute = 5,
17        pub FsControl = 6,
18        pub FsDevice = 4,
19        pub FsFullSize = 7,
20        pub FsObjectId = 8,
21        pub FsSectorSize = 11,
22        pub FsSize = 3,
23        pub FsVolume = 1,
24    }, Read
25}
26
27file_info_classes! {
28    /// Set file system information classes.
29    pub SetFileSystemInfo {
30        pub FsControl = 6,
31        pub FsObjectId = 8,
32    }, Write
33}
34
35/// Query attribute information for a file system.
36///
37/// [MS-FSCC 2.5.1](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/ebc7e6e5-4650-4e54-b17c-cf60f6fbeeaa>)
38#[binrw::binrw]
39#[derive(Debug, PartialEq, Eq)]
40pub struct FileFsAttributeInformation {
41    /// Contains a bitmask of flags that specify attributes of the specified file system as a combination of the following flags.
42    /// The value of this field MUST be a bitwise OR of zero or more of the following with the exception that FILE_FILE_COMPRESSION and FILE_VOLUME_IS_COMPRESSED cannot both be set.
43    /// Any flag values not explicitly mentioned here can be set to any value, and MUST be ignored.
44    pub attributes: FileSystemAttributes,
45    /// The maximum file name component length, in characters, supported by the specified file system.
46    /// The value of this field MUST be greater than zero and MUST be no more than 255.
47    pub maximum_component_name_length: u32,
48    #[bw(calc = file_system_name.size() as u32)]
49    pub file_system_name_length: u32,
50    /// the name of the file system. This field is not null-terminated and MUST be handled as a sequence of FileSystemNameLength bytes.
51    /// This field is intended to be informative only. A client SHOULD NOT infer file system type specific behavior from this field.
52    #[br(args { size: SizedStringSize::bytes(file_system_name_length) })]
53    pub file_system_name: SizedWideString,
54}
55
56/// File system attributes.
57///
58/// Used in [`FileFsAttributeInformation`]
59#[bitfield]
60#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
61#[bw(map = |&x| Self::into_bytes(x))]
62#[br(map = Self::from_bytes)]
63pub struct FileSystemAttributes {
64    /// The file system supports case-sensitive file names when looking up (searching for) file names in a directory.
65    pub case_sensitive_search: bool,
66    /// The file system preserves the case of file names when it places a name on disk.
67    pub case_preserved_names: bool,
68    /// The file system supports Unicode in file and directory names. This flag applies only to file and directory names; the file system neither restricts nor interprets the bytes of data within a file.
69    pub unicode_on_disk: bool,
70    /// The file system preserves and enforces access control lists (ACLs).
71    pub persistent_acls: bool,
72    /// The file volume supports file-based compression. This flag is incompatible with the `volume_is_compressed` flag.
73    pub file_compression: bool,
74    /// The file system supports per-user quotas.
75    pub volume_quotas: bool,
76    /// The file system supports sparse files.
77    pub supports_sparse_files: bool,
78    /// The file system supports reparse points.
79    pub supports_reparse_points: bool,
80    /// The file system supports remote storage.
81    pub supports_remote_storage: bool,
82    #[skip]
83    __: B6,
84    /// The specified volume is a compressed volume. This flag is incompatible with the `file_compression` flag.
85    pub volume_is_compressed: bool,
86    /// The file system supports object identifiers.
87    pub supports_object_ids: bool,
88    /// The file system supports the Encrypted File System (EFS).
89    pub supports_encryption: bool,
90    /// The file system supports named streams.
91    pub named_streams: bool,
92    /// If set, the volume has been mounted in read-only mode.
93    pub read_only_volume: bool,
94    /// The underlying volume is write once.
95    pub sequential_write_once: bool,
96    /// The volume supports transactions.
97    pub supports_transactions: bool,
98    /// The file system supports hard linking files.
99    pub supports_hard_links: bool,
100    /// The file system persistently stores Extended Attribute information per file.
101    pub supports_extended_attributes: bool,
102    /// The file system supports opening a file by FileID or ObjectID.
103    pub supports_open_by_file_id: bool,
104    /// The file system implements a USN change journal.
105    pub supports_usn_journal: bool,
106    /// The file system supports integrity streams.
107    pub support_integrity_streams: bool,
108    /// The file system supports sharing logical clusters between files on the same volume. The file system reallocates on writes to shared clusters. Indicates that `FSCTL_DUPLICATE_EXTENTS_TO_FILE` is a supported operation.
109    pub supports_block_refcounting: bool,
110    /// The file system tracks whether each cluster of a file contains valid data (either from explicit file writes or automatic zeros) or invalid data (has not yet been written to or zeroed). File systems that use Sparse VDL do not store a valid data length and do not require that valid data be contiguous within a file.
111    pub supports_sparse_vdl: bool,
112    #[skip]
113    __: B3,
114}
115
116/// Query or Set quota and content indexing control information for a file system volume.
117///
118/// Setting quota information requires the caller to have permission to open a volume handle or a handle to the quota index file for write access.
119///
120/// [MS-FSCC 2.5.2](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/e5a70738-7ee4-46d9-a5f7-6644daa49a51>)
121#[binrw::binrw]
122#[derive(Debug, PartialEq, Eq)]
123pub struct FileFsControlInformation {
124    /// The minimum amount of free disk space, in bytes, that is required for the operating system's content indexing service to begin document filtering. This value SHOULD be set to 0 and MUST be ignored.
125    pub free_space_start_filtering: u64,
126    /// The minimum amount of free disk space, in bytes, that is required for the indexing service to continue to filter documents and merge word lists. This value SHOULD be set to 0 and MUST be ignored.
127    pub free_space_threshold: u64,
128    /// The minimum amount of free disk space, in bytes, that is required for the content indexing service to continue filtering. This value SHOULD be set to 0, and MUST be ignored.
129    pub free_space_stop_filtering: u64,
130    /// The default per-user disk quota warning threshold, in bytes, for the volume. A value of [`u64::MAX`] specifies that no default quota warning threshold per user is set.
131    pub default_quota_threshold: u64,
132    /// The default per-user disk quota limit, in bytes, for the volume. A value of [`u64::MAX`] specifies that no default quota limit per user is set.
133    pub default_quota_limit: u64,
134    /// Contains a bitmask of flags that control quota enforcement and logging of user-related quota events on the volume.
135    pub file_system_control_flags: FileSystemControlFlags,
136}
137
138#[binrw::binrw]
139#[derive(Debug, PartialEq, Eq)]
140pub struct FileFsDeviceInformation {
141    /// This identifies the type of given volume.
142    pub device_type: FsDeviceType,
143    /// A bit field which identifies various characteristics about a given volume.
144    pub characteristics: FsDeviceCharacteristics,
145}
146
147#[binrw::binrw]
148#[derive(Debug, PartialEq, Eq, Clone, Copy)]
149#[brw(repr(u32))]
150pub enum FsDeviceType {
151    /// Volume resides on a CD ROM.
152    CdRom = 2,
153    /// Volume resides on a disk.
154    Disk = 7,
155}
156
157/// Characteristics of a file system volume.
158///
159/// See [`FileFsDeviceInformation`]
160#[bitfield]
161#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
162#[bw(map = |&x| Self::into_bytes(x))]
163#[br(map = Self::from_bytes)]
164pub struct FsDeviceCharacteristics {
165    /// Indicates that the storage device supports removable media.
166    /// Notice that this characteristic indicates removable media, not a removable device.
167    /// For example, drivers for JAZ drive devices specify this characteristic, but drivers for PCMCIA flash disks do not.
168    pub removable_media: bool,
169    /// Indicates that the device cannot be written to.
170    pub read_only: bool,
171    /// Indicates that the device is a floppy disk device.
172    pub floppy_diskette: bool,
173    /// Indicates that the device supports write-once media.
174    pub write_once_media: bool,
175
176    /// Indicates that the volume is for a remote file system like SMB or CIFS.
177    pub remote: bool,
178    /// Indicates that a file system is mounted on the device.
179    pub device_is_mounted: bool,
180    /// Indicates that the volume does not directly reside on storage media but resides on some other type of media (memory for example).
181    pub virtual_volume: bool,
182    #[skip]
183    __: bool,
184
185    /// By default, volumes do not check the ACL associated with the volume, but instead use the ACLs associated with individual files on the volume.
186    /// When this flag is set the volume ACL is also checked.
187    pub secure_open: bool,
188    #[skip]
189    __: B3,
190
191    /// Indicates that the device object is part of a Terminal Services device stack. See [MS-RDPBCGR] for more information.
192    pub ts: bool,
193    /// Indicates that a web-based Distributed Authoring and Versioning (WebDAV) file system is mounted on the device. See [MS-WDVME] for more information.
194    pub webda: bool,
195    #[skip]
196    __: B3,
197
198    /// The IO Manager normally performs a full security check for traverse access on every file open when the client is an appcontainer.
199    /// Setting of this flag bypasses this enforced traverse access check if the client token already has traverse privileges.
200    pub allow_appcontainer_traversal: bool,
201    /// Indicates that the given device resides on a portable bus like USB or Firewire and that the entire device (not just the media) can be removed from the system.
202    pub portable: bool,
203    #[skip]
204    __: B13,
205}
206
207/// File system control flags.
208///
209/// Used in [`FileFsControlInformation`]
210#[bitfield]
211#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
212#[bw(map = |&x| Self::into_bytes(x))]
213#[br(map = Self::from_bytes)]
214pub struct FileSystemControlFlags {
215    /// Quotas are tracked on the volume, but they are not enforced.
216    /// Tracked quotas enable reporting on the file system space used by system users.
217    /// If both this flag and FILE_VC_QUOTA_ENFORCE are specified, FILE_VC_QUOTA_ENFORCE is ignored.
218    ///
219    /// Note: This flag takes precedence over FILE_VC_QUOTA_ENFORCE.
220    /// In other words, if both FILE_VC_QUOTA_TRACK and FILE_VC_QUOTA_ENFORCE are set,
221    /// the FILE_VC_QUOTA_ENFORCE flag is ignored.
222    /// This flag will be ignored if a client attempts to set it.
223    pub quota_track: bool,
224    /// Quotas are tracked and enforced on the volume.
225    ///
226    /// Note: FILE_VC_QUOTA_TRACK takes precedence over this flag.
227    /// In other words, if both FILE_VC_QUOTA_TRACK and FILE_VC_QUOTA_ENFORCE are set,
228    /// the FILE_VC_QUOTA_ENFORCE flag is ignored.
229    /// This flag will be ignored if a client attempts to set it.
230    pub quota_enforce: bool,
231    /// Content indexing is disabled.
232    pub content_indexing_disabled: bool,
233    #[skip]
234    __: bool,
235
236    /// An event log entry will be created when the user exceeds his or her assigned quota warning threshold.
237    pub log_quota_threshold: bool,
238    /// An event log entry will be created when the user exceeds the assigned disk quota limit.
239    pub log_quota_limit: bool,
240    /// An event log entry will be created when the volume's free space threshold is exceeded.
241    pub log_volume_threshold: bool,
242    /// An event log entry will be created when the volume's free space limit is exceeded.
243    pub log_volume_limit: bool,
244
245    /// The quota information for the volume is incomplete because it is corrupt, or the system is in the process of rebuilding the quota information.
246    /// Note: This does not necessarily imply that FILE_VC_QUOTAS_REBUILDING is set. This flag will be ignored if a client attempts to set it.
247    pub quotas_incomplete: bool,
248
249    /// The file system is rebuilding the quota information for the volume.
250    /// Note: This does not necessarily imply that FILE_VC_QUOTAS_INCOMPLETE is set. This flag will be ignored if a client attempts to set it.
251    pub quotas_rebuilding: bool,
252    #[skip]
253    __: B22,
254}
255
256/// Query sector size information for a file system volume.
257///
258/// [MS-FSCC 2.5.4](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/63768db7-9012-4209-8cca-00781e7322f5)
259#[binrw::binrw]
260#[derive(Debug, PartialEq, Eq)]
261pub struct FileFsFullSizeInformation {
262    pub total_allocation_units: u64,
263    pub caller_available_allocation_units: u64,
264    pub actual_available_allocation_units: u64,
265    pub sectors_per_allocation_unit: u32,
266    pub bytes_per_sector: u32,
267}
268
269/// Query or Set the object ID for a file system data element. The operation MUST fail if the file system does not support object IDs.
270///
271/// [MS-FSCC 2.5.6](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/dbf535ae-315a-4508-8bc5-84276ea106d4>)
272#[binrw::binrw]
273#[derive(Debug, PartialEq, Eq)]
274pub struct FileFsObjectIdInformation {
275    /// Identifies the file system volume on the disk. This value is not required to be unique on the system.
276    pub object_id: Guid,
277    /// A 48-byte value containing extended information on the file system volume. If no extended information has been written for this file system volume, the server MUST return 48 bytes of 0x00 in this field.
278    pub extended_info: [u8; 48],
279}
280
281/// Query for the extended sector size and alignment information for a volume.
282///
283/// The message contains a FILE_FS_SECTOR_SIZE_INFORMATION data element.
284///
285/// [MS-FSCC 2.5.7](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/3e75d97f-1d0b-4e47-b435-73c513837a57>)
286#[binrw::binrw]
287#[derive(Debug, PartialEq, Eq)]
288pub struct FileFsSectorSizeInformation {
289    /// The number of bytes in a logical sector for the device backing the volume.
290    /// This field is the unit of logical addressing for the device and is not the unit of atomic write.
291    ///  Applications SHOULD NOT utilize this value for operations requiring physical sector alignment.
292    pub logical_bytes_per_sector: u32,
293    /// The number of bytes in a physical sector for the device backing the volume.
294    /// Note that this is the reported physical sector size of the device and is the unit of atomic write.
295    /// Applications SHOULD utilize this value for operations requiring sector alignment.
296    pub physical_bytes_per_sector: u32,
297    /// The number of bytes in a physical sector for the device backing the volume.
298    /// This is the reported physical sector size of the device and is the unit of performance.
299    /// Applications SHOULD utilize this value for operations requiring sector alignment.
300    pub physical_bytes_per_sector_for_performance: u32,
301    /// The unit, in bytes, that the file system on the volume will use for internal operations that require alignment and atomicity.
302    pub effective_physical_bytes_per_sector_for_atomicity: u32,
303    /// Flags for this operation.
304    pub flags: SectorSizeInfoFlags,
305    /// The logical sector offset within the first physical sector where the first logical sector is placed, in bytes.
306    /// If this value is set to SSINFO_OFFSET_UNKNOWN (0XFFFFFFFF), there was insufficient information to compute this field.
307    pub byte_offset_for_sector_alignment: u32,
308    /// The byte offset from the first physical sector where the first partition is placed.
309    /// If this value is set to SSINFO_OFFSET_UNKNOWN (0XFFFFFFFF),
310    /// there was either insufficient information or an error was encountered in computing this field.
311    pub byte_offset_for_partition_alignment: u32,
312}
313
314/// File system sector flags.
315#[bitfield]
316#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
317#[bw(map = |&x| Self::into_bytes(x))]
318#[br(map = Self::from_bytes)]
319pub struct SectorSizeInfoFlags {
320    /// When set, this flag indicates that the first physical sector of the device is aligned with the first logical sector.
321    /// When not set, the first physical sector of the device is misaligned with the first logical sector.
322    pub aligned_device: bool,
323    /// When set, this flag indicates that the partition is aligned to physical sector boundaries on the storage device.
324    pub partition_aligned_on_device: bool,
325    /// When set, the device reports that it does not incur a seek penalty (this typically indicates that the device does not have rotating media, such as flash-based disks).
326    pub no_seek_penalty: bool,
327    /// When set, the device supports TRIM operations, either T13 (ATA) TRIM or T10 (SCSI/SAS) UNMAP.
328    pub trim_enabled: bool,
329    #[skip]
330    __: B28,
331}
332
333/// Query sector size information for a file system volume.
334///
335/// [MS-FSCC 2.5.8](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/e13e068c-e3a7-4dd4-94fd-3892b492e6e7>)
336#[binrw::binrw]
337#[derive(Debug, PartialEq, Eq)]
338pub struct FileFsSizeInformation {
339    /// The total number of allocation units on the volume that are available to the user associated with the calling thread. This value MUST be greater than or equal to 0.
340    pub total_allocation_units: u64,
341    /// The total number of free allocation units on the volume that are available to the user associated with the calling thread. This value MUST be greater than or equal to 0.
342    pub available_allocation_units: u64,
343    /// The number of sectors in each allocation unit.
344    pub sectors_per_allocation_unit: u32,
345    /// The number of bytes in each sector.
346    pub bytes_per_sector: u32,
347}
348
349/// Query information on a volume on which a file system is mounted.
350///
351/// [MS-FSCC 2.5.9](<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/bf691378-c34e-4a13-976e-404ea1a87738>)
352#[binrw::binrw]
353#[derive(Debug, PartialEq, Eq)]
354pub struct FileFsVolumeInformation {
355    /// The time when the volume was created.
356    pub volume_creation_time: FileTime,
357    /// C contains the serial number of the volume.
358    /// The serial number is an opaque value generated by the file system at format time,
359    /// and is not necessarily related to any hardware serial number for the device on which the file system is located.
360    /// No specific format or content of this field is required for protocol interoperation.
361    /// This value is not required to be unique.
362    pub volume_serial_number: u32,
363    #[bw(calc = volume_label.size() as u32)]
364    pub volume_label_length: u32,
365    ///  Set to TRUE if the file system supports object-oriented file system objects; set to FALSE otherwise.
366    pub supports_objects: Boolean,
367    #[bw(calc = 0)]
368    #[br(assert(reserved == 0))]
369    reserved: u8,
370    /// The content of this field can be a null-terminated string or can be a string padded with the space character to be VolumeLabelLength bytes long.
371    #[br(args { size: SizedStringSize::bytes(volume_label_length) })]
372    pub volume_label: SizedWideString,
373}
374
375#[cfg(test)]
376mod tests {
377    use super::*;
378    use smb_dtyp::make_guid;
379    use smb_tests::test_binrw;
380    use time::macros::datetime;
381
382    test_binrw! {
383        struct FileFsVolumeInformation {
384            volume_creation_time: datetime!(2025-10-13 12:35:04.593237).into(),
385            volume_serial_number: 0x529d2cf4,
386            volume_label: "MyShare".into(),
387            supports_objects: false.into(),
388        } => "525119cd3d3cdc01f42c9d520e00000000004d00790053006800610072006500"
389    }
390
391    test_binrw! {
392        struct FileFsSizeInformation {
393            total_allocation_units: 61202244,
394            available_allocation_units: 45713576,
395            sectors_per_allocation_unit: 2,
396            bytes_per_sector: 512,
397        } => "44dfa50300000000a888b902000000000200000000020000"
398    }
399
400    test_binrw! {
401        struct FileFsFullSizeInformation {
402            total_allocation_units: 0x03a5df44,
403            actual_available_allocation_units: 0x02b98894,
404            caller_available_allocation_units: 0x02b98894,
405            sectors_per_allocation_unit: 2,
406            bytes_per_sector: 512,
407        } => "44dfa503000000009488b902000000009488b902000000000200000000020000"
408    }
409
410    test_binrw! {
411        struct FileFsDeviceInformation {
412            device_type: FsDeviceType::Disk,
413            characteristics: FsDeviceCharacteristics::new().with_device_is_mounted(true),
414        } => "0700000020000000"
415    }
416
417    test_binrw! {
418        struct FileFsAttributeInformation {
419            attributes: FileSystemAttributes::new()
420                .with_case_sensitive_search(true)
421                .with_case_preserved_names(true)
422                .with_unicode_on_disk(true)
423                .with_persistent_acls(true)
424                .with_volume_quotas(true)
425                .with_supports_sparse_files(true)
426                .with_supports_object_ids(true)
427                .with_named_streams(true),
428            maximum_component_name_length: 255,
429            file_system_name: "NTFS".into(),
430        } => "6f000500ff000000080000004e00540046005300"
431    }
432
433    test_binrw! {
434        struct FileFsSectorSizeInformation {
435            logical_bytes_per_sector: 512,
436            physical_bytes_per_sector: 512,
437            physical_bytes_per_sector_for_performance: 512,
438            effective_physical_bytes_per_sector_for_atomicity: 512,
439            flags: SectorSizeInfoFlags::new()
440                .with_aligned_device(true)
441                .with_partition_aligned_on_device(true),
442            byte_offset_for_sector_alignment: 0,
443            byte_offset_for_partition_alignment: 0,
444        } => "00020000000200000002000000020000030000000000000000000000"
445    }
446
447    test_binrw! {
448        struct FileFsObjectIdInformation {
449            object_id: make_guid!("ed3e2170-2733-48b3-e5c0-bd5334f85a37"),
450            extended_info: [0x61, 0x42, 0x6d, 0x53, 0x0, 0x6, 0x14, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x2e, 0x32, 0x30, 0x2e,
451                            0x36, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
452        } => "70213eed3327b348e5c0bd5334f85a3761426d5300061404000000000000000000000000342e32302e3600000000000000000000000000000000000000000000"
453    }
454}