1a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov/*
2a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov * Copyright (C) 2015 The Android Open Source Project
3bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * All rights reserved.
4a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov *
5bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * Redistribution and use in source and binary forms, with or without
6bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * modification, are permitted provided that the following conditions
7bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * are met:
8bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov *  * Redistributions of source code must retain the above copyright
9bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov *    notice, this list of conditions and the following disclaimer.
10bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov *  * Redistributions in binary form must reproduce the above copyright
11bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov *    notice, this list of conditions and the following disclaimer in
12bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov *    the documentation and/or other materials provided with the
13bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov *    distribution.
14a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov *
15bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * SUCH DAMAGE.
27a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov */
28a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov
29a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov#include "linker_utils.h"
3048ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov
31a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov#include "linker_debug.h"
3248ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov#include "linker_globals.h"
3348ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov
3448ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov#include "android-base/strings.h"
3548ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov
3648ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov#include <sys/stat.h>
3748ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov#include <unistd.h>
3848ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov
392a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanovvoid format_string(std::string* str, const std::vector<std::pair<std::string, std::string>>& params) {
402a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov  size_t pos = 0;
412a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov  while (pos < str->size()) {
422a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov    pos = str->find("$", pos);
432a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov    if (pos == std::string::npos) break;
442a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov    for (const auto& param : params) {
452a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov      const std::string& token = param.first;
462a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov      const std::string& replacement = param.second;
472a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov      if (str->substr(pos + 1, token.size()) == token) {
482a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov        str->replace(pos, token.size() + 1, replacement);
492a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov        // -1 to compensate for the ++pos below.
502a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov        pos += replacement.size() - 1;
512a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov        break;
522a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov      } else if (str->substr(pos + 1, token.size() + 2) == "{" + token + "}") {
532a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov        str->replace(pos, token.size() + 3, replacement);
542a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov        pos += replacement.size() - 1;
552a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov        break;
562a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov      }
572a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov    }
582a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov    // Skip $ in case it did not match any of the known substitutions.
592a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov    ++pos;
602a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov  }
612a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov}
622a6d9b25437c42fd3e0284a6e7a607c842f59fe0Dimitry Ivanov
6348ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanovstd::string dirname(const char* path) {
6448ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov  const char* last_slash = strrchr(path, '/');
6548ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov
6648ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov  if (last_slash == path) {
6748ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov    return "/";
6848ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov  } else if (last_slash == nullptr) {
6948ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov    return ".";
7048ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov  } else {
7148ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov    return std::string(path, last_slash - path);
7248ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov  }
7348ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov}
74a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov
75a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanovbool normalize_path(const char* path, std::string* normalized_path) {
76a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov  // Input should be an absolute path
77a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov  if (path[0] != '/') {
78769b33fadf45a039741f932672ac2c4f901d7d4aDimitry Ivanov    PRINT("normalize_path - invalid input: \"%s\", the input path should be absolute", path);
79a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov    return false;
80a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov  }
81a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov
82a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov  const size_t len = strlen(path) + 1;
83a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov  char buf[len];
84a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov
85a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov  const char* in_ptr = path;
86a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov  char* out_ptr = buf;
87a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov
88a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov  while (*in_ptr != 0) {
89a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov    if (*in_ptr == '/') {
90a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov      char c1 = in_ptr[1];
91a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov      if (c1 == '.') {
92a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov        char c2 = in_ptr[2];
93a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov        if (c2 == '/') {
94a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov          in_ptr += 2;
95a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov          continue;
96a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov        } else if (c2 == '.' && (in_ptr[3] == '/' || in_ptr[3] == 0)) {
97a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov          in_ptr += 3;
98a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov          while (out_ptr > buf && *--out_ptr != '/') {
99a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov          }
100a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov          if (in_ptr[0] == 0) {
101a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov            // retain '/'
102a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov            out_ptr++;
103a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov          }
104a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov          continue;
105a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov        }
106a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov      } else if (c1 == '/') {
107a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov        ++in_ptr;
108a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov        continue;
109a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov      }
110a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov    }
111a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov    *out_ptr++ = *in_ptr++;
112a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov  }
113a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov
114a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov  *out_ptr = 0;
115a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov  *normalized_path = buf;
116a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov  return true;
117a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov}
118a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov
11942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovbool file_is_in_dir(const std::string& file, const std::string& dir) {
12042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  const char* needle = dir.c_str();
12142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  const char* haystack = file.c_str();
12242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  size_t needle_len = strlen(needle);
12342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov
124284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov  return strncmp(haystack, needle, needle_len) == 0 &&
125284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov         haystack[needle_len] == '/' &&
126284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov         strchr(haystack + needle_len + 1, '/') == nullptr;
127284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov}
128284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov
129284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanovbool file_is_under_dir(const std::string& file, const std::string& dir) {
130284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov  const char* needle = dir.c_str();
131284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov  const char* haystack = file.c_str();
132284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov  size_t needle_len = strlen(needle);
133284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov
134284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov  return strncmp(haystack, needle, needle_len) == 0 &&
135284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov         haystack[needle_len] == '/';
13642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov}
13742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov
13842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovconst char* const kZipFileSeparator = "!/";
13942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov
14042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovbool parse_zip_path(const char* input_path, std::string* zip_path, std::string* entry_path) {
14142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  std::string normalized_path;
14242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  if (!normalize_path(input_path, &normalized_path)) {
14342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov    return false;
14442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  }
14542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov
14642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  const char* const path = normalized_path.c_str();
147769b33fadf45a039741f932672ac2c4f901d7d4aDimitry Ivanov  TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
14842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov
14942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  // Treat an '!/' separator inside a path as the separator between the name
15042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  // of the zip file on disk and the subdirectory to search within it.
15142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
15242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  // "bar/bas/x.so" within "foo.zip".
15342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  const char* const separator = strstr(path, kZipFileSeparator);
15442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  if (separator == nullptr) {
15542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov    return false;
15642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  }
15742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov
15842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  char buf[512];
15942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
16042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov    PRINT("Warning: ignoring very long library path: %s", path);
16142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov    return false;
16242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  }
16342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov
16442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  buf[separator - path] = '\0';
16542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov
16642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  *zip_path = buf;
16742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  *entry_path = &buf[separator - path + 2];
16842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov
16942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov  return true;
17042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov}
17142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov
17284bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanovconstexpr off64_t kPageMask = ~static_cast<off64_t>(PAGE_SIZE-1);
17384bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov
17484bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanovoff64_t page_start(off64_t offset) {
17584bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov  return offset & kPageMask;
17684bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov}
17784bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov
17884bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanovbool safe_add(off64_t* out, off64_t a, size_t b) {
17984bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov  CHECK(a >= 0);
18084bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov  if (static_cast<uint64_t>(INT64_MAX - a) < b) {
18184bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov    return false;
18284bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov  }
18384bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov
18484bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov  *out = a + b;
18584bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov  return true;
18684bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov}
18784bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov
18884bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanovsize_t page_offset(off64_t offset) {
18984bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov  return static_cast<size_t>(offset & (PAGE_SIZE-1));
19084bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov}
19184bab5a9552cebf57795ade0e1abd5f7aee46479Dmitriy Ivanov
19248ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanovvoid split_path(const char* path, const char* delimiters,
19348ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov                std::vector<std::string>* paths) {
19448ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov  if (path != nullptr && path[0] != 0) {
19548ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov    *paths = android::base::Split(path, delimiters);
19648ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov  }
19748ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov}
19848ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov
19948ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanovvoid resolve_paths(std::vector<std::string>& paths,
20048ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov                   std::vector<std::string>* resolved_paths) {
20148ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov  resolved_paths->clear();
20248ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov  for (const auto& path : paths) {
20301fdb6ad571187498f47e570ba17441f560ba65cDimitry Ivanov    // skip empty paths
20401fdb6ad571187498f47e570ba17441f560ba65cDimitry Ivanov    if (path.empty()) {
20501fdb6ad571187498f47e570ba17441f560ba65cDimitry Ivanov      continue;
20601fdb6ad571187498f47e570ba17441f560ba65cDimitry Ivanov    }
20701fdb6ad571187498f47e570ba17441f560ba65cDimitry Ivanov
20848ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov    char resolved_path[PATH_MAX];
20948ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov    const char* original_path = path.c_str();
21048ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov    if (realpath(original_path, resolved_path) != nullptr) {
21148ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov      struct stat s;
21248ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov      if (stat(resolved_path, &s) == 0) {
21348ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov        if (S_ISDIR(s.st_mode)) {
21448ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov          resolved_paths->push_back(resolved_path);
21548ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov        } else {
21648ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov          DL_WARN("Warning: \"%s\" is not a directory (excluding from path)", resolved_path);
21748ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov          continue;
21848ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov        }
21948ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov      } else {
22048ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov        DL_WARN("Warning: cannot stat file \"%s\": %s", resolved_path, strerror(errno));
22148ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov        continue;
22248ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov      }
22348ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov    } else {
22448ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov      std::string zip_path;
22548ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov      std::string entry_path;
22648ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov
22748ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov      std::string normalized_path;
22848ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov
22948ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov      if (!normalize_path(original_path, &normalized_path)) {
23048ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov        DL_WARN("Warning: unable to normalize \"%s\"", original_path);
23148ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov        continue;
23248ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov      }
23348ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov
23448ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov      if (parse_zip_path(normalized_path.c_str(), &zip_path, &entry_path)) {
23548ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov        if (realpath(zip_path.c_str(), resolved_path) == nullptr) {
23648ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov          DL_WARN("Warning: unable to resolve \"%s\": %s", zip_path.c_str(), strerror(errno));
23748ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov          continue;
23848ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov        }
23948ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov
24048ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov        resolved_paths->push_back(std::string(resolved_path) + kZipFileSeparator + entry_path);
24148ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov      }
24248ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov    }
24348ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov  }
24448ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov}
24548ec288d40d272e6fe5e68c4c0a9778b55e24f8aDimitry Ivanov
246