1 // import-archive.cc -- Go frontend read import data from an archive file.
3 // Copyright 2009 The Go Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
9 #include "go-diagnostics.h"
16 // Archive magic numbers.
18 static const char armag
[] =
20 '!', '<', 'a', 'r', 'c', 'h', '>', '\n'
23 static const char armagt
[] =
25 '!', '<', 't', 'h', 'i', 'n', '>', '\n'
28 static const char armagb
[] =
30 '<', 'b', 'i', 'g', 'a', 'f', '>', '\n'
33 static const char arfmag
[2] = { '`', '\n' };
35 // Archive fixed length header for AIX big format.
37 struct Archive_fl_header
39 // Archive magic string.
41 // Offset to member table.
43 // Offset to global symbol table.
45 // Offset to global symbol table for 64-bit objects.
47 // Offset to first archive member.
49 // Offset to last archive member.
51 // Offset to first member on free list.
55 // The header of an entry in an archive. This is all readable text,
56 // padded with spaces where necesary.
62 // The file modification time.
64 // The user's UID in decimal.
66 // The user's GID in decimal.
68 // The file mode in octal.
70 // The file size in decimal.
72 // The final magic code.
76 // The header of an entry in an AIX big archive.
77 // This is followed by ar_namlen bytes + 2 bytes for arfmag.
79 struct Archive_big_header
81 // The file size in decimal.
83 // The next member offset in decimal.
85 // The previous member offset in decimal.
87 // The file modification time in decimal.
89 // The user's UID in decimal.
91 // The user's GID in decimal.
93 // The file mode in octal.
95 // The file name length in decimal.
99 // The functions in this file extract Go export data from an archive.
101 const int Import::archive_magic_len
;
103 // Return true if BYTES, which are from the start of the file, are an
104 // archive magic number.
107 Import::is_archive_magic(const char* bytes
)
109 return (memcmp(bytes
, armag
, Import::archive_magic_len
) == 0
110 || memcmp(bytes
, armagt
, Import::archive_magic_len
) == 0
111 || memcmp(bytes
, armagb
, Import::archive_magic_len
) == 0);
114 // An object used to read an archive file.
119 Archive_file(const std::string
& filename
, int fd
, Location location
)
120 : filename_(filename
), fd_(fd
), filesize_(-1), first_member_offset_(0),
121 extended_names_(), is_thin_archive_(false), is_big_archive_(false),
122 location_(location
), nested_archives_()
129 // Return the file name.
132 { return this->filename_
; }
134 // Get the file size.
137 { return this->filesize_
; }
139 // Return the offset of the first member.
141 first_member_offset() const
142 { return this->first_member_offset_
; }
144 // Return whether this is a thin archive.
146 is_thin_archive() const
147 { return this->is_thin_archive_
; }
149 // Return whether this is a big archive.
151 is_big_archive() const
152 { return this->is_big_archive_
; }
154 // Return the location of the import statement.
157 { return this->location_
; }
161 read(off_t offset
, off_t size
, char*);
163 // Parse a decimal in readable text.
165 parse_decimal(const char* str
, off_t size
, long* res
) const;
167 // Read the archive header at OFF, setting *PNAME, *SIZE,
168 // *NESTED_OFF and *NEXT_OFF.
170 read_header(off_t off
, std::string
* pname
, off_t
* size
, off_t
* nested_off
,
173 // Interpret the header of HDR, the header of the archive member at
174 // file offset OFF. Return whether it succeeded. Set *SIZE to the
175 // size of the member. Set *PNAME to the name of the member. Set
176 // *NESTED_OFF to the offset in a nested archive.
178 interpret_header(const Archive_header
* hdr
, off_t off
,
179 std::string
* pname
, off_t
* size
, off_t
* nested_off
) const;
181 // Get the file and offset for an archive member.
183 get_file_and_offset(off_t off
, const std::string
& hdrname
,
184 off_t nested_off
, int* memfd
, off_t
* memoff
,
185 std::string
* memname
);
188 // Initialize a big archive (AIX)
190 initialize_big_archive();
192 // Initialize a normal archive
194 initialize_archive();
196 // Read the big archive header at OFF, setting *PNAME, *SIZE and *NEXT_OFF.
198 read_big_archive_header(off_t off
, std::string
* pname
,
199 off_t
* size
, off_t
* next_off
);
201 // Read the normal archive header at OFF, setting *PNAME, *SIZE,
202 // *NESTED_OFF and *NEXT_OFF.
204 read_archive_header(off_t off
, std::string
* pname
, off_t
* size
,
205 off_t
* nested_off
, off_t
* next_off
);
207 // For keeping track of open nested archives in a thin archive file.
208 typedef std::map
<std::string
, Archive_file
*> Nested_archive_table
;
210 // The name of the file.
211 std::string filename_
;
212 // The file descriptor.
216 // The first member offset;
217 off_t first_member_offset_
;
218 // The extended name table.
219 std::string extended_names_
;
220 // Whether this is a thin archive.
221 bool is_thin_archive_
;
222 // Whether this is a big archive.
223 bool is_big_archive_
;
224 // The location of the import statements.
226 // Table of nested archives.
227 Nested_archive_table nested_archives_
;
231 Archive_file::initialize()
234 if (fstat(this->fd_
, &st
) < 0)
236 go_error_at(this->location_
, "%s: %m", this->filename_
.c_str());
239 this->filesize_
= st
.st_size
;
241 char buf
[sizeof(armagt
)];
242 if (::lseek(this->fd_
, 0, SEEK_SET
) < 0
243 || ::read(this->fd_
, buf
, sizeof(armagt
)) != sizeof(armagt
))
245 go_error_at(this->location_
, "%s: %m", this->filename_
.c_str());
248 if (memcmp(buf
, armagt
, sizeof(armagt
)) == 0)
249 this->is_thin_archive_
= true;
250 else if (memcmp(buf
, armagb
, sizeof(armagb
)) == 0)
251 this->is_big_archive_
= true;
253 if (this->is_big_archive_
)
254 return this->initialize_big_archive();
256 return this->initialize_archive();
259 // Initialize a big archive (AIX).
262 Archive_file::initialize_big_archive()
264 Archive_fl_header flhdr
;
266 // Read the fixed length header.
267 if (::lseek(this->fd_
, 0, SEEK_SET
) < 0
268 || ::read(this->fd_
, &flhdr
, sizeof(flhdr
)) != sizeof(flhdr
))
270 go_error_at(this->location_
, "%s: could not read archive header",
271 this->filename_
.c_str());
275 // Parse offset of the first member.
277 if (!this->parse_decimal(flhdr
.fl_fstmoff
, sizeof(flhdr
.fl_fstmoff
), &off
))
279 char* buf
= new char[sizeof(flhdr
.fl_fstmoff
) + 1];
280 memcpy(buf
, flhdr
.fl_fstmoff
, sizeof(flhdr
.fl_fstmoff
));
281 go_error_at(this->location_
,
282 ("%s: malformed first member offset in archive header"
283 " (expected decimal, got %s)"),
284 this->filename_
.c_str(), buf
);
288 if (off
== 0) // Empty archive.
289 this->first_member_offset_
= this->filesize_
;
291 this->first_member_offset_
= off
;
295 // Initialize a normal archive.
298 Archive_file::initialize_archive()
300 this->first_member_offset_
= sizeof(armag
);
301 if (this->first_member_offset_
== this->filesize_
)
307 // Look for the extended name table.
308 std::string filename
;
311 if (!this->read_header(this->first_member_offset_
, &filename
,
312 &size
, NULL
, &next_off
))
314 if (filename
.empty())
316 // We found the symbol table.
317 if (!this->read_header(next_off
, &filename
, &size
, NULL
, NULL
))
322 char* rdbuf
= new char[size
];
323 if (::read(this->fd_
, rdbuf
, size
) != size
)
325 go_error_at(this->location_
, "%s: could not read extended names",
330 this->extended_names_
.assign(rdbuf
, size
);
337 // Read bytes from the file.
340 Archive_file::read(off_t offset
, off_t size
, char* buf
)
342 if (::lseek(this->fd_
, offset
, SEEK_SET
) < 0
343 || ::read(this->fd_
, buf
, size
) != size
)
345 go_error_at(this->location_
, "%s: %m", this->filename_
.c_str());
351 // Parse a decimal in readable text.
354 Archive_file::parse_decimal(const char* str
, off_t size
, long* res
) const
356 char* buf
= new char[size
+ 1];
357 memcpy(buf
, str
, size
);
358 char* ps
= buf
+ size
;
359 while (ps
> buf
&& ps
[-1] == ' ')
365 *res
= strtol(buf
, &end
, 10);
368 || (*res
== LONG_MAX
&& errno
== ERANGE
))
377 // Read the header at OFF. Set *PNAME to the name, *SIZE to the size,
378 // *NESTED_OFF to the nested offset, and *NEXT_OFF to the next member offset.
381 Archive_file::read_header(off_t off
, std::string
* pname
, off_t
* size
,
382 off_t
* nested_off
, off_t
* next_off
)
384 if (::lseek(this->fd_
, off
, SEEK_SET
) < 0)
386 go_error_at(this->location_
, "%s: %m", this->filename_
.c_str());
389 if (this->is_big_archive_
)
390 return this->read_big_archive_header(off
, pname
, size
, next_off
);
392 return this->read_archive_header(off
, pname
, size
, nested_off
, next_off
);
395 // Read the big archive header at OFF, setting *PNAME, *SIZE and *NEXT_OFF.
398 Archive_file::read_big_archive_header(off_t off
, std::string
* pname
,
399 off_t
* size
, off_t
* next_off
)
401 Archive_big_header hdr
;
404 got
= ::read(this->fd_
, &hdr
, sizeof hdr
);
405 if (got
!= sizeof hdr
)
408 go_error_at(this->location_
, "%s: %m", this->filename_
.c_str());
410 go_error_at(this->location_
, "%s: short entry header at %ld",
411 this->filename_
.c_str(), static_cast<long>(off
));
413 go_error_at(this->location_
, "%s: unexpected EOF at %ld",
414 this->filename_
.c_str(), static_cast<long>(off
));
418 if (!this->parse_decimal(hdr
.ar_size
, sizeof(hdr
.ar_size
), &local_size
))
420 char* buf
= new char[sizeof(hdr
.ar_size
) + 1];
421 memcpy(buf
, hdr
.ar_size
, sizeof(hdr
.ar_size
));
422 go_error_at(this->location_
,
423 ("%s: malformed ar_size in entry header at %ld"
424 " (expected decimal, got %s)"),
425 this->filename_
.c_str(), static_cast<long>(off
), buf
);
432 if (!this->parse_decimal(hdr
.ar_namlen
, sizeof(hdr
.ar_namlen
), &namlen
))
434 char* buf
= new char[sizeof(hdr
.ar_namlen
) + 1];
435 memcpy(buf
, hdr
.ar_namlen
, sizeof(hdr
.ar_namlen
));
436 go_error_at(this->location_
,
437 ("%s: malformed ar_namlen in entry header at %ld"
438 " (expected decimal, got %s)"),
439 this->filename_
.c_str(), static_cast<long>(off
), buf
);
443 // Read member name following member header.
444 char* rdbuf
= new char[namlen
];
445 got
= ::read(this->fd_
, rdbuf
, namlen
);
448 go_error_at(this->location_
,
449 "%s: malformed member name in entry header at %ld",
450 this->filename_
.c_str(), static_cast<long>(off
));
454 pname
->assign(rdbuf
, namlen
);
458 if (!this->parse_decimal(hdr
.ar_nxtmem
, sizeof(hdr
.ar_nxtmem
), &local_next_off
))
460 char* buf
= new char[sizeof(hdr
.ar_nxtmem
) + 1];
461 memcpy(buf
, hdr
.ar_nxtmem
, sizeof(hdr
.ar_nxtmem
));
462 go_error_at(this->location_
,
463 ("%s: malformed ar_nxtmem in entry header at %ld"
464 " (expected decimal, got %s)"),
465 this->filename_
.c_str(), static_cast<long>(off
), buf
);
469 if (next_off
!= NULL
)
471 if (local_next_off
== 0) // Last member.
472 *next_off
= this->filesize_
;
474 *next_off
= local_next_off
;
479 // Read the normal archive header at OFF, setting *PNAME, *SIZE,
480 // *NESTED_OFF and *NEXT_OFF.
483 Archive_file::read_archive_header(off_t off
, std::string
* pname
, off_t
* size
,
484 off_t
* nested_off
, off_t
* next_off
)
487 ssize_t got
= ::read(this->fd_
, &hdr
, sizeof hdr
);
488 if (got
!= sizeof hdr
)
491 go_error_at(this->location_
, "%s: %m", this->filename_
.c_str());
493 go_error_at(this->location_
, "%s: short archive header at %ld",
494 this->filename_
.c_str(), static_cast<long>(off
));
496 go_error_at(this->location_
, "%s: unexpected EOF at %ld",
497 this->filename_
.c_str(), static_cast<long>(off
));
499 off_t local_nested_off
;
500 if (!this->interpret_header(&hdr
, off
, pname
, size
, &local_nested_off
))
502 if (nested_off
!= NULL
)
503 *nested_off
= local_nested_off
;
505 off_t local_next_off
;
506 local_next_off
= off
+ sizeof(Archive_header
);
507 if (!this->is_thin_archive_
|| pname
->empty() || *pname
== "/")
508 local_next_off
+= *size
;
509 if ((local_next_off
& 1) != 0)
511 if (local_next_off
> this->filesize_
) // Last member.
512 local_next_off
= this->filesize_
;
513 if (next_off
!= NULL
)
514 *next_off
= local_next_off
;
518 // Interpret the header of HDR, the header of the archive member at
522 Archive_file::interpret_header(const Archive_header
* hdr
, off_t off
,
523 std::string
* pname
, off_t
* size
,
524 off_t
* nested_off
) const
526 if (memcmp(hdr
->ar_fmag
, arfmag
, sizeof arfmag
) != 0)
528 go_error_at(this->location_
, "%s: malformed archive header at %lu",
529 this->filename_
.c_str(), static_cast<unsigned long>(off
));
534 if (!this->parse_decimal(hdr
->ar_size
, sizeof hdr
->ar_size
, &local_size
))
536 go_error_at(this->location_
, "%s: malformed archive header size at %lu",
537 this->filename_
.c_str(), static_cast<unsigned long>(off
));
543 if (hdr
->ar_name
[0] != '/')
545 const char* name_end
= strchr(hdr
->ar_name
, '/');
547 || name_end
- hdr
->ar_name
>= static_cast<int>(sizeof hdr
->ar_name
))
549 go_error_at(this->location_
,
550 "%s: malformed archive header name at %lu",
551 this->filename_
.c_str(), static_cast<unsigned long>(off
));
554 pname
->assign(hdr
->ar_name
, name_end
- hdr
->ar_name
);
556 else if (hdr
->ar_name
[1] == ' ')
558 // This is the symbol table.
561 else if (hdr
->ar_name
[1] == 'S' && hdr
->ar_name
[2] == 'Y'
562 && hdr
->ar_name
[3] == 'M' && hdr
->ar_name
[4] == '6'
563 && hdr
->ar_name
[5] == '4' && hdr
->ar_name
[6] == '/'
564 && hdr
->ar_name
[7] == ' '
567 // 64-bit symbol table.
570 else if (hdr
->ar_name
[1] == '/')
572 // This is the extended name table.
573 pname
->assign(1, '/');
579 long x
= strtol(hdr
->ar_name
+ 1, &end
, 10);
582 y
= strtol(end
+ 1, &end
, 10);
585 || (x
== LONG_MAX
&& errno
== ERANGE
)
586 || static_cast<size_t>(x
) >= this->extended_names_
.size())
588 go_error_at(this->location_
, "%s: bad extended name index at %lu",
589 this->filename_
.c_str(), static_cast<unsigned long>(off
));
593 const char* name
= this->extended_names_
.data() + x
;
594 const char* name_end
= strchr(name
, '\n');
595 if (static_cast<size_t>(name_end
- name
) > this->extended_names_
.size()
596 || name_end
[-1] != '/')
598 go_error_at(this->location_
,
599 "%s: bad extended name entry at header %lu",
600 this->filename_
.c_str(), static_cast<unsigned long>(off
));
603 pname
->assign(name
, name_end
- 1 - name
);
610 // Get the file and offset for an archive member.
613 Archive_file::get_file_and_offset(off_t off
, const std::string
& hdrname
,
614 off_t nested_off
, int* memfd
, off_t
* memoff
,
615 std::string
* memname
)
617 if (this->is_big_archive_
)
620 *memoff
= (off
+ sizeof(Archive_big_header
) + hdrname
.length()
622 if ((*memoff
& 1) != 0)
624 *memname
= this->filename_
+ '(' + hdrname
+ ')';
627 else if (!this->is_thin_archive_
)
630 *memoff
= off
+ sizeof(Archive_header
);
631 *memname
= this->filename_
+ '(' + hdrname
+ ')';
635 std::string filename
= hdrname
;
636 if (!IS_ABSOLUTE_PATH(filename
.c_str()))
638 const char* archive_path
= this->filename_
.c_str();
639 const char* basename
= lbasename(archive_path
);
640 if (basename
> archive_path
)
641 filename
.replace(0, 0,
642 this->filename_
.substr(0, basename
- archive_path
));
647 // This is a member of a nested archive.
649 Nested_archive_table::const_iterator p
=
650 this->nested_archives_
.find(filename
);
651 if (p
!= this->nested_archives_
.end())
655 int nfd
= open(filename
.c_str(), O_RDONLY
| O_BINARY
);
658 go_error_at(this->location_
, "%s: can't open nested archive %s",
659 this->filename_
.c_str(), filename
.c_str());
662 nfile
= new Archive_file(filename
, nfd
, this->location_
);
663 if (!nfile
->initialize())
668 this->nested_archives_
[filename
] = nfile
;
674 if (!nfile
->read_header(nested_off
, &nname
, &nsize
, &nnested_off
, NULL
))
676 return nfile
->get_file_and_offset(nested_off
, nname
, nnested_off
,
677 memfd
, memoff
, memname
);
680 // An external member of a thin archive.
681 *memfd
= open(filename
.c_str(), O_RDONLY
| O_BINARY
);
684 go_error_at(this->location_
, "%s: %m", filename
.c_str());
692 // An archive member iterator. This is more-or-less copied from gold.
694 class Archive_iterator
697 // The header of an archive member. This is what this iterator
701 // The name of the member.
703 // The file offset of the member.
705 // The file offset of a nested archive member.
707 // The size of the member.
711 Archive_iterator(Archive_file
* afile
, off_t off
)
712 : afile_(afile
), off_(off
)
713 { this->read_next_header(); }
717 { return this->header_
; }
721 { return &this->header_
; }
726 if (this->off_
== this->afile_
->filesize())
728 this->off_
= this->next_off_
;
729 this->read_next_header();
736 Archive_iterator ret
= *this;
742 operator==(const Archive_iterator
& p
) const
743 { return this->off_
== p
->off
; }
746 operator!=(const Archive_iterator
& p
) const
747 { return this->off_
!= p
->off
; }
753 // The underlying archive file.
754 Archive_file
* afile_
;
755 // The current offset in the file.
757 // The offset of the next member.
759 // The current archive header.
763 // Read the next archive header.
766 Archive_iterator::read_next_header()
768 off_t filesize
= this->afile_
->filesize();
771 if (this->off_
== filesize
)
773 this->header_
.off
= filesize
;
777 if (!this->afile_
->read_header(this->off_
, &this->header_
.name
,
779 &this->header_
.nested_off
,
782 this->header_
.off
= filesize
;
785 this->header_
.off
= this->off_
;
787 // Skip special members.
788 if (!this->header_
.name
.empty() && this->header_
.name
!= "/")
791 this->off_
= this->next_off_
;
798 archive_begin(Archive_file
* afile
)
800 return Archive_iterator(afile
, afile
->first_member_offset());
806 archive_end(Archive_file
* afile
)
808 return Archive_iterator(afile
, afile
->filesize());
811 // A type of Import_stream which concatenates other Import_streams
814 class Stream_concatenate
: public Import::Stream
823 add(Import::Stream
* is
)
824 { this->inputs_
.push_back(is
); }
828 do_peek(size_t, const char**);
834 std::list
<Import::Stream
*> inputs_
;
840 Stream_concatenate::do_peek(size_t length
, const char** bytes
)
844 if (this->inputs_
.empty())
846 if (this->inputs_
.front()->peek(length
, bytes
))
848 delete this->inputs_
.front();
849 this->inputs_
.pop_front();
856 Stream_concatenate::do_advance(size_t skip
)
860 if (this->inputs_
.empty())
862 if (!this->inputs_
.front()->at_eof())
864 // We just assume that this will do the right thing. It
865 // should be OK since we should never want to skip past
867 this->inputs_
.front()->advance(skip
);
870 delete this->inputs_
.front();
871 this->inputs_
.pop_front();
875 // Import data from an archive. We walk through the archive and
876 // import data from each member.
879 Import::find_archive_export_data(const std::string
& filename
, int fd
,
882 Archive_file
afile(filename
, fd
, location
);
883 if (!afile
.initialize())
886 Stream_concatenate
* ret
= new Stream_concatenate
;
888 bool any_data
= false;
889 bool any_members
= false;
890 Archive_iterator pend
= archive_end(&afile
);
891 for (Archive_iterator p
= archive_begin(&afile
); p
!= pend
; p
++)
896 std::string member_name
;
897 if (!afile
.get_file_and_offset(p
->off
, p
->name
, p
->nested_off
,
898 &member_fd
, &member_off
, &member_name
))
901 Import::Stream
* is
= Import::find_object_export_data(member_name
,
914 // It's normal to have an empty archive file when using gobuild.
915 return new Stream_from_string("");