Always build absolute paths the same way
Fix a bug where output paths like:
C:\foo\bar
triggered bad logic to detect relative paths and turned the path into
.\C:\foo\bar
Fix this by moving absolute path detection logic into a common helper
function and calling it consistently.
Bug: 29091703
Test: unittests, angler-eng builds with this change, manual testing on
windows demonstrates issue is fixed
Change-Id: I8bc83a3e3943931d95db3e4147d4f8b1b07e907a
diff --git a/Android.mk b/Android.mk
index 5b844e4..b27a4df 100644
--- a/Android.mk
+++ b/Android.mk
@@ -99,6 +99,7 @@
ast_cpp_unittest.cpp \
ast_java_unittest.cpp \
generate_cpp_unittest.cpp \
+ io_delegate_unittest.cpp \
options_unittest.cpp \
tests/end_to_end_tests.cpp \
tests/fake_io_delegate.cpp \
diff --git a/aidl.cpp b/aidl.cpp
index 6f542bf..10a90e4 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -77,23 +77,10 @@
string expected;
string fn;
size_t len;
- char cwd[MAXPATHLEN];
bool valid = false;
-#ifdef _WIN32
- if (isalpha(filename[0]) && filename[1] == ':'
- && filename[2] == OS_PATH_SEPARATOR) {
-#else
- if (filename[0] == OS_PATH_SEPARATOR) {
-#endif
- fn = filename;
- } else {
- fn = getcwd(cwd, sizeof(cwd));
- len = fn.length();
- if (fn[len-1] != OS_PATH_SEPARATOR) {
- fn += OS_PATH_SEPARATOR;
- }
- fn += filename;
+ if (!IoDelegate::GetAbsolutePath(filename, &fn)) {
+ return false;
}
if (!package.empty()) {
diff --git a/io_delegate.cpp b/io_delegate.cpp
index 66891dd..62be3f5 100644
--- a/io_delegate.cpp
+++ b/io_delegate.cpp
@@ -41,6 +41,45 @@
namespace android {
namespace aidl {
+bool IoDelegate::GetAbsolutePath(const string& path, string* absolute_path) {
+#ifdef _WIN32
+
+ char buf[4096];
+ DWORD path_len = GetFullPathName(path.c_str(), sizeof(buf), buf, nullptr);
+ if (path_len <= 0 || path_len >= sizeof(buf)) {
+ LOG(ERROR) << "Failed to GetFullPathName(" << path << ")";
+ return false;
+ }
+ *absolute_path = buf;
+
+ return true;
+
+#else
+
+ if (path.empty()) {
+ LOG(ERROR) << "Giving up on finding an absolute path to represent the "
+ "empty string.";
+ return false;
+ }
+ if (path[0] == OS_PATH_SEPARATOR) {
+ *absolute_path = path;
+ return true;
+ }
+
+ char buf[4096];
+ if (getcwd(buf, sizeof(buf)) == nullptr) {
+ LOG(ERROR) << "Path of current working directory does not fit in "
+ << sizeof(buf) << " bytes";
+ return false;
+ }
+
+ *absolute_path = buf;
+ *absolute_path += OS_PATH_SEPARATOR;
+ *absolute_path += path;
+ return true;
+#endif
+}
+
unique_ptr<string> IoDelegate::GetFileContents(
const string& filename,
const string& content_suffix) const {
@@ -112,15 +151,26 @@
return true;
}
- string base = ".";
- if (path[0] == OS_PATH_SEPARATOR) {
- base = "/";
+ string absolute_path;
+ if (!GetAbsolutePath(path, &absolute_path)) {
+ return false;
}
- auto split = Split(path, string{1u, OS_PATH_SEPARATOR});
- split.pop_back();
+ auto directories = Split(absolute_path, string{1u, OS_PATH_SEPARATOR});
- return CreatedNestedDirs(base, split);
+ // The "base" directory is just the root of the file system. On Windows,
+ // this will look like "C:\" but on Unix style file systems we get an empty
+ // string after splitting "/foo" with "/"
+ string base = directories[0];
+ if (base.empty()) {
+ base = "/";
+ }
+ directories.erase(directories.begin());
+
+ // Remove the actual file in question, we're just creating the directory path.
+ directories.pop_back();
+
+ return CreatedNestedDirs(base, directories);
}
unique_ptr<CodeWriter> IoDelegate::GetCodeWriter(
diff --git a/io_delegate.h b/io_delegate.h
index b0a703b..dc9a3e3 100644
--- a/io_delegate.h
+++ b/io_delegate.h
@@ -34,6 +34,12 @@
IoDelegate() = default;
virtual ~IoDelegate() = default;
+ // Stores an absolute version of |path| to |*absolute_path|,
+ // possibly prefixing it with the current working directory.
+ // Returns false and does not set |*absolute_path| on error.
+ static bool GetAbsolutePath(const std::string& path,
+ std::string* absolute_path);
+
// Returns a unique_ptr to the contents of |filename|.
// Will append the optional |content_suffix| to the returned contents.
virtual std::unique_ptr<std::string> GetFileContents(
diff --git a/io_delegate_unittest.cpp b/io_delegate_unittest.cpp
new file mode 100644
index 0000000..5227d0b
--- /dev/null
+++ b/io_delegate_unittest.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "io_delegate.h"
+
+using std::string;
+
+namespace android {
+namespace aidl {
+
+TEST(IoDelegateTest, CannotGetAbsolutePathFromEmptyString) {
+ string absolute_path;
+ EXPECT_FALSE(IoDelegate::GetAbsolutePath("", &absolute_path));
+ EXPECT_TRUE(absolute_path.empty());
+}
+
+TEST(IoDelegateTest, CurrentlyInfersLinuxAbsolutePath) {
+ string absolute_path;
+ EXPECT_TRUE(IoDelegate::GetAbsolutePath("foo", &absolute_path));
+ ASSERT_FALSE(absolute_path.empty());
+ // Should find our desired file at the end of |absolute_path|
+ // But we don't know the prefix, since it's the current working directory
+ EXPECT_TRUE(absolute_path.rfind("/foo") == absolute_path.length() - 4);
+ // Whatever our current working directory, the path is absolute.
+ EXPECT_EQ(absolute_path[0], '/');
+}
+
+} // namespace android
+} // namespace aidl