blob: 6df5f6d96d2402660687f931ad9b4e100971d30a [file] [log] [blame]
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
Dimitry Ivanovbcc4da92017-02-15 15:31:13 -08003 * All rights reserved.
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07004 *
Dimitry Ivanovbcc4da92017-02-15 15:31:13 -08005 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070014 *
Dimitry Ivanovbcc4da92017-02-15 15:31:13 -080015 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070027 */
28
29#include "linker_utils.h"
Dimitry Ivanov48ec2882016-08-04 11:50:36 -070030
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070031#include "linker_debug.h"
Dimitry Ivanov48ec2882016-08-04 11:50:36 -070032#include "linker_globals.h"
33
34#include "android-base/strings.h"
35
36#include <sys/stat.h>
37#include <unistd.h>
38
39std::string dirname(const char* path) {
40 const char* last_slash = strrchr(path, '/');
41
42 if (last_slash == path) {
43 return "/";
44 } else if (last_slash == nullptr) {
45 return ".";
46 } else {
47 return std::string(path, last_slash - path);
48 }
49}
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070050
51bool normalize_path(const char* path, std::string* normalized_path) {
52 // Input should be an absolute path
53 if (path[0] != '/') {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -070054 PRINT("normalize_path - invalid input: \"%s\", the input path should be absolute", path);
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070055 return false;
56 }
57
58 const size_t len = strlen(path) + 1;
59 char buf[len];
60
61 const char* in_ptr = path;
62 char* out_ptr = buf;
63
64 while (*in_ptr != 0) {
65 if (*in_ptr == '/') {
66 char c1 = in_ptr[1];
67 if (c1 == '.') {
68 char c2 = in_ptr[2];
69 if (c2 == '/') {
70 in_ptr += 2;
71 continue;
72 } else if (c2 == '.' && (in_ptr[3] == '/' || in_ptr[3] == 0)) {
73 in_ptr += 3;
74 while (out_ptr > buf && *--out_ptr != '/') {
75 }
76 if (in_ptr[0] == 0) {
77 // retain '/'
78 out_ptr++;
79 }
80 continue;
81 }
82 } else if (c1 == '/') {
83 ++in_ptr;
84 continue;
85 }
86 }
87 *out_ptr++ = *in_ptr++;
88 }
89
90 *out_ptr = 0;
91 *normalized_path = buf;
92 return true;
93}
94
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070095bool file_is_in_dir(const std::string& file, const std::string& dir) {
96 const char* needle = dir.c_str();
97 const char* haystack = file.c_str();
98 size_t needle_len = strlen(needle);
99
Dimitry Ivanov284ae352015-12-08 10:47:13 -0800100 return strncmp(haystack, needle, needle_len) == 0 &&
101 haystack[needle_len] == '/' &&
102 strchr(haystack + needle_len + 1, '/') == nullptr;
103}
104
105bool file_is_under_dir(const std::string& file, const std::string& dir) {
106 const char* needle = dir.c_str();
107 const char* haystack = file.c_str();
108 size_t needle_len = strlen(needle);
109
110 return strncmp(haystack, needle, needle_len) == 0 &&
111 haystack[needle_len] == '/';
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700112}
113
114const char* const kZipFileSeparator = "!/";
115
116bool parse_zip_path(const char* input_path, std::string* zip_path, std::string* entry_path) {
117 std::string normalized_path;
118 if (!normalize_path(input_path, &normalized_path)) {
119 return false;
120 }
121
122 const char* const path = normalized_path.c_str();
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700123 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700124
125 // Treat an '!/' separator inside a path as the separator between the name
126 // of the zip file on disk and the subdirectory to search within it.
127 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
128 // "bar/bas/x.so" within "foo.zip".
129 const char* const separator = strstr(path, kZipFileSeparator);
130 if (separator == nullptr) {
131 return false;
132 }
133
134 char buf[512];
135 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
136 PRINT("Warning: ignoring very long library path: %s", path);
137 return false;
138 }
139
140 buf[separator - path] = '\0';
141
142 *zip_path = buf;
143 *entry_path = &buf[separator - path + 2];
144
145 return true;
146}
147
Dmitriy Ivanov84bab5a2015-11-20 13:34:11 -0800148constexpr off64_t kPageMask = ~static_cast<off64_t>(PAGE_SIZE-1);
149
150off64_t page_start(off64_t offset) {
151 return offset & kPageMask;
152}
153
154bool safe_add(off64_t* out, off64_t a, size_t b) {
155 CHECK(a >= 0);
156 if (static_cast<uint64_t>(INT64_MAX - a) < b) {
157 return false;
158 }
159
160 *out = a + b;
161 return true;
162}
163
164size_t page_offset(off64_t offset) {
165 return static_cast<size_t>(offset & (PAGE_SIZE-1));
166}
167
Dimitry Ivanov48ec2882016-08-04 11:50:36 -0700168void split_path(const char* path, const char* delimiters,
169 std::vector<std::string>* paths) {
170 if (path != nullptr && path[0] != 0) {
171 *paths = android::base::Split(path, delimiters);
172 }
173}
174
175void resolve_paths(std::vector<std::string>& paths,
176 std::vector<std::string>* resolved_paths) {
177 resolved_paths->clear();
178 for (const auto& path : paths) {
Dimitry Ivanov01fdb6a2016-09-07 14:48:27 -0700179 // skip empty paths
180 if (path.empty()) {
181 continue;
182 }
183
Dimitry Ivanov48ec2882016-08-04 11:50:36 -0700184 char resolved_path[PATH_MAX];
185 const char* original_path = path.c_str();
186 if (realpath(original_path, resolved_path) != nullptr) {
187 struct stat s;
188 if (stat(resolved_path, &s) == 0) {
189 if (S_ISDIR(s.st_mode)) {
190 resolved_paths->push_back(resolved_path);
191 } else {
192 DL_WARN("Warning: \"%s\" is not a directory (excluding from path)", resolved_path);
193 continue;
194 }
195 } else {
196 DL_WARN("Warning: cannot stat file \"%s\": %s", resolved_path, strerror(errno));
197 continue;
198 }
199 } else {
200 std::string zip_path;
201 std::string entry_path;
202
203 std::string normalized_path;
204
205 if (!normalize_path(original_path, &normalized_path)) {
206 DL_WARN("Warning: unable to normalize \"%s\"", original_path);
207 continue;
208 }
209
210 if (parse_zip_path(normalized_path.c_str(), &zip_path, &entry_path)) {
211 if (realpath(zip_path.c_str(), resolved_path) == nullptr) {
212 DL_WARN("Warning: unable to resolve \"%s\": %s", zip_path.c_str(), strerror(errno));
213 continue;
214 }
215
216 resolved_paths->push_back(std::string(resolved_path) + kZipFileSeparator + entry_path);
217 }
218 }
219 }
220}
221