forked from rui314/mold
-
Notifications
You must be signed in to change notification settings - Fork 0
/
archive-file.h
129 lines (108 loc) · 3.16 KB
/
archive-file.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#pragma once
#include "mold.h"
#include "filetype.h"
namespace mold {
struct ArHdr {
char ar_name[16];
char ar_date[12];
char ar_uid[6];
char ar_gid[6];
char ar_mode[8];
char ar_size[10];
char ar_fmag[2];
};
template <typename C>
std::vector<MappedFile<C> *>
read_thin_archive_members(C &ctx, MappedFile<C> *mf) {
u8 *begin = mf->data;
u8 *data = begin + 8;
std::vector<MappedFile<C> *> vec;
std::string_view strtab;
while (data < begin + mf->size) {
// Each header is aligned to a 2 byte boundary.
if ((begin - data) % 2)
data++;
ArHdr &hdr = *(ArHdr *)data;
u8 *body = data + sizeof(hdr);
u64 size = atol(hdr.ar_size);
// Read a string table.
if (memcmp(hdr.ar_name, "// ", 3) == 0) {
strtab = {(char *)body, (size_t)size};
data = body + size;
continue;
}
// Skip a symbol table.
if (memcmp(hdr.ar_name, "/ ", 2) == 0) {
data = body + size;
continue;
}
if (hdr.ar_name[0] != '/')
Fatal(ctx) << mf->name << ": filename is not stored as a long filename";
const char *start = strtab.data() + atoi(hdr.ar_name + 1);
std::string name(start, (const char *)strstr(start, "/\n"));
std::string path = name.starts_with('/') ?
name : (filepath(mf->name).parent_path() / name).string();
vec.push_back(MappedFile<C>::must_open(ctx, path));
data = body;
}
return vec;
}
template <typename C>
std::vector<MappedFile<C> *>
read_fat_archive_members(C &ctx, MappedFile<C> *mf) {
u8 *begin = mf->data;
u8 *data = begin + 8;
std::vector<MappedFile<C> *> vec;
std::string_view strtab;
while (begin + mf->size - data >= 2) {
if ((begin - data) % 2)
data++;
ArHdr &hdr = *(ArHdr *)data;
u8 *body = data + sizeof(hdr);
u64 size = atol(hdr.ar_size);
data = body + size;
// Read if string table
if (memcmp(hdr.ar_name, "// ", 3) == 0) {
strtab = {(char *)body, (size_t)size};
continue;
}
// Skip if symbol table
if (memcmp(hdr.ar_name, "/ ", 2) == 0)
continue;
// Read the name field
std::string name;
if (memcmp(hdr.ar_name, "#1/", 3) == 0) {
size_t namelen = (size_t)atoi(hdr.ar_name + 3);
name = {(char *)(&hdr + 1), namelen};
if (size_t pos = name.find('\0'))
name = name.substr(0, pos);
body += namelen;
} else if (hdr.ar_name[0] == '/') {
const char *start = strtab.data() + atoi(hdr.ar_name + 1);
name = {start, (const char *)strstr(start, "/\n")};
} else {
char *end = (char *)memchr(hdr.ar_name, '/', sizeof(hdr.ar_name));
if (!end)
end = hdr.ar_name + sizeof(hdr.ar_name);
name = {hdr.ar_name, end};
}
// Skip if symbol table
if (name == "__.SYMDEF" || name == "__.SYMDEF SORTED")
continue;
vec.push_back(mf->slice(ctx, name, body - begin, size));
}
return vec;
}
template <typename C>
std::vector<MappedFile<C> *>
read_archive_members(C &ctx, MappedFile<C> *mf) {
switch (get_file_type(mf)) {
case FileType::AR:
return read_fat_archive_members(ctx, mf);
case FileType::THIN_AR:
return read_thin_archive_members(ctx, mf);
default:
unreachable();
}
}
} // namespace mold