Packages
hackney
3.0.3
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/boringssl/util/ar/ar.go
// Copyright 2017 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ar.go contains functions for parsing .a archive files.
package ar
import (
"bytes"
"errors"
"fmt"
"io"
"strconv"
"strings"
)
// ParseAR parses an archive file from r and returns a map from filename to
// contents, or else an error.
func ParseAR(r io.Reader) (map[string][]byte, error) {
// See https://en.wikipedia.org/wiki/Ar_(Unix)#File_format_details
const expectedMagic = "!<arch>\n"
var magic [len(expectedMagic)]byte
if _, err := io.ReadFull(r, magic[:]); err != nil {
return nil, err
}
if string(magic[:]) != expectedMagic {
return nil, errors.New("ar: not an archive file")
}
const filenameTableName = "//"
const symbolTableName = "/"
var longFilenameTable []byte
ret := make(map[string][]byte)
for {
var header [60]byte
if _, err := io.ReadFull(r, header[:]); err != nil {
if err == io.EOF {
break
}
return nil, errors.New("ar: error reading file header: " + err.Error())
}
name := strings.TrimRight(string(header[:16]), " ")
sizeStr := strings.TrimRight(string(header[48:58]), "\x00 ")
size, err := strconv.ParseUint(sizeStr, 10, 64)
if err != nil {
return nil, errors.New("ar: failed to parse file size: " + err.Error())
}
// File contents are padded to a multiple of two bytes
storedSize := size
if storedSize%2 == 1 {
storedSize++
}
contents := make([]byte, storedSize)
if _, err := io.ReadFull(r, contents); err != nil {
return nil, errors.New("ar: error reading file contents: " + err.Error())
}
contents = contents[:size]
switch {
case name == filenameTableName:
if longFilenameTable != nil {
return nil, errors.New("ar: two filename tables found")
}
longFilenameTable = contents
continue
case name == symbolTableName:
continue
case len(name) > 1 && name[0] == '/':
if longFilenameTable == nil {
return nil, errors.New("ar: long filename reference found before filename table")
}
// A long filename is stored as "/" followed by a
// base-10 offset in the filename table.
offset, err := strconv.ParseUint(name[1:], 10, 64)
if err != nil {
return nil, errors.New("ar: failed to parse filename offset: " + err.Error())
}
if offset > uint64((^uint(0))>>1) {
return nil, errors.New("ar: filename offset overflow")
}
if int(offset) > len(longFilenameTable) {
return nil, errors.New("ar: filename offset out of bounds")
}
filename := longFilenameTable[offset:]
// Windows terminates filenames with NUL characters,
// while sysv/GNU uses /.
if i := bytes.IndexAny(filename, "/\x00"); i < 0 {
return nil, errors.New("ar: unterminated filename in table")
} else {
filename = filename[:i]
}
name = string(filename)
default:
name = strings.TrimRight(name, "/")
}
// Post-processing for BSD:
// https://en.wikipedia.org/wiki/Ar_(Unix)#BSD_variant
//
// If the name is of the form #1/XXX, XXX identifies the length of the
// name, and the name itself is stored as a prefix of the data, possibly
// null-padded.
var namelen uint
n, err := fmt.Sscanf(name, "#1/%d", &namelen)
if err == nil && n == 1 && len(contents) >= int(namelen) {
name = string(contents[:namelen])
contents = contents[namelen:]
// Names can be null padded; find the first null (if any). Note that
// this also handles the case of a null followed by non-null
// characters. It's not clear whether those can ever show up in
// practice, but we might as well handle them in case they can show
// up.
var null int
for ; null < len(name); null++ {
if name[null] == 0 {
break
}
}
name = name[:null]
}
if name == "__.SYMDEF" || name == "__.SYMDEF SORTED" {
continue
}
ret[name] = contents
}
return ret, nil
}