1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use std::convert::From;
use std::path::{Path, PathBuf};
use std::os::unix::fs::MetadataExt;
use generic_array::GenericArray;

use config::*;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
/// Mirrors the state of a path on the filesystem.
pub enum ArchiveEntryPerReplica {
    Empty,
    Directory(ArchiveEntryExists),
    File(ArchiveEntryExists),
    Symlink(ArchiveEntryExists)
}

impl ArchiveEntryPerReplica {
    /// Creates an array of ArchiveEntryPerReplica instances that reflect the current state of `path` inside `roots`.
    pub fn from_roots<AL: ArchiveLen>(roots: &[PathBuf], path: &Path) -> GenericArray<ArchiveEntryPerReplica, AL> {
        GenericArray::map_slice(roots, |root: &PathBuf| ArchiveEntryPerReplica::from(root.join(path).as_ref()))
    }

    /// Returns true if the entries are equal in type but not necessarily in content.
    pub fn equal_ty(a: &ArchiveEntryPerReplica, b: &ArchiveEntryPerReplica) -> bool {
        match *a {
            ArchiveEntryPerReplica::Empty => match *b {
                ArchiveEntryPerReplica::Empty => true,
                _ => false
            },
            ArchiveEntryPerReplica::File(_) => match *b {
                ArchiveEntryPerReplica::File(_) => true,
                _ => false
            },
            ArchiveEntryPerReplica::Directory(_) => match *b {
                ArchiveEntryPerReplica::Directory(_) => true,
                _ => false
            },
            ArchiveEntryPerReplica::Symlink(_) => match *b {
                ArchiveEntryPerReplica::Symlink(_) => true,
                _ => false
            }
        }
    }

    /// Returns true if the entry is a file or a symlink
    pub fn is_file_or_symlink(&self) -> bool {
        match *self {
            ArchiveEntryPerReplica::File(_) | ArchiveEntryPerReplica::Symlink(_) => true,
            _ => false,
        }
    }

    /// Returns true if the entry is present (ie: it is not empty)
    pub fn entry_exists(&self) -> bool {
        match *self {
            ArchiveEntryPerReplica::Empty => false,
            _ => true,
        }
    }
}

impl<'a> From<&'a Path> for ArchiveEntryPerReplica {
    fn from(path: &'a Path) -> ArchiveEntryPerReplica {
        if !path.exists() {
            ArchiveEntryPerReplica::Empty
        } else {
            let metadata = path.metadata().unwrap();
            let entry = ArchiveEntryExists {
                ino: metadata.ino(),
                ctime: metadata.ctime()
            };
            let ty = metadata.file_type();
            if ty.is_file() {
                ArchiveEntryPerReplica::File(entry)
            } else if ty.is_dir() {
                ArchiveEntryPerReplica::Directory(entry)
            } else if ty.is_symlink() {
                ArchiveEntryPerReplica::Symlink(entry)
            } else {
                unreachable!()
            }
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ArchiveEntryExists {
    ino: u64,
    ctime: i64
}