distant_protocol/common/
metadata.rs

1use std::path::PathBuf;
2
3use bitflags::bitflags;
4use serde::{Deserialize, Serialize};
5
6use crate::common::FileType;
7
8/// Represents metadata about some path on a remote machine.
9#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
10pub struct Metadata {
11    /// Canonicalized path to the file or directory, resolving symlinks, only included if flagged
12    /// during the request.
13    #[serde(default, skip_serializing_if = "Option::is_none")]
14    pub canonicalized_path: Option<PathBuf>,
15
16    /// Represents the type of the entry as a file/dir/symlink.
17    pub file_type: FileType,
18
19    /// Size of the file/directory/symlink in bytes.
20    pub len: u64,
21
22    /// Whether or not the file/directory/symlink is marked as unwriteable.
23    pub readonly: bool,
24
25    /// Represents the last time (in seconds) when the file/directory/symlink was accessed;
26    /// can be optional as certain systems don't support this.
27    #[serde(default, skip_serializing_if = "Option::is_none")]
28    pub accessed: Option<u64>,
29
30    /// Represents when (in seconds) the file/directory/symlink was created;
31    /// can be optional as certain systems don't support this.
32    #[serde(default, skip_serializing_if = "Option::is_none")]
33    pub created: Option<u64>,
34
35    /// Represents the last time (in seconds) when the file/directory/symlink was modified;
36    /// can be optional as certain systems don't support this.
37    #[serde(default, skip_serializing_if = "Option::is_none")]
38    pub modified: Option<u64>,
39
40    /// Represents metadata that is specific to a unix remote machine.
41    #[serde(default, skip_serializing_if = "Option::is_none")]
42    pub unix: Option<UnixMetadata>,
43
44    /// Represents metadata that is specific to a windows remote machine.
45    #[serde(default, skip_serializing_if = "Option::is_none")]
46    pub windows: Option<WindowsMetadata>,
47}
48
49/// Represents unix-specific metadata about some path on a remote machine.
50#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
51pub struct UnixMetadata {
52    /// Represents whether or not owner can read from the file.
53    pub owner_read: bool,
54
55    /// Represents whether or not owner can write to the file.
56    pub owner_write: bool,
57
58    /// Represents whether or not owner can execute the file.
59    pub owner_exec: bool,
60
61    /// Represents whether or not associated group can read from the file.
62    pub group_read: bool,
63
64    /// Represents whether or not associated group can write to the file.
65    pub group_write: bool,
66
67    /// Represents whether or not associated group can execute the file.
68    pub group_exec: bool,
69
70    /// Represents whether or not other can read from the file.
71    pub other_read: bool,
72
73    /// Represents whether or not other can write to the file.
74    pub other_write: bool,
75
76    /// Represents whether or not other can execute the file.
77    pub other_exec: bool,
78}
79
80impl From<u32> for UnixMetadata {
81    /// Create from a unix mode bitset
82    fn from(mode: u32) -> Self {
83        let flags = UnixFilePermissionFlags::from_bits_truncate(mode);
84        Self {
85            owner_read: flags.contains(UnixFilePermissionFlags::OWNER_READ),
86            owner_write: flags.contains(UnixFilePermissionFlags::OWNER_WRITE),
87            owner_exec: flags.contains(UnixFilePermissionFlags::OWNER_EXEC),
88            group_read: flags.contains(UnixFilePermissionFlags::GROUP_READ),
89            group_write: flags.contains(UnixFilePermissionFlags::GROUP_WRITE),
90            group_exec: flags.contains(UnixFilePermissionFlags::GROUP_EXEC),
91            other_read: flags.contains(UnixFilePermissionFlags::OTHER_READ),
92            other_write: flags.contains(UnixFilePermissionFlags::OTHER_WRITE),
93            other_exec: flags.contains(UnixFilePermissionFlags::OTHER_EXEC),
94        }
95    }
96}
97
98impl From<UnixMetadata> for u32 {
99    /// Convert to a unix mode bitset.
100    fn from(metadata: UnixMetadata) -> Self {
101        let mut flags = UnixFilePermissionFlags::empty();
102
103        if metadata.owner_read {
104            flags.insert(UnixFilePermissionFlags::OWNER_READ);
105        }
106        if metadata.owner_write {
107            flags.insert(UnixFilePermissionFlags::OWNER_WRITE);
108        }
109        if metadata.owner_exec {
110            flags.insert(UnixFilePermissionFlags::OWNER_EXEC);
111        }
112
113        if metadata.group_read {
114            flags.insert(UnixFilePermissionFlags::GROUP_READ);
115        }
116        if metadata.group_write {
117            flags.insert(UnixFilePermissionFlags::GROUP_WRITE);
118        }
119        if metadata.group_exec {
120            flags.insert(UnixFilePermissionFlags::GROUP_EXEC);
121        }
122
123        if metadata.other_read {
124            flags.insert(UnixFilePermissionFlags::OTHER_READ);
125        }
126        if metadata.other_write {
127            flags.insert(UnixFilePermissionFlags::OTHER_WRITE);
128        }
129        if metadata.other_exec {
130            flags.insert(UnixFilePermissionFlags::OTHER_EXEC);
131        }
132
133        flags.bits()
134    }
135}
136
137impl UnixMetadata {
138    pub fn is_readonly(self) -> bool {
139        !(self.owner_write || self.group_write || self.other_write)
140    }
141}
142
143bitflags! {
144    struct UnixFilePermissionFlags: u32 {
145        const OWNER_READ = 0o400;
146        const OWNER_WRITE = 0o200;
147        const OWNER_EXEC = 0o100;
148        const GROUP_READ = 0o40;
149        const GROUP_WRITE = 0o20;
150        const GROUP_EXEC = 0o10;
151        const OTHER_READ = 0o4;
152        const OTHER_WRITE = 0o2;
153        const OTHER_EXEC = 0o1;
154    }
155}
156
157/// Represents windows-specific metadata about some path on a remote machine
158#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
159pub struct WindowsMetadata {
160    /// Represents whether or not a file or directory is an archive
161    pub archive: bool,
162
163    /// Represents whether or not a file or directory is compressed
164    pub compressed: bool,
165
166    /// Represents whether or not the file or directory is encrypted
167    pub encrypted: bool,
168
169    /// Represents whether or not a file or directory is hidden
170    pub hidden: bool,
171
172    /// Represents whether or not a directory or user data stream is configured with integrity
173    pub integrity_stream: bool,
174
175    /// Represents whether or not a file does not have other attributes set
176    pub normal: bool,
177
178    /// Represents whether or not a file or directory is not to be indexed by content indexing
179    /// service
180    pub not_content_indexed: bool,
181
182    /// Represents whether or not a user data stream is not to be read by the background data
183    /// integrity scanner
184    pub no_scrub_data: bool,
185
186    /// Represents whether or not the data of a file is not available immediately
187    pub offline: bool,
188
189    /// Represents whether or not a file or directory is not fully present locally
190    pub recall_on_data_access: bool,
191
192    /// Represents whether or not a file or directory has no physical representation on the local
193    /// system (is virtual)
194    pub recall_on_open: bool,
195
196    /// Represents whether or not a file or directory has an associated reparse point, or a file is
197    /// a symbolic link
198    pub reparse_point: bool,
199
200    /// Represents whether or not a file is a sparse file
201    pub sparse_file: bool,
202
203    /// Represents whether or not a file or directory is used partially or exclusively by the
204    /// operating system
205    pub system: bool,
206
207    /// Represents whether or not a file is being used for temporary storage
208    pub temporary: bool,
209}
210
211impl From<u32> for WindowsMetadata {
212    /// Create from a windows file attribute bitset
213    fn from(file_attributes: u32) -> Self {
214        let flags = WindowsFileAttributeFlags::from_bits_truncate(file_attributes);
215        Self {
216            archive: flags.contains(WindowsFileAttributeFlags::ARCHIVE),
217            compressed: flags.contains(WindowsFileAttributeFlags::COMPRESSED),
218            encrypted: flags.contains(WindowsFileAttributeFlags::ENCRYPTED),
219            hidden: flags.contains(WindowsFileAttributeFlags::HIDDEN),
220            integrity_stream: flags.contains(WindowsFileAttributeFlags::INTEGRITY_SYSTEM),
221            normal: flags.contains(WindowsFileAttributeFlags::NORMAL),
222            not_content_indexed: flags.contains(WindowsFileAttributeFlags::NOT_CONTENT_INDEXED),
223            no_scrub_data: flags.contains(WindowsFileAttributeFlags::NO_SCRUB_DATA),
224            offline: flags.contains(WindowsFileAttributeFlags::OFFLINE),
225            recall_on_data_access: flags.contains(WindowsFileAttributeFlags::RECALL_ON_DATA_ACCESS),
226            recall_on_open: flags.contains(WindowsFileAttributeFlags::RECALL_ON_OPEN),
227            reparse_point: flags.contains(WindowsFileAttributeFlags::REPARSE_POINT),
228            sparse_file: flags.contains(WindowsFileAttributeFlags::SPARSE_FILE),
229            system: flags.contains(WindowsFileAttributeFlags::SYSTEM),
230            temporary: flags.contains(WindowsFileAttributeFlags::TEMPORARY),
231        }
232    }
233}
234
235impl From<WindowsMetadata> for u32 {
236    /// Convert to a windows file attribute bitset
237    fn from(metadata: WindowsMetadata) -> Self {
238        let mut flags = WindowsFileAttributeFlags::empty();
239
240        if metadata.archive {
241            flags.insert(WindowsFileAttributeFlags::ARCHIVE);
242        }
243        if metadata.compressed {
244            flags.insert(WindowsFileAttributeFlags::COMPRESSED);
245        }
246        if metadata.encrypted {
247            flags.insert(WindowsFileAttributeFlags::ENCRYPTED);
248        }
249        if metadata.hidden {
250            flags.insert(WindowsFileAttributeFlags::HIDDEN);
251        }
252        if metadata.integrity_stream {
253            flags.insert(WindowsFileAttributeFlags::INTEGRITY_SYSTEM);
254        }
255        if metadata.normal {
256            flags.insert(WindowsFileAttributeFlags::NORMAL);
257        }
258        if metadata.not_content_indexed {
259            flags.insert(WindowsFileAttributeFlags::NOT_CONTENT_INDEXED);
260        }
261        if metadata.no_scrub_data {
262            flags.insert(WindowsFileAttributeFlags::NO_SCRUB_DATA);
263        }
264        if metadata.offline {
265            flags.insert(WindowsFileAttributeFlags::OFFLINE);
266        }
267        if metadata.recall_on_data_access {
268            flags.insert(WindowsFileAttributeFlags::RECALL_ON_DATA_ACCESS);
269        }
270        if metadata.recall_on_open {
271            flags.insert(WindowsFileAttributeFlags::RECALL_ON_OPEN);
272        }
273        if metadata.reparse_point {
274            flags.insert(WindowsFileAttributeFlags::REPARSE_POINT);
275        }
276        if metadata.sparse_file {
277            flags.insert(WindowsFileAttributeFlags::SPARSE_FILE);
278        }
279        if metadata.system {
280            flags.insert(WindowsFileAttributeFlags::SYSTEM);
281        }
282        if metadata.temporary {
283            flags.insert(WindowsFileAttributeFlags::TEMPORARY);
284        }
285
286        flags.bits()
287    }
288}
289
290bitflags! {
291    struct WindowsFileAttributeFlags: u32 {
292        const ARCHIVE = 0x20;
293        const COMPRESSED = 0x800;
294        const ENCRYPTED = 0x4000;
295        const HIDDEN = 0x2;
296        const INTEGRITY_SYSTEM = 0x8000;
297        const NORMAL = 0x80;
298        const NOT_CONTENT_INDEXED = 0x2000;
299        const NO_SCRUB_DATA = 0x20000;
300        const OFFLINE = 0x1000;
301        const RECALL_ON_DATA_ACCESS = 0x400000;
302        const RECALL_ON_OPEN = 0x40000;
303        const REPARSE_POINT = 0x400;
304        const SPARSE_FILE = 0x200;
305        const SYSTEM = 0x4;
306        const TEMPORARY = 0x100;
307        const VIRTUAL = 0x10000;
308    }
309}
310
311#[cfg(test)]
312mod tests {
313    use super::*;
314
315    mod metadata {
316        use super::*;
317
318        #[test]
319        fn should_be_able_to_serialize_minimal_metadata_to_json() {
320            let metadata = Metadata {
321                canonicalized_path: None,
322                file_type: FileType::Dir,
323                len: 999,
324                readonly: true,
325                accessed: None,
326                created: None,
327                modified: None,
328                unix: None,
329                windows: None,
330            };
331
332            let value = serde_json::to_value(metadata).unwrap();
333            assert_eq!(
334                value,
335                serde_json::json!({
336                    "file_type": "dir",
337                    "len": 999,
338                    "readonly": true,
339                })
340            );
341        }
342
343        #[test]
344        fn should_be_able_to_serialize_full_metadata_to_json() {
345            let metadata = Metadata {
346                canonicalized_path: Some(PathBuf::from("test-dir")),
347                file_type: FileType::Dir,
348                len: 999,
349                readonly: true,
350                accessed: Some(u64::MAX),
351                created: Some(u64::MAX),
352                modified: Some(u64::MAX),
353                unix: Some(UnixMetadata {
354                    owner_read: true,
355                    owner_write: false,
356                    owner_exec: false,
357                    group_read: true,
358                    group_write: false,
359                    group_exec: false,
360                    other_read: true,
361                    other_write: false,
362                    other_exec: false,
363                }),
364                windows: Some(WindowsMetadata {
365                    archive: true,
366                    compressed: false,
367                    encrypted: true,
368                    hidden: false,
369                    integrity_stream: true,
370                    normal: false,
371                    not_content_indexed: true,
372                    no_scrub_data: false,
373                    offline: true,
374                    recall_on_data_access: false,
375                    recall_on_open: true,
376                    reparse_point: false,
377                    sparse_file: true,
378                    system: false,
379                    temporary: true,
380                }),
381            };
382
383            let value = serde_json::to_value(metadata).unwrap();
384            assert_eq!(
385                value,
386                serde_json::json!({
387                    "canonicalized_path": "test-dir",
388                    "file_type": "dir",
389                    "len": 999,
390                    "readonly": true,
391                    "accessed": u64::MAX,
392                    "created": u64::MAX,
393                    "modified": u64::MAX,
394                    "unix": {
395                        "owner_read": true,
396                        "owner_write": false,
397                        "owner_exec": false,
398                        "group_read": true,
399                        "group_write": false,
400                        "group_exec": false,
401                        "other_read": true,
402                        "other_write": false,
403                        "other_exec": false,
404                    },
405                    "windows": {
406                        "archive": true,
407                        "compressed": false,
408                        "encrypted": true,
409                        "hidden": false,
410                        "integrity_stream": true,
411                        "normal": false,
412                        "not_content_indexed": true,
413                        "no_scrub_data": false,
414                        "offline": true,
415                        "recall_on_data_access": false,
416                        "recall_on_open": true,
417                        "reparse_point": false,
418                        "sparse_file": true,
419                        "system": false,
420                        "temporary": true,
421                    }
422                })
423            );
424        }
425
426        #[test]
427        fn should_be_able_to_deserialize_minimal_metadata_from_json() {
428            let value = serde_json::json!({
429                "file_type": "dir",
430                "len": 999,
431                "readonly": true,
432            });
433
434            let metadata: Metadata = serde_json::from_value(value).unwrap();
435            assert_eq!(
436                metadata,
437                Metadata {
438                    canonicalized_path: None,
439                    file_type: FileType::Dir,
440                    len: 999,
441                    readonly: true,
442                    accessed: None,
443                    created: None,
444                    modified: None,
445                    unix: None,
446                    windows: None,
447                }
448            );
449        }
450
451        #[test]
452        fn should_be_able_to_deserialize_full_metadata_from_json() {
453            let value = serde_json::json!({
454                "canonicalized_path": "test-dir",
455                "file_type": "dir",
456                "len": 999,
457                "readonly": true,
458                "accessed": u64::MAX,
459                "created": u64::MAX,
460                "modified": u64::MAX,
461                "unix": {
462                    "owner_read": true,
463                    "owner_write": false,
464                    "owner_exec": false,
465                    "group_read": true,
466                    "group_write": false,
467                    "group_exec": false,
468                    "other_read": true,
469                    "other_write": false,
470                    "other_exec": false,
471                },
472                "windows": {
473                    "archive": true,
474                    "compressed": false,
475                    "encrypted": true,
476                    "hidden": false,
477                    "integrity_stream": true,
478                    "normal": false,
479                    "not_content_indexed": true,
480                    "no_scrub_data": false,
481                    "offline": true,
482                    "recall_on_data_access": false,
483                    "recall_on_open": true,
484                    "reparse_point": false,
485                    "sparse_file": true,
486                    "system": false,
487                    "temporary": true,
488                }
489            });
490
491            let metadata: Metadata = serde_json::from_value(value).unwrap();
492            assert_eq!(
493                metadata,
494                Metadata {
495                    canonicalized_path: Some(PathBuf::from("test-dir")),
496                    file_type: FileType::Dir,
497                    len: 999,
498                    readonly: true,
499                    accessed: Some(u64::MAX),
500                    created: Some(u64::MAX),
501                    modified: Some(u64::MAX),
502                    unix: Some(UnixMetadata {
503                        owner_read: true,
504                        owner_write: false,
505                        owner_exec: false,
506                        group_read: true,
507                        group_write: false,
508                        group_exec: false,
509                        other_read: true,
510                        other_write: false,
511                        other_exec: false,
512                    }),
513                    windows: Some(WindowsMetadata {
514                        archive: true,
515                        compressed: false,
516                        encrypted: true,
517                        hidden: false,
518                        integrity_stream: true,
519                        normal: false,
520                        not_content_indexed: true,
521                        no_scrub_data: false,
522                        offline: true,
523                        recall_on_data_access: false,
524                        recall_on_open: true,
525                        reparse_point: false,
526                        sparse_file: true,
527                        system: false,
528                        temporary: true,
529                    }),
530                }
531            );
532        }
533
534        #[test]
535        fn should_be_able_to_serialize_minimal_metadata_to_msgpack() {
536            let metadata = Metadata {
537                canonicalized_path: None,
538                file_type: FileType::Dir,
539                len: 999,
540                readonly: true,
541                accessed: None,
542                created: None,
543                modified: None,
544                unix: None,
545                windows: None,
546            };
547
548            // NOTE: We don't actually check the output here because it's an implementation detail
549            // and could change as we change how serialization is done. This is merely to verify
550            // that we can serialize since there are times when serde fails to serialize at
551            // runtime.
552            let _ = rmp_serde::encode::to_vec_named(&metadata).unwrap();
553        }
554
555        #[test]
556        fn should_be_able_to_serialize_full_metadata_to_msgpack() {
557            let metadata = Metadata {
558                canonicalized_path: Some(PathBuf::from("test-dir")),
559                file_type: FileType::Dir,
560                len: 999,
561                readonly: true,
562                accessed: Some(u64::MAX),
563                created: Some(u64::MAX),
564                modified: Some(u64::MAX),
565                unix: Some(UnixMetadata {
566                    owner_read: true,
567                    owner_write: false,
568                    owner_exec: false,
569                    group_read: true,
570                    group_write: false,
571                    group_exec: false,
572                    other_read: true,
573                    other_write: false,
574                    other_exec: false,
575                }),
576                windows: Some(WindowsMetadata {
577                    archive: true,
578                    compressed: false,
579                    encrypted: true,
580                    hidden: false,
581                    integrity_stream: true,
582                    normal: false,
583                    not_content_indexed: true,
584                    no_scrub_data: false,
585                    offline: true,
586                    recall_on_data_access: false,
587                    recall_on_open: true,
588                    reparse_point: false,
589                    sparse_file: true,
590                    system: false,
591                    temporary: true,
592                }),
593            };
594
595            // NOTE: We don't actually check the output here because it's an implementation detail
596            // and could change as we change how serialization is done. This is merely to verify
597            // that we can serialize since there are times when serde fails to serialize at
598            // runtime.
599            let _ = rmp_serde::encode::to_vec_named(&metadata).unwrap();
600        }
601
602        #[test]
603        fn should_be_able_to_deserialize_minimal_metadata_from_msgpack() {
604            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
605            // verify that we are not corrupting or preventing issues when serializing on a
606            // client/server and then trying to deserialize on the other side. This has happened
607            // enough times with minor changes that we need tests to verify.
608            let buf = rmp_serde::encode::to_vec_named(&Metadata {
609                canonicalized_path: None,
610                file_type: FileType::Dir,
611                len: 999,
612                readonly: true,
613                accessed: None,
614                created: None,
615                modified: None,
616                unix: None,
617                windows: None,
618            })
619            .unwrap();
620
621            let metadata: Metadata = rmp_serde::decode::from_slice(&buf).unwrap();
622            assert_eq!(
623                metadata,
624                Metadata {
625                    canonicalized_path: None,
626                    file_type: FileType::Dir,
627                    len: 999,
628                    readonly: true,
629                    accessed: None,
630                    created: None,
631                    modified: None,
632                    unix: None,
633                    windows: None,
634                }
635            );
636        }
637
638        #[test]
639        fn should_be_able_to_deserialize_full_metadata_from_msgpack() {
640            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
641            // verify that we are not corrupting or preventing issues when serializing on a
642            // client/server and then trying to deserialize on the other side. This has happened
643            // enough times with minor changes that we need tests to verify.
644            let buf = rmp_serde::encode::to_vec_named(&Metadata {
645                canonicalized_path: Some(PathBuf::from("test-dir")),
646                file_type: FileType::Dir,
647                len: 999,
648                readonly: true,
649                accessed: Some(u64::MAX),
650                created: Some(u64::MAX),
651                modified: Some(u64::MAX),
652                unix: Some(UnixMetadata {
653                    owner_read: true,
654                    owner_write: false,
655                    owner_exec: false,
656                    group_read: true,
657                    group_write: false,
658                    group_exec: false,
659                    other_read: true,
660                    other_write: false,
661                    other_exec: false,
662                }),
663                windows: Some(WindowsMetadata {
664                    archive: true,
665                    compressed: false,
666                    encrypted: true,
667                    hidden: false,
668                    integrity_stream: true,
669                    normal: false,
670                    not_content_indexed: true,
671                    no_scrub_data: false,
672                    offline: true,
673                    recall_on_data_access: false,
674                    recall_on_open: true,
675                    reparse_point: false,
676                    sparse_file: true,
677                    system: false,
678                    temporary: true,
679                }),
680            })
681            .unwrap();
682
683            let metadata: Metadata = rmp_serde::decode::from_slice(&buf).unwrap();
684            assert_eq!(
685                metadata,
686                Metadata {
687                    canonicalized_path: Some(PathBuf::from("test-dir")),
688                    file_type: FileType::Dir,
689                    len: 999,
690                    readonly: true,
691                    accessed: Some(u64::MAX),
692                    created: Some(u64::MAX),
693                    modified: Some(u64::MAX),
694                    unix: Some(UnixMetadata {
695                        owner_read: true,
696                        owner_write: false,
697                        owner_exec: false,
698                        group_read: true,
699                        group_write: false,
700                        group_exec: false,
701                        other_read: true,
702                        other_write: false,
703                        other_exec: false,
704                    }),
705                    windows: Some(WindowsMetadata {
706                        archive: true,
707                        compressed: false,
708                        encrypted: true,
709                        hidden: false,
710                        integrity_stream: true,
711                        normal: false,
712                        not_content_indexed: true,
713                        no_scrub_data: false,
714                        offline: true,
715                        recall_on_data_access: false,
716                        recall_on_open: true,
717                        reparse_point: false,
718                        sparse_file: true,
719                        system: false,
720                        temporary: true,
721                    }),
722                }
723            );
724        }
725    }
726
727    mod unix_metadata {
728        use super::*;
729
730        #[test]
731        fn should_be_able_to_serialize_to_json() {
732            let metadata = UnixMetadata {
733                owner_read: true,
734                owner_write: false,
735                owner_exec: false,
736                group_read: true,
737                group_write: false,
738                group_exec: false,
739                other_read: true,
740                other_write: false,
741                other_exec: false,
742            };
743
744            let value = serde_json::to_value(metadata).unwrap();
745            assert_eq!(
746                value,
747                serde_json::json!({
748                    "owner_read": true,
749                    "owner_write": false,
750                    "owner_exec": false,
751                    "group_read": true,
752                    "group_write": false,
753                    "group_exec": false,
754                    "other_read": true,
755                    "other_write": false,
756                    "other_exec": false,
757                })
758            );
759        }
760
761        #[test]
762        fn should_be_able_to_deserialize_from_json() {
763            let value = serde_json::json!({
764                "owner_read": true,
765                "owner_write": false,
766                "owner_exec": false,
767                "group_read": true,
768                "group_write": false,
769                "group_exec": false,
770                "other_read": true,
771                "other_write": false,
772                "other_exec": false,
773            });
774
775            let metadata: UnixMetadata = serde_json::from_value(value).unwrap();
776            assert_eq!(
777                metadata,
778                UnixMetadata {
779                    owner_read: true,
780                    owner_write: false,
781                    owner_exec: false,
782                    group_read: true,
783                    group_write: false,
784                    group_exec: false,
785                    other_read: true,
786                    other_write: false,
787                    other_exec: false,
788                }
789            );
790        }
791
792        #[test]
793        fn should_be_able_to_serialize_to_msgpack() {
794            let metadata = UnixMetadata {
795                owner_read: true,
796                owner_write: false,
797                owner_exec: false,
798                group_read: true,
799                group_write: false,
800                group_exec: false,
801                other_read: true,
802                other_write: false,
803                other_exec: false,
804            };
805
806            // NOTE: We don't actually check the output here because it's an implementation detail
807            // and could change as we change how serialization is done. This is merely to verify
808            // that we can serialize since there are times when serde fails to serialize at
809            // runtime.
810            let _ = rmp_serde::encode::to_vec_named(&metadata).unwrap();
811        }
812
813        #[test]
814        fn should_be_able_to_deserialize_from_msgpack() {
815            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
816            // verify that we are not corrupting or preventing issues when serializing on a
817            // client/server and then trying to deserialize on the other side. This has happened
818            // enough times with minor changes that we need tests to verify.
819            let buf = rmp_serde::encode::to_vec_named(&UnixMetadata {
820                owner_read: true,
821                owner_write: false,
822                owner_exec: false,
823                group_read: true,
824                group_write: false,
825                group_exec: false,
826                other_read: true,
827                other_write: false,
828                other_exec: false,
829            })
830            .unwrap();
831
832            let metadata: UnixMetadata = rmp_serde::decode::from_slice(&buf).unwrap();
833            assert_eq!(
834                metadata,
835                UnixMetadata {
836                    owner_read: true,
837                    owner_write: false,
838                    owner_exec: false,
839                    group_read: true,
840                    group_write: false,
841                    group_exec: false,
842                    other_read: true,
843                    other_write: false,
844                    other_exec: false,
845                }
846            );
847        }
848    }
849
850    mod windows_metadata {
851        use super::*;
852
853        #[test]
854        fn should_be_able_to_serialize_to_json() {
855            let metadata = WindowsMetadata {
856                archive: true,
857                compressed: false,
858                encrypted: true,
859                hidden: false,
860                integrity_stream: true,
861                normal: false,
862                not_content_indexed: true,
863                no_scrub_data: false,
864                offline: true,
865                recall_on_data_access: false,
866                recall_on_open: true,
867                reparse_point: false,
868                sparse_file: true,
869                system: false,
870                temporary: true,
871            };
872
873            let value = serde_json::to_value(metadata).unwrap();
874            assert_eq!(
875                value,
876                serde_json::json!({
877                    "archive": true,
878                    "compressed": false,
879                    "encrypted": true,
880                    "hidden": false,
881                    "integrity_stream": true,
882                    "normal": false,
883                    "not_content_indexed": true,
884                    "no_scrub_data": false,
885                    "offline": true,
886                    "recall_on_data_access": false,
887                    "recall_on_open": true,
888                    "reparse_point": false,
889                    "sparse_file": true,
890                    "system": false,
891                    "temporary": true,
892                })
893            );
894        }
895
896        #[test]
897        fn should_be_able_to_deserialize_from_json() {
898            let value = serde_json::json!({
899                "archive": true,
900                "compressed": false,
901                "encrypted": true,
902                "hidden": false,
903                "integrity_stream": true,
904                "normal": false,
905                "not_content_indexed": true,
906                "no_scrub_data": false,
907                "offline": true,
908                "recall_on_data_access": false,
909                "recall_on_open": true,
910                "reparse_point": false,
911                "sparse_file": true,
912                "system": false,
913                "temporary": true,
914            });
915
916            let metadata: WindowsMetadata = serde_json::from_value(value).unwrap();
917            assert_eq!(
918                metadata,
919                WindowsMetadata {
920                    archive: true,
921                    compressed: false,
922                    encrypted: true,
923                    hidden: false,
924                    integrity_stream: true,
925                    normal: false,
926                    not_content_indexed: true,
927                    no_scrub_data: false,
928                    offline: true,
929                    recall_on_data_access: false,
930                    recall_on_open: true,
931                    reparse_point: false,
932                    sparse_file: true,
933                    system: false,
934                    temporary: true,
935                }
936            );
937        }
938
939        #[test]
940        fn should_be_able_to_serialize_to_msgpack() {
941            let metadata = WindowsMetadata {
942                archive: true,
943                compressed: false,
944                encrypted: true,
945                hidden: false,
946                integrity_stream: true,
947                normal: false,
948                not_content_indexed: true,
949                no_scrub_data: false,
950                offline: true,
951                recall_on_data_access: false,
952                recall_on_open: true,
953                reparse_point: false,
954                sparse_file: true,
955                system: false,
956                temporary: true,
957            };
958
959            // NOTE: We don't actually check the output here because it's an implementation detail
960            // and could change as we change how serialization is done. This is merely to verify
961            // that we can serialize since there are times when serde fails to serialize at
962            // runtime.
963            let _ = rmp_serde::encode::to_vec_named(&metadata).unwrap();
964        }
965
966        #[test]
967        fn should_be_able_to_deserialize_from_msgpack() {
968            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
969            // verify that we are not corrupting or preventing issues when serializing on a
970            // client/server and then trying to deserialize on the other side. This has happened
971            // enough times with minor changes that we need tests to verify.
972            let buf = rmp_serde::encode::to_vec_named(&WindowsMetadata {
973                archive: true,
974                compressed: false,
975                encrypted: true,
976                hidden: false,
977                integrity_stream: true,
978                normal: false,
979                not_content_indexed: true,
980                no_scrub_data: false,
981                offline: true,
982                recall_on_data_access: false,
983                recall_on_open: true,
984                reparse_point: false,
985                sparse_file: true,
986                system: false,
987                temporary: true,
988            })
989            .unwrap();
990
991            let metadata: WindowsMetadata = rmp_serde::decode::from_slice(&buf).unwrap();
992            assert_eq!(
993                metadata,
994                WindowsMetadata {
995                    archive: true,
996                    compressed: false,
997                    encrypted: true,
998                    hidden: false,
999                    integrity_stream: true,
1000                    normal: false,
1001                    not_content_indexed: true,
1002                    no_scrub_data: false,
1003                    offline: true,
1004                    recall_on_data_access: false,
1005                    recall_on_open: true,
1006                    reparse_point: false,
1007                    sparse_file: true,
1008                    system: false,
1009                    temporary: true,
1010                }
1011            );
1012        }
1013    }
1014}