1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "linker_utils.h" 18 #include "linker_debug.h" 19 20 bool normalize_path(const char* path, std::string* normalized_path) { 21 // Input should be an absolute path 22 if (path[0] != '/') { 23 PRINT("normalize_path - invalid input: \"%s\", the input path should be absolute", path); 24 return false; 25 } 26 27 const size_t len = strlen(path) + 1; 28 char buf[len]; 29 30 const char* in_ptr = path; 31 char* out_ptr = buf; 32 33 while (*in_ptr != 0) { 34 if (*in_ptr == '/') { 35 char c1 = in_ptr[1]; 36 if (c1 == '.') { 37 char c2 = in_ptr[2]; 38 if (c2 == '/') { 39 in_ptr += 2; 40 continue; 41 } else if (c2 == '.' && (in_ptr[3] == '/' || in_ptr[3] == 0)) { 42 in_ptr += 3; 43 while (out_ptr > buf && *--out_ptr != '/') { 44 } 45 if (in_ptr[0] == 0) { 46 // retain '/' 47 out_ptr++; 48 } 49 continue; 50 } 51 } else if (c1 == '/') { 52 ++in_ptr; 53 continue; 54 } 55 } 56 *out_ptr++ = *in_ptr++; 57 } 58 59 *out_ptr = 0; 60 *normalized_path = buf; 61 return true; 62 } 63 64 bool file_is_in_dir(const std::string& file, const std::string& dir) { 65 const char* needle = dir.c_str(); 66 const char* haystack = file.c_str(); 67 size_t needle_len = strlen(needle); 68 69 return strncmp(haystack, needle, needle_len) == 0 && 70 haystack[needle_len] == '/' && 71 strchr(haystack + needle_len + 1, '/') == nullptr; 72 } 73 74 bool file_is_under_dir(const std::string& file, const std::string& dir) { 75 const char* needle = dir.c_str(); 76 const char* haystack = file.c_str(); 77 size_t needle_len = strlen(needle); 78 79 return strncmp(haystack, needle, needle_len) == 0 && 80 haystack[needle_len] == '/'; 81 } 82 83 const char* const kZipFileSeparator = "!/"; 84 85 bool parse_zip_path(const char* input_path, std::string* zip_path, std::string* entry_path) { 86 std::string normalized_path; 87 if (!normalize_path(input_path, &normalized_path)) { 88 return false; 89 } 90 91 const char* const path = normalized_path.c_str(); 92 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path); 93 94 // Treat an '!/' separator inside a path as the separator between the name 95 // of the zip file on disk and the subdirectory to search within it. 96 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for 97 // "bar/bas/x.so" within "foo.zip". 98 const char* const separator = strstr(path, kZipFileSeparator); 99 if (separator == nullptr) { 100 return false; 101 } 102 103 char buf[512]; 104 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) { 105 PRINT("Warning: ignoring very long library path: %s", path); 106 return false; 107 } 108 109 buf[separator - path] = '\0'; 110 111 *zip_path = buf; 112 *entry_path = &buf[separator - path + 2]; 113 114 return true; 115 } 116 117 constexpr off64_t kPageMask = ~static_cast<off64_t>(PAGE_SIZE-1); 118 119 off64_t page_start(off64_t offset) { 120 return offset & kPageMask; 121 } 122 123 bool safe_add(off64_t* out, off64_t a, size_t b) { 124 CHECK(a >= 0); 125 if (static_cast<uint64_t>(INT64_MAX - a) < b) { 126 return false; 127 } 128 129 *out = a + b; 130 return true; 131 } 132 133 size_t page_offset(off64_t offset) { 134 return static_cast<size_t>(offset & (PAGE_SIZE-1)); 135 } 136 137