Snap for 8701348 from 0dcba40553c64657174464a0488b0784f2a6e413 to mainline-tethering-release
Change-Id: Ibb50bb670d775594030625686ed8fba7286d3081
diff --git a/file.cpp b/file.cpp
index 97cc2b2..a580dcc 100644
--- a/file.cpp
+++ b/file.cpp
@@ -468,18 +468,19 @@
return Dirname(GetExecutablePath());
}
+#if defined(_WIN32)
std::string Basename(const std::string& path) {
+ // TODO: how much of this is actually necessary for mingw?
+
// Copy path because basename may modify the string passed in.
std::string result(path);
-#if !defined(__BIONIC__)
// Use lock because basename() may write to a process global and return a
// pointer to that. Note that this locking strategy only works if all other
// callers to basename in the process also grab this same lock, but its
// better than nothing. Bionic's basename returns a thread-local buffer.
static std::mutex& basename_lock = *new std::mutex();
std::lock_guard<std::mutex> lock(basename_lock);
-#endif
// Note that if std::string uses copy-on-write strings, &str[0] will cause
// the copy to be made, so there is no chance of us accidentally writing to
@@ -492,6 +493,65 @@
return result;
}
+#else
+// Copied from bionic so that Basename() below can be portable and thread-safe.
+static int __basename_r(const char* path, char* buffer, size_t buffer_size) {
+ const char* startp = nullptr;
+ const char* endp = nullptr;
+ int len;
+ int result;
+
+ // Empty or NULL string gets treated as ".".
+ if (path == nullptr || *path == '\0') {
+ startp = ".";
+ len = 1;
+ goto Exit;
+ }
+
+ // Strip trailing slashes.
+ endp = path + strlen(path) - 1;
+ while (endp > path && *endp == '/') {
+ endp--;
+ }
+
+ // All slashes becomes "/".
+ if (endp == path && *endp == '/') {
+ startp = "/";
+ len = 1;
+ goto Exit;
+ }
+
+ // Find the start of the base.
+ startp = endp;
+ while (startp > path && *(startp - 1) != '/') {
+ startp--;
+ }
+
+ len = endp - startp +1;
+
+ Exit:
+ result = len;
+ if (buffer == nullptr) {
+ return result;
+ }
+ if (len > static_cast<int>(buffer_size) - 1) {
+ len = buffer_size - 1;
+ result = -1;
+ errno = ERANGE;
+ }
+
+ if (len >= 0) {
+ memcpy(buffer, startp, len);
+ buffer[len] = 0;
+ }
+ return result;
+}
+std::string Basename(const std::string& path) {
+ char buf[PATH_MAX];
+ __basename_r(path.c_str(), buf, sizeof(buf));
+ return buf;
+}
+#endif
std::string Dirname(const std::string& path) {
// Copy path because dirname may modify the string passed in.
diff --git a/file_test.cpp b/file_test.cpp
index 120228d..c739664 100644
--- a/file_test.cpp
+++ b/file_test.cpp
@@ -333,6 +333,17 @@
EXPECT_EQ("sh", android::base::Basename("/system/bin/sh"));
EXPECT_EQ("sh", android::base::Basename("sh"));
EXPECT_EQ("sh", android::base::Basename("/system/bin/sh/"));
+
+ // Since we've copy & pasted bionic's implementation, copy & paste the tests.
+ EXPECT_EQ(".", android::base::Basename(""));
+ EXPECT_EQ("lib", android::base::Basename("/usr/lib"));
+ EXPECT_EQ("usr", android::base::Basename("/usr/"));
+ EXPECT_EQ("usr", android::base::Basename("usr"));
+ EXPECT_EQ("/", android::base::Basename("/"));
+ EXPECT_EQ(".", android::base::Basename("."));
+ EXPECT_EQ("..", android::base::Basename(".."));
+ EXPECT_EQ("/", android::base::Basename("///"));
+ EXPECT_EQ("lib", android::base::Basename("//usr//lib//"));
}
TEST(file, Dirname) {