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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// See https://en.wikipedia.org/wiki/Tar_%28computing%29#UStar_format
/// Indicate for the type of file described by a header.
///
/// Each `Header` has an `entry_type` method returning an instance of this type
/// which can be used to inspect what the header is describing.

/// A non-exhaustive enum representing the possible entry types
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub enum EntryType {
    /// Regular file
    Regular,
    /// Hard link
    Link,
    /// Symbolic link
    Symlink,
    /// Character device
    Char,
    /// Block device
    Block,
    /// Directory
    Directory,
    /// Named pipe (fifo)
    Fifo,
    /// Implementation-defined 'high-performance' type, treated as regular file
    Continuous,
    /// GNU extension - long file name
    GNULongName,
    /// GNU extension - long link name (link target)
    GNULongLink,
    /// GNU extension - sparse file
    GNUSparse,
    /// Global extended header
    XGlobalHeader,
    /// Extended Header
    XHeader,
    /// Unknown header,
    Other(u8),
}

impl EntryType {
    /// Creates a new entry type from a raw byte.
    ///
    /// Note that the other named constructors of entry type may be more
    /// appropriate to create a file type from.
    pub fn new(byte: u8) -> EntryType {
        match byte {
            b'\x00' | b'0' => EntryType::Regular,
            b'1' => EntryType::Link,
            b'2' => EntryType::Symlink,
            b'3' => EntryType::Char,
            b'4' => EntryType::Block,
            b'5' => EntryType::Directory,
            b'6' => EntryType::Fifo,
            b'7' => EntryType::Continuous,
            b'x' => EntryType::XHeader,
            b'g' => EntryType::XGlobalHeader,
            b'L' => EntryType::GNULongName,
            b'K' => EntryType::GNULongLink,
            b'S' => EntryType::GNUSparse,
            other => EntryType::Other(other),
        }
    }

    /// Returns the raw underlying byte that this entry type represents.
    pub fn as_byte(self) -> u8 {
        match self {
            EntryType::Regular => b'0',
            EntryType::Link => b'1',
            EntryType::Symlink => b'2',
            EntryType::Char => b'3',
            EntryType::Block => b'4',
            EntryType::Directory => b'5',
            EntryType::Fifo => b'6',
            EntryType::Continuous => b'7',
            EntryType::XHeader => b'x',
            EntryType::XGlobalHeader => b'g',
            EntryType::GNULongName => b'L',
            EntryType::GNULongLink => b'K',
            EntryType::GNUSparse => b'S',
            EntryType::Other(other) => other,
        }
    }

    /// Creates a new entry type representing a regular file.
    pub fn file() -> EntryType {
        EntryType::Regular
    }

    /// Creates a new entry type representing a hard link.
    pub fn hard_link() -> EntryType {
        EntryType::Link
    }

    /// Creates a new entry type representing a symlink.
    pub fn symlink() -> EntryType {
        EntryType::Symlink
    }

    /// Creates a new entry type representing a character special device.
    pub fn character_special() -> EntryType {
        EntryType::Char
    }

    /// Creates a new entry type representing a block special device.
    pub fn block_special() -> EntryType {
        EntryType::Block
    }

    /// Creates a new entry type representing a directory.
    pub fn dir() -> EntryType {
        EntryType::Directory
    }

    /// Creates a new entry type representing a FIFO.
    pub fn fifo() -> EntryType {
        EntryType::Fifo
    }

    /// Creates a new entry type representing a contiguous file.
    pub fn contiguous() -> EntryType {
        EntryType::Continuous
    }

    /// Returns whether this type represents a regular file.
    pub fn is_file(self) -> bool {
        self == EntryType::Regular
    }

    /// Returns whether this type represents a hard link.
    pub fn is_hard_link(self) -> bool {
        self == EntryType::Link
    }

    /// Returns whether this type represents a symlink.
    pub fn is_symlink(self) -> bool {
        self == EntryType::Symlink
    }

    /// Returns whether this type represents a character special device.
    pub fn is_character_special(self) -> bool {
        self == EntryType::Char
    }

    /// Returns whether this type represents a block special device.
    pub fn is_block_special(self) -> bool {
        self == EntryType::Block
    }

    /// Returns whether this type represents a directory.
    pub fn is_dir(self) -> bool {
        self == EntryType::Directory
    }

    /// Returns whether this type represents a FIFO.
    pub fn is_fifo(self) -> bool {
        self == EntryType::Fifo
    }

    /// Returns whether this type represents a contiguous file.
    pub fn is_contiguous(self) -> bool {
        self == EntryType::Continuous
    }

    /// Returns whether this type represents a GNU long name header.
    pub fn is_gnu_longname(self) -> bool {
        self == EntryType::GNULongName
    }

    /// Returns whether this type represents a GNU sparse header.
    pub fn is_gnu_sparse(self) -> bool {
        self == EntryType::GNUSparse
    }

    /// Returns whether this type represents a GNU long link header.
    pub fn is_gnu_longlink(self) -> bool {
        self == EntryType::GNULongLink
    }

    /// Returns whether this type represents a GNU long name header.
    pub fn is_pax_global_extensions(self) -> bool {
        self == EntryType::XGlobalHeader
    }

    /// Returns whether this type represents a GNU long link header.
    pub fn is_pax_local_extensions(self) -> bool {
        self == EntryType::XHeader
    }
}