1#![allow(unused_parens)]
17
18use binrw::{meta::ReadEndian, prelude::*};
19use modular_bitfield::prelude::*;
20use smb_dtyp::access_mask;
21
22pub mod chained_list;
23pub mod common_info;
24pub mod directory_info;
25pub mod error;
26pub mod filesystem_info;
27mod notify;
28pub mod query_file_info;
29pub mod quota;
30pub mod set_file_info;
31
32pub use chained_list::{CHAINED_ITEM_PREFIX_SIZE, ChainedItem, ChainedItemList};
33pub use common_info::*;
34pub use directory_info::*;
35pub use error::SmbFsccError;
36pub use filesystem_info::*;
37pub use notify::*;
38pub use query_file_info::*;
39pub use quota::*;
40pub use set_file_info::*;
41
42#[bitfield]
44#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
45#[bw(map = |&x| Self::into_bytes(x))]
46#[br(map = Self::from_bytes)]
47pub struct FileAttributes {
48 pub readonly: bool,
49 pub hidden: bool,
50 pub system: bool,
51 #[skip]
52 __: bool,
53
54 pub directory: bool,
55 pub archive: bool,
56 #[skip]
57 __: bool,
58 pub normal: bool,
59
60 pub temporary: bool,
61 pub sparse_file: bool,
62 pub reparse_point: bool,
63 pub compressed: bool,
64
65 pub offline: bool,
66 pub not_content_indexed: bool,
67 pub encrypted: bool,
68 pub integrity_stream: bool,
69
70 #[skip]
71 __: bool,
72 pub no_scrub_data: bool,
73 pub recall_on_open: bool,
74 pub pinned: bool,
75
76 pub unpinned: bool,
77 #[skip]
78 __: bool,
79 pub recall_on_data_access: bool,
80 #[skip]
81 __: B9,
82}
83
84access_mask! {
85pub struct FileAccessMask {
86 file_read_data: bool,
87 file_write_data: bool,
88 file_append_data: bool,
89 file_read_ea: bool,
90
91 file_write_ea: bool,
92 file_execute: bool,
93 file_delete_child: bool,
94 file_read_attributes: bool,
95
96 file_write_attributes: bool,
97 #[skip]
98 __: B7,
99}}
100
101access_mask! {
102pub struct DirAccessMask {
103 list_directory: bool,
104 add_file: bool,
105 add_subdirectory: bool,
106 read_ea: bool,
107
108 write_ea: bool,
109 traverse: bool,
110 delete_child: bool,
111 read_attributes: bool,
112
113 write_attributes: bool,
114 #[skip]
115 __: B7,
116}}
117
118impl From<FileAccessMask> for DirAccessMask {
119 fn from(mask: FileAccessMask) -> Self {
120 Self::from_bytes(mask.into_bytes())
122 }
123}
124
125impl From<DirAccessMask> for FileAccessMask {
126 fn from(val: DirAccessMask) -> Self {
127 FileAccessMask::from_bytes(val.into_bytes())
129 }
130}
131
132pub trait FileInfoType:
138 Sized + for<'a> BinRead<Args<'static> = (Self::Class,)> + ReadEndian + std::fmt::Debug
139{
140 type Class;
142
143 fn class(&self) -> Self::Class;
145}
146
147#[macro_export]
151macro_rules! file_info_classes {
152 ($svis:vis $name:ident {
153 $($vis:vis $field_name:ident = $cid:literal,)+
154 }, $brw_ty:ty) => {
155 #[allow(unused_imports)]
156 use binrw::prelude::*;
157 paste::paste! {
158 pub trait [<$name Value>] :
160 TryFrom<$name, Error = $crate::SmbFsccError>
161 + Send + 'static
162 + Into<$name>
163 + for <'a> [<Bin $brw_ty>]<Args<'a> = ()> {
164 const CLASS_ID: [<$name Class>];
165 }
166
167 #[binrw::binrw]
169 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
170 #[brw(repr(u8))]
171 $svis enum [<$name Class>] {
172 $(
173 $vis [<$field_name Information>] = $cid,
174 )*
175 }
176
177 #[binrw::binrw]
179 #[derive(Debug, PartialEq, Eq)]
180 #[brw(little)]
181 #[br(import(c: [<$name Class>]))]
182 $svis enum $name {
183 $(
184 #[br(pre_assert(matches!(c, [<$name Class>]::[<$field_name Information>])))]
185 [<$field_name Information>]([<File $field_name Information>]),
186 )*
187 }
188
189 impl std::fmt::Display for [<$name Class>] {
190 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
191 match self {
192 $(
193 [<$name Class>]::[<$field_name Information>] => write!(f, stringify!([<$field_name Information>])),
194 )*
195 }
196 }
197 }
198
199 impl $crate::FileInfoType for $name {
200 type Class = [<$name Class>];
201 fn class(&self) -> Self::Class {
202 match self {
203 $(
204 $name::[<$field_name Information>](_) => [<$name Class>]::[<$field_name Information>],
205 )*
206 }
207 }
208 }
209
210 $(
211 impl From<[<File $field_name Information>]> for $name {
212 fn from(value: [<File $field_name Information>]) -> $name {
213 $name::[<$field_name Information>](value)
214 }
215 }
216
217 impl TryFrom<$name> for [<File $field_name Information>] {
218 type Error = $crate::SmbFsccError;
219
220 fn try_from(value: $name) -> Result<Self, Self::Error> {
221 pub use $crate::FileInfoType;
222 match value {
223 $name::[<$field_name Information>](v) => Ok(v),
224 _ => Err($crate::SmbFsccError::UnexpectedInformationType(<Self as [<$name Value>]>::CLASS_ID as u8, value.class() as u8)),
225 }
226 }
227 }
228
229 impl [<$name Value>] for [<File $field_name Information>] {
230 const CLASS_ID: [<$name Class>] = [<$name Class>]::[<$field_name Information>];
231 }
232 )*
233 }
234 }
235}