-
Notifications
You must be signed in to change notification settings - Fork 1
/
TarHeader.php
139 lines (107 loc) · 3.02 KB
/
TarHeader.php
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
<?php
namespace ownCloud\TarStreamer;
class TarHeader {
private $name = '';
private $mode = '777';
private $uid = '0';
private $gid = '0';
private $size;
private $mtime = '';
private $typeflag;
private $linkname = '';
private $magic = 'ustar';
private $version = '00';
private $uname = '';
private $gname = '';
private $devmajor = '';
private $devminor = '';
private $prefix = '';
private $reserved = '';
public function setName($name) {
$this->name = $name;
return $this;
}
public function setSize($size) {
$this->size = $size;
return $this;
}
public function setMtime($mtime) {
$this->mtime = $mtime;
return $this;
}
public function setTypeflag($typeflag) {
$this->typeflag = $typeflag;
return $this;
}
public function setPrefix($prefix) {
$this->prefix = $prefix;
return $this;
}
public function getHeader() {
$fields = [
['a100', substr($this->name, 0, 100)],
['a8', str_pad($this->mode, 7, '0', STR_PAD_LEFT)],
['a8', decoct((int) str_pad($this->uid, 7, '0', STR_PAD_LEFT))],
['a8', decoct((int) str_pad($this->gid, 7, '0', STR_PAD_LEFT))],
['a12', str_pad(decoct((int)$this->size), 11, '0', STR_PAD_LEFT)],
['a12', str_pad(decoct((int)$this->mtime), 11, '0', STR_PAD_LEFT)],
// We calculate checksum later
['a8', ''],
['a1', $this->typeflag],
['a100', $this->linkname],
['a6', $this->magic],
['a2', $this->version],
['a32', $this->uname],
['a32', $this->gname],
['a8', $this->devmajor],
['a8', $this->devminor],
['a155', substr($this->prefix, 0, 155)],
['a12', $this->reserved],
];
// pack fields and calculate "total" length
$header = $this->packFields($fields);
// Compute header checksum
$checksum = str_pad(decoct($this->computeUnsignedChecksum($header)), 6, "0", STR_PAD_LEFT);
for ($i = 0; $i < 6; $i++) {
$header[(148 + $i)] = substr($checksum, $i, 1);
}
$header[154] = \chr(0);
$header[155] = \chr(32);
return $header;
}
/**
* Create a format string and argument list for pack(), then call pack() and return the result.
*
* @param array $fields key being the format string and value being the data to pack
* @return string binary packed data returned from pack()
*/
protected function packFields($fields) {
list($fmt, $args) = ['', []];
// populate format string and argument list
foreach ($fields as $field) {
$fmt .= $field[0];
$args[] = $field[1];
}
// prepend format string to argument list
array_unshift($args, $fmt);
// build output string from header and compressed data
return \call_user_func_array('pack', $args);
}
/**
* Generate unsigned checksum of header
*
* @param string $header
* @return float|int unsigned checksum
*/
protected function computeUnsignedChecksum($header) {
$unsignedChecksum = 0;
for ($i = 0; $i < 512; $i++) {
$unsignedChecksum += \ord($header[$i]);
}
for ($i = 0; $i < 8; $i++) {
$unsignedChecksum -= \ord($header[148 + $i]);
}
$unsignedChecksum += \ord(" ") * 8;
return $unsignedChecksum;
}
}