diff options
author | Yun Peng <pcloudy@google.com> | 2018-01-11 04:37:39 -0800 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-01-11 04:40:54 -0800 |
commit | 5fa8dbd9d536417cfe544114a2584dfef9785dd7 (patch) | |
tree | c17a48f80f89c7500fa1c0f309e202cb01d956f5 /src/tools/launcher | |
parent | 2e631c99495f75270d2639542cefb531ec262d67 (diff) |
Windows, Java launcher: Use relativize paths in classpath jar
Fixed https://github.com/bazelbuild/bazel/issues/4408
Change-Id: Id62b25e675822bbed91a448e70bdcb76e722721e
PiperOrigin-RevId: 181591585
Diffstat (limited to 'src/tools/launcher')
-rw-r--r-- | src/tools/launcher/java_launcher.cc | 53 | ||||
-rw-r--r-- | src/tools/launcher/util/launcher_util.cc | 83 | ||||
-rw-r--r-- | src/tools/launcher/util/launcher_util.h | 9 | ||||
-rw-r--r-- | src/tools/launcher/util/launcher_util_test.cc | 62 |
4 files changed, 197 insertions, 10 deletions
diff --git a/src/tools/launcher/java_launcher.cc b/src/tools/launcher/java_launcher.cc index 8a91fef871..15a3354fb3 100644 --- a/src/tools/launcher/java_launcher.cc +++ b/src/tools/launcher/java_launcher.cc @@ -16,6 +16,7 @@ #include <string> #include <vector> +#include "src/main/cpp/util/file_platform.h" #include "src/tools/launcher/java_launcher.h" #include "src/tools/launcher/util/launcher_util.h" @@ -115,26 +116,58 @@ vector<string> JavaBinaryLauncher::ProcessesCommandLine() { return args; } +// Return an absolute normalized path for the directory of manifest jar +static string GetManifestJarDir(const string& binary_base_path) { + string abs_manifest_jar_dir; + std::size_t slash = binary_base_path.find_last_of("/\\"); + if (slash == string::npos) { + abs_manifest_jar_dir = ""; + } else { + abs_manifest_jar_dir = binary_base_path.substr(0, slash); + } + if (!blaze_util::IsAbsolute(binary_base_path)) { + abs_manifest_jar_dir = blaze_util::GetCwd() + "\\" + abs_manifest_jar_dir; + } + string result; + if (!NormalizePath(abs_manifest_jar_dir, &result)) { + die("GetManifestJarDir Failed"); + } + return result; +} + string JavaBinaryLauncher::CreateClasspathJar(const string& classpath) { - static constexpr const char* URI_PREFIX = "file:/"; + string binary_base_path = + GetBinaryPathWithoutExtension(this->GetCommandlineArguments()[0]); + string abs_manifest_jar_dir_norm = GetManifestJarDir(binary_base_path); + ostringstream manifest_classpath; manifest_classpath << "Class-Path:"; stringstream classpath_ss(classpath); - string path; + string path, path_norm; while (getline(classpath_ss, path, ';')) { manifest_classpath << ' '; - manifest_classpath << URI_PREFIX; - for (const auto& x : path) { - if (x == ' ') { - manifest_classpath << "%20"; - } else { - manifest_classpath << x; + if (blaze_util::IsAbsolute(path)) { + if (!NormalizePath(path, &path_norm) || + !RelativeTo(path_norm, abs_manifest_jar_dir_norm, &path)) { + die("CreateClasspathJar failed"); } } + if (path.find_first_of(" \\") != string::npos) { + for (const auto& x : path) { + if (x == ' ') { + manifest_classpath << "%20"; + } + if (x == '\\') { + manifest_classpath << "/"; + } else { + manifest_classpath << x; + } + } + } else { + manifest_classpath << path; + } } - string binary_base_path = - GetBinaryPathWithoutExtension(this->GetCommandlineArguments()[0]); string rand_id = "-" + GetRandomStr(10); string jar_manifest_file_path = binary_base_path + rand_id + ".jar_manifest"; ofstream jar_manifest_file(jar_manifest_file_path); diff --git a/src/tools/launcher/util/launcher_util.cc b/src/tools/launcher/util/launcher_util.cc index b4513559e4..83aa3f8988 100644 --- a/src/tools/launcher/util/launcher_util.cc +++ b/src/tools/launcher/util/launcher_util.cc @@ -19,6 +19,7 @@ #include <stdlib.h> #include <string.h> #include <windows.h> +#include <algorithm> #include <sstream> #include <string> @@ -170,5 +171,87 @@ string GetRandomStr(size_t len) { return rand_str.str(); } +bool NormalizePath(const string& path, string* result) { + if (!blaze_util::AsWindowsPath(path, result)) { + PrintError("Failed to normalize %s", path.c_str()); + return false; + } + std::transform(result->begin(), result->end(), result->begin(), ::tolower); + return true; +} + +bool RelativeTo(const string& path, const string& base, string* result) { + if (blaze_util::IsAbsolute(path) != blaze_util::IsAbsolute(base)) { + PrintError( + "Cannot calculate relative path from an absolute and a non-absolute" + " path.\npath = %s\nbase = %s", + path.c_str(), base.c_str()); + return false; + } + + if (blaze_util::IsAbsolute(path) && blaze_util::IsAbsolute(base) && + path[0] != base[0]) { + PrintError( + "Cannot calculate relative path from absolute path under different " + "drives." + "\npath = %s\nbase = %s", + path.c_str(), base.c_str()); + return false; + } + + // Record the back slash position after the last matched path fragment + int pos = 0; + int back_slash_pos = -1; + while (path[pos] == base[pos] && base[pos] != '\0') { + if (path[pos] == '\\') { + back_slash_pos = pos; + } + pos++; + } + + if (base[pos] == '\0' && path[pos] == '\0') { + // base == path in this case + result->assign(""); + return true; + } + + if ((base[pos] == '\0' && path[pos] == '\\') || + (base[pos] == '\\' && path[pos] == '\0')) { + // In this case, one of the paths is the parent of another one. + // We should move back_slash_pos to the end of the shorter path. + // eg. path = c:\foo\bar, base = c:\foo => back_slash_pos = 6 + // or path = c:\foo, base = c:\foo\bar => back_slash_pos = 6 + back_slash_pos = pos; + } + + ostringstream buffer; + + // Create the ..\\ prefix + // eg. path = C:\foo\bar1, base = C:\foo\bar2, we need ..\ prefix + // In case "base" is a parent of "path", we set back_slash_pos to the end + // of "base", so we need no prefix when back_slash_pos + 1 > base.length(). + // back_slash_pos + 1 == base.length() is not possible because the last + // character of a normalized path won't be back slash. + if (back_slash_pos + 1 < base.length()) { + buffer << "..\\"; + } + for (int i = back_slash_pos + 1; i < base.length(); i++) { + if (base[i] == '\\') { + buffer << "..\\"; + } + } + + // Add the result of not matched path fragments into result + // eg. path = C:\foo\bar1, base = C:\foo\bar2, adding `bar1` + // In case "path" is a parent of "base", we set back_slash_pos to the end + // of "path", so we need no suffix when back_slash_pos == path.length(). + if (back_slash_pos != path.length()) { + buffer << path.substr(back_slash_pos + 1); + } + + result->assign(buffer.str()); + return true; +} + } // namespace launcher } // namespace bazel diff --git a/src/tools/launcher/util/launcher_util.h b/src/tools/launcher/util/launcher_util.h index 3877b7c5af..ae254bd09a 100644 --- a/src/tools/launcher/util/launcher_util.h +++ b/src/tools/launcher/util/launcher_util.h @@ -76,6 +76,15 @@ bool SetEnv(const std::string& env_name, const std::string& value); // The string consists of a-zA-Z0-9 std::string GetRandomStr(size_t len); +// Normalize a path to a Windows path in lower case +bool NormalizePath(const std::string& path, std::string* result); + +// Calculate a relative path from `path` to `base`. +// This function expects normalized Windows path in lower case. +// `path` and `base` should be both absolute or both relative. +bool RelativeTo(const std::string& path, const std::string& base, + std::string* result); + } // namespace launcher } // namespace bazel diff --git a/src/tools/launcher/util/launcher_util_test.cc b/src/tools/launcher/util/launcher_util_test.cc index 9024d1d11e..f8ddf803f3 100644 --- a/src/tools/launcher/util/launcher_util_test.cc +++ b/src/tools/launcher/util/launcher_util_test.cc @@ -113,5 +113,67 @@ TEST_F(LaunchUtilTest, SetAndGetEnvTest) { ASSERT_FALSE(GetEnv("FOO", &value)); } +TEST_F(LaunchUtilTest, NormalizePathTest) { + string value; + ASSERT_TRUE(NormalizePath("C:\\foo\\bar\\", &value)); + ASSERT_EQ("c:\\foo\\bar", value); + ASSERT_TRUE(NormalizePath("c:/foo/bar/", &value)); + ASSERT_EQ("c:\\foo\\bar", value); + ASSERT_TRUE(NormalizePath("FoO\\\\bAr\\", &value)); + ASSERT_EQ("foo\\bar", value); + ASSERT_TRUE(NormalizePath("X\\Y/Z\\", &value)); + ASSERT_EQ("x\\y\\z", value); + ASSERT_TRUE(NormalizePath("c://foo//bar", &value)); + ASSERT_EQ("c:\\foo\\bar", value); + ASSERT_FALSE(NormalizePath("c:foo\\bar", &value)); +} + +TEST_F(LaunchUtilTest, RelativeToTest) { + string value; + ASSERT_TRUE(RelativeTo("c:\\foo\\bar1", "c:\\foo\\bar2", &value)); + ASSERT_EQ("..\\bar1", value); + ASSERT_TRUE(RelativeTo("c:\\foo\\bar", "c:\\", &value)); + ASSERT_EQ("foo\\bar", value); + ASSERT_TRUE(RelativeTo("c:\\foo\\bar", "c:\\foo\\bar", &value)); + ASSERT_EQ("", value); + ASSERT_TRUE(RelativeTo("c:\\foo\\bar", "c:\\foo", &value)); + ASSERT_EQ("bar", value); + ASSERT_TRUE(RelativeTo("c:\\foo\\bar", "c:\\foo\\ba", &value)); + ASSERT_EQ("..\\bar", value); + ASSERT_TRUE(RelativeTo("c:\\", "c:\\foo", &value)); + ASSERT_EQ("..\\", value); + ASSERT_TRUE(RelativeTo("c:\\", "c:\\a\\b\\c", &value)); + ASSERT_EQ("..\\..\\..\\", value); + ASSERT_TRUE(RelativeTo("c:\\aa\\bb\\cc", "c:\\a\\b", &value)); + ASSERT_EQ("..\\..\\aa\\bb\\cc", value); + + ASSERT_TRUE(RelativeTo("foo\\bar", "foo\\bar", &value)); + ASSERT_EQ("", value); + ASSERT_TRUE(RelativeTo("foo\\bar1", "foo\\bar2", &value)); + ASSERT_EQ("..\\bar1", value); + ASSERT_TRUE(RelativeTo("foo\\bar1", "foo\\bar", &value)); + ASSERT_EQ("..\\bar1", value); + ASSERT_TRUE(RelativeTo("foo\\bar1", "foo", &value)); + ASSERT_EQ("bar1", value); + ASSERT_TRUE(RelativeTo("foo\\bar1", "fo", &value)); + ASSERT_EQ("..\\foo\\bar1", value); + ASSERT_TRUE(RelativeTo("foo\\ba", "foo\\bar", &value)); + ASSERT_EQ("..\\ba", value); + ASSERT_TRUE(RelativeTo("foo", "foo\\bar", &value)); + ASSERT_EQ("..\\", value); + ASSERT_TRUE(RelativeTo("fo", "foo\\bar", &value)); + ASSERT_EQ("..\\..\\fo", value); + ASSERT_TRUE(RelativeTo("", "foo\\bar", &value)); + ASSERT_EQ("..\\..\\", value); + ASSERT_TRUE(RelativeTo("foo\\bar", "", &value)); + ASSERT_EQ("foo\\bar", value); + ASSERT_TRUE(RelativeTo("a\\b\\c", "x\\y", &value)); + ASSERT_EQ("..\\..\\a\\b\\c", value); + + ASSERT_FALSE(RelativeTo("c:\\foo\\bar1", "foo\\bar2", &value)); + ASSERT_FALSE(RelativeTo("c:foo\\bar1", "c:\\foo\\bar2", &value)); + ASSERT_FALSE(RelativeTo("c:\\foo\\bar1", "d:\\foo\\bar2", &value)); +} + } // namespace launcher } // namespace bazel |