-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalign.go
84 lines (70 loc) · 1.77 KB
/
align.go
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
package tar
import (
"fmt"
"os"
"strings"
"syscall"
)
// Align adds a dummy PAXRecord field to theh header to ensure the
// next file contents start aligned with the Blksize for the `dest`
// file.
func Align(dest *os.File, hdr *Header) error {
fi, err := dest.Stat()
if err != nil {
return err
}
st := fi.Sys().(*syscall.Stat_t)
return alignTo(hdr, st.Size, st.Blksize)
}
const paxPaddingKey = "ENGFLOW.padding"
type counter struct {
n int
}
func (c *counter) Write(d []byte) (int, error) {
n := len(d)
c.n += n
return n, nil
}
func hdrSize(hdr *Header) int64 {
buf := counter{}
tw := NewWriter(&buf)
h := *hdr
tw.WriteHeader(&h)
// no need to call flush; WriteHeader always writes multiples of 512.
return int64(buf.n)
}
func alignTo(hdr *Header, tarSize, bs int64) error {
for {
if (tarSize+hdrSize(hdr))%bs == 0 {
return nil
}
if hdr.PAXRecords == nil {
hdr.PAXRecords = map[string]string{}
}
hdr.PAXRecords[paxPaddingKey] = ""
needPadding := bs - (tarSize+hdrSize(hdr))%bs
if needPadding == 0 {
return nil
}
h := *hdr
h.PAXRecords = nil
pureHeaderSz := hdrSize(&h)
// Account for TypeXHeader which is gone because we
// cleared PAXRecords
pureHeaderSz += blockSize
r, err := paxSpecialFile(hdr.PAXRecords)
if err != nil {
return err
}
missing := bs - (tarSize+(int64(len(r))+pureHeaderSz))%bs
// Filling out exactly is tricky to get right, b/c the
// size field in the PAX k/v encoding is variable
// size. Just get to the middle of the tar block.
missing -= blockSize / 2
hdr.PAXRecords[paxPaddingKey] = strings.Repeat("x", int(missing))
if needPadding := (bs - (tarSize+hdrSize(hdr))%bs) % bs; needPadding != 0 {
return fmt.Errorf("giving up") // this shouldn't happen, but don't crash.
}
}
return nil
}