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