#include "ggc.h"
#include "lto-streamer.h"
+/* Handle opening elf files on hosts, such as Windows, that may use
+ text file handling that will break binary access. */
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
/* Initialize FILE, an LTO file object for FILENAME. */
static void
-lto_file_init (lto_file *file, const char *filename)
+lto_file_init (lto_file *file, const char *filename, off_t offset)
{
file->filename = filename;
+ file->offset = offset;
}
/* An ELF file. */
lto_elf_file_open (const char *filename, bool writable)
{
lto_elf_file *elf_file;
- lto_file *result;
+ lto_file *result = NULL;
off_t offset;
+ long loffset;
+ off_t header_offset;
const char *offset_p;
char *fname;
+ int consumed;
- offset_p = strchr (filename, '@');
- if (!offset_p)
- {
- fname = xstrdup (filename);
- offset = 0;
- }
- else
+ offset_p = strrchr (filename, '@');
+ if (offset_p
+ && offset_p != filename
+ && sscanf (offset_p, "@%li%n", &loffset, &consumed) >= 1
+ && strlen (offset_p) == (unsigned int)consumed)
{
- int64_t t;
fname = (char *) xmalloc (offset_p - filename + 1);
memcpy (fname, filename, offset_p - filename);
fname[offset_p - filename] = '\0';
- offset_p++;
- sscanf(offset_p, "%" PRId64 , &t);
- offset = t;
+ offset = (off_t)loffset;
/* elf_rand expects the offset to point to the ar header, not the
object itself. Subtract the size of the ar header (60 bytes).
We don't uses sizeof (struct ar_hd) to avoid including ar.h */
- offset -= 60;
+ header_offset = offset - 60;
+ }
+ else
+ {
+ fname = xstrdup (filename);
+ offset = 0;
+ header_offset = 0;
}
/* Set up. */
elf_file = XCNEW (lto_elf_file);
result = (lto_file *) elf_file;
- lto_file_init (result, fname);
+ lto_file_init (result, fname, offset);
elf_file->fd = -1;
/* Open the file. */
- elf_file->fd = open (fname, writable ? O_WRONLY|O_CREAT : O_RDONLY, 0666);
+ elf_file->fd = open (fname, writable ? O_WRONLY|O_CREAT|O_BINARY
+ : O_RDONLY|O_BINARY, 0666);
if (elf_file->fd == -1)
{
error ("could not open file %s", fname);
if (offset != 0)
{
Elf *e;
- off_t t = elf_rand (elf_file->elf, offset);
- if (t != offset)
+ off_t t = elf_rand (elf_file->elf, header_offset);
+ if (t != header_offset)
{
error ("could not seek in archive");
goto fail;
return result;
fail:
- lto_elf_file_close (result);
+ if (result)
+ lto_elf_file_close (result);
return NULL;
}