OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [go/] [gofrontend/] [import-archive.cc] - Blame information for rev 714

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 714 jeremybenn
// import-archive.cc -- Go frontend read import data from an archive file.
2
 
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.
6
 
7
#include "go-system.h"
8
 
9
#include "import.h"
10
 
11
#ifndef O_BINARY
12
#define O_BINARY 0
13
#endif
14
 
15
// Archive magic numbers.
16
 
17
static const char armag[] =
18
{
19
  '!', '<', 'a', 'r', 'c', 'h', '>', '\n'
20
};
21
 
22
static const char armagt[] =
23
{
24
  '!', '<', 't', 'h', 'i', 'n', '>', '\n'
25
};
26
 
27
static const char arfmag[2] = { '`', '\n' };
28
 
29
// The header of an entry in an archive.  This is all readable text,
30
// padded with spaces where necesary.
31
 
32
struct Archive_header
33
{
34
  // The entry name.
35
  char ar_name[16];
36
  // The file modification time.
37
  char ar_date[12];
38
  // The user's UID in decimal.
39
  char ar_uid[6];
40
  // The user's GID in decimal.
41
  char ar_gid[6];
42
  // The file mode in octal.
43
  char ar_mode[8];
44
  // The file size in decimal.
45
  char ar_size[10];
46
  // The final magic code.
47
  char ar_fmag[2];
48
};
49
 
50
// The functions in this file extract Go export data from an archive.
51
 
52
const int Import::archive_magic_len;
53
 
54
// Return true if BYTES, which are from the start of the file, are an
55
// archive magic number.
56
 
57
bool
58
Import::is_archive_magic(const char* bytes)
59
{
60
  return (memcmp(bytes, armag, Import::archive_magic_len) == 0
61
          || memcmp(bytes, armagt, Import::archive_magic_len) == 0);
62
}
63
 
64
// An object used to read an archive file.
65
 
66
class Archive_file
67
{
68
 public:
69
  Archive_file(const std::string& filename, int fd, Location location)
70
    : filename_(filename), fd_(fd), filesize_(-1), extended_names_(),
71
      is_thin_archive_(false), location_(location), nested_archives_()
72
  { }
73
 
74
  // Initialize.
75
  bool
76
  initialize();
77
 
78
  // Return the file name.
79
  const std::string&
80
  filename() const
81
  { return this->filename_; }
82
 
83
  // Get the file size.
84
  off_t
85
  filesize() const
86
  { return this->filesize_; }
87
 
88
  // Return whether this is a thin archive.
89
  bool
90
  is_thin_archive() const
91
  { return this->is_thin_archive_; }
92
 
93
  // Return the location of the import statement.
94
  Location
95
  location() const
96
  { return this->location_; }
97
 
98
  // Read bytes.
99
  bool
100
  read(off_t offset, off_t size, char*);
101
 
102
  // Read the archive header at OFF, setting *PNAME, *SIZE, and
103
  // *NESTED_OFF.
104
  bool
105
  read_header(off_t off, std::string* pname, off_t* size, off_t* nested_off);
106
 
107
  // Interpret the header of HDR, the header of the archive member at
108
  // file offset OFF.  Return whether it succeeded.  Set *SIZE to the
109
  // size of the member.  Set *PNAME to the name of the member.  Set
110
  // *NESTED_OFF to the offset in a nested archive.
111
  bool
112
  interpret_header(const Archive_header* hdr, off_t off,
113
                   std::string* pname, off_t* size, off_t* nested_off) const;
114
 
115
  // Get the file and offset for an archive member.
116
  bool
117
  get_file_and_offset(off_t off, const std::string& hdrname,
118
                      off_t nested_off, int* memfd, off_t* memoff,
119
                      std::string* memname);
120
 
121
 private:
122
  // For keeping track of open nested archives in a thin archive file.
123
  typedef std::map<std::string, Archive_file*> Nested_archive_table;
124
 
125
  // The name of the file.
126
  std::string filename_;
127
  // The file descriptor.
128
  int fd_;
129
  // The file size;
130
  off_t filesize_;
131
  // The extended name table.
132
  std::string extended_names_;
133
  // Whether this is a thin archive.
134
  bool is_thin_archive_;
135
  // The location of the import statements.
136
  Location location_;
137
  // Table of nested archives.
138
  Nested_archive_table nested_archives_;
139
};
140
 
141
bool
142
Archive_file::initialize()
143
{
144
  struct stat st;
145
  if (fstat(this->fd_, &st) < 0)
146
    {
147
      error_at(this->location_, "%s: %m", this->filename_.c_str());
148
      return false;
149
    }
150
  this->filesize_ = st.st_size;
151
 
152
  char buf[sizeof(armagt)];
153
  if (::lseek(this->fd_, 0, SEEK_SET) < 0
154
      || ::read(this->fd_, buf, sizeof(armagt)) != sizeof(armagt))
155
    {
156
      error_at(this->location_, "%s: %m", this->filename_.c_str());
157
      return false;
158
    }
159
  this->is_thin_archive_ = memcmp(buf, armagt, sizeof(armagt)) == 0;
160
 
161
  if (this->filesize_ == sizeof(armag))
162
    {
163
      // Empty archive.
164
      return true;
165
    }
166
 
167
  // Look for the extended name table.
168
  std::string filename;
169
  off_t size;
170
  if (!this->read_header(sizeof(armagt), &filename, &size, NULL))
171
    return false;
172
  if (filename.empty())
173
    {
174
      // We found the symbol table.
175
      off_t off = sizeof(armagt) + sizeof(Archive_header) + size;
176
      if ((off & 1) != 0)
177
        ++off;
178
      if (!this->read_header(off, &filename, &size, NULL))
179
        filename.clear();
180
    }
181
  if (filename == "/")
182
    {
183
      char* rdbuf = new char[size];
184
      if (::read(this->fd_, rdbuf, size) != size)
185
        {
186
          error_at(this->location_, "%s: could not read extended names",
187
                   filename.c_str());
188
          delete[] rdbuf;
189
          return false;
190
        }
191
      this->extended_names_.assign(rdbuf, size);
192
      delete[] rdbuf;
193
    }
194
 
195
  return true;
196
}
197
 
198
// Read bytes from the file.
199
 
200
bool
201
Archive_file::read(off_t offset, off_t size, char* buf)
202
{
203
  if (::lseek(this->fd_, offset, SEEK_SET) < 0
204
      || ::read(this->fd_, buf, size) != size)
205
    {
206
      error_at(this->location_, "%s: %m", this->filename_.c_str());
207
      return false;
208
    }
209
  return true;
210
}
211
 
212
// Read the header at OFF.  Set *PNAME to the name, *SIZE to the size,
213
// and *NESTED_OFF to the nested offset.
214
 
215
bool
216
Archive_file::read_header(off_t off, std::string* pname, off_t* size,
217
                          off_t* nested_off)
218
{
219
  Archive_header hdr;
220
  if (::lseek(this->fd_, off, SEEK_SET) < 0)
221
    {
222
      error_at(this->location_, "%s: %m", this->filename_.c_str());
223
      return false;
224
    }
225
  ssize_t got = ::read(this->fd_, &hdr, sizeof hdr);
226
  if (got != sizeof hdr)
227
    {
228
      if (got < 0)
229
        error_at(this->location_, "%s: %m", this->filename_.c_str());
230
      else if (got > 0)
231
        error_at(this->location_, "%s: short archive header at %ld",
232
                 this->filename_.c_str(), static_cast<long>(off));
233
      else
234
        error_at(this->location_, "%s: unexpected EOF at %ld",
235
                 this->filename_.c_str(), static_cast<long>(off));
236
    }
237
  off_t local_nested_off;
238
  if (!this->interpret_header(&hdr, off, pname, size, &local_nested_off))
239
    return false;
240
  if (nested_off != NULL)
241
    *nested_off = local_nested_off;
242
  return true;
243
}
244
 
245
// Interpret the header of HDR, the header of the archive member at
246
// file offset OFF.
247
 
248
bool
249
Archive_file::interpret_header(const Archive_header* hdr, off_t off,
250
                               std::string* pname, off_t* size,
251
                               off_t* nested_off) const
252
{
253
  if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
254
    {
255
      error_at(this->location_, "%s: malformed archive header at %lu",
256
               this->filename_.c_str(), static_cast<unsigned long>(off));
257
      return false;
258
    }
259
 
260
  const int size_string_size = sizeof hdr->ar_size;
261
  char size_string[size_string_size + 1];
262
  memcpy(size_string, hdr->ar_size, size_string_size);
263
  char* ps = size_string + size_string_size;
264
  while (ps[-1] == ' ')
265
    --ps;
266
  *ps = '\0';
267
 
268
  errno = 0;
269
  char* end;
270
  *size = strtol(size_string, &end, 10);
271
  if (*end != '\0'
272
      || *size < 0
273
      || (*size == LONG_MAX && errno == ERANGE))
274
    {
275
      error_at(this->location_, "%s: malformed archive header size at %lu",
276
               this->filename_.c_str(), static_cast<unsigned long>(off));
277
      return false;
278
    }
279
 
280
  if (hdr->ar_name[0] != '/')
281
    {
282
      const char* name_end = strchr(hdr->ar_name, '/');
283
      if (name_end == NULL
284
          || name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
285
        {
286
          error_at(this->location_, "%s: malformed archive header name at %lu",
287
                   this->filename_.c_str(), static_cast<unsigned long>(off));
288
          return false;
289
        }
290
      pname->assign(hdr->ar_name, name_end - hdr->ar_name);
291
      *nested_off = 0;
292
    }
293
  else if (hdr->ar_name[1] == ' ')
294
    {
295
      // This is the symbol table.
296
      pname->clear();
297
    }
298
  else if (hdr->ar_name[1] == '/')
299
    {
300
      // This is the extended name table.
301
      pname->assign(1, '/');
302
    }
303
  else
304
    {
305
      errno = 0;
306
      long x = strtol(hdr->ar_name + 1, &end, 10);
307
      long y = 0;
308
      if (*end == ':')
309
        y = strtol(end + 1, &end, 10);
310
      if (*end != ' '
311
          || x < 0
312
          || (x == LONG_MAX && errno == ERANGE)
313
          || static_cast<size_t>(x) >= this->extended_names_.size())
314
        {
315
          error_at(this->location_, "%s: bad extended name index at %lu",
316
                   this->filename_.c_str(), static_cast<unsigned long>(off));
317
          return false;
318
        }
319
 
320
      const char* name = this->extended_names_.data() + x;
321
      const char* name_end = strchr(name, '\n');
322
      if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
323
          || name_end[-1] != '/')
324
        {
325
          error_at(this->location_, "%s: bad extended name entry at header %lu",
326
                   this->filename_.c_str(), static_cast<unsigned long>(off));
327
          return false;
328
        }
329
      pname->assign(name, name_end - 1 - name);
330
      if (nested_off != NULL)
331
        *nested_off = y;
332
    }
333
 
334
  return true;
335
}
336
 
337
// Get the file and offset for an archive member.
338
 
339
bool
340
Archive_file::get_file_and_offset(off_t off, const std::string& hdrname,
341
                                  off_t nested_off, int* memfd, off_t* memoff,
342
                                  std::string* memname)
343
{
344
  if (!this->is_thin_archive_)
345
    {
346
      *memfd = this->fd_;
347
      *memoff = off + sizeof(Archive_header);
348
      *memname = this->filename_ + '(' + hdrname + ')';
349
      return true;
350
    }
351
 
352
  std::string filename = hdrname;
353
  if (!IS_ABSOLUTE_PATH(filename.c_str()))
354
    {
355
      const char* archive_path = this->filename_.c_str();
356
      const char* basename = lbasename(archive_path);
357
      if (basename > archive_path)
358
        filename.replace(0, 0,
359
                         this->filename_.substr(0, basename - archive_path));
360
    }
361
 
362
  if (nested_off > 0)
363
    {
364
      // This is a member of a nested archive.
365
      Archive_file* nfile;
366
      Nested_archive_table::const_iterator p =
367
        this->nested_archives_.find(filename);
368
      if (p != this->nested_archives_.end())
369
        nfile = p->second;
370
      else
371
        {
372
          int nfd = open(filename.c_str(), O_RDONLY | O_BINARY);
373
          if (nfd < 0)
374
            {
375
              error_at(this->location_, "%s: can't open nested archive %s",
376
                       this->filename_.c_str(), filename.c_str());
377
              return false;
378
            }
379
          nfile = new Archive_file(filename, nfd, this->location_);
380
          if (!nfile->initialize())
381
            {
382
              delete nfile;
383
              return false;
384
            }
385
          this->nested_archives_[filename] = nfile;
386
        }
387
 
388
      std::string nname;
389
      off_t nsize;
390
      off_t nnested_off;
391
      if (!nfile->read_header(nested_off, &nname, &nsize, &nnested_off))
392
        return false;
393
      return nfile->get_file_and_offset(nested_off, nname, nnested_off,
394
                                        memfd, memoff, memname);
395
    }
396
 
397
  // An external member of a thin archive.
398
  *memfd = open(filename.c_str(), O_RDONLY | O_BINARY);
399
  if (*memfd < 0)
400
    {
401
      error_at(this->location_, "%s: %m", filename.c_str());
402
      return false;
403
    }
404
  *memoff = 0;
405
  *memname = filename;
406
  return true;
407
}
408
 
409
// An archive member iterator.  This is more-or-less copied from gold.
410
 
411
class Archive_iterator
412
{
413
 public:
414
  // The header of an archive member.  This is what this iterator
415
  // points to.
416
  struct Header
417
  {
418
    // The name of the member.
419
    std::string name;
420
    // The file offset of the member.
421
    off_t off;
422
    // The file offset of a nested archive member.
423
    off_t nested_off;
424
    // The size of the member.
425
    off_t size;
426
  };
427
 
428
  Archive_iterator(Archive_file* afile, off_t off)
429
    : afile_(afile), off_(off)
430
  { this->read_next_header(); }
431
 
432
  const Header&
433
  operator*() const
434
  { return this->header_; }
435
 
436
  const Header*
437
  operator->() const
438
  { return &this->header_; }
439
 
440
  Archive_iterator&
441
  operator++()
442
  {
443
    if (this->off_ == this->afile_->filesize())
444
      return *this;
445
    this->off_ += sizeof(Archive_header);
446
    if (!this->afile_->is_thin_archive())
447
      this->off_ += this->header_.size;
448
    if ((this->off_ & 1) != 0)
449
      ++this->off_;
450
    this->read_next_header();
451
    return *this;
452
  }
453
 
454
  Archive_iterator
455
  operator++(int)
456
  {
457
    Archive_iterator ret = *this;
458
    ++*this;
459
    return ret;
460
  }
461
 
462
  bool
463
  operator==(const Archive_iterator p) const
464
  { return this->off_ == p->off; }
465
 
466
  bool
467
  operator!=(const Archive_iterator p) const
468
  { return this->off_ != p->off; }
469
 
470
 private:
471
  void
472
  read_next_header();
473
 
474
  // The underlying archive file.
475
  Archive_file* afile_;
476
  // The current offset in the file.
477
  off_t off_;
478
  // The current archive header.
479
  Header header_;
480
};
481
 
482
// Read the next archive header.
483
 
484
void
485
Archive_iterator::read_next_header()
486
{
487
  off_t filesize = this->afile_->filesize();
488
  while (true)
489
    {
490
      if (filesize - this->off_ < static_cast<off_t>(sizeof(Archive_header)))
491
        {
492
          if (filesize != this->off_)
493
            {
494
              error_at(this->afile_->location(),
495
                       "%s: short archive header at %lu",
496
                       this->afile_->filename().c_str(),
497
                       static_cast<unsigned long>(this->off_));
498
              this->off_ = filesize;
499
            }
500
          this->header_.off = filesize;
501
          return;
502
        }
503
 
504
      char buf[sizeof(Archive_header)];
505
      if (!this->afile_->read(this->off_, sizeof(Archive_header), buf))
506
        {
507
          this->header_.off = filesize;
508
          return;
509
        }
510
 
511
      const Archive_header* hdr = reinterpret_cast<const Archive_header*>(buf);
512
      if (!this->afile_->interpret_header(hdr, this->off_, &this->header_.name,
513
                                          &this->header_.size,
514
                                          &this->header_.nested_off))
515
        {
516
          this->header_.off = filesize;
517
          return;
518
        }
519
      this->header_.off = this->off_;
520
 
521
      // Skip special members.
522
      if (!this->header_.name.empty() && this->header_.name != "/")
523
        return;
524
 
525
      this->off_ += sizeof(Archive_header) + this->header_.size;
526
      if ((this->off_ & 1) != 0)
527
        ++this->off_;
528
    }
529
}
530
 
531
// Initial iterator.
532
 
533
Archive_iterator
534
archive_begin(Archive_file* afile)
535
{
536
  return Archive_iterator(afile, sizeof(armag));
537
}
538
 
539
// Final iterator.
540
 
541
Archive_iterator
542
archive_end(Archive_file* afile)
543
{
544
  return Archive_iterator(afile, afile->filesize());
545
}
546
 
547
// A type of Import_stream which concatenates other Import_streams
548
// together.
549
 
550
class Stream_concatenate : public Import::Stream
551
{
552
 public:
553
  Stream_concatenate()
554
    : inputs_()
555
  { }
556
 
557
  // Add a new stream.
558
  void
559
  add(Import::Stream* is)
560
  { this->inputs_.push_back(is); }
561
 
562
 protected:
563
  bool
564
  do_peek(size_t, const char**);
565
 
566
  void
567
  do_advance(size_t);
568
 
569
 private:
570
  std::list<Import::Stream*> inputs_;
571
};
572
 
573
// Peek ahead.
574
 
575
bool
576
Stream_concatenate::do_peek(size_t length, const char** bytes)
577
{
578
  while (true)
579
    {
580
      if (this->inputs_.empty())
581
        return false;
582
      if (this->inputs_.front()->peek(length, bytes))
583
        return true;
584
      delete this->inputs_.front();
585
      this->inputs_.pop_front();
586
    }
587
}
588
 
589
// Advance.
590
 
591
void
592
Stream_concatenate::do_advance(size_t skip)
593
{
594
  while (true)
595
    {
596
      if (this->inputs_.empty())
597
        return;
598
      if (!this->inputs_.front()->at_eof())
599
        {
600
          // We just assume that this will do the right thing.  It
601
          // should be OK since we should never want to skip past
602
          // multiple streams.
603
          this->inputs_.front()->advance(skip);
604
          return;
605
        }
606
      delete this->inputs_.front();
607
      this->inputs_.pop_front();
608
    }
609
}
610
 
611
// Import data from an archive.  We walk through the archive and
612
// import data from each member.
613
 
614
Import::Stream*
615
Import::find_archive_export_data(const std::string& filename, int fd,
616
                                 Location location)
617
{
618
  Archive_file afile(filename, fd, location);
619
  if (!afile.initialize())
620
    return NULL;
621
 
622
  Stream_concatenate* ret = new Stream_concatenate;
623
 
624
  bool any_data = false;
625
  bool any_members = false;
626
  Archive_iterator pend = archive_end(&afile);
627
  for (Archive_iterator p = archive_begin(&afile); p != pend; p++)
628
    {
629
      any_members = true;
630
      int member_fd;
631
      off_t member_off;
632
      std::string member_name;
633
      if (!afile.get_file_and_offset(p->off, p->name, p->nested_off,
634
                                     &member_fd, &member_off, &member_name))
635
        return NULL;
636
 
637
      Import::Stream* is = Import::find_object_export_data(member_name,
638
                                                           member_fd,
639
                                                           member_off,
640
                                                           location);
641
      if (is != NULL)
642
        {
643
          ret->add(is);
644
          any_data = true;
645
        }
646
    }
647
 
648
  if (!any_members)
649
    {
650
      // It's normal to have an empty archive file when using gobuild.
651
      return new Stream_from_string("");
652
    }
653
 
654
  if (!any_data)
655
    {
656
      delete ret;
657
      return NULL;
658
    }
659
 
660
  return ret;
661
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.