github.com/bir3/gocompiler@v0.9.2202/src/cmd/internal/archive/archive.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package archive implements reading of archive files generated by the Go 6 // toolchain. 7 package archive 8 9 import ( 10 "bufio" 11 "bytes" 12 "github.com/bir3/gocompiler/src/cmd/internal/bio" 13 "github.com/bir3/gocompiler/src/cmd/internal/goobj" 14 "errors" 15 "fmt" 16 "io" 17 "log" 18 "os" 19 "strconv" 20 "strings" 21 "time" 22 "unicode/utf8" 23 ) 24 25 /* 26 The archive format is: 27 28 First, on a line by itself 29 !<arch> 30 31 Then zero or more file records. Each file record has a fixed-size one-line header 32 followed by data bytes followed by an optional padding byte. The header is: 33 34 %-16s%-12d%-6d%-6d%-8o%-10d` 35 name mtime uid gid mode size 36 37 (note the trailing backquote). The %-16s here means at most 16 *bytes* of 38 the name, and if shorter, space padded on the right. 39 */ 40 41 // A Data is a reference to data stored in an object file. 42 // It records the offset and size of the data, so that a client can 43 // read the data only if necessary. 44 type Data struct { 45 Offset int64 46 Size int64 47 } 48 49 type Archive struct { 50 f *os.File 51 Entries []Entry 52 } 53 54 func (a *Archive) File() *os.File { return a.f } 55 56 type Entry struct { 57 Name string 58 Type EntryType 59 Mtime int64 60 Uid int 61 Gid int 62 Mode os.FileMode 63 Data 64 Obj *GoObj // nil if this entry is not a Go object file 65 } 66 67 type EntryType int 68 69 const ( 70 EntryPkgDef EntryType = iota 71 EntryGoObj 72 EntryNativeObj 73 EntrySentinelNonObj 74 ) 75 76 func (e *Entry) String() string { 77 return fmt.Sprintf("%s %6d/%-6d %12d %s %s", 78 (e.Mode & 0777).String(), 79 e.Uid, 80 e.Gid, 81 e.Size, 82 time.Unix(e.Mtime, 0).Format(timeFormat), 83 e.Name) 84 } 85 86 type GoObj struct { 87 TextHeader []byte 88 Arch string 89 Data 90 } 91 92 const ( 93 entryHeader = "%s%-12d%-6d%-6d%-8o%-10d`\n" 94 // In entryHeader the first entry, the name, is always printed as 16 bytes right-padded. 95 entryLen = 16 + 12 + 6 + 6 + 8 + 10 + 1 + 1 96 timeFormat = "Jan _2 15:04 2006" 97 ) 98 99 var ( 100 archiveHeader = []byte("!<arch>\n") 101 archiveMagic = []byte("`\n") 102 goobjHeader = []byte("go objec") // truncated to size of archiveHeader 103 104 errCorruptArchive = errors.New("corrupt archive") 105 errTruncatedArchive = errors.New("truncated archive") 106 errCorruptObject = errors.New("corrupt object file") 107 errNotObject = errors.New("unrecognized object file format") 108 ) 109 110 type ErrGoObjOtherVersion struct{ magic []byte } 111 112 func (e ErrGoObjOtherVersion) Error() string { 113 return fmt.Sprintf("go object of a different version: %q", e.magic) 114 } 115 116 // An objReader is an object file reader. 117 type objReader struct { 118 a *Archive 119 b *bio.Reader 120 err error 121 offset int64 122 limit int64 123 tmp [256]byte 124 } 125 126 func (r *objReader) init(f *os.File) { 127 r.a = &Archive{f, nil} 128 r.offset, _ = f.Seek(0, io.SeekCurrent) 129 r.limit, _ = f.Seek(0, io.SeekEnd) 130 f.Seek(r.offset, io.SeekStart) 131 r.b = bio.NewReader(f) 132 } 133 134 // error records that an error occurred. 135 // It returns only the first error, so that an error 136 // caused by an earlier error does not discard information 137 // about the earlier error. 138 func (r *objReader) error(err error) error { 139 if r.err == nil { 140 if err == io.EOF { 141 err = io.ErrUnexpectedEOF 142 } 143 r.err = err 144 } 145 // panic("corrupt") // useful for debugging 146 return r.err 147 } 148 149 // peek returns the next n bytes without advancing the reader. 150 func (r *objReader) peek(n int) ([]byte, error) { 151 if r.err != nil { 152 return nil, r.err 153 } 154 if r.offset >= r.limit { 155 r.error(io.ErrUnexpectedEOF) 156 return nil, r.err 157 } 158 b, err := r.b.Peek(n) 159 if err != nil { 160 if err != bufio.ErrBufferFull { 161 r.error(err) 162 } 163 } 164 return b, err 165 } 166 167 // readByte reads and returns a byte from the input file. 168 // On I/O error or EOF, it records the error but returns byte 0. 169 // A sequence of 0 bytes will eventually terminate any 170 // parsing state in the object file. In particular, it ends the 171 // reading of a varint. 172 func (r *objReader) readByte() byte { 173 if r.err != nil { 174 return 0 175 } 176 if r.offset >= r.limit { 177 r.error(io.ErrUnexpectedEOF) 178 return 0 179 } 180 b, err := r.b.ReadByte() 181 if err != nil { 182 if err == io.EOF { 183 err = io.ErrUnexpectedEOF 184 } 185 r.error(err) 186 b = 0 187 } else { 188 r.offset++ 189 } 190 return b 191 } 192 193 // readFull reads exactly len(b) bytes from the input file. 194 // If an error occurs, read returns the error but also 195 // records it, so it is safe for callers to ignore the result 196 // as long as delaying the report is not a problem. 197 func (r *objReader) readFull(b []byte) error { 198 if r.err != nil { 199 return r.err 200 } 201 if r.offset+int64(len(b)) > r.limit { 202 return r.error(io.ErrUnexpectedEOF) 203 } 204 n, err := io.ReadFull(r.b, b) 205 r.offset += int64(n) 206 if err != nil { 207 return r.error(err) 208 } 209 return nil 210 } 211 212 // skip skips n bytes in the input. 213 func (r *objReader) skip(n int64) { 214 if n < 0 { 215 r.error(fmt.Errorf("debug/goobj: internal error: misuse of skip")) 216 } 217 if n < int64(len(r.tmp)) { 218 // Since the data is so small, a just reading from the buffered 219 // reader is better than flushing the buffer and seeking. 220 r.readFull(r.tmp[:n]) 221 } else if n <= int64(r.b.Buffered()) { 222 // Even though the data is not small, it has already been read. 223 // Advance the buffer instead of seeking. 224 for n > int64(len(r.tmp)) { 225 r.readFull(r.tmp[:]) 226 n -= int64(len(r.tmp)) 227 } 228 r.readFull(r.tmp[:n]) 229 } else { 230 // Seek, giving up buffered data. 231 r.b.MustSeek(r.offset+n, io.SeekStart) 232 r.offset += n 233 } 234 } 235 236 // New writes to f to make a new archive. 237 func New(f *os.File) (*Archive, error) { 238 _, err := f.Write(archiveHeader) 239 if err != nil { 240 return nil, err 241 } 242 return &Archive{f: f}, nil 243 } 244 245 // Parse parses an object file or archive from f. 246 func Parse(f *os.File, verbose bool) (*Archive, error) { 247 var r objReader 248 r.init(f) 249 t, err := r.peek(8) 250 if err != nil { 251 if err == io.EOF { 252 err = io.ErrUnexpectedEOF 253 } 254 return nil, err 255 } 256 257 switch { 258 default: 259 return nil, errNotObject 260 261 case bytes.Equal(t, archiveHeader): 262 if err := r.parseArchive(verbose); err != nil { 263 return nil, err 264 } 265 case bytes.Equal(t, goobjHeader): 266 off := r.offset 267 o := &GoObj{} 268 if err := r.parseObject(o, r.limit-off); err != nil { 269 return nil, err 270 } 271 r.a.Entries = []Entry{{ 272 Name: f.Name(), 273 Type: EntryGoObj, 274 Data: Data{off, r.limit - off}, 275 Obj: o, 276 }} 277 } 278 279 return r.a, nil 280 } 281 282 // trimSpace removes trailing spaces from b and returns the corresponding string. 283 // This effectively parses the form used in archive headers. 284 func trimSpace(b []byte) string { 285 return string(bytes.TrimRight(b, " ")) 286 } 287 288 // parseArchive parses a Unix archive of Go object files. 289 func (r *objReader) parseArchive(verbose bool) error { 290 r.readFull(r.tmp[:8]) // consume header (already checked) 291 for r.offset < r.limit { 292 if err := r.readFull(r.tmp[:60]); err != nil { 293 return err 294 } 295 data := r.tmp[:60] 296 297 // Each file is preceded by this text header (slice indices in first column): 298 // 0:16 name 299 // 16:28 date 300 // 28:34 uid 301 // 34:40 gid 302 // 40:48 mode 303 // 48:58 size 304 // 58:60 magic - `\n 305 // We only care about name, size, and magic, unless in verbose mode. 306 // The fields are space-padded on the right. 307 // The size is in decimal. 308 // The file data - size bytes - follows the header. 309 // Headers are 2-byte aligned, so if size is odd, an extra padding 310 // byte sits between the file data and the next header. 311 // The file data that follows is padded to an even number of bytes: 312 // if size is odd, an extra padding byte is inserted betw the next header. 313 if len(data) < 60 { 314 return errTruncatedArchive 315 } 316 if !bytes.Equal(data[58:60], archiveMagic) { 317 return errCorruptArchive 318 } 319 name := trimSpace(data[0:16]) 320 var err error 321 get := func(start, end, base, bitsize int) int64 { 322 if err != nil { 323 return 0 324 } 325 var v int64 326 v, err = strconv.ParseInt(trimSpace(data[start:end]), base, bitsize) 327 return v 328 } 329 size := get(48, 58, 10, 64) 330 var ( 331 mtime int64 332 uid, gid int 333 mode os.FileMode 334 ) 335 if verbose { 336 mtime = get(16, 28, 10, 64) 337 uid = int(get(28, 34, 10, 32)) 338 gid = int(get(34, 40, 10, 32)) 339 mode = os.FileMode(get(40, 48, 8, 32)) 340 } 341 if err != nil { 342 return errCorruptArchive 343 } 344 data = data[60:] 345 fsize := size + size&1 346 if fsize < 0 || fsize < size { 347 return errCorruptArchive 348 } 349 switch name { 350 case "__.PKGDEF": 351 r.a.Entries = append(r.a.Entries, Entry{ 352 Name: name, 353 Type: EntryPkgDef, 354 Mtime: mtime, 355 Uid: uid, 356 Gid: gid, 357 Mode: mode, 358 Data: Data{r.offset, size}, 359 }) 360 r.skip(size) 361 case "preferlinkext", "dynimportfail": 362 if size == 0 { 363 // These are not actual objects, but rather sentinel 364 // entries put into the archive by the Go command to 365 // be read by the linker. See #62036. 366 r.a.Entries = append(r.a.Entries, Entry{ 367 Name: name, 368 Type: EntrySentinelNonObj, 369 Mtime: mtime, 370 Uid: uid, 371 Gid: gid, 372 Mode: mode, 373 Data: Data{r.offset, size}, 374 }) 375 break 376 } 377 fallthrough 378 default: 379 var typ EntryType 380 var o *GoObj 381 offset := r.offset 382 p, err := r.peek(8) 383 if err != nil { 384 return err 385 } 386 if bytes.Equal(p, goobjHeader) { 387 typ = EntryGoObj 388 o = &GoObj{} 389 err := r.parseObject(o, size) 390 if err != nil { 391 return err 392 } 393 } else { 394 typ = EntryNativeObj 395 r.skip(size) 396 } 397 r.a.Entries = append(r.a.Entries, Entry{ 398 Name: name, 399 Type: typ, 400 Mtime: mtime, 401 Uid: uid, 402 Gid: gid, 403 Mode: mode, 404 Data: Data{offset, size}, 405 Obj: o, 406 }) 407 } 408 if size&1 != 0 { 409 r.skip(1) 410 } 411 } 412 return nil 413 } 414 415 // parseObject parses a single Go object file. 416 // The object file consists of a textual header ending in "\n!\n" 417 // and then the part we want to parse begins. 418 // The format of that part is defined in a comment at the top 419 // of cmd/internal/goobj/objfile.go. 420 func (r *objReader) parseObject(o *GoObj, size int64) error { 421 h := make([]byte, 0, 256) 422 var c1, c2, c3 byte 423 for { 424 c1, c2, c3 = c2, c3, r.readByte() 425 h = append(h, c3) 426 // The new export format can contain 0 bytes. 427 // Don't consider them errors, only look for r.err != nil. 428 if r.err != nil { 429 return errCorruptObject 430 } 431 if c1 == '\n' && c2 == '!' && c3 == '\n' { 432 break 433 } 434 } 435 o.TextHeader = h 436 hs := strings.Fields(string(h)) 437 if len(hs) >= 4 { 438 o.Arch = hs[3] 439 } 440 o.Offset = r.offset 441 o.Size = size - int64(len(h)) 442 443 p, err := r.peek(8) 444 if err != nil { 445 return err 446 } 447 if !bytes.Equal(p, []byte(goobj.Magic)) { 448 if bytes.HasPrefix(p, []byte("\x00go1")) && bytes.HasSuffix(p, []byte("ld")) { 449 return r.error(ErrGoObjOtherVersion{p[1:]}) // strip the \x00 byte 450 } 451 return r.error(errCorruptObject) 452 } 453 r.skip(o.Size) 454 return nil 455 } 456 457 // AddEntry adds an entry to the end of a, with the content from r. 458 func (a *Archive) AddEntry(typ EntryType, name string, mtime int64, uid, gid int, mode os.FileMode, size int64, r io.Reader) { 459 off, err := a.f.Seek(0, io.SeekEnd) 460 if err != nil { 461 log.Fatal(err) 462 } 463 n, err := fmt.Fprintf(a.f, entryHeader, exactly16Bytes(name), mtime, uid, gid, mode, size) 464 if err != nil || n != entryLen { 465 log.Fatal("writing entry header: ", err) 466 } 467 n1, _ := io.CopyN(a.f, r, size) 468 if n1 != size { 469 log.Fatal(err) 470 } 471 if (off+size)&1 != 0 { 472 a.f.Write([]byte{0}) // pad to even byte 473 } 474 a.Entries = append(a.Entries, Entry{ 475 Name: name, 476 Type: typ, 477 Mtime: mtime, 478 Uid: uid, 479 Gid: gid, 480 Mode: mode, 481 Data: Data{off + entryLen, size}, 482 }) 483 } 484 485 // exactly16Bytes truncates the string if necessary so it is at most 16 bytes long, 486 // then pads the result with spaces to be exactly 16 bytes. 487 // Fmt uses runes for its width calculation, but we need bytes in the entry header. 488 func exactly16Bytes(s string) string { 489 for len(s) > 16 { 490 _, wid := utf8.DecodeLastRuneInString(s) 491 s = s[:len(s)-wid] 492 } 493 const sixteenSpaces = " " 494 s += sixteenSpaces[:16-len(s)] 495 return s 496 } 497 498 // architecture-independent object file output 499 const HeaderSize = 60 500 501 func ReadHeader(b *bufio.Reader, name string) int { 502 var buf [HeaderSize]byte 503 if _, err := io.ReadFull(b, buf[:]); err != nil { 504 return -1 505 } 506 aname := strings.Trim(string(buf[0:16]), " ") 507 if !strings.HasPrefix(aname, name) { 508 return -1 509 } 510 asize := strings.Trim(string(buf[48:58]), " ") 511 i, _ := strconv.Atoi(asize) 512 return i 513 } 514 515 func FormatHeader(arhdr []byte, name string, size int64) { 516 copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size)) 517 }