...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package main
16
17 import (
18 "encoding/binary"
19 "fmt"
20 "io"
21 "os"
22 "strconv"
23 "strings"
24 )
25
26 const (
27
28
29 arHeader = "!<arch>\n"
30
31
32
33 entryLength = 60
34 )
35
36 var zeroBytes = []byte("0 ")
37
38 type header struct {
39 NameRaw [16]byte
40 ModTimeRaw [12]byte
41 OwnerIdRaw [6]byte
42 GroupIdRaw [6]byte
43 FileModeRaw [8]byte
44 FileSizeRaw [10]byte
45 EndRaw [2]byte
46 }
47
48 func (h *header) name() string {
49 return strings.TrimRight(string(h.NameRaw[:]), " ")
50 }
51
52 func (h *header) size() int64 {
53 s, err := strconv.Atoi(strings.TrimRight(string(h.FileSizeRaw[:]), " "))
54 if err != nil {
55 panic(err)
56 }
57 return int64(s)
58 }
59
60 func (h *header) next() int64 {
61 size := h.size()
62 return size + size%2
63 }
64
65 func (h *header) deterministic() *header {
66 h2 := *h
67 copy(h2.ModTimeRaw[:], zeroBytes)
68 copy(h2.OwnerIdRaw[:], zeroBytes)
69 copy(h2.GroupIdRaw[:], zeroBytes)
70 copy(h2.FileModeRaw[:], zeroBytes)
71 return &h2
72 }
73
74
75
76
77
78
79
80 func stripArMetadata(archivePath string) error {
81 archive, err := os.OpenFile(archivePath, os.O_RDWR, 0)
82 if err != nil {
83 return err
84 }
85 defer archive.Close()
86
87 magic := make([]byte, len(arHeader))
88 if _, err := io.ReadFull(archive, magic); err != nil {
89 return err
90 }
91
92 if string(magic) != arHeader {
93 return fmt.Errorf("%s is not an archive", archivePath)
94 }
95
96 for {
97 hdr := &header{}
98 if err := binary.Read(archive, binary.BigEndian, hdr); err == io.EOF {
99 return nil
100 } else if err != nil {
101 return err
102 }
103
104
105 archive.Seek(-entryLength, os.SEEK_CUR)
106 if err := binary.Write(archive, binary.BigEndian, hdr.deterministic()); err != nil {
107 return err
108 }
109
110 if _, err := archive.Seek(hdr.next(), os.SEEK_CUR); err == io.EOF {
111 return nil
112 } else if err != nil {
113 return err
114 }
115 }
116 }
117
View as plain text