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