-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtar.rs
131 lines (106 loc) · 2.96 KB
/
tar.rs
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
use packtool::{Packed, View};
fn main() {
assert_eq!(Header::SIZE, 512,);
let bytes = std::fs::read("example.tar").expect("need example tar file");
let mut sub = bytes.as_slice();
while sub.len() > Header::SIZE {
let header_view = View::<'_, Header>::try_from_slice(&sub[..Header::SIZE])
.expect("should start with a header");
let header = header_view.unpack();
let file = std::str::from_utf8(&header.filename.0).expect("valid filename");
let file_size = header.file_size.to_size();
let file_padding = 512 - file_size % 512;
println!("compressed file: {} ({} bytes)", file, file_size);
sub = &sub[Header::SIZE + file_size + file_padding..];
if sub.len() == 1024 {
break;
}
}
}
#[derive(Packed)]
pub struct FileName([u8; 100]);
#[derive(Packed)]
pub struct FileMode([u8; 8]);
#[derive(Packed)]
pub struct Owner(u64);
#[derive(Packed)]
pub struct Group(u64);
#[derive(Packed)]
pub struct FileSize([u8; 12]);
#[derive(Packed)]
pub struct LastUpdate([u8; 12]);
#[derive(Packed)]
pub struct Checksum([u8; 8]);
#[derive(Packed)]
#[repr(u8)]
pub enum TypeFlag {
NormalFile = 0x30,
HardLink = 0x31,
SymbolicLink = 0x32,
CharacterSpecial = 0x33,
BlockSpecial = 0x34,
Directory = 0x35,
Fifo = 0x36,
ContiguousFile = 0x37,
GlobalExtended = 0x67,
ExtendedHeader = 0x78,
// TODO: support for enum with field value size == enum size
// #[packed(range = "0x41..=0x5a")]
// Vendor(u8)
}
#[derive(Packed)]
#[packed(value = b"ustar\x00")]
pub struct UStar;
#[derive(Packed)]
#[packed(value = b"00")]
pub struct Version;
#[derive(Packed)]
pub struct OwnerUserName([u8; 32]);
#[derive(Packed)]
pub struct OwnerGroupName([u8; 32]);
#[derive(Packed)]
pub struct DeviceMajorNumber([u8; 8]);
#[derive(Packed)]
pub struct DeviceMinorNumber([u8; 8]);
#[derive(Packed)]
pub struct FileNamePrefix([u8; 155]);
#[derive(Packed)]
#[packed(value = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")]
pub struct HeaderPadding;
#[derive(Packed)]
pub struct Header {
filename: FileName,
file_mode: FileMode,
owner: Owner,
group: Group,
file_size: FileSize,
last_update: LastUpdate,
checksum: Checksum,
type_flag: TypeFlag,
linked_file: FileName,
ustar: UStar,
version: Version,
user_name: OwnerUserName,
group_name: OwnerGroupName,
device_major_number: DeviceMajorNumber,
device_minor_number: DeviceMinorNumber,
filename_prefix: FileNamePrefix,
_padding: HeaderPadding,
}
impl FileSize {
fn to_size(&self) -> usize {
let mut size = 0;
for o in self.0.iter().copied() {
match o {
b'0'..=b'8' => {
size = (size * 8) + (o - b'0') as usize;
}
0x00 | 0x20 => {}
_ => {
panic!("unknown octal value: {:?}", o)
}
}
}
size
}
}