1#![allow(unused_parens)]
17
18use binrw::{io::TakeSeekExt, meta::ReadEndian, prelude::*};
19use modular_bitfield::prelude::*;
20use smb_dtyp::access_mask;
21
22use smb_dtyp::SID;
23use smb_dtyp::binrw_util::prelude::*;
24pub mod chained_item;
25pub mod common_info;
26pub mod directory_info;
27pub mod error;
28pub mod filesystem_info;
29pub mod query_file_info;
30pub mod set_file_info;
31
32pub use chained_item::{ChainedItem, ChainedItemList};
33pub use common_info::*;
34pub use directory_info::*;
35pub use error::SmbFsccError;
36pub use filesystem_info::*;
37pub use query_file_info::*;
38pub use set_file_info::*;
39
40#[bitfield]
42#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
43#[bw(map = |&x| Self::into_bytes(x))]
44#[br(map = Self::from_bytes)]
45pub struct FileAttributes {
46 pub readonly: bool,
47 pub hidden: bool,
48 pub system: bool,
49 #[skip]
50 __: bool,
51
52 pub directory: bool,
53 pub archive: bool,
54 #[skip]
55 __: bool,
56 pub normal: bool,
57
58 pub temporary: bool,
59 pub sparse_file: bool,
60 pub reparse_point: bool,
61 pub compressed: bool,
62
63 pub offline: bool,
64 pub not_content_indexed: bool,
65 pub encrypted: bool,
66 pub integrity_stream: bool,
67
68 #[skip]
69 __: bool,
70 pub no_scrub_data: bool,
71 pub recall_on_open: bool,
72 pub pinned: bool,
73
74 pub unpinned: bool,
75 #[skip]
76 __: bool,
77 pub recall_on_data_access: bool,
78 #[skip]
79 __: B9,
80}
81
82access_mask! {
83pub struct FileAccessMask {
84 file_read_data: bool,
85 file_write_data: bool,
86 file_append_data: bool,
87 file_read_ea: bool,
88
89 file_write_ea: bool,
90 file_execute: bool,
91 file_delete_child: bool,
92 file_read_attributes: bool,
93
94 file_write_attributes: bool,
95 #[skip]
96 __: B7,
97}}
98
99access_mask! {
100pub struct DirAccessMask {
101 list_directory: bool,
102 add_file: bool,
103 add_subdirectory: bool,
104 read_ea: bool,
105
106 write_ea: bool,
107 traverse: bool,
108 delete_child: bool,
109 read_attributes: bool,
110
111 write_attributes: bool,
112 #[skip]
113 __: B7,
114}}
115
116impl From<FileAccessMask> for DirAccessMask {
117 fn from(mask: FileAccessMask) -> Self {
118 Self::from_bytes(mask.into_bytes())
120 }
121}
122
123impl From<DirAccessMask> for FileAccessMask {
124 fn from(val: DirAccessMask) -> Self {
125 FileAccessMask::from_bytes(val.into_bytes())
127 }
128}
129
130#[binrw::binrw]
131#[derive(Debug, PartialEq, Eq)]
132#[bw(import(has_next: bool))]
133pub struct FileNotifyInformationInner {
134 pub action: NotifyAction,
135 #[bw(try_calc = file_name.size().try_into())]
136 file_name_length: u32,
137 #[br(args(file_name_length.into()))]
138 pub file_name: SizedWideString,
139}
140
141pub type FileNotifyInformation = ChainedItem<FileNotifyInformationInner>;
142
143#[binrw::binrw]
144#[derive(Debug, PartialEq, Eq)]
145#[brw(repr(u32))]
146pub enum NotifyAction {
147 Added = 0x1,
148 Removed = 0x2,
149 Modified = 0x3,
150 RenamedOldName = 0x4,
151 RenamedNewName = 0x5,
152 AddedStream = 0x6,
153 RemovedStream = 0x7,
154 ModifiedStream = 0x8,
155 RemovedByDelete = 0x9,
156 IdNotTunnelled = 0xa,
157 TunnelledIdCollision = 0xb,
158}
159
160pub trait FileInfoType:
166 Sized + for<'a> BinRead<Args<'static> = (Self::Class,)> + ReadEndian + std::fmt::Debug
167{
168 type Class;
170
171 fn class(&self) -> Self::Class;
173}
174
175#[macro_export]
179macro_rules! file_info_classes {
180 ($svis:vis $name:ident {
181 $($vis:vis $field_name:ident = $cid:literal,)+
182 }, $brw_ty:ty) => {
183 #[allow(unused_imports)]
184 use binrw::prelude::*;
185 paste::paste! {
186 pub trait [<$name Value>] :
188 TryFrom<$name, Error = $crate::SmbFsccError>
189 + Send + 'static
190 + Into<$name>
191 + for <'a> [<Bin $brw_ty>]<Args<'a> = ()> {
192 const CLASS_ID: [<$name Class>];
193 }
194
195 #[binrw::binrw]
197 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
198 #[brw(repr(u8))]
199 $svis enum [<$name Class>] {
200 $(
201 $vis [<$field_name Information>] = $cid,
202 )*
203 }
204
205 #[binrw::binrw]
207 #[derive(Debug, PartialEq, Eq)]
208 #[brw(little)]
209 #[br(import(c: [<$name Class>]))]
210 $svis enum $name {
211 $(
212 #[br(pre_assert(matches!(c, [<$name Class>]::[<$field_name Information>])))]
213 [<$field_name Information>]([<File $field_name Information>]),
214 )*
215 }
216
217 impl std::fmt::Display for [<$name Class>] {
218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 match self {
220 $(
221 [<$name Class>]::[<$field_name Information>] => write!(f, stringify!([<$field_name Information>])),
222 )*
223 }
224 }
225 }
226
227 impl $crate::FileInfoType for $name {
228 type Class = [<$name Class>];
229 fn class(&self) -> Self::Class {
230 match self {
231 $(
232 $name::[<$field_name Information>](_) => [<$name Class>]::[<$field_name Information>],
233 )*
234 }
235 }
236 }
237
238 $(
239 impl From<[<File $field_name Information>]> for $name {
240 fn from(value: [<File $field_name Information>]) -> $name {
241 $name::[<$field_name Information>](value)
242 }
243 }
244
245 impl TryFrom<$name> for [<File $field_name Information>] {
246 type Error = $crate::SmbFsccError;
247
248 fn try_from(value: $name) -> Result<Self, Self::Error> {
249 pub use $crate::FileInfoType;
250 match value {
251 $name::[<$field_name Information>](v) => Ok(v),
252 _ => Err($crate::SmbFsccError::UnexpectedInformationType(<Self as [<$name Value>]>::CLASS_ID as u8, value.class() as u8)),
253 }
254 }
255 }
256
257 impl [<$name Value>] for [<File $field_name Information>] {
258 const CLASS_ID: [<$name Class>] = [<$name Class>]::[<$field_name Information>];
259 }
260 )*
261 }
262 }
263}
264
265#[binrw::binrw]
266#[derive(Debug)]
267pub struct FileQuotaInformationInner {
268 #[bw(calc = PosMarker::default())]
269 sid_length: PosMarker<u32>,
270 pub change_time: FileTime,
271 pub quota_used: u64,
272 pub quota_threshold: u64,
273 pub quota_limit: u64,
274 #[br(map_stream = |s| s.take_seek(sid_length.value as u64))]
275 #[bw(write_with = PosMarker::write_size, args(&sid_length))]
276 pub sid: SID,
277}
278
279pub type FileQuotaInformation = ChainedItem<FileQuotaInformationInner>;
280
281#[binrw::binrw]
282#[derive(Debug)]
283pub struct FileGetQuotaInformationInner {
284 #[bw(calc = PosMarker::default())]
285 sid_length: PosMarker<u32>,
286 #[br(map_stream = |s| s.take_seek(sid_length.value as u64))]
287 #[bw(write_with = PosMarker::write_size, args(&sid_length))]
288 pub sid: SID,
289}
290
291pub type FileGetQuotaInformation = ChainedItem<FileGetQuotaInformationInner>;