Skip to main content

tailtalk_packets/afp/
bitmap.rs

1use bitflags::bitflags;
2
3bitflags! {
4    /// Bitmap of requested volume information. One or more of these can be set in a request
5    /// by FPGetVolParms or during FPOpenVol. The response should be packed in the same order
6    /// as the bits are defined below.
7    /// E.g. If ATTRIBUTES and CREATION_DATE are set, the first 2 bytes of the payload
8    /// will be the attributes flag, and the next 4 bytes are the creation date.
9    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
10    pub struct FPVolumeBitmap: u16 {
11        /// Request for volume attributes. Single bit flag response of read-only, 1 is true, 0 is false.
12        const ATTRIBUTES = 0x0001;
13        /// Request for volume signature, i.e a flat without directories, fixed directory ID, or variable directory IDs.
14        const SIGNATURE = 0x0002;
15        /// Request for creation date of this volume (In 32-bit Macintosh time)
16        const CREATION_DATE = 0x0004;
17        /// Request for last modified date of this volume (In 32-bit Macintosh time)
18        const MODIFICATION_DATE = 0x0008;
19        /// Request for the last time this volume was backed up (In 32-bit Macintosh time)
20        const BACKUP_DATE = 0x0010;
21        /// Request for the volume's 16-bit ID assigned by the server.
22        const VOLUME_ID = 0x0020;
23        /// Request for the number of bytes free for this volume as a 32-bit value.
24        const BYTES_FREE = 0x0040;
25        /// Request for the size of this volume in bytes as a 32-bit value.
26        const BYTES_TOTAL = 0x0080;
27        /// Request for the name of this volume as a Pascal string.
28        const VOLUME_NAME = 0x0100;
29    }
30}
31
32/// Converts from a host-endian u16 to a FPVolumeBitmap. Note that this
33/// does not convert endianness - the caller must convert from network byte order first if applicable.
34impl From<u16> for FPVolumeBitmap {
35    fn from(value: u16) -> Self {
36        Self::from_bits_truncate(value)
37    }
38}
39
40/// Converts from a FPVolumeBitmap to a host-endian u16. Note that this
41/// does not convert endianness - the caller must convert to network byte order after calling this if applicable.
42impl From<FPVolumeBitmap> for u16 {
43    fn from(val: FPVolumeBitmap) -> Self {
44        val.bits()
45    }
46}
47
48bitflags! {
49    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
50    #[repr(transparent)]
51    pub struct FPDirectoryBitmap: u16 {
52        /// Request for the attributes of this directory.
53        /// TODO: Implement attributes bit flag response
54        const ATTRIBUTES = 1;
55        /// Request for the parent directory ID of this directory.
56        /// Response: 32-bit directory ID
57        const PARENT_DIR_ID = 1 << 1;
58        /// Request for the creation date of this directory.
59        /// Response: 32-bit Macintosh time
60        const CREATE_DATE = 1 << 2;
61        /// Request for the last modification date of ths directory.
62        /// Response: 32-bit Macintosh time
63        const MODIFICATION_DATE = 1 << 3;
64        /// Request for the last backup date of this directory.
65        /// Response: 32-bit Macintosh time
66        const BACKUP_DATE = 1 << 4;
67        /// Request for the Finder information of this directory.
68        /// Response: 32-byte Finder information
69        const FINDER_INFO = 1 << 5;
70        /// Request for the long name of this directory.
71        /// Response: Offset returned in order to a pascal string with the long name
72        const LONG_NAME = 1 << 6;
73        /// Request for the short name of this directory.
74        /// Response: Offset returned in order to a pascal string with the short name
75        const SHORT_NAME = 1 << 7;
76        /// Request for the directory ID of this directory.
77        /// Response: 32-bit directory ID
78        const DIR_ID = 1 << 8;
79        /// Request for the number of offspring of this directory.
80        /// Response: 16-bit number of offspring
81        const OFFSPRING_COUNT = 1 << 9;
82        /// Request for the owner ID of this directory.
83        /// Response: 32-bit owner ID
84        const OWNER_ID = 1 << 10;
85        /// Request for the group ID of this directory.
86        /// Response: 32-bit group ID
87        const GROUP_ID = 1 << 11;
88        /// Request for the access rights of this directory.
89        /// Response: 4-byte value in the order of owner, group, and world followed by a User Access Rights summary byte
90        const ACCESS_RIGHTS = 1 << 12;
91        /// TODO: What is this?
92        const PRODOS_INFO = 1 << 13;
93    }
94}
95
96/// Converts from a host-endian u16 to a FPDirectoryBitmap. Note that this
97/// does not convert endianness - the caller must convert from network byte order first if applicable.
98impl From<u16> for FPDirectoryBitmap {
99    fn from(value: u16) -> Self {
100        Self::from_bits_truncate(value)
101    }
102}
103
104/// Converts from a FPDirectoryBitmap to a host-endian u16. Note that this
105/// does not convert endianness - the caller must convert to network byte order after calling this if applicable.
106impl From<FPDirectoryBitmap> for u16 {
107    fn from(val: FPDirectoryBitmap) -> Self {
108        val.bits()
109    }
110}
111
112impl FPDirectoryBitmap {
113    /// Returns the expected offset of the long_name value based on the set bitmap values.
114    pub fn long_name_offset(&self) -> usize {
115        let mut offset = 0;
116        if self.contains(FPDirectoryBitmap::ATTRIBUTES) {
117            offset += 2;
118        }
119        if self.contains(FPDirectoryBitmap::PARENT_DIR_ID) {
120            offset += 4;
121        }
122        if self.contains(FPDirectoryBitmap::CREATE_DATE) {
123            offset += 4;
124        }
125        if self.contains(FPDirectoryBitmap::MODIFICATION_DATE) {
126            offset += 4;
127        }
128        if self.contains(FPDirectoryBitmap::BACKUP_DATE) {
129            offset += 4;
130        }
131        if self.contains(FPDirectoryBitmap::FINDER_INFO) {
132            offset += 32;
133        }
134        if self.contains(FPDirectoryBitmap::LONG_NAME) {
135            offset += 2;
136        }
137        if self.contains(FPDirectoryBitmap::SHORT_NAME) {
138            offset += 2;
139        }
140        if self.contains(FPDirectoryBitmap::DIR_ID) {
141            offset += 4;
142        }
143        if self.contains(FPDirectoryBitmap::OFFSPRING_COUNT) {
144            offset += 2;
145        }
146        if self.contains(FPDirectoryBitmap::OWNER_ID) {
147            offset += 4;
148        }
149        if self.contains(FPDirectoryBitmap::GROUP_ID) {
150            offset += 4;
151        }
152        if self.contains(FPDirectoryBitmap::ACCESS_RIGHTS) {
153            offset += 4;
154        }
155        if self.contains(FPDirectoryBitmap::PRODOS_INFO) {
156            offset += 6;
157        }
158        offset
159    }
160
161    pub fn response_len(&self, name_len: usize) -> usize {
162        self.long_name_offset() + name_len + 1
163    }
164}
165
166bitflags! {
167    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
168    pub struct FPFileBitmap: u16 {
169        const ATTRIBUTES = 1;
170        const PARENT_DIR_ID = 1 << 1;
171        const CREATE_DATE = 1 << 2;
172        const MODIFICATION_DATE = 1 << 3;
173        const BACKUP_DATE = 1 << 4;
174        const FINDER_INFO = 1 << 5;
175        const LONG_NAME = 1 << 6;
176        const SHORT_NAME = 1 << 7;
177        const FILE_NUMBER = 1 << 8;
178        const DATA_FORK_LENGTH = 1 << 9;
179        const RESOURCE_FORK_LENGTH = 1 << 10;
180        const ACCESS_RIGHTS = 1 << 12;
181        const PRODOS_INFO = 1 << 13;
182    }
183}
184
185/// Converts from a host-endian u16 to a FPFileBitmap. Note that this
186/// does not convert endianness - the caller must convert from network byte order first if applicable.
187impl From<u16> for FPFileBitmap {
188    fn from(value: u16) -> Self {
189        Self::from_bits_truncate(value)
190    }
191}
192
193/// Converts from a FPFileBitmap to a host-endian u16. Note that this
194/// does not convert endianness - the caller must convert to network byte order after calling this if applicable.
195impl From<FPFileBitmap> for u16 {
196    fn from(val: FPFileBitmap) -> Self {
197        val.bits()
198    }
199}
200
201impl FPFileBitmap {
202    /// Returns the expected offset of the long_name value based on the set bitmap values.
203    pub fn long_name_offset(&self) -> usize {
204        let mut offset = 0;
205        if self.contains(FPFileBitmap::ATTRIBUTES) {
206            offset += 2;
207        }
208        if self.contains(FPFileBitmap::PARENT_DIR_ID) {
209            offset += 4;
210        }
211        if self.contains(FPFileBitmap::CREATE_DATE) {
212            offset += 4;
213        }
214        if self.contains(FPFileBitmap::MODIFICATION_DATE) {
215            offset += 4;
216        }
217        if self.contains(FPFileBitmap::BACKUP_DATE) {
218            offset += 4;
219        }
220        if self.contains(FPFileBitmap::FINDER_INFO) {
221            offset += 32;
222        }
223        if self.contains(FPFileBitmap::LONG_NAME) {
224            offset += 2;
225        }
226        if self.contains(FPFileBitmap::SHORT_NAME) {
227            offset += 2;
228        }
229        if self.contains(FPFileBitmap::FILE_NUMBER) {
230            offset += 4;
231        }
232        if self.contains(FPFileBitmap::DATA_FORK_LENGTH) {
233            offset += 4;
234        }
235        if self.contains(FPFileBitmap::RESOURCE_FORK_LENGTH) {
236            offset += 4;
237        }
238        if self.contains(FPFileBitmap::PRODOS_INFO) {
239            offset += 6;
240        }
241        offset
242    }
243
244    pub fn response_len(&self, name_len: usize) -> usize {
245        self.long_name_offset() + name_len + 1
246    }
247}
248
249bitflags! {
250    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
251    pub struct FPFileAttributes: u16 {
252        const INVISIBLE = 1;
253        const MULTI_USER = 1 << 1;
254        const SYSTEM = 1 << 2;
255        const DAlreadyOpen = 1 << 3;
256        const RAlreadyOpen = 1 << 4;
257        const ReadOnly = 1 << 5;
258        const BackupNeeded = 1 << 6;
259        const RenameInhibit = 1 << 7;
260        const DeleteInhibit = 1 << 8;
261        const CopyProtect = 1 << 10;
262        const SetClear = 1 << 15;
263    }
264}
265
266impl From<u16> for FPFileAttributes {
267    fn from(value: u16) -> Self {
268        Self::from_bits_truncate(value)
269    }
270}
271
272impl From<FPFileAttributes> for u16 {
273    fn from(val: FPFileAttributes) -> Self {
274        val.bits()
275    }
276}
277
278bitflags! {
279    /// AFP Directory Access Rights bitmap. This represents the access privileges for a single
280    /// category (owner, group, or everyone). The full Access Rights parameter is a 4-byte value
281    /// consisting of:
282    /// - Byte 0: User Access Rights Summary (effective privileges for current user, includes OWNER flag)
283    /// - Byte 1: Owner's access privileges
284    /// - Byte 2: Group's access privileges
285    /// - Byte 3: Everyone's access privileges
286    ///
287    /// Each byte uses the same bit format defined here.
288    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
289    pub struct FPAccessRights: u8 {
290        /// Search access - Can list directory parameters and traverse into subdirectories
291        const SEARCH = 0x01;
292        /// Read access - Can list file parameters and read file contents
293        const READ = 0x02;
294        /// Write access - Can modify, add, and delete files/directories
295        const WRITE = 0x04;
296        /// Owner flag - Only valid in User Access Rights Summary byte (byte 0).
297        /// Set if the current user is the owner of the directory.
298        const OWNER = 0x80;
299    }
300}
301
302impl From<u8> for FPAccessRights {
303    fn from(value: u8) -> Self {
304        Self::from_bits_truncate(value)
305    }
306}
307
308pub fn afp_rights_to_mode(rights: FPAccessRights) -> u32 {
309    let mut mode = 0;
310    if rights.contains(FPAccessRights::READ) {
311        mode |= 4;
312    }
313    if rights.contains(FPAccessRights::WRITE) {
314        mode |= 2;
315    }
316    if rights.contains(FPAccessRights::SEARCH) {
317        mode |= 1;
318    }
319    mode
320}
321
322pub fn mode_to_afp_rights(mode: u32) -> FPAccessRights {
323    let mut rights = FPAccessRights::empty();
324    if mode & 4 != 0 {
325        rights |= FPAccessRights::READ;
326    }
327    if mode & 2 != 0 {
328        rights |= FPAccessRights::WRITE;
329    }
330    if mode & 1 != 0 {
331        rights |= FPAccessRights::SEARCH;
332    }
333    rights
334}
335
336impl From<FPAccessRights> for u8 {
337    fn from(rights: FPAccessRights) -> u8 {
338        rights.bits()
339    }
340}
341
342bitflags! {
343    #[derive(Debug, Clone, Copy)]
344    pub struct FPByteRangeLockFlags: u8 {
345        const UNLOCK = 0b00000001;
346        const END = 0b10000000;
347    }
348}
349
350impl From<u8> for FPByteRangeLockFlags {
351    fn from(value: u8) -> Self {
352        Self::from_bits_truncate(value)
353    }
354}
355
356impl From<FPByteRangeLockFlags> for u8 {
357    fn from(val: FPByteRangeLockFlags) -> Self {
358        val.bits()
359    }
360}