// Copyright 2018 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package xcoffimport ()const (SAIAMAG = 0x8AIAFMAG = "`\n"AIAMAG = "<aiaff>\n"AIAMAGBIG = "<bigaf>\n"// SizeofFL_HSZ_BIG = 0x80AR_HSZ_BIG = 0x70)type bigarFileHeader struct { Flmagic [SAIAMAG]byte// Archive magic string Flmemoff [20]byte// Member table offset Flgstoff [20]byte// 32-bits global symtab offset Flgst64off [20]byte// 64-bits global symtab offset Flfstmoff [20]byte// First member offset Fllstmoff [20]byte// Last member offset Flfreeoff [20]byte// First member on free list offset}type bigarMemberHeader struct { Arsize [20]byte// File member size Arnxtmem [20]byte// Next member pointer Arprvmem [20]byte// Previous member pointer Ardate [12]byte// File member date Aruid [12]byte// File member uid Argid [12]byte// File member gid Armode [12]byte// File member mode (octal) Arnamlen [4]byte// File member name length// _ar_nam is removed because it's easier to get name without it.}// Archive represents an open AIX big archive.typeArchivestruct {ArchiveHeader Members []*Member closer io.Closer}// ArchiveHeader holds information about a big archive file headertypeArchiveHeaderstruct { magic string}// Member represents a member of an AIX big archive.typeMemberstruct {MemberHeader sr *io.SectionReader}// MemberHeader holds information about a big archive membertypeMemberHeaderstruct { Name string Size uint64}// OpenArchive opens the named archive using os.Open and prepares it for use// as an AIX big archive.func ( string) (*Archive, error) { , := os.Open()if != nil {returnnil, } , := NewArchive()if != nil { .Close()returnnil, } .closer = return , nil}// Close closes the Archive.// If the Archive was created using NewArchive directly instead of OpenArchive,// Close has no effect.func ( *Archive) () error {varerrorif .closer != nil { = .closer.Close() .closer = nil }return}// NewArchive creates a new Archive for accessing an AIX big archive in an underlying reader.func ( io.ReaderAt) (*Archive, error) { := func( []byte) (int64, error) {returnstrconv.ParseInt(strings.TrimSpace(string()), 10, 64) } := io.NewSectionReader(, 0, 1<<63-1)// Read File Headervar [SAIAMAG]byteif , := .ReadAt([:], 0); != nil {returnnil, } := new(Archive)switchstring([:]) {caseAIAMAGBIG: .magic = string([:])caseAIAMAG:returnnil, fmt.Errorf("small AIX archive not supported")default:returnnil, fmt.Errorf("unrecognised archive magic: 0x%x", ) }varbigarFileHeaderif , := .Seek(0, io.SeekStart); != nil {returnnil, }if := binary.Read(, binary.BigEndian, &); != nil {returnnil, } , := (.Flfstmoff[:])if != nil {returnnil, fmt.Errorf("error parsing offset of first member in archive header(%q); %v", , ) }if == 0 {// Occurs if the archive is empty.return , nil } , := (.Fllstmoff[:])if != nil {returnnil, fmt.Errorf("error parsing offset of first member in archive header(%q); %v", , ) }// Read membersfor {// Read Member Header // The member header is normally 2 bytes larger. But it's easier // to read the name if the header is read without _ar_nam. // However, AIAFMAG must be read afterward.if , := .Seek(, io.SeekStart); != nil {returnnil, }varbigarMemberHeaderif := binary.Read(, binary.BigEndian, &); != nil {returnnil, } := new(Member) .Members = append(.Members, ) , := (.Arsize[:])if != nil {returnnil, fmt.Errorf("error parsing size in member header(%q); %v", , ) } .Size = uint64()// Read name , := (.Arnamlen[:])if != nil {returnnil, fmt.Errorf("error parsing name length in member header(%q); %v", , ) } := make([]byte, )if := binary.Read(, binary.BigEndian, ); != nil {returnnil, } .Name = string() := + AR_HSZ_BIG + if &1 != 0 { ++if , := .Seek(1, io.SeekCurrent); != nil {returnnil, } }// Read AIAFMAG stringvar [2]byteif := binary.Read(, binary.BigEndian, &); != nil {returnnil, }ifstring([:]) != AIAFMAG {returnnil, fmt.Errorf("AIAFMAG not found after member header") } += 2// Add the two bytes of AIAFMAG .sr = io.NewSectionReader(, , )if == {break } , = (.Arnxtmem[:])if != nil {returnnil, fmt.Errorf("error parsing offset of first member in archive header(%q); %v", , ) } }return , nil}// GetFile returns the XCOFF file defined by member name.// FIXME: This doesn't work if an archive has two members with the same// name which can occur if an archive has both 32-bits and 64-bits files.func ( *Archive) ( string) (*File, error) {for , := range .Members {if .Name == {returnNewFile(.sr) } }returnnil, fmt.Errorf("unknown member %s in archive", )}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.