xref: /aosp_15_r20/external/bazelbuild-rules_go/go/tools/builders/ar.go (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1*9bb1b549SSpandan Das// Copyright 2018 The Bazel Authors. All rights reserved.
2*9bb1b549SSpandan Das//
3*9bb1b549SSpandan Das// Licensed under the Apache License, Version 2.0 (the "License");
4*9bb1b549SSpandan Das// you may not use this file except in compliance with the License.
5*9bb1b549SSpandan Das// You may obtain a copy of the License at
6*9bb1b549SSpandan Das//
7*9bb1b549SSpandan Das//    http://www.apache.org/licenses/LICENSE-2.0
8*9bb1b549SSpandan Das//
9*9bb1b549SSpandan Das// Unless required by applicable law or agreed to in writing, software
10*9bb1b549SSpandan Das// distributed under the License is distributed on an "AS IS" BASIS,
11*9bb1b549SSpandan Das// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9bb1b549SSpandan Das// See the License for the specific language governing permissions and
13*9bb1b549SSpandan Das// limitations under the License.
14*9bb1b549SSpandan Das
15*9bb1b549SSpandan Daspackage main
16*9bb1b549SSpandan Das
17*9bb1b549SSpandan Dasimport (
18*9bb1b549SSpandan Das	"encoding/binary"
19*9bb1b549SSpandan Das	"fmt"
20*9bb1b549SSpandan Das	"io"
21*9bb1b549SSpandan Das	"os"
22*9bb1b549SSpandan Das	"strconv"
23*9bb1b549SSpandan Das	"strings"
24*9bb1b549SSpandan Das)
25*9bb1b549SSpandan Das
26*9bb1b549SSpandan Dastype header struct {
27*9bb1b549SSpandan Das	NameRaw     [16]byte
28*9bb1b549SSpandan Das	ModTimeRaw  [12]byte
29*9bb1b549SSpandan Das	OwnerIdRaw  [6]byte
30*9bb1b549SSpandan Das	GroupIdRaw  [6]byte
31*9bb1b549SSpandan Das	FileModeRaw [8]byte
32*9bb1b549SSpandan Das	FileSizeRaw [10]byte
33*9bb1b549SSpandan Das	EndRaw      [2]byte
34*9bb1b549SSpandan Das}
35*9bb1b549SSpandan Das
36*9bb1b549SSpandan Dasfunc (h *header) name() string {
37*9bb1b549SSpandan Das	return strings.TrimRight(string(h.NameRaw[:]), " ")
38*9bb1b549SSpandan Das}
39*9bb1b549SSpandan Das
40*9bb1b549SSpandan Dasfunc (h *header) size() int64 {
41*9bb1b549SSpandan Das	s, err := strconv.Atoi(strings.TrimRight(string(h.FileSizeRaw[:]), " "))
42*9bb1b549SSpandan Das	if err != nil {
43*9bb1b549SSpandan Das		panic(err)
44*9bb1b549SSpandan Das	}
45*9bb1b549SSpandan Das	return int64(s)
46*9bb1b549SSpandan Das}
47*9bb1b549SSpandan Das
48*9bb1b549SSpandan Dasfunc (h *header) next() int64 {
49*9bb1b549SSpandan Das	size := h.size()
50*9bb1b549SSpandan Das	return size + size%2
51*9bb1b549SSpandan Das}
52*9bb1b549SSpandan Das
53*9bb1b549SSpandan Dasfunc (h *header) deterministic() *header {
54*9bb1b549SSpandan Das	h2 := *h
55*9bb1b549SSpandan Das	copy(h2.ModTimeRaw[:], zeroBytes)
56*9bb1b549SSpandan Das	copy(h2.OwnerIdRaw[:], zeroBytes)
57*9bb1b549SSpandan Das	copy(h2.GroupIdRaw[:], zeroBytes)
58*9bb1b549SSpandan Das	copy(h2.FileModeRaw[:], zeroBytes) // GNU ar also clears this
59*9bb1b549SSpandan Das	return &h2
60*9bb1b549SSpandan Das}
61*9bb1b549SSpandan Das
62*9bb1b549SSpandan Das// stripArMetadata strips the archive metadata of non-deterministic data:
63*9bb1b549SSpandan Das// - Timestamps
64*9bb1b549SSpandan Das// - User IDs
65*9bb1b549SSpandan Das// - Group IDs
66*9bb1b549SSpandan Das// - File Modes
67*9bb1b549SSpandan Das// The archive is modified in place.
68*9bb1b549SSpandan Dasfunc stripArMetadata(archivePath string) error {
69*9bb1b549SSpandan Das	archive, err := os.OpenFile(archivePath, os.O_RDWR, 0)
70*9bb1b549SSpandan Das	if err != nil {
71*9bb1b549SSpandan Das		return err
72*9bb1b549SSpandan Das	}
73*9bb1b549SSpandan Das	defer archive.Close()
74*9bb1b549SSpandan Das
75*9bb1b549SSpandan Das	magic := make([]byte, len(arHeader))
76*9bb1b549SSpandan Das	if _, err := io.ReadFull(archive, magic); err != nil {
77*9bb1b549SSpandan Das		return err
78*9bb1b549SSpandan Das	}
79*9bb1b549SSpandan Das
80*9bb1b549SSpandan Das	if string(magic) != arHeader {
81*9bb1b549SSpandan Das		return fmt.Errorf("%s is not an archive", archivePath)
82*9bb1b549SSpandan Das	}
83*9bb1b549SSpandan Das
84*9bb1b549SSpandan Das	for {
85*9bb1b549SSpandan Das		hdr := &header{}
86*9bb1b549SSpandan Das		if err := binary.Read(archive, binary.BigEndian, hdr); err == io.EOF {
87*9bb1b549SSpandan Das			return nil
88*9bb1b549SSpandan Das		} else if err != nil {
89*9bb1b549SSpandan Das			return err
90*9bb1b549SSpandan Das		}
91*9bb1b549SSpandan Das
92*9bb1b549SSpandan Das		// Seek back at the beginning of the header and overwrite it.
93*9bb1b549SSpandan Das		archive.Seek(-entryLength, os.SEEK_CUR)
94*9bb1b549SSpandan Das		if err := binary.Write(archive, binary.BigEndian, hdr.deterministic()); err != nil {
95*9bb1b549SSpandan Das			return err
96*9bb1b549SSpandan Das		}
97*9bb1b549SSpandan Das
98*9bb1b549SSpandan Das		if _, err := archive.Seek(hdr.next(), os.SEEK_CUR); err == io.EOF {
99*9bb1b549SSpandan Das			return nil
100*9bb1b549SSpandan Das		} else if err != nil {
101*9bb1b549SSpandan Das			return err
102*9bb1b549SSpandan Das		}
103*9bb1b549SSpandan Das	}
104*9bb1b549SSpandan Das}
105