in go/tools/builders/pack.go [192:278]
func readMetadata(r *bufio.Reader, nameData *[]byte) (name string, size int64, err error) {
retry:
// Each file is preceded by a 60-byte header that contains its metadata.
// We only care about two fields, name and size. Other fields (mtime,
// owner, group, mode) are ignored because they don't affect compilation.
var entry [entryLength]byte
if _, err := io.ReadFull(r, entry[:]); err != nil {
return "", 0, err
}
sizeField := strings.TrimSpace(string(entry[48:58]))
size, err = strconv.ParseInt(sizeField, 10, 64)
if err != nil {
return "", 0, err
}
nameField := strings.TrimRight(string(entry[:16]), " ")
switch {
case strings.HasPrefix(nameField, "#1/"):
// BSD-style name. The number of bytes in the name is written here in
// ASCII, right-padded with spaces. The actual name is stored at the
// beginning of the file data, left-padded with NUL bytes.
nameField = nameField[len("#1/"):]
nameLen, err := strconv.ParseInt(nameField, 10, 64)
if err != nil {
return "", 0, err
}
nameBuf := make([]byte, nameLen)
if _, err := io.ReadFull(r, nameBuf); err != nil {
return "", 0, err
}
name = strings.TrimRight(string(nameBuf), "\x00")
size -= nameLen
case nameField == "//":
// GNU / SysV-style name data. This is a fake file that contains names
// for files with long names. We read this into nameData, then read
// the next entry.
*nameData = make([]byte, size)
if _, err := io.ReadFull(r, *nameData); err != nil {
return "", 0, err
}
if size%2 != 0 {
// Files are aligned at 2-byte offsets. Discard the padding byte if the
// size was odd.
if _, err := r.ReadByte(); err != nil {
return "", 0, err
}
}
goto retry
case nameField == "/":
// GNU / SysV-style symbol lookup table. Skip.
if err := skipFile(r, size); err != nil {
return "", 0, err
}
goto retry
case strings.HasPrefix(nameField, "/"):
// GNU / SysV-style long file name. The number that follows the slash is
// an offset into the name data that should have been read earlier.
// The file name ends with a slash.
nameField = nameField[1:]
nameOffset, err := strconv.Atoi(nameField)
if err != nil {
return "", 0, err
}
if nameData == nil || nameOffset < 0 || nameOffset >= len(*nameData) {
return "", 0, fmt.Errorf("invalid name length: %d", nameOffset)
}
i := bytes.IndexByte((*nameData)[nameOffset:], '/')
if i < 0 {
return "", 0, errors.New("file name does not end with '/'")
}
name = string((*nameData)[nameOffset : nameOffset+i])
case strings.HasSuffix(nameField, "/"):
// GNU / SysV-style short file name.
name = nameField[:len(nameField)-1]
default:
// Common format name.
name = nameField
}
return name, size, err
}