Make android::base::Dirname() thread-safe.

See 91a10d912827b818d0c1931ede3a2afaa93b18cd where we did this for
Basename(). We don't know that Dirname() has caused similar problems,
but there's no reason it couldn't...

Bug: http://b/231951809
Test: treehugger
Change-Id: I64bb362a3652654066101511a7a500c8223d62f7
diff --git a/file.cpp b/file.cpp
index a580dcc..d0cec7d 100644
--- a/file.cpp
+++ b/file.cpp
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -553,18 +554,19 @@
 }
 #endif
 
+#if defined(_WIN32)
 std::string Dirname(const std::string& path) {
+  // TODO: how much of this is actually necessary for mingw?
+
   // Copy path because dirname may modify the string passed in.
   std::string result(path);
 
-#if !defined(__BIONIC__)
   // Use lock because dirname() may write to a process global and return a
   // pointer to that. Note that this locking strategy only works if all other
   // callers to dirname in the process also grab this same lock, but its
   // better than nothing.  Bionic's dirname returns a thread-local buffer.
   static std::mutex& dirname_lock = *new std::mutex();
   std::lock_guard<std::mutex> lock(dirname_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
@@ -577,6 +579,72 @@
 
   return result;
 }
+#else
+// Copied from bionic so that Dirname() below can be portable and thread-safe.
+static int __dirname_r(const char* path, char* buffer, size_t buffer_size) {
+  const char* endp = nullptr;
+  int len;
+  int result;
+
+  // Empty or NULL string gets treated as ".".
+  if (path == nullptr || *path == '\0') {
+    path = ".";
+    len = 1;
+    goto Exit;
+  }
+
+  // Strip trailing slashes.
+  endp = path + strlen(path) - 1;
+  while (endp > path && *endp == '/') {
+    endp--;
+  }
+
+  // Find the start of the dir.
+  while (endp > path && *endp != '/') {
+    endp--;
+  }
+
+  // Either the dir is "/" or there are no slashes.
+  if (endp == path) {
+    path = (*endp == '/') ? "/" : ".";
+    len = 1;
+    goto Exit;
+  }
+
+  do {
+    endp--;
+  } while (endp > path && *endp == '/');
+
+  len = endp - path + 1;
+
+ Exit:
+  result = len;
+  if (len + 1 > MAXPATHLEN) {
+    errno = ENAMETOOLONG;
+    return -1;
+  }
+  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, path, len);
+    buffer[len] = 0;
+  }
+  return result;
+}
+std::string Dirname(const std::string& path) {
+  char buf[PATH_MAX];
+  __dirname_r(path.c_str(), buf, sizeof(buf));
+  return buf;
+}
+#endif
 
 }  // namespace base
 }  // namespace android