annotate gcc/go/gofrontend/import-archive.cc @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 1830386684a0
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 // import-archive.cc -- Go frontend read import data from an archive file.
kono
parents:
diff changeset
2
kono
parents:
diff changeset
3 // Copyright 2009 The Go Authors. All rights reserved.
kono
parents:
diff changeset
4 // Use of this source code is governed by a BSD-style
kono
parents:
diff changeset
5 // license that can be found in the LICENSE file.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 #include "go-system.h"
kono
parents:
diff changeset
8
kono
parents:
diff changeset
9 #include "go-diagnostics.h"
kono
parents:
diff changeset
10 #include "import.h"
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 #ifndef O_BINARY
kono
parents:
diff changeset
13 #define O_BINARY 0
kono
parents:
diff changeset
14 #endif
kono
parents:
diff changeset
15
kono
parents:
diff changeset
16 // Archive magic numbers.
kono
parents:
diff changeset
17
kono
parents:
diff changeset
18 static const char armag[] =
kono
parents:
diff changeset
19 {
kono
parents:
diff changeset
20 '!', '<', 'a', 'r', 'c', 'h', '>', '\n'
kono
parents:
diff changeset
21 };
kono
parents:
diff changeset
22
kono
parents:
diff changeset
23 static const char armagt[] =
kono
parents:
diff changeset
24 {
kono
parents:
diff changeset
25 '!', '<', 't', 'h', 'i', 'n', '>', '\n'
kono
parents:
diff changeset
26 };
kono
parents:
diff changeset
27
kono
parents:
diff changeset
28 static const char armagb[] =
kono
parents:
diff changeset
29 {
kono
parents:
diff changeset
30 '<', 'b', 'i', 'g', 'a', 'f', '>', '\n'
kono
parents:
diff changeset
31 };
kono
parents:
diff changeset
32
kono
parents:
diff changeset
33 static const char arfmag[2] = { '`', '\n' };
kono
parents:
diff changeset
34
kono
parents:
diff changeset
35 // Archive fixed length header for AIX big format.
kono
parents:
diff changeset
36
kono
parents:
diff changeset
37 struct Archive_fl_header
kono
parents:
diff changeset
38 {
kono
parents:
diff changeset
39 // Archive magic string.
kono
parents:
diff changeset
40 char fl_magic[8];
kono
parents:
diff changeset
41 // Offset to member table.
kono
parents:
diff changeset
42 char fl_memoff[20];
kono
parents:
diff changeset
43 // Offset to global symbol table.
kono
parents:
diff changeset
44 char fl_gstoff[20];
kono
parents:
diff changeset
45 // Offset to global symbol table for 64-bit objects.
kono
parents:
diff changeset
46 char fl_gst64off[20];
kono
parents:
diff changeset
47 // Offset to first archive member.
kono
parents:
diff changeset
48 char fl_fstmoff[20];
kono
parents:
diff changeset
49 // Offset to last archive member.
kono
parents:
diff changeset
50 char fl_lstmoff[20];
kono
parents:
diff changeset
51 // Offset to first member on free list.
kono
parents:
diff changeset
52 char fl_freeoff[20];
kono
parents:
diff changeset
53 };
kono
parents:
diff changeset
54
kono
parents:
diff changeset
55 // The header of an entry in an archive. This is all readable text,
kono
parents:
diff changeset
56 // padded with spaces where necesary.
kono
parents:
diff changeset
57
kono
parents:
diff changeset
58 struct Archive_header
kono
parents:
diff changeset
59 {
kono
parents:
diff changeset
60 // The entry name.
kono
parents:
diff changeset
61 char ar_name[16];
kono
parents:
diff changeset
62 // The file modification time.
kono
parents:
diff changeset
63 char ar_date[12];
kono
parents:
diff changeset
64 // The user's UID in decimal.
kono
parents:
diff changeset
65 char ar_uid[6];
kono
parents:
diff changeset
66 // The user's GID in decimal.
kono
parents:
diff changeset
67 char ar_gid[6];
kono
parents:
diff changeset
68 // The file mode in octal.
kono
parents:
diff changeset
69 char ar_mode[8];
kono
parents:
diff changeset
70 // The file size in decimal.
kono
parents:
diff changeset
71 char ar_size[10];
kono
parents:
diff changeset
72 // The final magic code.
kono
parents:
diff changeset
73 char ar_fmag[2];
kono
parents:
diff changeset
74 };
kono
parents:
diff changeset
75
kono
parents:
diff changeset
76 // The header of an entry in an AIX big archive.
kono
parents:
diff changeset
77 // This is followed by ar_namlen bytes + 2 bytes for arfmag.
kono
parents:
diff changeset
78
kono
parents:
diff changeset
79 struct Archive_big_header
kono
parents:
diff changeset
80 {
kono
parents:
diff changeset
81 // The file size in decimal.
kono
parents:
diff changeset
82 char ar_size[20];
kono
parents:
diff changeset
83 // The next member offset in decimal.
kono
parents:
diff changeset
84 char ar_nxtmem[20];
kono
parents:
diff changeset
85 // The previous member offset in decimal.
kono
parents:
diff changeset
86 char ar_prvmem[20];
kono
parents:
diff changeset
87 // The file modification time in decimal.
kono
parents:
diff changeset
88 char ar_date[12];
kono
parents:
diff changeset
89 // The user's UID in decimal.
kono
parents:
diff changeset
90 char ar_uid[12];
kono
parents:
diff changeset
91 // The user's GID in decimal.
kono
parents:
diff changeset
92 char ar_gid[12];
kono
parents:
diff changeset
93 // The file mode in octal.
kono
parents:
diff changeset
94 char ar_mode[12];
kono
parents:
diff changeset
95 // The file name length in decimal.
kono
parents:
diff changeset
96 char ar_namlen[4];
kono
parents:
diff changeset
97 };
kono
parents:
diff changeset
98
kono
parents:
diff changeset
99 // The functions in this file extract Go export data from an archive.
kono
parents:
diff changeset
100
kono
parents:
diff changeset
101 const int Import::archive_magic_len;
kono
parents:
diff changeset
102
kono
parents:
diff changeset
103 // Return true if BYTES, which are from the start of the file, are an
kono
parents:
diff changeset
104 // archive magic number.
kono
parents:
diff changeset
105
kono
parents:
diff changeset
106 bool
kono
parents:
diff changeset
107 Import::is_archive_magic(const char* bytes)
kono
parents:
diff changeset
108 {
kono
parents:
diff changeset
109 return (memcmp(bytes, armag, Import::archive_magic_len) == 0
kono
parents:
diff changeset
110 || memcmp(bytes, armagt, Import::archive_magic_len) == 0
kono
parents:
diff changeset
111 || memcmp(bytes, armagb, Import::archive_magic_len) == 0);
kono
parents:
diff changeset
112 }
kono
parents:
diff changeset
113
kono
parents:
diff changeset
114 // An object used to read an archive file.
kono
parents:
diff changeset
115
kono
parents:
diff changeset
116 class Archive_file
kono
parents:
diff changeset
117 {
kono
parents:
diff changeset
118 public:
kono
parents:
diff changeset
119 Archive_file(const std::string& filename, int fd, Location location)
kono
parents:
diff changeset
120 : filename_(filename), fd_(fd), filesize_(-1), first_member_offset_(0),
kono
parents:
diff changeset
121 extended_names_(), is_thin_archive_(false), is_big_archive_(false),
kono
parents:
diff changeset
122 location_(location), nested_archives_()
kono
parents:
diff changeset
123 { }
kono
parents:
diff changeset
124
kono
parents:
diff changeset
125 // Initialize.
kono
parents:
diff changeset
126 bool
kono
parents:
diff changeset
127 initialize();
kono
parents:
diff changeset
128
kono
parents:
diff changeset
129 // Return the file name.
kono
parents:
diff changeset
130 const std::string&
kono
parents:
diff changeset
131 filename() const
kono
parents:
diff changeset
132 { return this->filename_; }
kono
parents:
diff changeset
133
kono
parents:
diff changeset
134 // Get the file size.
kono
parents:
diff changeset
135 off_t
kono
parents:
diff changeset
136 filesize() const
kono
parents:
diff changeset
137 { return this->filesize_; }
kono
parents:
diff changeset
138
kono
parents:
diff changeset
139 // Return the offset of the first member.
kono
parents:
diff changeset
140 off_t
kono
parents:
diff changeset
141 first_member_offset() const
kono
parents:
diff changeset
142 { return this->first_member_offset_; }
kono
parents:
diff changeset
143
kono
parents:
diff changeset
144 // Return whether this is a thin archive.
kono
parents:
diff changeset
145 bool
kono
parents:
diff changeset
146 is_thin_archive() const
kono
parents:
diff changeset
147 { return this->is_thin_archive_; }
kono
parents:
diff changeset
148
kono
parents:
diff changeset
149 // Return whether this is a big archive.
kono
parents:
diff changeset
150 bool
kono
parents:
diff changeset
151 is_big_archive() const
kono
parents:
diff changeset
152 { return this->is_big_archive_; }
kono
parents:
diff changeset
153
kono
parents:
diff changeset
154 // Return the location of the import statement.
kono
parents:
diff changeset
155 Location
kono
parents:
diff changeset
156 location() const
kono
parents:
diff changeset
157 { return this->location_; }
kono
parents:
diff changeset
158
kono
parents:
diff changeset
159 // Read bytes.
kono
parents:
diff changeset
160 bool
kono
parents:
diff changeset
161 read(off_t offset, off_t size, char*);
kono
parents:
diff changeset
162
kono
parents:
diff changeset
163 // Parse a decimal in readable text.
kono
parents:
diff changeset
164 bool
kono
parents:
diff changeset
165 parse_decimal(const char* str, off_t size, long* res) const;
kono
parents:
diff changeset
166
kono
parents:
diff changeset
167 // Read the archive header at OFF, setting *PNAME, *SIZE,
kono
parents:
diff changeset
168 // *NESTED_OFF and *NEXT_OFF.
kono
parents:
diff changeset
169 bool
kono
parents:
diff changeset
170 read_header(off_t off, std::string* pname, off_t* size, off_t* nested_off,
kono
parents:
diff changeset
171 off_t* next_off);
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 // Interpret the header of HDR, the header of the archive member at
kono
parents:
diff changeset
174 // file offset OFF. Return whether it succeeded. Set *SIZE to the
kono
parents:
diff changeset
175 // size of the member. Set *PNAME to the name of the member. Set
kono
parents:
diff changeset
176 // *NESTED_OFF to the offset in a nested archive.
kono
parents:
diff changeset
177 bool
kono
parents:
diff changeset
178 interpret_header(const Archive_header* hdr, off_t off,
kono
parents:
diff changeset
179 std::string* pname, off_t* size, off_t* nested_off) const;
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 // Get the file and offset for an archive member.
kono
parents:
diff changeset
182 bool
kono
parents:
diff changeset
183 get_file_and_offset(off_t off, const std::string& hdrname,
kono
parents:
diff changeset
184 off_t nested_off, int* memfd, off_t* memoff,
kono
parents:
diff changeset
185 std::string* memname);
kono
parents:
diff changeset
186
kono
parents:
diff changeset
187 private:
kono
parents:
diff changeset
188 // Initialize a big archive (AIX)
kono
parents:
diff changeset
189 bool
kono
parents:
diff changeset
190 initialize_big_archive();
kono
parents:
diff changeset
191
kono
parents:
diff changeset
192 // Initialize a normal archive
kono
parents:
diff changeset
193 bool
kono
parents:
diff changeset
194 initialize_archive();
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 // Read the big archive header at OFF, setting *PNAME, *SIZE and *NEXT_OFF.
kono
parents:
diff changeset
197 bool
kono
parents:
diff changeset
198 read_big_archive_header(off_t off, std::string* pname,
kono
parents:
diff changeset
199 off_t* size, off_t* next_off);
kono
parents:
diff changeset
200
kono
parents:
diff changeset
201 // Read the normal archive header at OFF, setting *PNAME, *SIZE,
kono
parents:
diff changeset
202 // *NESTED_OFF and *NEXT_OFF.
kono
parents:
diff changeset
203 bool
kono
parents:
diff changeset
204 read_archive_header(off_t off, std::string* pname, off_t* size,
kono
parents:
diff changeset
205 off_t* nested_off, off_t* next_off);
kono
parents:
diff changeset
206
kono
parents:
diff changeset
207 // For keeping track of open nested archives in a thin archive file.
kono
parents:
diff changeset
208 typedef std::map<std::string, Archive_file*> Nested_archive_table;
kono
parents:
diff changeset
209
kono
parents:
diff changeset
210 // The name of the file.
kono
parents:
diff changeset
211 std::string filename_;
kono
parents:
diff changeset
212 // The file descriptor.
kono
parents:
diff changeset
213 int fd_;
kono
parents:
diff changeset
214 // The file size;
kono
parents:
diff changeset
215 off_t filesize_;
kono
parents:
diff changeset
216 // The first member offset;
kono
parents:
diff changeset
217 off_t first_member_offset_;
kono
parents:
diff changeset
218 // The extended name table.
kono
parents:
diff changeset
219 std::string extended_names_;
kono
parents:
diff changeset
220 // Whether this is a thin archive.
kono
parents:
diff changeset
221 bool is_thin_archive_;
kono
parents:
diff changeset
222 // Whether this is a big archive.
kono
parents:
diff changeset
223 bool is_big_archive_;
kono
parents:
diff changeset
224 // The location of the import statements.
kono
parents:
diff changeset
225 Location location_;
kono
parents:
diff changeset
226 // Table of nested archives.
kono
parents:
diff changeset
227 Nested_archive_table nested_archives_;
kono
parents:
diff changeset
228 };
kono
parents:
diff changeset
229
kono
parents:
diff changeset
230 bool
kono
parents:
diff changeset
231 Archive_file::initialize()
kono
parents:
diff changeset
232 {
kono
parents:
diff changeset
233 struct stat st;
kono
parents:
diff changeset
234 if (fstat(this->fd_, &st) < 0)
kono
parents:
diff changeset
235 {
kono
parents:
diff changeset
236 go_error_at(this->location_, "%s: %m", this->filename_.c_str());
kono
parents:
diff changeset
237 return false;
kono
parents:
diff changeset
238 }
kono
parents:
diff changeset
239 this->filesize_ = st.st_size;
kono
parents:
diff changeset
240
kono
parents:
diff changeset
241 char buf[sizeof(armagt)];
kono
parents:
diff changeset
242 if (::lseek(this->fd_, 0, SEEK_SET) < 0
kono
parents:
diff changeset
243 || ::read(this->fd_, buf, sizeof(armagt)) != sizeof(armagt))
kono
parents:
diff changeset
244 {
kono
parents:
diff changeset
245 go_error_at(this->location_, "%s: %m", this->filename_.c_str());
kono
parents:
diff changeset
246 return false;
kono
parents:
diff changeset
247 }
kono
parents:
diff changeset
248 if (memcmp(buf, armagt, sizeof(armagt)) == 0)
kono
parents:
diff changeset
249 this->is_thin_archive_ = true;
kono
parents:
diff changeset
250 else if (memcmp(buf, armagb, sizeof(armagb)) == 0)
kono
parents:
diff changeset
251 this->is_big_archive_ = true;
kono
parents:
diff changeset
252
kono
parents:
diff changeset
253 if (this->is_big_archive_)
kono
parents:
diff changeset
254 return this->initialize_big_archive();
kono
parents:
diff changeset
255 else
kono
parents:
diff changeset
256 return this->initialize_archive();
kono
parents:
diff changeset
257 }
kono
parents:
diff changeset
258
kono
parents:
diff changeset
259 // Initialize a big archive (AIX).
kono
parents:
diff changeset
260
kono
parents:
diff changeset
261 bool
kono
parents:
diff changeset
262 Archive_file::initialize_big_archive()
kono
parents:
diff changeset
263 {
kono
parents:
diff changeset
264 Archive_fl_header flhdr;
kono
parents:
diff changeset
265
kono
parents:
diff changeset
266 // Read the fixed length header.
kono
parents:
diff changeset
267 if (::lseek(this->fd_, 0, SEEK_SET) < 0
kono
parents:
diff changeset
268 || ::read(this->fd_, &flhdr, sizeof(flhdr)) != sizeof(flhdr))
kono
parents:
diff changeset
269 {
kono
parents:
diff changeset
270 go_error_at(this->location_, "%s: could not read archive header",
kono
parents:
diff changeset
271 this->filename_.c_str());
kono
parents:
diff changeset
272 return false;
kono
parents:
diff changeset
273 }
kono
parents:
diff changeset
274
kono
parents:
diff changeset
275 // Parse offset of the first member.
kono
parents:
diff changeset
276 long off;
kono
parents:
diff changeset
277 if (!this->parse_decimal(flhdr.fl_fstmoff, sizeof(flhdr.fl_fstmoff), &off))
kono
parents:
diff changeset
278 {
kono
parents:
diff changeset
279 char* buf = new char[sizeof(flhdr.fl_fstmoff) + 1];
kono
parents:
diff changeset
280 memcpy(buf, flhdr.fl_fstmoff, sizeof(flhdr.fl_fstmoff));
kono
parents:
diff changeset
281 go_error_at(this->location_,
kono
parents:
diff changeset
282 ("%s: malformed first member offset in archive header"
kono
parents:
diff changeset
283 " (expected decimal, got %s)"),
kono
parents:
diff changeset
284 this->filename_.c_str(), buf);
kono
parents:
diff changeset
285 delete[] buf;
kono
parents:
diff changeset
286 return false;
kono
parents:
diff changeset
287 }
kono
parents:
diff changeset
288 if (off == 0) // Empty archive.
kono
parents:
diff changeset
289 this->first_member_offset_ = this->filesize_;
kono
parents:
diff changeset
290 else
kono
parents:
diff changeset
291 this->first_member_offset_ = off;
kono
parents:
diff changeset
292 return true;
kono
parents:
diff changeset
293 }
kono
parents:
diff changeset
294
kono
parents:
diff changeset
295 // Initialize a normal archive.
kono
parents:
diff changeset
296
kono
parents:
diff changeset
297 bool
kono
parents:
diff changeset
298 Archive_file::initialize_archive()
kono
parents:
diff changeset
299 {
kono
parents:
diff changeset
300 this->first_member_offset_ = sizeof(armag);
kono
parents:
diff changeset
301 if (this->first_member_offset_ == this->filesize_)
kono
parents:
diff changeset
302 {
kono
parents:
diff changeset
303 // Empty archive.
kono
parents:
diff changeset
304 return true;
kono
parents:
diff changeset
305 }
kono
parents:
diff changeset
306
kono
parents:
diff changeset
307 // Look for the extended name table.
kono
parents:
diff changeset
308 std::string filename;
kono
parents:
diff changeset
309 off_t size;
kono
parents:
diff changeset
310 off_t next_off;
kono
parents:
diff changeset
311 if (!this->read_header(this->first_member_offset_, &filename,
kono
parents:
diff changeset
312 &size, NULL, &next_off))
kono
parents:
diff changeset
313 return false;
kono
parents:
diff changeset
314 if (filename.empty())
kono
parents:
diff changeset
315 {
kono
parents:
diff changeset
316 // We found the symbol table.
kono
parents:
diff changeset
317 if (!this->read_header(next_off, &filename, &size, NULL, NULL))
kono
parents:
diff changeset
318 filename.clear();
kono
parents:
diff changeset
319 }
kono
parents:
diff changeset
320 if (filename == "/")
kono
parents:
diff changeset
321 {
kono
parents:
diff changeset
322 char* rdbuf = new char[size];
kono
parents:
diff changeset
323 if (::read(this->fd_, rdbuf, size) != size)
kono
parents:
diff changeset
324 {
kono
parents:
diff changeset
325 go_error_at(this->location_, "%s: could not read extended names",
kono
parents:
diff changeset
326 filename.c_str());
kono
parents:
diff changeset
327 delete[] rdbuf;
kono
parents:
diff changeset
328 return false;
kono
parents:
diff changeset
329 }
kono
parents:
diff changeset
330 this->extended_names_.assign(rdbuf, size);
kono
parents:
diff changeset
331 delete[] rdbuf;
kono
parents:
diff changeset
332 }
kono
parents:
diff changeset
333
kono
parents:
diff changeset
334 return true;
kono
parents:
diff changeset
335 }
kono
parents:
diff changeset
336
kono
parents:
diff changeset
337 // Read bytes from the file.
kono
parents:
diff changeset
338
kono
parents:
diff changeset
339 bool
kono
parents:
diff changeset
340 Archive_file::read(off_t offset, off_t size, char* buf)
kono
parents:
diff changeset
341 {
kono
parents:
diff changeset
342 if (::lseek(this->fd_, offset, SEEK_SET) < 0
kono
parents:
diff changeset
343 || ::read(this->fd_, buf, size) != size)
kono
parents:
diff changeset
344 {
kono
parents:
diff changeset
345 go_error_at(this->location_, "%s: %m", this->filename_.c_str());
kono
parents:
diff changeset
346 return false;
kono
parents:
diff changeset
347 }
kono
parents:
diff changeset
348 return true;
kono
parents:
diff changeset
349 }
kono
parents:
diff changeset
350
kono
parents:
diff changeset
351 // Parse a decimal in readable text.
kono
parents:
diff changeset
352
kono
parents:
diff changeset
353 bool
kono
parents:
diff changeset
354 Archive_file::parse_decimal(const char* str, off_t size, long* res) const
kono
parents:
diff changeset
355 {
kono
parents:
diff changeset
356 char* buf = new char[size + 1];
kono
parents:
diff changeset
357 memcpy(buf, str, size);
kono
parents:
diff changeset
358 char* ps = buf + size;
kono
parents:
diff changeset
359 while (ps > buf && ps[-1] == ' ')
kono
parents:
diff changeset
360 --ps;
kono
parents:
diff changeset
361 *ps = '\0';
kono
parents:
diff changeset
362
kono
parents:
diff changeset
363 errno = 0;
kono
parents:
diff changeset
364 char* end;
kono
parents:
diff changeset
365 *res = strtol(buf, &end, 10);
kono
parents:
diff changeset
366 if (*end != '\0'
kono
parents:
diff changeset
367 || *res < 0
kono
parents:
diff changeset
368 || (*res == LONG_MAX && errno == ERANGE))
kono
parents:
diff changeset
369 {
kono
parents:
diff changeset
370 delete[] buf;
kono
parents:
diff changeset
371 return false;
kono
parents:
diff changeset
372 }
kono
parents:
diff changeset
373 delete[] buf;
kono
parents:
diff changeset
374 return true;
kono
parents:
diff changeset
375 }
kono
parents:
diff changeset
376
kono
parents:
diff changeset
377 // Read the header at OFF. Set *PNAME to the name, *SIZE to the size,
kono
parents:
diff changeset
378 // *NESTED_OFF to the nested offset, and *NEXT_OFF to the next member offset.
kono
parents:
diff changeset
379
kono
parents:
diff changeset
380 bool
kono
parents:
diff changeset
381 Archive_file::read_header(off_t off, std::string* pname, off_t* size,
kono
parents:
diff changeset
382 off_t* nested_off, off_t* next_off)
kono
parents:
diff changeset
383 {
kono
parents:
diff changeset
384 if (::lseek(this->fd_, off, SEEK_SET) < 0)
kono
parents:
diff changeset
385 {
kono
parents:
diff changeset
386 go_error_at(this->location_, "%s: %m", this->filename_.c_str());
kono
parents:
diff changeset
387 return false;
kono
parents:
diff changeset
388 }
kono
parents:
diff changeset
389 if (this->is_big_archive_)
kono
parents:
diff changeset
390 return this->read_big_archive_header(off, pname, size, next_off);
kono
parents:
diff changeset
391 else
kono
parents:
diff changeset
392 return this->read_archive_header(off, pname, size, nested_off, next_off);
kono
parents:
diff changeset
393 }
kono
parents:
diff changeset
394
kono
parents:
diff changeset
395 // Read the big archive header at OFF, setting *PNAME, *SIZE and *NEXT_OFF.
kono
parents:
diff changeset
396
kono
parents:
diff changeset
397 bool
kono
parents:
diff changeset
398 Archive_file::read_big_archive_header(off_t off, std::string* pname,
kono
parents:
diff changeset
399 off_t* size, off_t* next_off)
kono
parents:
diff changeset
400 {
kono
parents:
diff changeset
401 Archive_big_header hdr;
kono
parents:
diff changeset
402 ssize_t got;
kono
parents:
diff changeset
403
kono
parents:
diff changeset
404 got = ::read(this->fd_, &hdr, sizeof hdr);
kono
parents:
diff changeset
405 if (got != sizeof hdr)
kono
parents:
diff changeset
406 {
kono
parents:
diff changeset
407 if (got < 0)
kono
parents:
diff changeset
408 go_error_at(this->location_, "%s: %m", this->filename_.c_str());
kono
parents:
diff changeset
409 else if (got > 0)
kono
parents:
diff changeset
410 go_error_at(this->location_, "%s: short entry header at %ld",
kono
parents:
diff changeset
411 this->filename_.c_str(), static_cast<long>(off));
kono
parents:
diff changeset
412 else
kono
parents:
diff changeset
413 go_error_at(this->location_, "%s: unexpected EOF at %ld",
kono
parents:
diff changeset
414 this->filename_.c_str(), static_cast<long>(off));
kono
parents:
diff changeset
415 }
kono
parents:
diff changeset
416
kono
parents:
diff changeset
417 long local_size;
kono
parents:
diff changeset
418 if (!this->parse_decimal(hdr.ar_size, sizeof(hdr.ar_size), &local_size))
kono
parents:
diff changeset
419 {
kono
parents:
diff changeset
420 char* buf = new char[sizeof(hdr.ar_size) + 1];
kono
parents:
diff changeset
421 memcpy(buf, hdr.ar_size, sizeof(hdr.ar_size));
kono
parents:
diff changeset
422 go_error_at(this->location_,
kono
parents:
diff changeset
423 ("%s: malformed ar_size in entry header at %ld"
kono
parents:
diff changeset
424 " (expected decimal, got %s)"),
kono
parents:
diff changeset
425 this->filename_.c_str(), static_cast<long>(off), buf);
kono
parents:
diff changeset
426 delete[] buf;
kono
parents:
diff changeset
427 return false;
kono
parents:
diff changeset
428 }
kono
parents:
diff changeset
429 *size = local_size;
kono
parents:
diff changeset
430
kono
parents:
diff changeset
431 long namlen;
kono
parents:
diff changeset
432 if (!this->parse_decimal(hdr.ar_namlen, sizeof(hdr.ar_namlen), &namlen))
kono
parents:
diff changeset
433 {
kono
parents:
diff changeset
434 char* buf = new char[sizeof(hdr.ar_namlen) + 1];
kono
parents:
diff changeset
435 memcpy(buf, hdr.ar_namlen, sizeof(hdr.ar_namlen));
kono
parents:
diff changeset
436 go_error_at(this->location_,
kono
parents:
diff changeset
437 ("%s: malformed ar_namlen in entry header at %ld"
kono
parents:
diff changeset
438 " (expected decimal, got %s)"),
kono
parents:
diff changeset
439 this->filename_.c_str(), static_cast<long>(off), buf);
kono
parents:
diff changeset
440 delete[] buf;
kono
parents:
diff changeset
441 return false;
kono
parents:
diff changeset
442 }
kono
parents:
diff changeset
443 // Read member name following member header.
kono
parents:
diff changeset
444 char* rdbuf = new char[namlen];
kono
parents:
diff changeset
445 got = ::read(this->fd_, rdbuf, namlen);
kono
parents:
diff changeset
446 if (got != namlen)
kono
parents:
diff changeset
447 {
kono
parents:
diff changeset
448 go_error_at(this->location_,
kono
parents:
diff changeset
449 "%s: malformed member name in entry header at %ld",
kono
parents:
diff changeset
450 this->filename_.c_str(), static_cast<long>(off));
kono
parents:
diff changeset
451 delete[] rdbuf;
kono
parents:
diff changeset
452 return false;
kono
parents:
diff changeset
453 }
kono
parents:
diff changeset
454 pname->assign(rdbuf, namlen);
kono
parents:
diff changeset
455 delete[] rdbuf;
kono
parents:
diff changeset
456
kono
parents:
diff changeset
457 long local_next_off;
kono
parents:
diff changeset
458 if (!this->parse_decimal(hdr.ar_nxtmem, sizeof(hdr.ar_nxtmem), &local_next_off))
kono
parents:
diff changeset
459 {
kono
parents:
diff changeset
460 char* buf = new char[sizeof(hdr.ar_nxtmem) + 1];
kono
parents:
diff changeset
461 memcpy(buf, hdr.ar_nxtmem, sizeof(hdr.ar_nxtmem));
kono
parents:
diff changeset
462 go_error_at(this->location_,
kono
parents:
diff changeset
463 ("%s: malformed ar_nxtmem in entry header at %ld"
kono
parents:
diff changeset
464 " (expected decimal, got %s)"),
kono
parents:
diff changeset
465 this->filename_.c_str(), static_cast<long>(off), buf);
kono
parents:
diff changeset
466 delete[] buf;
kono
parents:
diff changeset
467 return false;
kono
parents:
diff changeset
468 }
kono
parents:
diff changeset
469 if (next_off != NULL)
kono
parents:
diff changeset
470 {
kono
parents:
diff changeset
471 if (local_next_off == 0) // Last member.
kono
parents:
diff changeset
472 *next_off = this->filesize_;
kono
parents:
diff changeset
473 else
kono
parents:
diff changeset
474 *next_off = local_next_off;
kono
parents:
diff changeset
475 }
kono
parents:
diff changeset
476 return true;
kono
parents:
diff changeset
477 }
kono
parents:
diff changeset
478
kono
parents:
diff changeset
479 // Read the normal archive header at OFF, setting *PNAME, *SIZE,
kono
parents:
diff changeset
480 // *NESTED_OFF and *NEXT_OFF.
kono
parents:
diff changeset
481
kono
parents:
diff changeset
482 bool
kono
parents:
diff changeset
483 Archive_file::read_archive_header(off_t off, std::string* pname, off_t* size,
kono
parents:
diff changeset
484 off_t* nested_off, off_t* next_off)
kono
parents:
diff changeset
485 {
kono
parents:
diff changeset
486 Archive_header hdr;
kono
parents:
diff changeset
487 ssize_t got = ::read(this->fd_, &hdr, sizeof hdr);
kono
parents:
diff changeset
488 if (got != sizeof hdr)
kono
parents:
diff changeset
489 {
kono
parents:
diff changeset
490 if (got < 0)
kono
parents:
diff changeset
491 go_error_at(this->location_, "%s: %m", this->filename_.c_str());
kono
parents:
diff changeset
492 else if (got > 0)
kono
parents:
diff changeset
493 go_error_at(this->location_, "%s: short archive header at %ld",
kono
parents:
diff changeset
494 this->filename_.c_str(), static_cast<long>(off));
kono
parents:
diff changeset
495 else
kono
parents:
diff changeset
496 go_error_at(this->location_, "%s: unexpected EOF at %ld",
kono
parents:
diff changeset
497 this->filename_.c_str(), static_cast<long>(off));
kono
parents:
diff changeset
498 }
kono
parents:
diff changeset
499 off_t local_nested_off;
kono
parents:
diff changeset
500 if (!this->interpret_header(&hdr, off, pname, size, &local_nested_off))
kono
parents:
diff changeset
501 return false;
kono
parents:
diff changeset
502 if (nested_off != NULL)
kono
parents:
diff changeset
503 *nested_off = local_nested_off;
kono
parents:
diff changeset
504
kono
parents:
diff changeset
505 off_t local_next_off;
kono
parents:
diff changeset
506 local_next_off = off + sizeof(Archive_header);
kono
parents:
diff changeset
507 if (!this->is_thin_archive_ || pname->empty() || *pname == "/")
kono
parents:
diff changeset
508 local_next_off += *size;
kono
parents:
diff changeset
509 if ((local_next_off & 1) != 0)
kono
parents:
diff changeset
510 ++local_next_off;
kono
parents:
diff changeset
511 if (local_next_off > this->filesize_) // Last member.
kono
parents:
diff changeset
512 local_next_off = this->filesize_;
kono
parents:
diff changeset
513 if (next_off != NULL)
kono
parents:
diff changeset
514 *next_off = local_next_off;
kono
parents:
diff changeset
515 return true;
kono
parents:
diff changeset
516 }
kono
parents:
diff changeset
517
kono
parents:
diff changeset
518 // Interpret the header of HDR, the header of the archive member at
kono
parents:
diff changeset
519 // file offset OFF.
kono
parents:
diff changeset
520
kono
parents:
diff changeset
521 bool
kono
parents:
diff changeset
522 Archive_file::interpret_header(const Archive_header* hdr, off_t off,
kono
parents:
diff changeset
523 std::string* pname, off_t* size,
kono
parents:
diff changeset
524 off_t* nested_off) const
kono
parents:
diff changeset
525 {
kono
parents:
diff changeset
526 if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
kono
parents:
diff changeset
527 {
kono
parents:
diff changeset
528 go_error_at(this->location_, "%s: malformed archive header at %lu",
kono
parents:
diff changeset
529 this->filename_.c_str(), static_cast<unsigned long>(off));
kono
parents:
diff changeset
530 return false;
kono
parents:
diff changeset
531 }
kono
parents:
diff changeset
532
kono
parents:
diff changeset
533 long local_size;
kono
parents:
diff changeset
534 if (!this->parse_decimal(hdr->ar_size, sizeof hdr->ar_size, &local_size))
kono
parents:
diff changeset
535 {
kono
parents:
diff changeset
536 go_error_at(this->location_, "%s: malformed archive header size at %lu",
kono
parents:
diff changeset
537 this->filename_.c_str(), static_cast<unsigned long>(off));
kono
parents:
diff changeset
538 return false;
kono
parents:
diff changeset
539 }
kono
parents:
diff changeset
540 *size = local_size;
kono
parents:
diff changeset
541
kono
parents:
diff changeset
542 *nested_off = 0;
kono
parents:
diff changeset
543 if (hdr->ar_name[0] != '/')
kono
parents:
diff changeset
544 {
kono
parents:
diff changeset
545 const char* name_end = strchr(hdr->ar_name, '/');
kono
parents:
diff changeset
546 if (name_end == NULL
kono
parents:
diff changeset
547 || name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
kono
parents:
diff changeset
548 {
kono
parents:
diff changeset
549 go_error_at(this->location_,
kono
parents:
diff changeset
550 "%s: malformed archive header name at %lu",
kono
parents:
diff changeset
551 this->filename_.c_str(), static_cast<unsigned long>(off));
kono
parents:
diff changeset
552 return false;
kono
parents:
diff changeset
553 }
kono
parents:
diff changeset
554 pname->assign(hdr->ar_name, name_end - hdr->ar_name);
kono
parents:
diff changeset
555 }
kono
parents:
diff changeset
556 else if (hdr->ar_name[1] == ' ')
kono
parents:
diff changeset
557 {
kono
parents:
diff changeset
558 // This is the symbol table.
kono
parents:
diff changeset
559 pname->clear();
kono
parents:
diff changeset
560 }
kono
parents:
diff changeset
561 else if (hdr->ar_name[1] == 'S' && hdr->ar_name[2] == 'Y'
kono
parents:
diff changeset
562 && hdr->ar_name[3] == 'M' && hdr->ar_name[4] == '6'
kono
parents:
diff changeset
563 && hdr->ar_name[5] == '4' && hdr->ar_name[6] == '/'
kono
parents:
diff changeset
564 && hdr->ar_name[7] == ' '
kono
parents:
diff changeset
565 )
kono
parents:
diff changeset
566 {
kono
parents:
diff changeset
567 // 64-bit symbol table.
kono
parents:
diff changeset
568 pname->clear();
kono
parents:
diff changeset
569 }
kono
parents:
diff changeset
570 else if (hdr->ar_name[1] == '/')
kono
parents:
diff changeset
571 {
kono
parents:
diff changeset
572 // This is the extended name table.
kono
parents:
diff changeset
573 pname->assign(1, '/');
kono
parents:
diff changeset
574 }
kono
parents:
diff changeset
575 else
kono
parents:
diff changeset
576 {
kono
parents:
diff changeset
577 char* end;
kono
parents:
diff changeset
578 errno = 0;
kono
parents:
diff changeset
579 long x = strtol(hdr->ar_name + 1, &end, 10);
kono
parents:
diff changeset
580 long y = 0;
kono
parents:
diff changeset
581 if (*end == ':')
kono
parents:
diff changeset
582 y = strtol(end + 1, &end, 10);
kono
parents:
diff changeset
583 if (*end != ' '
kono
parents:
diff changeset
584 || x < 0
kono
parents:
diff changeset
585 || (x == LONG_MAX && errno == ERANGE)
kono
parents:
diff changeset
586 || static_cast<size_t>(x) >= this->extended_names_.size())
kono
parents:
diff changeset
587 {
kono
parents:
diff changeset
588 go_error_at(this->location_, "%s: bad extended name index at %lu",
kono
parents:
diff changeset
589 this->filename_.c_str(), static_cast<unsigned long>(off));
kono
parents:
diff changeset
590 return false;
kono
parents:
diff changeset
591 }
kono
parents:
diff changeset
592
kono
parents:
diff changeset
593 const char* name = this->extended_names_.data() + x;
kono
parents:
diff changeset
594 const char* name_end = strchr(name, '\n');
kono
parents:
diff changeset
595 if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
kono
parents:
diff changeset
596 || name_end[-1] != '/')
kono
parents:
diff changeset
597 {
kono
parents:
diff changeset
598 go_error_at(this->location_,
kono
parents:
diff changeset
599 "%s: bad extended name entry at header %lu",
kono
parents:
diff changeset
600 this->filename_.c_str(), static_cast<unsigned long>(off));
kono
parents:
diff changeset
601 return false;
kono
parents:
diff changeset
602 }
kono
parents:
diff changeset
603 pname->assign(name, name_end - 1 - name);
kono
parents:
diff changeset
604 *nested_off = y;
kono
parents:
diff changeset
605 }
kono
parents:
diff changeset
606
kono
parents:
diff changeset
607 return true;
kono
parents:
diff changeset
608 }
kono
parents:
diff changeset
609
kono
parents:
diff changeset
610 // Get the file and offset for an archive member.
kono
parents:
diff changeset
611
kono
parents:
diff changeset
612 bool
kono
parents:
diff changeset
613 Archive_file::get_file_and_offset(off_t off, const std::string& hdrname,
kono
parents:
diff changeset
614 off_t nested_off, int* memfd, off_t* memoff,
kono
parents:
diff changeset
615 std::string* memname)
kono
parents:
diff changeset
616 {
kono
parents:
diff changeset
617 if (this->is_big_archive_)
kono
parents:
diff changeset
618 {
kono
parents:
diff changeset
619 *memfd = this->fd_;
kono
parents:
diff changeset
620 *memoff = (off + sizeof(Archive_big_header) + hdrname.length()
kono
parents:
diff changeset
621 + sizeof(arfmag));
kono
parents:
diff changeset
622 if ((*memoff & 1) != 0)
kono
parents:
diff changeset
623 ++*memoff;
kono
parents:
diff changeset
624 *memname = this->filename_ + '(' + hdrname + ')';
kono
parents:
diff changeset
625 return true;
kono
parents:
diff changeset
626 }
kono
parents:
diff changeset
627 else if (!this->is_thin_archive_)
kono
parents:
diff changeset
628 {
kono
parents:
diff changeset
629 *memfd = this->fd_;
kono
parents:
diff changeset
630 *memoff = off + sizeof(Archive_header);
kono
parents:
diff changeset
631 *memname = this->filename_ + '(' + hdrname + ')';
kono
parents:
diff changeset
632 return true;
kono
parents:
diff changeset
633 }
kono
parents:
diff changeset
634
kono
parents:
diff changeset
635 std::string filename = hdrname;
kono
parents:
diff changeset
636 if (!IS_ABSOLUTE_PATH(filename.c_str()))
kono
parents:
diff changeset
637 {
kono
parents:
diff changeset
638 const char* archive_path = this->filename_.c_str();
kono
parents:
diff changeset
639 const char* basename = lbasename(archive_path);
kono
parents:
diff changeset
640 if (basename > archive_path)
kono
parents:
diff changeset
641 filename.replace(0, 0,
kono
parents:
diff changeset
642 this->filename_.substr(0, basename - archive_path));
kono
parents:
diff changeset
643 }
kono
parents:
diff changeset
644
kono
parents:
diff changeset
645 if (nested_off > 0)
kono
parents:
diff changeset
646 {
kono
parents:
diff changeset
647 // This is a member of a nested archive.
kono
parents:
diff changeset
648 Archive_file* nfile;
kono
parents:
diff changeset
649 Nested_archive_table::const_iterator p =
kono
parents:
diff changeset
650 this->nested_archives_.find(filename);
kono
parents:
diff changeset
651 if (p != this->nested_archives_.end())
kono
parents:
diff changeset
652 nfile = p->second;
kono
parents:
diff changeset
653 else
kono
parents:
diff changeset
654 {
kono
parents:
diff changeset
655 int nfd = open(filename.c_str(), O_RDONLY | O_BINARY);
kono
parents:
diff changeset
656 if (nfd < 0)
kono
parents:
diff changeset
657 {
kono
parents:
diff changeset
658 go_error_at(this->location_, "%s: can't open nested archive %s",
kono
parents:
diff changeset
659 this->filename_.c_str(), filename.c_str());
kono
parents:
diff changeset
660 return false;
kono
parents:
diff changeset
661 }
kono
parents:
diff changeset
662 nfile = new Archive_file(filename, nfd, this->location_);
kono
parents:
diff changeset
663 if (!nfile->initialize())
kono
parents:
diff changeset
664 {
kono
parents:
diff changeset
665 delete nfile;
kono
parents:
diff changeset
666 return false;
kono
parents:
diff changeset
667 }
kono
parents:
diff changeset
668 this->nested_archives_[filename] = nfile;
kono
parents:
diff changeset
669 }
kono
parents:
diff changeset
670
kono
parents:
diff changeset
671 std::string nname;
kono
parents:
diff changeset
672 off_t nsize;
kono
parents:
diff changeset
673 off_t nnested_off;
kono
parents:
diff changeset
674 if (!nfile->read_header(nested_off, &nname, &nsize, &nnested_off, NULL))
kono
parents:
diff changeset
675 return false;
kono
parents:
diff changeset
676 return nfile->get_file_and_offset(nested_off, nname, nnested_off,
kono
parents:
diff changeset
677 memfd, memoff, memname);
kono
parents:
diff changeset
678 }
kono
parents:
diff changeset
679
kono
parents:
diff changeset
680 // An external member of a thin archive.
kono
parents:
diff changeset
681 *memfd = open(filename.c_str(), O_RDONLY | O_BINARY);
kono
parents:
diff changeset
682 if (*memfd < 0)
kono
parents:
diff changeset
683 {
kono
parents:
diff changeset
684 go_error_at(this->location_, "%s: %m", filename.c_str());
kono
parents:
diff changeset
685 return false;
kono
parents:
diff changeset
686 }
kono
parents:
diff changeset
687 *memoff = 0;
kono
parents:
diff changeset
688 *memname = filename;
kono
parents:
diff changeset
689 return true;
kono
parents:
diff changeset
690 }
kono
parents:
diff changeset
691
kono
parents:
diff changeset
692 // An archive member iterator. This is more-or-less copied from gold.
kono
parents:
diff changeset
693
kono
parents:
diff changeset
694 class Archive_iterator
kono
parents:
diff changeset
695 {
kono
parents:
diff changeset
696 public:
kono
parents:
diff changeset
697 // The header of an archive member. This is what this iterator
kono
parents:
diff changeset
698 // points to.
kono
parents:
diff changeset
699 struct Header
kono
parents:
diff changeset
700 {
kono
parents:
diff changeset
701 // The name of the member.
kono
parents:
diff changeset
702 std::string name;
kono
parents:
diff changeset
703 // The file offset of the member.
kono
parents:
diff changeset
704 off_t off;
kono
parents:
diff changeset
705 // The file offset of a nested archive member.
kono
parents:
diff changeset
706 off_t nested_off;
kono
parents:
diff changeset
707 // The size of the member.
kono
parents:
diff changeset
708 off_t size;
kono
parents:
diff changeset
709 };
kono
parents:
diff changeset
710
kono
parents:
diff changeset
711 Archive_iterator(Archive_file* afile, off_t off)
kono
parents:
diff changeset
712 : afile_(afile), off_(off)
kono
parents:
diff changeset
713 { this->read_next_header(); }
kono
parents:
diff changeset
714
kono
parents:
diff changeset
715 const Header&
kono
parents:
diff changeset
716 operator*() const
kono
parents:
diff changeset
717 { return this->header_; }
kono
parents:
diff changeset
718
kono
parents:
diff changeset
719 const Header*
kono
parents:
diff changeset
720 operator->() const
kono
parents:
diff changeset
721 { return &this->header_; }
kono
parents:
diff changeset
722
kono
parents:
diff changeset
723 Archive_iterator&
kono
parents:
diff changeset
724 operator++()
kono
parents:
diff changeset
725 {
kono
parents:
diff changeset
726 if (this->off_ == this->afile_->filesize())
kono
parents:
diff changeset
727 return *this;
kono
parents:
diff changeset
728 this->off_ = this->next_off_;
kono
parents:
diff changeset
729 this->read_next_header();
kono
parents:
diff changeset
730 return *this;
kono
parents:
diff changeset
731 }
kono
parents:
diff changeset
732
kono
parents:
diff changeset
733 Archive_iterator
kono
parents:
diff changeset
734 operator++(int)
kono
parents:
diff changeset
735 {
kono
parents:
diff changeset
736 Archive_iterator ret = *this;
kono
parents:
diff changeset
737 ++*this;
kono
parents:
diff changeset
738 return ret;
kono
parents:
diff changeset
739 }
kono
parents:
diff changeset
740
kono
parents:
diff changeset
741 bool
kono
parents:
diff changeset
742 operator==(const Archive_iterator& p) const
kono
parents:
diff changeset
743 { return this->off_ == p->off; }
kono
parents:
diff changeset
744
kono
parents:
diff changeset
745 bool
kono
parents:
diff changeset
746 operator!=(const Archive_iterator& p) const
kono
parents:
diff changeset
747 { return this->off_ != p->off; }
kono
parents:
diff changeset
748
kono
parents:
diff changeset
749 private:
kono
parents:
diff changeset
750 void
kono
parents:
diff changeset
751 read_next_header();
kono
parents:
diff changeset
752
kono
parents:
diff changeset
753 // The underlying archive file.
kono
parents:
diff changeset
754 Archive_file* afile_;
kono
parents:
diff changeset
755 // The current offset in the file.
kono
parents:
diff changeset
756 off_t off_;
kono
parents:
diff changeset
757 // The offset of the next member.
kono
parents:
diff changeset
758 off_t next_off_;
kono
parents:
diff changeset
759 // The current archive header.
kono
parents:
diff changeset
760 Header header_;
kono
parents:
diff changeset
761 };
kono
parents:
diff changeset
762
kono
parents:
diff changeset
763 // Read the next archive header.
kono
parents:
diff changeset
764
kono
parents:
diff changeset
765 void
kono
parents:
diff changeset
766 Archive_iterator::read_next_header()
kono
parents:
diff changeset
767 {
kono
parents:
diff changeset
768 off_t filesize = this->afile_->filesize();
kono
parents:
diff changeset
769 while (true)
kono
parents:
diff changeset
770 {
kono
parents:
diff changeset
771 if (this->off_ == filesize)
kono
parents:
diff changeset
772 {
kono
parents:
diff changeset
773 this->header_.off = filesize;
kono
parents:
diff changeset
774 return;
kono
parents:
diff changeset
775 }
kono
parents:
diff changeset
776
kono
parents:
diff changeset
777 if (!this->afile_->read_header(this->off_, &this->header_.name,
kono
parents:
diff changeset
778 &this->header_.size,
kono
parents:
diff changeset
779 &this->header_.nested_off,
kono
parents:
diff changeset
780 &this->next_off_))
kono
parents:
diff changeset
781 {
kono
parents:
diff changeset
782 this->header_.off = filesize;
kono
parents:
diff changeset
783 return;
kono
parents:
diff changeset
784 }
kono
parents:
diff changeset
785 this->header_.off = this->off_;
kono
parents:
diff changeset
786
kono
parents:
diff changeset
787 // Skip special members.
kono
parents:
diff changeset
788 if (!this->header_.name.empty() && this->header_.name != "/")
kono
parents:
diff changeset
789 return;
kono
parents:
diff changeset
790
kono
parents:
diff changeset
791 this->off_ = this->next_off_;
kono
parents:
diff changeset
792 }
kono
parents:
diff changeset
793 }
kono
parents:
diff changeset
794
kono
parents:
diff changeset
795 // Initial iterator.
kono
parents:
diff changeset
796
kono
parents:
diff changeset
797 Archive_iterator
kono
parents:
diff changeset
798 archive_begin(Archive_file* afile)
kono
parents:
diff changeset
799 {
kono
parents:
diff changeset
800 return Archive_iterator(afile, afile->first_member_offset());
kono
parents:
diff changeset
801 }
kono
parents:
diff changeset
802
kono
parents:
diff changeset
803 // Final iterator.
kono
parents:
diff changeset
804
kono
parents:
diff changeset
805 Archive_iterator
kono
parents:
diff changeset
806 archive_end(Archive_file* afile)
kono
parents:
diff changeset
807 {
kono
parents:
diff changeset
808 return Archive_iterator(afile, afile->filesize());
kono
parents:
diff changeset
809 }
kono
parents:
diff changeset
810
kono
parents:
diff changeset
811 // A type of Import_stream which concatenates other Import_streams
kono
parents:
diff changeset
812 // together.
kono
parents:
diff changeset
813
kono
parents:
diff changeset
814 class Stream_concatenate : public Import::Stream
kono
parents:
diff changeset
815 {
kono
parents:
diff changeset
816 public:
kono
parents:
diff changeset
817 Stream_concatenate()
kono
parents:
diff changeset
818 : inputs_()
kono
parents:
diff changeset
819 { }
kono
parents:
diff changeset
820
kono
parents:
diff changeset
821 // Add a new stream.
kono
parents:
diff changeset
822 void
kono
parents:
diff changeset
823 add(Import::Stream* is)
kono
parents:
diff changeset
824 { this->inputs_.push_back(is); }
kono
parents:
diff changeset
825
kono
parents:
diff changeset
826 protected:
kono
parents:
diff changeset
827 bool
kono
parents:
diff changeset
828 do_peek(size_t, const char**);
kono
parents:
diff changeset
829
kono
parents:
diff changeset
830 void
kono
parents:
diff changeset
831 do_advance(size_t);
kono
parents:
diff changeset
832
kono
parents:
diff changeset
833 private:
kono
parents:
diff changeset
834 std::list<Import::Stream*> inputs_;
kono
parents:
diff changeset
835 };
kono
parents:
diff changeset
836
kono
parents:
diff changeset
837 // Peek ahead.
kono
parents:
diff changeset
838
kono
parents:
diff changeset
839 bool
kono
parents:
diff changeset
840 Stream_concatenate::do_peek(size_t length, const char** bytes)
kono
parents:
diff changeset
841 {
kono
parents:
diff changeset
842 while (true)
kono
parents:
diff changeset
843 {
kono
parents:
diff changeset
844 if (this->inputs_.empty())
kono
parents:
diff changeset
845 return false;
kono
parents:
diff changeset
846 if (this->inputs_.front()->peek(length, bytes))
kono
parents:
diff changeset
847 return true;
kono
parents:
diff changeset
848 delete this->inputs_.front();
kono
parents:
diff changeset
849 this->inputs_.pop_front();
kono
parents:
diff changeset
850 }
kono
parents:
diff changeset
851 }
kono
parents:
diff changeset
852
kono
parents:
diff changeset
853 // Advance.
kono
parents:
diff changeset
854
kono
parents:
diff changeset
855 void
kono
parents:
diff changeset
856 Stream_concatenate::do_advance(size_t skip)
kono
parents:
diff changeset
857 {
kono
parents:
diff changeset
858 while (true)
kono
parents:
diff changeset
859 {
kono
parents:
diff changeset
860 if (this->inputs_.empty())
kono
parents:
diff changeset
861 return;
kono
parents:
diff changeset
862 if (!this->inputs_.front()->at_eof())
kono
parents:
diff changeset
863 {
kono
parents:
diff changeset
864 // We just assume that this will do the right thing. It
kono
parents:
diff changeset
865 // should be OK since we should never want to skip past
kono
parents:
diff changeset
866 // multiple streams.
kono
parents:
diff changeset
867 this->inputs_.front()->advance(skip);
kono
parents:
diff changeset
868 return;
kono
parents:
diff changeset
869 }
kono
parents:
diff changeset
870 delete this->inputs_.front();
kono
parents:
diff changeset
871 this->inputs_.pop_front();
kono
parents:
diff changeset
872 }
kono
parents:
diff changeset
873 }
kono
parents:
diff changeset
874
kono
parents:
diff changeset
875 // Import data from an archive. We walk through the archive and
kono
parents:
diff changeset
876 // import data from each member.
kono
parents:
diff changeset
877
kono
parents:
diff changeset
878 Import::Stream*
kono
parents:
diff changeset
879 Import::find_archive_export_data(const std::string& filename, int fd,
kono
parents:
diff changeset
880 Location location)
kono
parents:
diff changeset
881 {
kono
parents:
diff changeset
882 Archive_file afile(filename, fd, location);
kono
parents:
diff changeset
883 if (!afile.initialize())
kono
parents:
diff changeset
884 return NULL;
kono
parents:
diff changeset
885
kono
parents:
diff changeset
886 Stream_concatenate* ret = new Stream_concatenate;
kono
parents:
diff changeset
887
kono
parents:
diff changeset
888 bool any_data = false;
kono
parents:
diff changeset
889 bool any_members = false;
kono
parents:
diff changeset
890 Archive_iterator pend = archive_end(&afile);
kono
parents:
diff changeset
891 for (Archive_iterator p = archive_begin(&afile); p != pend; p++)
kono
parents:
diff changeset
892 {
kono
parents:
diff changeset
893 any_members = true;
kono
parents:
diff changeset
894 int member_fd;
kono
parents:
diff changeset
895 off_t member_off;
kono
parents:
diff changeset
896 std::string member_name;
kono
parents:
diff changeset
897 if (!afile.get_file_and_offset(p->off, p->name, p->nested_off,
kono
parents:
diff changeset
898 &member_fd, &member_off, &member_name))
kono
parents:
diff changeset
899 return NULL;
kono
parents:
diff changeset
900
kono
parents:
diff changeset
901 Import::Stream* is = Import::find_object_export_data(member_name,
kono
parents:
diff changeset
902 member_fd,
kono
parents:
diff changeset
903 member_off,
kono
parents:
diff changeset
904 location);
kono
parents:
diff changeset
905 if (is != NULL)
kono
parents:
diff changeset
906 {
kono
parents:
diff changeset
907 ret->add(is);
kono
parents:
diff changeset
908 any_data = true;
kono
parents:
diff changeset
909 }
kono
parents:
diff changeset
910 }
kono
parents:
diff changeset
911
kono
parents:
diff changeset
912 if (!any_members)
kono
parents:
diff changeset
913 {
kono
parents:
diff changeset
914 // It's normal to have an empty archive file when using gobuild.
kono
parents:
diff changeset
915 return new Stream_from_string("");
kono
parents:
diff changeset
916 }
kono
parents:
diff changeset
917
kono
parents:
diff changeset
918 if (!any_data)
kono
parents:
diff changeset
919 {
kono
parents:
diff changeset
920 delete ret;
kono
parents:
diff changeset
921 return NULL;
kono
parents:
diff changeset
922 }
kono
parents:
diff changeset
923
kono
parents:
diff changeset
924 return ret;
kono
parents:
diff changeset
925 }