Merge "init: Adding header guard to tokenizer"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index aa9ef55..aa0256d 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -801,11 +801,13 @@
             return 1;
         }
 
+        std::string error;
         InstallStatus r;
         if (kill_forward) {
             r = remove_listener(pieces[0].c_str(), transport);
         } else {
-            r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind);
+            r = install_listener(pieces[0], pieces[1].c_str(), transport,
+                                 no_rebind, &error);
         }
         if (r == INSTALL_STATUS_OK) {
 #if ADB_HOST
@@ -821,7 +823,8 @@
           case INSTALL_STATUS_OK: message = "success (!)"; break;
           case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break;
           case INSTALL_STATUS_CANNOT_BIND:
-            message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno));
+            message = android::base::StringPrintf("cannot bind to socket: %s",
+                                                  error.c_str());
             break;
           case INSTALL_STATUS_CANNOT_REBIND:
             message = android::base::StringPrintf("cannot rebind existing socket");
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 418662c..6d75966 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -153,8 +153,8 @@
     }
 
     int fd;
+    std::string reason;
     if (__adb_server_name) {
-        std::string reason;
         fd = network_connect(__adb_server_name, __adb_server_port, SOCK_STREAM, 0, &reason);
         if (fd == -1) {
             *error = android::base::StringPrintf("can't connect to %s:%d: %s",
@@ -163,9 +163,10 @@
             return -2;
         }
     } else {
-        fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
+        fd = network_loopback_client(__adb_server_port, SOCK_STREAM, &reason);
         if (fd == -1) {
-            *error = perror_str("cannot connect to daemon");
+            *error = android::base::StringPrintf("cannot connect to daemon: %s",
+                                                 reason.c_str());
             return -2;
         }
     }
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index 8fd5cbf..0ae21db 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -28,30 +28,7 @@
 #include <string>
 
 #include "base/file.h"
-
-class TemporaryFile {
- public:
-  TemporaryFile() {
-    init("/data/local/tmp");
-    if (fd == -1) {
-      init("/tmp");
-    }
-  }
-
-  ~TemporaryFile() {
-    close(fd);
-    unlink(filename);
-  }
-
-  int fd;
-  char filename[1024];
-
- private:
-  void init(const char* tmp_dir) {
-    snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
-    fd = mkstemp(filename);
-  }
-};
+#include "base/test_utils.h"
 
 TEST(io, ReadFdExactly_whole) {
   const char expected[] = "Foobar";
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index bb45022..1e7ce5d 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -110,27 +110,30 @@
     free_listener(reinterpret_cast<alistener*>(listener));
 }
 
-static int local_name_to_fd(const char* name) {
+static int local_name_to_fd(const char* name, std::string* error) {
     if (!strncmp("tcp:", name, 4)) {
         int port = atoi(name + 4);
         if (gListenAll > 0) {
-            return socket_inaddr_any_server(port, SOCK_STREAM);
+            return network_inaddr_any_server(port, SOCK_STREAM, error);
         } else {
-            return socket_loopback_server(port, SOCK_STREAM);
+            return network_loopback_server(port, SOCK_STREAM, error);
         }
     }
 #if !defined(_WIN32)  // No Unix-domain sockets on Windows.
     // It's nonsensical to support the "reserved" space on the adb host side
     if (!strncmp(name, "local:", 6)) {
-        return socket_local_server(name + 6, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+        return network_local_server(name + 6,
+                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
     } else if (!strncmp(name, "localabstract:", 14)) {
-        return socket_local_server(name + 14, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+        return network_local_server(name + 14,
+                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
     } else if (!strncmp(name, "localfilesystem:", 16)) {
-        return socket_local_server(name + 16, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
+        return network_local_server(name + 16,
+                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM, error);
     }
 
 #endif
-    printf("unknown local portname '%s'\n", name);
+    *error = android::base::StringPrintf("unknown local portname '%s'", name);
     return -1;
 }
 
@@ -178,7 +181,8 @@
 InstallStatus install_listener(const std::string& local_name,
                                   const char *connect_to,
                                   atransport* transport,
-                                  int no_rebind)
+                                  int no_rebind,
+                                  std::string* error)
 {
     for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
         if (local_name == l->local_name) {
@@ -226,9 +230,9 @@
         goto nomem;
     }
 
-    listener->fd = local_name_to_fd(listener->local_name);
+    listener->fd = local_name_to_fd(listener->local_name, error);
     if (listener->fd < 0) {
-        printf("cannot bind '%s': %s\n", listener->local_name, strerror(errno));
+        printf("cannot bind '%s': %s\n", listener->local_name, error->c_str());
         free(listener->local_name);
         free(listener->connect_to);
         free(listener);
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index 67deb21..fa98eed 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -33,7 +33,8 @@
 InstallStatus install_listener(const std::string& local_name,
                                const char* connect_to,
                                atransport* transport,
-                               int no_rebind);
+                               int no_rebind,
+                               std::string* error);
 
 std::string format_listeners();
 
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 6fa6c2e..12208cd 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -28,17 +28,10 @@
 #include <base/logging.h>
 #include <base/stringprintf.h>
 #include <base/strings.h>
-#include <cutils/sockets.h>
 
 #include "adb_trace.h"
 #include "sysdeps.h"
 
-#if defined(_WIN32)
-#include <ws2tcpip.h>
-#else
-#include <netdb.h>
-#endif
-
 bool getcwd(std::string* s) {
   char* cwd = getcwd(nullptr, 0);
   if (cwd != nullptr) *s = cwd;
@@ -72,24 +65,36 @@
   return result;
 }
 
-int mkdirs(const std::string& path) {
-    // TODO: rewrite this function and merge it with the *other* mkdirs in adb.
-    std::unique_ptr<char> path_rw(strdup(path.c_str()));
-    int ret;
-    char* x = path_rw.get() + 1;
+std::string adb_basename(const std::string& path) {
+    size_t base = path.find_last_of(OS_PATH_SEPARATORS);
+    return (base != std::string::npos) ? path.substr(base + 1) : path;
+}
 
-    for(;;) {
-        x = const_cast<char*>(adb_dirstart(x));
-        if(x == 0) return 0;
-        *x = 0;
-        ret = adb_mkdir(path_rw.get(), 0775);
-        *x = OS_PATH_SEPARATOR;
-        if((ret < 0) && (errno != EEXIST)) {
-            return ret;
+static bool real_mkdirs(const std::string& path) {
+    std::vector<std::string> path_components = android::base::Split(path, OS_PATH_SEPARATOR_STR);
+    // TODO: all the callers do unlink && mkdirs && adb_creat ---
+    // that's probably the operation we should expose.
+    path_components.pop_back();
+    std::string partial_path;
+    for (const auto& path_component : path_components) {
+        if (partial_path.back() != OS_PATH_SEPARATOR) partial_path += OS_PATH_SEPARATOR;
+        partial_path += path_component;
+        if (adb_mkdir(partial_path.c_str(), 0775) == -1 && errno != EEXIST) {
+            return false;
         }
-        x++;
     }
-    return 0;
+    return true;
+}
+
+bool mkdirs(const std::string& path) {
+#if defined(_WIN32)
+    // Replace '/' with '\\' so we can share the code.
+    std::string clean_path = path;
+    std::replace(clean_path.begin(), clean_path.end(), '/', '\\');
+    return real_mkdirs(clean_path);
+#else
+    return real_mkdirs(path);
+#endif
 }
 
 void dump_hex(const void* data, size_t byte_count) {
@@ -166,18 +171,3 @@
                << " (" << *canonical_address << ")";
     return true;
 }
-
-int network_connect(const std::string& host, int port, int type, int timeout, std::string* error) {
-    int getaddrinfo_error = 0;
-    int fd = socket_network_client_timeout(host.c_str(), port, type, timeout, &getaddrinfo_error);
-    if (fd != -1) {
-        return fd;
-    }
-    if (getaddrinfo_error != 0) {
-        // TODO: gai_strerror is not thread safe on Win32.
-        *error = gai_strerror(getaddrinfo_error);
-    } else {
-        *error = strerror(errno);
-    }
-    return -1;
-}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 673aaac..8c5208c 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -21,8 +21,9 @@
 
 bool getcwd(std::string* cwd);
 bool directory_exists(const std::string& path);
+std::string adb_basename(const std::string& path);
 
-int mkdirs(const std::string& path);
+bool mkdirs(const std::string& path);
 
 std::string escape_arg(const std::string& s);
 
@@ -39,6 +40,4 @@
                          std::string* host, int* port,
                          std::string* error);
 
-int network_connect(const std::string& host, int port, int type, int timeout, std::string* error);
-
 #endif
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index 7aa610a..309ac02 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -18,6 +18,13 @@
 
 #include <gtest/gtest.h>
 
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdeps.h"
+
+#include <base/test_utils.h>
+
 TEST(adb_utils, directory_exists) {
   ASSERT_TRUE(directory_exists("/proc"));
   ASSERT_FALSE(directory_exists("/proc/self")); // Symbolic link.
@@ -51,6 +58,11 @@
   ASSERT_EQ(R"('abc)')", escape_arg("abc)"));
 }
 
+TEST(adb_utils, adb_basename) {
+  EXPECT_EQ("sh", adb_basename("/system/bin/sh"));
+  EXPECT_EQ("sh", adb_basename("sh"));
+}
+
 TEST(adb_utils, parse_host_and_port) {
   std::string canonical_address;
   std::string host;
@@ -132,3 +144,11 @@
   EXPECT_FALSE(parse_host_and_port("1.2.3.4:0", &canonical_address, &host, &port, &error));
   EXPECT_FALSE(parse_host_and_port("1.2.3.4:65536", &canonical_address, &host, &port, &error));
 }
+
+TEST(adb_utils, mkdirs) {
+  TemporaryDir td;
+  std::string path = std::string(td.path) + "/dir/subdir/file";
+  EXPECT_TRUE(mkdirs(path));
+  EXPECT_NE(-1, adb_creat(path.c_str(), 0600));
+  EXPECT_FALSE(mkdirs(path + "/subdir/"));
+}
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index c018b8a..2b174cd 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -150,9 +150,10 @@
     local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
     adb_auth_init();
 
+    std::string error;
     std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
-    if (install_listener(local_name, "*smartsocket*", nullptr, 0)) {
-        LOG(FATAL) << "Could not install *smartsocket* listener";
+    if (install_listener(local_name, "*smartsocket*", nullptr, 0, &error)) {
+        LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
     }
 
     if (is_daemon) {
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index d54faec..d7a0c8d 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -847,25 +847,25 @@
  * Given <hint>, try to construct an absolute path to the
  * ANDROID_PRODUCT_OUT dir.
  */
-static std::string find_product_out_path(const char* hint) {
-    if (hint == NULL || hint[0] == '\0') {
+static std::string find_product_out_path(const std::string& hint) {
+    if (hint.empty()) {
         return "";
     }
 
     // If it's already absolute, don't bother doing any work.
-    if (adb_is_absolute_host_path(hint)) {
+    if (adb_is_absolute_host_path(hint.c_str())) {
         return hint;
     }
 
     // If there are any slashes in it, assume it's a relative path;
     // make it absolute.
-    if (adb_dirstart(hint) != nullptr) {
+    if (hint.find_first_of(OS_PATH_SEPARATORS) != std::string::npos) {
         std::string cwd;
         if (!getcwd(&cwd)) {
             fprintf(stderr, "adb: getcwd failed: %s\n", strerror(errno));
             return "";
         }
-        return android::base::StringPrintf("%s%s%s", cwd.c_str(), OS_PATH_SEPARATOR_STR, hint);
+        return android::base::StringPrintf("%s%c%s", cwd.c_str(), OS_PATH_SEPARATOR, hint.c_str());
     }
 
     // It's a string without any slashes.  Try to do something with it.
@@ -889,7 +889,7 @@
     path += hint;
     if (!directory_exists(path)) {
         fprintf(stderr, "adb: Couldn't find a product dir based on -p %s; "
-                        "\"%s\" doesn't exist\n", hint, path.c_str());
+                        "\"%s\" doesn't exist\n", hint.c_str(), path.c_str());
         return "";
     }
     return path;
@@ -990,7 +990,7 @@
             /* this is a special flag used only when the ADB client launches the ADB Server */
             is_daemon = 1;
         } else if (!strncmp(argv[0], "-p", 2)) {
-            const char *product = NULL;
+            const char* product = nullptr;
             if (argv[0][2] == '\0') {
                 if (argc < 2) return usage();
                 product = argv[1];
@@ -1462,22 +1462,11 @@
     return pm_command(transport, serial, argc, argv);
 }
 
-static int delete_file(TransportType transport, const char* serial, char* filename) {
+static int delete_file(TransportType transport, const char* serial, const std::string& filename) {
     std::string cmd = "shell:rm -f " + escape_arg(filename);
     return send_shell_command(transport, serial, cmd);
 }
 
-static const char* get_basename(const char* filename)
-{
-    const char* basename = adb_dirstop(filename);
-    if (basename) {
-        basename++;
-        return basename;
-    } else {
-        return filename;
-    }
-}
-
 static int install_app(TransportType transport, const char* serial, int argc, const char** argv) {
     static const char *const DATA_DEST = "/data/local/tmp/%s";
     static const char *const SD_DEST = "/sdcard/tmp/%s";
@@ -1514,13 +1503,12 @@
     }
 
     const char* apk_file = argv[last_apk];
-    char apk_dest[PATH_MAX];
-    snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
-    int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);
+    std::string apk_dest = android::base::StringPrintf(where, adb_basename(apk_file).c_str());
+    int err = do_sync_push(apk_file, apk_dest.c_str(), 0 /* no show progress */);
     if (err) {
         goto cleanup_apk;
     } else {
-        argv[last_apk] = apk_dest; /* destination name, not source location */
+        argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
     }
 
     err = pm_command(transport, serial, argc, argv);
@@ -1604,7 +1592,7 @@
 
         std::string cmd = android::base::StringPrintf(
                 "exec:pm install-write -S %" PRIu64 " %d %d_%s -",
-                static_cast<uint64_t>(sb.st_size), session_id, i, get_basename(file));
+                static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
 
         int localFd = adb_open(file, O_RDONLY);
         if (localFd < 0) {
diff --git a/adb/console.cpp b/adb/console.cpp
index b7f5345..ba5a72b 100644
--- a/adb/console.cpp
+++ b/adb/console.cpp
@@ -71,9 +71,11 @@
         return -1;
     }
 
-    int fd = socket_loopback_client(port, SOCK_STREAM);
+    std::string error;
+    int fd = network_loopback_client(port, SOCK_STREAM, &error);
     if (fd == -1) {
-        fprintf(stderr, "error: could not connect to TCP port %d\n", port);
+        fprintf(stderr, "error: could not connect to TCP port %d: %s\n", port,
+                error.c_str());
         return -1;
     }
     return fd;
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 157c97b..a63d67e 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -177,10 +177,13 @@
                 LOG(FATAL) << "Could not set selinux context";
             }
         }
+        std::string error;
         std::string local_name =
             android::base::StringPrintf("tcp:%d", server_port);
-        if (install_listener(local_name, "*smartsocket*", nullptr, 0)) {
-            LOG(FATAL) << "Could not install *smartsocket* listener";
+        if (install_listener(local_name, "*smartsocket*", nullptr, 0,
+                             &error)) {
+            LOG(FATAL) << "Could not install *smartsocket* listener: "
+                << error;
         }
     }
 
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 49d42a3..da80013 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -35,6 +35,8 @@
 #include "adb_utils.h"
 #include "file_sync_service.h"
 
+#include <base/stringprintf.h>
+
 static unsigned long long total_bytes;
 static long long start_time;
 
@@ -92,36 +94,30 @@
 typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
 
 static int sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
+    int len = strlen(path);
+    if (len > 1024) goto fail;
+
     syncmsg msg;
-    char buf[257];
-    int len;
-
-    len = strlen(path);
-    if(len > 1024) goto fail;
-
     msg.req.id = ID_LIST;
     msg.req.namelen = htoll(len);
 
-    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
-       !WriteFdExactly(fd, path, len)) {
+    if (!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || !WriteFdExactly(fd, path, len)) {
         goto fail;
     }
 
-    for(;;) {
-        if(!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
-        if(msg.dent.id == ID_DONE) return 0;
-        if(msg.dent.id != ID_DENT) break;
+    for (;;) {
+        if (!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
+        if (msg.dent.id == ID_DONE) return 0;
+        if (msg.dent.id != ID_DENT) break;
 
         len = ltohl(msg.dent.namelen);
-        if(len > 256) break;
+        if (len > 256) break;
 
-        if(!ReadFdExactly(fd, buf, len)) break;
+        char buf[257];
+        if (!ReadFdExactly(fd, buf, len)) break;
         buf[len] = 0;
 
-        func(ltohl(msg.dent.mode),
-             ltohl(msg.dent.size),
-             ltohl(msg.dent.time),
-             buf, cookie);
+        func(ltohl(msg.dent.mode), ltohl(msg.dent.size), ltohl(msg.dent.time), buf, cookie);
     }
 
 fail:
@@ -220,7 +216,7 @@
     return 0;
 }
 
-static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress)
+static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, bool show_progress)
 {
     int lfd, err = 0;
     unsigned long long size = 0;
@@ -274,7 +270,7 @@
 }
 
 static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
-                             int show_progress)
+                             bool show_progress)
 {
     int err = 0;
     int total = 0;
@@ -308,10 +304,8 @@
 #else
 static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
 {
-    int len, ret;
-
-    len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
-    if(len < 0) {
+    int len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
+    if (len < 0) {
         fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
         return -1;
     }
@@ -320,9 +314,9 @@
     sbuf->size = htoll(len + 1);
     sbuf->id = ID_DATA;
 
-    ret = !WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
-    if(ret)
+    if (!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
         return -1;
+    }
 
     total_bytes += len + 1;
 
@@ -331,7 +325,7 @@
 #endif
 
 static int sync_send(int fd, const char *lpath, const char *rpath,
-                     unsigned mtime, mode_t mode, int show_progress)
+                     unsigned mtime, mode_t mode, bool show_progress)
 {
     syncmsg msg;
     int len, r;
@@ -396,7 +390,7 @@
     return -1;
 }
 
-static int sync_recv(int fd, const char* rpath, const char* lpath, int show_progress) {
+static int sync_recv(int fd, const char* rpath, const char* lpath, bool show_progress) {
     syncmsg msg;
     int len;
     int lfd = -1;
@@ -523,12 +517,12 @@
         return 1;
     }
 
-    if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
+    if (sync_ls(fd, path, do_sync_ls_cb, 0)) {
         return 1;
-    } else {
-        sync_quit(fd);
-        return 0;
     }
+
+    sync_quit(fd);
+    return 0;
 }
 
 struct copyinfo
@@ -712,11 +706,7 @@
 }
 
 
-int do_sync_push(const char *lpath, const char *rpath, int show_progress)
-{
-    struct stat st;
-    unsigned mode;
-
+int do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
     std::string error;
     int fd = adb_connect("sync:", &error);
     if (fd < 0) {
@@ -724,51 +714,38 @@
         return 1;
     }
 
-    if(stat(lpath, &st)) {
+    struct stat st;
+    if (stat(lpath, &st)) {
         fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
         sync_quit(fd);
         return 1;
     }
 
-    if(S_ISDIR(st.st_mode)) {
+    if (S_ISDIR(st.st_mode)) {
         BEGIN();
-        if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
+        if (copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
             return 1;
-        } else {
-            END();
-            sync_quit(fd);
         }
     } else {
-        if(sync_readmode(fd, rpath, &mode)) {
+        unsigned mode;
+        if (sync_readmode(fd, rpath, &mode)) {
             return 1;
         }
-        if((mode != 0) && S_ISDIR(mode)) {
-                /* if we're copying a local file to a remote directory,
-                ** we *really* want to copy to remotedir + "/" + localfilename
-                */
-            const char *name = adb_dirstop(lpath);
-            if(name == 0) {
-                name = lpath;
-            } else {
-                name++;
-            }
-            int  tmplen = strlen(name) + strlen(rpath) + 2;
-            char *tmp = reinterpret_cast<char*>(
-                malloc(strlen(name) + strlen(rpath) + 2));
-            if(tmp == 0) return 1;
-            snprintf(tmp, tmplen, "%s/%s", rpath, name);
-            rpath = tmp;
+        std::string path_holder;
+        if ((mode != 0) && S_ISDIR(mode)) {
+            // If we're copying a local file to a remote directory,
+            // we really want to copy to remote_dir + "/" + local_filename.
+            path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
+            rpath = path_holder.c_str();
         }
         BEGIN();
-        if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
+        if (sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
             return 1;
-        } else {
-            END();
-            sync_quit(fd);
-            return 0;
         }
     }
 
+    END();
+    sync_quit(fd);
     return 0;
 }
 
@@ -934,11 +911,7 @@
     return ret;
 }
 
-int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs)
-{
-    unsigned mode, time;
-    struct stat st;
-
+int do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
     std::string error;
     int fd = adb_connect("sync:", &error);
     if (fd < 0) {
@@ -946,56 +919,46 @@
         return 1;
     }
 
-    if(sync_readtime(fd, rpath, &time, &mode)) {
+    unsigned mode, time;
+    if (sync_readtime(fd, rpath, &time, &mode)) {
         return 1;
     }
-    if(mode == 0) {
+    if (mode == 0) {
         fprintf(stderr,"remote object '%s' does not exist\n", rpath);
         return 1;
     }
 
-    if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
-        if(stat(lpath, &st) == 0) {
-            if(S_ISDIR(st.st_mode)) {
-                    /* if we're copying a remote file to a local directory,
-                    ** we *really* want to copy to localdir + "/" + remotefilename
-                    */
-                const char *name = adb_dirstop(rpath);
-                if(name == 0) {
-                    name = rpath;
-                } else {
-                    name++;
-                }
-                int  tmplen = strlen(name) + strlen(lpath) + 2;
-                char *tmp = reinterpret_cast<char*>(malloc(tmplen));
-                if(tmp == 0) return 1;
-                snprintf(tmp, tmplen, "%s/%s", lpath, name);
-                lpath = tmp;
+    if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
+        std::string path_holder;
+        struct stat st;
+        if (stat(lpath, &st) == 0) {
+            if (S_ISDIR(st.st_mode)) {
+                // If we're copying a remote file to a local directory,
+                // we really want to copy to local_dir + "/" + basename(remote).
+                path_holder = android::base::StringPrintf("%s/%s", lpath, adb_basename(rpath).c_str());
+                lpath = path_holder.c_str();
             }
         }
         BEGIN();
         if (sync_recv(fd, rpath, lpath, show_progress)) {
             return 1;
         } else {
-            if (copy_attrs && set_time_and_mode(lpath, time, mode))
+            if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
                 return 1;
-            END();
-            sync_quit(fd);
-            return 0;
+            }
         }
     } else if(S_ISDIR(mode)) {
         BEGIN();
         if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
             return 1;
-        } else {
-            END();
-            sync_quit(fd);
-            return 0;
         }
     } else {
         fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
         return 1;
     }
+    END();
+    sync_quit(fd);
+    return 0;
 }
 
 int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
@@ -1012,9 +975,8 @@
     BEGIN();
     if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
         return 1;
-    } else {
-        END();
-        sync_quit(fd);
-        return 0;
     }
+    END();
+    sync_quit(fd);
+    return 0;
 }
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 2067836..ea019f4 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -34,47 +34,46 @@
 #include "adb_io.h"
 #include "private/android_filesystem_config.h"
 
-static bool should_use_fs_config(const char* path) {
+#include <base/strings.h>
+
+static bool should_use_fs_config(const std::string& path) {
     // TODO: use fs_config to configure permissions on /data.
-    return strncmp("/system/", path, strlen("/system/")) == 0 ||
-           strncmp("/vendor/", path, strlen("/vendor/")) == 0 ||
-           strncmp("/oem/", path, strlen("/oem/")) == 0;
+    return android::base::StartsWith(path, "/system/") ||
+           android::base::StartsWith(path, "/vendor/") ||
+           android::base::StartsWith(path, "/oem/");
 }
 
-static int mkdirs(char *name)
-{
-    int ret;
-    char *x = name + 1;
+static bool secure_mkdirs(const std::string& path) {
     uid_t uid = -1;
     gid_t gid = -1;
     unsigned int mode = 0775;
     uint64_t cap = 0;
 
-    if(name[0] != '/') return -1;
+    if (path[0] != '/') return false;
 
-    for(;;) {
-        x = const_cast<char*>(adb_dirstart(x));
-        if(x == 0) return 0;
-        *x = 0;
-        if (should_use_fs_config(name)) {
-            fs_config(name, 1, &uid, &gid, &mode, &cap);
+    std::vector<std::string> path_components = android::base::Split(path, "/");
+    path_components.pop_back(); // For "/system/bin/sh", only create "/system/bin".
+
+    std::string partial_path;
+    for (auto& path_component : path_components) {
+        if (partial_path.back() != OS_PATH_SEPARATOR) partial_path += OS_PATH_SEPARATOR;
+        partial_path += path_component;
+
+        if (should_use_fs_config(partial_path)) {
+            fs_config(partial_path.c_str(), 1, &uid, &gid, &mode, &cap);
         }
-        ret = adb_mkdir(name, mode);
-        if((ret < 0) && (errno != EEXIST)) {
-            D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
-            *x = '/';
-            return ret;
-        } else if(ret == 0) {
-            ret = chown(name, uid, gid);
-            if (ret < 0) {
-                *x = '/';
-                return ret;
+        if (adb_mkdir(partial_path.c_str(), mode) == -1) {
+            if (errno != EEXIST) {
+                return false;
             }
-            selinux_android_restorecon(name, 0);
+        } else {
+            if (chown(partial_path.c_str(), uid, gid) == -1) {
+                return false;
+            }
+            selinux_android_restorecon(partial_path.c_str(), 0);
         }
-        *x++ = '/';
     }
-    return 0;
+    return true;
 }
 
 static int do_stat(int s, const char *path)
@@ -99,26 +98,24 @@
 
 static int do_list(int s, const char *path)
 {
-    DIR *d;
     struct dirent *de;
     struct stat st;
-    syncmsg msg;
-    int len;
 
     char tmp[1024 + 256 + 1];
     char *fname;
 
-    len = strlen(path);
+    size_t len = strlen(path);
     memcpy(tmp, path, len);
     tmp[len] = '/';
     fname = tmp + len + 1;
 
+    syncmsg msg;
     msg.dent.id = ID_DENT;
 
-    d = opendir(path);
-    if(d == 0) goto done;
+    std::unique_ptr<DIR, int(*)(DIR*)> d(opendir(path), closedir);
+    if (!d) goto done;
 
-    while((de = readdir(d))) {
+    while ((de = readdir(d.get()))) {
         int len = strlen(de->d_name);
 
             /* not supposed to be possible, but
@@ -134,14 +131,11 @@
 
             if(!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ||
                !WriteFdExactly(s, de->d_name, len)) {
-                closedir(d);
                 return -1;
             }
         }
     }
 
-    closedir(d);
-
 done:
     msg.dent.id = ID_DONE;
     msg.dent.mode = 0;
@@ -182,7 +176,7 @@
 
     fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
     if(fd < 0 && errno == ENOENT) {
-        if(mkdirs(path) != 0) {
+        if (!secure_mkdirs(path)) {
             if(fail_errno(s))
                 return -1;
             fd = -1;
@@ -294,7 +288,7 @@
 
     ret = symlink(buffer, path);
     if(ret && errno == ENOENT) {
-        if(mkdirs(path) != 0) {
+        if (!secure_mkdirs(path)) {
             fail_errno(s);
             return -1;
         }
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 344eb98..1d3e3bd 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -68,9 +68,9 @@
 
 void file_sync_service(int fd, void *cookie);
 int do_sync_ls(const char *path);
-int do_sync_push(const char *lpath, const char *rpath, int show_progress);
+int do_sync_push(const char *lpath, const char *rpath, bool show_progress);
 int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
-int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);
+int do_sync_pull(const char *rpath, const char *lpath, bool show_progress, int pullTime);
 
 #define SYNC_DATA_MAX (64*1024)
 
diff --git a/adb/services.cpp b/adb/services.cpp
index 708ef42..63a0a76 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -432,7 +432,8 @@
         int port = atoi(name + 4);
         name = strchr(name + 4, ':');
         if(name == 0) {
-            ret = socket_loopback_client(port, SOCK_STREAM);
+            std::string error;
+            ret = network_loopback_client(port, SOCK_STREAM, &error);
             if (ret >= 0)
                 disable_tcp_nagle(ret);
         } else {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 729bbcb..a57f650 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -26,6 +26,8 @@
 
 #include <errno.h>
 
+#include <string>
+
 /*
  * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
  * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
@@ -54,8 +56,11 @@
 #include <windows.h>
 #include <ws2tcpip.h>
 
+#include <string>
+
 #include "fdevent.h"
 
+#define OS_PATH_SEPARATORS "\\/"
 #define OS_PATH_SEPARATOR '\\'
 #define OS_PATH_SEPARATOR_STR "\\"
 #define ENV_PATH_SEPARATOR_STR ";"
@@ -120,9 +125,8 @@
 #undef  unlink
 #define unlink  ___xxx_unlink
 
-static __inline__ int  adb_mkdir(const char*  path, int mode)
-{
-	return _mkdir(path);
+static __inline__ int adb_mkdir(const std::string& path, int mode) {
+	return _mkdir(path.c_str());
 }
 #undef   mkdir
 #define  mkdir  ___xxx_mkdir
@@ -210,6 +214,12 @@
     Sleep( mseconds );
 }
 
+int network_loopback_client(int port, int type, std::string* error);
+int network_loopback_server(int port, int type, std::string* error);
+int network_inaddr_any_server(int port, int type, std::string* error);
+int network_connect(const std::string& host, int port, int type, int timeout,
+                    std::string* error);
+
 extern int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen);
 
 #undef   accept
@@ -234,41 +244,18 @@
 
 extern int  adb_socketpair( int  sv[2] );
 
-static __inline__  char*  adb_dirstart( const char*  path )
-{
-    char*  p  = strchr(path, '/');
-    char*  p2 = strchr(path, '\\');
-
-    if ( !p )
-        p = p2;
-    else if ( p2 && p2 > p )
-        p = p2;
-
-    return p;
-}
-
-static __inline__  const char*  adb_dirstop( const char*  path )
-{
-    const char*  p  = strrchr(path, '/');
-    const char*  p2 = strrchr(path, '\\');
-
-    if ( !p )
-        p = p2;
-    else if ( p2 && p2 > p )
-        p = p2;
-
-    return p;
-}
-
-static __inline__  int  adb_is_absolute_host_path( const char*  path )
-{
+static __inline__ int adb_is_absolute_host_path(const char* path) {
     return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
 }
 
+// Like strerror(), but for Win32 error codes.
+std::string SystemErrorCodeToString(DWORD error_code);
+
 #else /* !_WIN32 a.k.a. Unix */
 
 #include "fdevent.h"
 #include <cutils/misc.h>
+#include <cutils/sockets.h>
 #include <cutils/threads.h>
 #include <signal.h>
 #include <sys/wait.h>
@@ -279,11 +266,15 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <stdarg.h>
+#include <netdb.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <string.h>
 #include <unistd.h>
 
+#include <string>
+
+#define OS_PATH_SEPARATORS "/"
 #define OS_PATH_SEPARATOR '/'
 #define OS_PATH_SEPARATOR_STR "/"
 #define ENV_PATH_SEPARATOR_STR ":"
@@ -426,6 +417,48 @@
 #undef   creat
 #define  creat  ___xxx_creat
 
+// Helper for network_* functions.
+inline int _fd_set_error_str(int fd, std::string* error) {
+  if (fd == -1) {
+    *error = strerror(errno);
+  }
+  return fd;
+}
+
+inline int network_loopback_client(int port, int type, std::string* error) {
+  return _fd_set_error_str(socket_loopback_client(port, type), error);
+}
+
+inline int network_loopback_server(int port, int type, std::string* error) {
+  return _fd_set_error_str(socket_loopback_server(port, type), error);
+}
+
+inline int network_inaddr_any_server(int port, int type, std::string* error) {
+  return _fd_set_error_str(socket_inaddr_any_server(port, type), error);
+}
+
+inline int network_local_server(const char *name, int namespace_id, int type,
+                                std::string* error) {
+  return _fd_set_error_str(socket_local_server(name, namespace_id, type),
+                           error);
+}
+
+inline int network_connect(const std::string& host, int port, int type,
+                           int timeout, std::string* error) {
+  int getaddrinfo_error = 0;
+  int fd = socket_network_client_timeout(host.c_str(), port, type, timeout,
+                                         &getaddrinfo_error);
+  if (fd != -1) {
+    return fd;
+  }
+  if (getaddrinfo_error != 0) {
+    *error = gai_strerror(getaddrinfo_error);
+  } else {
+    *error = strerror(errno);
+  }
+  return -1;
+}
+
 static __inline__ int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
 {
     int fd;
@@ -510,10 +543,11 @@
     usleep( mseconds*1000 );
 }
 
-static __inline__ int  adb_mkdir(const char*  path, int mode)
+static __inline__ int  adb_mkdir(const std::string& path, int mode)
 {
-    return mkdir(path, mode);
+    return mkdir(path.c_str(), mode);
 }
+
 #undef   mkdir
 #define  mkdir  ___xxx_mkdir
 
@@ -521,18 +555,7 @@
 {
 }
 
-static __inline__ const char*  adb_dirstart(const char*  path)
-{
-    return strchr(path, '/');
-}
-
-static __inline__ const char*  adb_dirstop(const char*  path)
-{
-    return strrchr(path, '/');
-}
-
-static __inline__  int  adb_is_absolute_host_path( const char*  path )
-{
+static __inline__ int adb_is_absolute_host_path(const char* path) {
     return path[0] == '/';
 }
 
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index a274892..9fdc24c 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -25,8 +25,15 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <memory>
+#include <string>
+
 #include <cutils/sockets.h>
 
+#include <base/logging.h>
+#include <base/stringprintf.h>
+#include <base/strings.h>
+
 #include "adb.h"
 
 extern void fatal(const char *fmt, ...);
@@ -80,6 +87,29 @@
 
 #define assert(cond)  do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0)
 
+std::string SystemErrorCodeToString(const DWORD error_code) {
+  const int kErrorMessageBufferSize = 256;
+  char msgbuf[kErrorMessageBufferSize];
+  DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
+  DWORD len = FormatMessageA(flags, nullptr, error_code, 0, msgbuf,
+                             arraysize(msgbuf), nullptr);
+  if (len == 0) {
+    return android::base::StringPrintf(
+        "Error (%lu) while retrieving error. (%lu)", GetLastError(),
+        error_code);
+  }
+
+  std::string msg(msgbuf);
+  // Messages returned by the system end with line breaks.
+  msg = android::base::Trim(msg);
+  // There are many Windows error messages compared to POSIX, so include the
+  // numeric error code for easier, quicker, accurate identification. Use
+  // decimal instead of hex because there are decimal ranges like 10000-11999
+  // for Winsock.
+  android::base::StringAppendF(&msg, " (%lu)", error_code);
+  return msg;
+}
+
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -253,6 +283,23 @@
     return 0;
 }
 
+// Deleter for unique_fh.
+class fh_deleter {
+ public:
+  void operator()(struct FHRec_* fh) {
+    // We're called from a destructor and destructors should not overwrite
+    // errno because callers may do:
+    //   errno = EBLAH;
+    //   return -1; // calls destructor, which should not overwrite errno
+    const int saved_errno = errno;
+    _fh_close(fh);
+    errno = saved_errno;
+  }
+};
+
+// Like std::unique_ptr, but calls _fh_close() instead of operator delete().
+typedef std::unique_ptr<struct FHRec_, fh_deleter> unique_fh;
+
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -467,21 +514,6 @@
 }
 
 
-int  adb_shutdown(int  fd)
-{
-    FH   f = _fh_from_int(fd, __func__);
-
-    if (!f || f->clazz != &_fh_socket_class) {
-        D("adb_shutdown: invalid fd %d\n", fd);
-        return -1;
-    }
-
-    D( "adb_shutdown: %s\n", f->name);
-    shutdown( f->fh_socket, SD_BOTH );
-    return 0;
-}
-
-
 int  adb_close(int  fd)
 {
     FH   f = _fh_from_int(fd, __func__);
@@ -505,29 +537,63 @@
 
 #undef setsockopt
 
-static void _socket_set_errno( void ) {
-    switch (WSAGetLastError()) {
+static void _socket_set_errno( const DWORD err ) {
+    // The Windows C Runtime (MSVCRT.DLL) strerror() does not support a lot of
+    // POSIX and socket error codes, so this can only meaningfully map so much.
+    switch ( err ) {
     case 0:              errno = 0; break;
     case WSAEWOULDBLOCK: errno = EAGAIN; break;
     case WSAEINTR:       errno = EINTR; break;
+    case WSAEFAULT:      errno = EFAULT; break;
+    case WSAEINVAL:      errno = EINVAL; break;
+    case WSAEMFILE:      errno = EMFILE; break;
     default:
-        D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError() );
         errno = EINVAL;
+        D( "_socket_set_errno: mapping Windows error code %lu to errno %d\n",
+           err, errno );
     }
 }
 
 static void _fh_socket_init( FH  f ) {
     f->fh_socket = INVALID_SOCKET;
     f->event     = WSACreateEvent();
+    if (f->event == WSA_INVALID_EVENT) {
+        D("WSACreateEvent failed: %s\n",
+          SystemErrorCodeToString(WSAGetLastError()).c_str());
+
+        // _event_socket_start assumes that this field is INVALID_HANDLE_VALUE
+        // on failure, instead of NULL which is what Windows really returns on
+        // error. It might be better to change all the other code to look for
+        // NULL, but that is a much riskier change.
+        f->event = INVALID_HANDLE_VALUE;
+    }
     f->mask      = 0;
 }
 
 static int _fh_socket_close( FH  f ) {
-    /* gently tell any peer that we're closing the socket */
-    shutdown( f->fh_socket, SD_BOTH );
-    closesocket( f->fh_socket );
-    f->fh_socket = INVALID_SOCKET;
-    CloseHandle( f->event );
+    if (f->fh_socket != INVALID_SOCKET) {
+        /* gently tell any peer that we're closing the socket */
+        if (shutdown(f->fh_socket, SD_BOTH) == SOCKET_ERROR) {
+            // If the socket is not connected, this returns an error. We want to
+            // minimize logging spam, so don't log these errors for now.
+#if 0
+            D("socket shutdown failed: %s\n",
+              SystemErrorCodeToString(WSAGetLastError()).c_str());
+#endif
+        }
+        if (closesocket(f->fh_socket) == SOCKET_ERROR) {
+            D("closesocket failed: %s\n",
+              SystemErrorCodeToString(WSAGetLastError()).c_str());
+        }
+        f->fh_socket = INVALID_SOCKET;
+    }
+    if (f->event != NULL) {
+        if (!CloseHandle(f->event)) {
+            D("CloseHandle failed: %s\n",
+              SystemErrorCodeToString(GetLastError()).c_str());
+        }
+        f->event = NULL;
+    }
     f->mask = 0;
     return 0;
 }
@@ -540,7 +606,10 @@
 static int _fh_socket_read(FH f, void* buf, int len) {
     int  result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
     if (result == SOCKET_ERROR) {
-        _socket_set_errno();
+        const DWORD err = WSAGetLastError();
+        D("recv fd %d failed: %s\n", _fh_to_int(f),
+          SystemErrorCodeToString(err).c_str());
+        _socket_set_errno(err);
         result = -1;
     }
     return  result;
@@ -549,7 +618,10 @@
 static int _fh_socket_write(FH f, const void* buf, int len) {
     int  result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
     if (result == SOCKET_ERROR) {
-        _socket_set_errno();
+        const DWORD err = WSAGetLastError();
+        D("send fd %d failed: %s\n", _fh_to_int(f),
+          SystemErrorCodeToString(err).c_str());
+        _socket_set_errno(err);
         result = -1;
     }
     return result;
@@ -570,31 +642,39 @@
 static void
 _cleanup_winsock( void )
 {
+    // TODO: WSAStartup() might be called multiple times and this won't properly
+    // cleanup the right number of times. Plus, WSACleanup() probably doesn't
+    // make sense since it might interrupt other threads using Winsock (since
+    // our various threads are not explicitly cleanly shutdown at process exit).
     WSACleanup();
 }
 
 static void
 _init_winsock( void )
 {
+    // TODO: Multiple threads calling this may potentially cause multiple calls
+    // to WSAStartup() and multiple atexit() calls.
     if (!_winsock_init) {
         WSADATA  wsaData;
         int      rc = WSAStartup( MAKEWORD(2,2), &wsaData);
         if (rc != 0) {
-            fatal( "adb: could not initialize Winsock\n" );
+            fatal( "adb: could not initialize Winsock: %s",
+                   SystemErrorCodeToString( rc ).c_str());
         }
         atexit( _cleanup_winsock );
         _winsock_init = 1;
     }
 }
 
-int socket_loopback_client(int port, int type)
-{
-    FH  f = _fh_alloc( &_fh_socket_class );
+int network_loopback_client(int port, int type, std::string* error) {
     struct sockaddr_in addr;
     SOCKET  s;
 
-    if (!f)
+    unique_fh  f(_fh_alloc(&_fh_socket_class));
+    if (!f) {
+        *error = strerror(errno);
         return -1;
+    }
 
     if (!_winsock_init)
         _init_winsock();
@@ -606,32 +686,40 @@
 
     s = socket(AF_INET, type, 0);
     if(s == INVALID_SOCKET) {
-        D("socket_loopback_client: could not create socket\n" );
-        _fh_close(f);
+        *error = SystemErrorCodeToString(WSAGetLastError());
+        D("could not create socket: %s\n", error->c_str());
+        return -1;
+    }
+    f->fh_socket = s;
+
+    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
+        *error = SystemErrorCodeToString(WSAGetLastError());
+        D("could not connect to %s:%d: %s\n",
+          type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
         return -1;
     }
 
-    f->fh_socket = s;
-    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port );
-        _fh_close(f);
-        return -1;
-    }
-    snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
-    D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
-    return _fh_to_int(f);
+    const int fd = _fh_to_int(f.get());
+    snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", fd,
+              type != SOCK_STREAM ? "udp:" : "", port );
+    D( "port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp",
+       fd );
+    f.release();
+    return fd;
 }
 
 #define LISTEN_BACKLOG 4
 
-int socket_loopback_server(int port, int type)
-{
-    FH   f = _fh_alloc( &_fh_socket_class );
+// interface_address is INADDR_LOOPBACK or INADDR_ANY.
+static int _network_server(int port, int type, u_long interface_address,
+                           std::string* error) {
     struct sockaddr_in addr;
     SOCKET  s;
     int  n;
 
+    unique_fh   f(_fh_alloc(&_fh_socket_class));
     if (!f) {
+        *error = strerror(errno);
         return -1;
     }
 
@@ -641,149 +729,151 @@
     memset(&addr, 0, sizeof(addr));
     addr.sin_family = AF_INET;
     addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    addr.sin_addr.s_addr = htonl(interface_address);
 
+    // TODO: Consider using dual-stack socket that can simultaneously listen on
+    // IPv4 and IPv6.
     s = socket(AF_INET, type, 0);
-    if(s == INVALID_SOCKET) return -1;
+    if (s == INVALID_SOCKET) {
+        *error = SystemErrorCodeToString(WSAGetLastError());
+        D("could not create socket: %s\n", error->c_str());
+        return -1;
+    }
 
     f->fh_socket = s;
 
     n = 1;
-    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
+    if (setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n,
+                   sizeof(n)) == SOCKET_ERROR) {
+        *error = SystemErrorCodeToString(WSAGetLastError());
+        D("setsockopt level %d optname %d failed: %s\n",
+          SOL_SOCKET, SO_EXCLUSIVEADDRUSE, error->c_str());
+        return -1;
+    }
 
-    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
+    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
+        *error = SystemErrorCodeToString(WSAGetLastError());
+        D("could not bind to %s:%d: %s\n",
+          type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
         return -1;
     }
     if (type == SOCK_STREAM) {
-        int ret;
-
-        ret = listen(s, LISTEN_BACKLOG);
-        if (ret < 0) {
-            _fh_close(f);
+        if (listen(s, LISTEN_BACKLOG) == SOCKET_ERROR) {
+            *error = SystemErrorCodeToString(WSAGetLastError());
+            D("could not listen on %s:%d: %s\n",
+              type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
             return -1;
         }
     }
-    snprintf( f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
-    D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
-    return _fh_to_int(f);
+    const int fd = _fh_to_int(f.get());
+    snprintf( f->name, sizeof(f->name), "%d(%s-server:%s%d)", fd,
+              interface_address == INADDR_LOOPBACK ? "lo" : "any",
+              type != SOCK_STREAM ? "udp:" : "", port );
+    D( "port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp",
+       fd );
+    f.release();
+    return fd;
 }
 
+int network_loopback_server(int port, int type, std::string* error) {
+    return _network_server(port, type, INADDR_LOOPBACK, error);
+}
 
-int socket_network_client_timeout(const char *host, int port, int type, int timeout,
-                                  int* getaddrinfo_error) {
-    FH  f = _fh_alloc( &_fh_socket_class );
-    if (!f) return -1;
+int network_inaddr_any_server(int port, int type, std::string* error) {
+    return _network_server(port, type, INADDR_ANY, error);
+}
+
+int network_connect(const std::string& host, int port, int type, int timeout, std::string* error) {
+    unique_fh f(_fh_alloc(&_fh_socket_class));
+    if (!f) {
+        *error = strerror(errno);
+        return -1;
+    }
 
     if (!_winsock_init) _init_winsock();
 
-    hostent* hp = gethostbyname(host);
-    if(hp == 0) {
-        _fh_close(f);
+    struct addrinfo hints;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = type;
+
+    char port_str[16];
+    snprintf(port_str, sizeof(port_str), "%d", port);
+
+    struct addrinfo* addrinfo_ptr = nullptr;
+    if (getaddrinfo(host.c_str(), port_str, &hints, &addrinfo_ptr) != 0) {
+        *error = SystemErrorCodeToString(WSAGetLastError());
+        D("could not resolve host '%s' and port %s: %s\n", host.c_str(),
+          port_str, error->c_str());
         return -1;
     }
+    std::unique_ptr<struct addrinfo, decltype(freeaddrinfo)*>
+        addrinfo(addrinfo_ptr, freeaddrinfo);
+    addrinfo_ptr = nullptr;
 
-    sockaddr_in addr;
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = hp->h_addrtype;
-    addr.sin_port = htons(port);
-    memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
-
-    SOCKET s = socket(hp->h_addrtype, type, 0);
+    // TODO: Try all the addresses if there's more than one? This just uses
+    // the first. Or, could call WSAConnectByName() (Windows Vista and newer)
+    // which tries all addresses, takes a timeout and more.
+    SOCKET s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
+                      addrinfo->ai_protocol);
     if(s == INVALID_SOCKET) {
-        _fh_close(f);
+        *error = SystemErrorCodeToString(WSAGetLastError());
+        D("could not create socket: %s\n", error->c_str());
         return -1;
     }
     f->fh_socket = s;
 
-    // TODO: implement timeouts for Windows.
-
-    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
+    // TODO: Implement timeouts for Windows. Seems like the default in theory
+    // (according to http://serverfault.com/a/671453) and in practice is 21 sec.
+    if(connect(s, addrinfo->ai_addr, addrinfo->ai_addrlen) == SOCKET_ERROR) {
+        *error = SystemErrorCodeToString(WSAGetLastError());
+        D("could not connect to %s:%s:%s: %s\n",
+          type != SOCK_STREAM ? "udp" : "tcp", host.c_str(), port_str,
+          error->c_str());
         return -1;
     }
 
-    snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
-    D( "socket_network_client_timeout: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
-    return _fh_to_int(f);
-}
-
-
-int socket_inaddr_any_server(int port, int type)
-{
-    FH  f = _fh_alloc( &_fh_socket_class );
-    struct sockaddr_in addr;
-    SOCKET  s;
-    int n;
-
-    if (!f)
-        return -1;
-
-    if (!_winsock_init)
-        _init_winsock();
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-    s = socket(AF_INET, type, 0);
-    if(s == INVALID_SOCKET) {
-        _fh_close(f);
-        return -1;
-    }
-
-    f->fh_socket = s;
-    n = 1;
-    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
-
-    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
-        return -1;
-    }
-
-    if (type == SOCK_STREAM) {
-        int ret;
-
-        ret = listen(s, LISTEN_BACKLOG);
-        if (ret < 0) {
-            _fh_close(f);
-            return -1;
-        }
-    }
-    snprintf( f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
-    D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
-    return _fh_to_int(f);
+    const int fd = _fh_to_int(f.get());
+    snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", fd,
+              type != SOCK_STREAM ? "udp:" : "", port );
+    D( "host '%s' port %d type %s => fd %d\n", host.c_str(), port,
+       type != SOCK_STREAM ? "udp" : "tcp", fd );
+    f.release();
+    return fd;
 }
 
 #undef accept
 int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
 {
     FH   serverfh = _fh_from_int(serverfd, __func__);
-    FH   fh;
 
     if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
-        D( "adb_socket_accept: invalid fd %d\n", serverfd );
+        D("adb_socket_accept: invalid fd %d\n", serverfd);
+        errno = EBADF;
         return -1;
     }
 
-    fh = _fh_alloc( &_fh_socket_class );
+    unique_fh fh(_fh_alloc( &_fh_socket_class ));
     if (!fh) {
-        D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" );
+        PLOG(ERROR) << "adb_socket_accept: failed to allocate accepted socket "
+                       "descriptor";
         return -1;
     }
 
     fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
     if (fh->fh_socket == INVALID_SOCKET) {
         const DWORD err = WSAGetLastError();
-        _fh_close( fh );
-        D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, err );
+        LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd <<
+                      " failed: " + SystemErrorCodeToString(err);
+        _socket_set_errno( err );
         return -1;
     }
 
-    snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name );
-    D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) );
-    return  _fh_to_int(fh);
+    const int fd = _fh_to_int(fh.get());
+    snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name );
+    D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, fd );
+    fh.release();
+    return  fd;
 }
 
 
@@ -793,10 +883,42 @@
 
     if ( !fh || fh->clazz != &_fh_socket_class ) {
         D("adb_setsockopt: invalid fd %d\n", fd);
+        errno = EBADF;
+        return -1;
+    }
+    int result = setsockopt( fh->fh_socket, level, optname,
+                             reinterpret_cast<const char*>(optval), optlen );
+    if ( result == SOCKET_ERROR ) {
+        const DWORD err = WSAGetLastError();
+        D( "adb_setsockopt: setsockopt on fd %d level %d optname %d "
+           "failed: %s\n", fd, level, optname,
+           SystemErrorCodeToString(err).c_str() );
+        _socket_set_errno( err );
+        result = -1;
+    }
+    return result;
+}
+
+
+int  adb_shutdown(int  fd)
+{
+    FH   f = _fh_from_int(fd, __func__);
+
+    if (!f || f->clazz != &_fh_socket_class) {
+        D("adb_shutdown: invalid fd %d\n", fd);
+        errno = EBADF;
         return -1;
     }
 
-    return setsockopt( fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen );
+    D( "adb_shutdown: %s\n", f->name);
+    if (shutdown(f->fh_socket, SD_BOTH) == SOCKET_ERROR) {
+        const DWORD err = WSAGetLastError();
+        D("socket shutdown fd %d failed: %s\n", fd,
+          SystemErrorCodeToString(err).c_str());
+        _socket_set_errno(err);
+        return -1;
+    }
+    return 0;
 }
 
 /**************************************************************************/
@@ -1199,16 +1321,19 @@
 int  adb_socketpair(int sv[2]) {
     SocketPair pair;
 
-    FH fa = _fh_alloc(&_fh_socketpair_class);
-    FH fb = _fh_alloc(&_fh_socketpair_class);
-
-    if (!fa || !fb)
-        goto Fail;
+    unique_fh fa(_fh_alloc(&_fh_socketpair_class));
+    if (!fa) {
+        return -1;
+    }
+    unique_fh fb(_fh_alloc(&_fh_socketpair_class));
+    if (!fb) {
+        return -1;
+    }
 
     pair = reinterpret_cast<SocketPair>(malloc(sizeof(*pair)));
     if (pair == NULL) {
         D("adb_socketpair: not enough memory to allocate pipes\n" );
-        goto Fail;
+        return -1;
     }
 
     bip_buffer_init( &pair->a2b_bip );
@@ -1217,10 +1342,10 @@
     fa->fh_pair = pair;
     fb->fh_pair = pair;
     pair->used  = 2;
-    pair->a_fd  = fa;
+    pair->a_fd  = fa.get();
 
-    sv[0] = _fh_to_int(fa);
-    sv[1] = _fh_to_int(fb);
+    sv[0] = _fh_to_int(fa.get());
+    sv[1] = _fh_to_int(fb.get());
 
     pair->a2b_bip.fdin  = sv[0];
     pair->a2b_bip.fdout = sv[1];
@@ -1230,12 +1355,9 @@
     snprintf( fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1] );
     snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] );
     D( "adb_socketpair: returns (%d, %d)\n", sv[0], sv[1] );
+    fa.release();
+    fb.release();
     return 0;
-
-Fail:
-    _fh_close(fb);
-    _fh_close(fa);
-    return -1;
 }
 
 /**************************************************************************/
@@ -2083,6 +2205,7 @@
     hook->check   = _event_socket_check;
     hook->peek    = _event_socket_peek;
 
+    // TODO: check return value?
     _event_socket_start( hook );
 }
 
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 87aff88..4a273c4 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -126,19 +126,18 @@
 static int
 read_packet(int  fd, const char* name, apacket** ppacket)
 {
-    char *p = (char*)ppacket;  /* really read a packet address */
-    int   r;
-    int   len = sizeof(*ppacket);
-    char  buff[8];
+    char buff[8];
     if (!name) {
         snprintf(buff, sizeof buff, "fd=%d", fd);
         name = buff;
     }
+    char* p = reinterpret_cast<char*>(ppacket);  /* really read a packet address */
+    int len = sizeof(apacket*);
     while(len > 0) {
-        r = adb_read(fd, p, len);
+        int r = adb_read(fd, p, len);
         if(r > 0) {
             len -= r;
-            p   += r;
+            p += r;
         } else {
             D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
             if((r < 0) && (errno == EINTR)) continue;
@@ -155,20 +154,18 @@
 static int
 write_packet(int  fd, const char* name, apacket** ppacket)
 {
-    char *p = (char*) ppacket;  /* we really write the packet address */
-    int r, len = sizeof(ppacket);
     char buff[8];
     if (!name) {
         snprintf(buff, sizeof buff, "fd=%d", fd);
         name = buff;
     }
-
     if (ADB_TRACING) {
         dump_packet(name, "to remote", *ppacket);
     }
-    len = sizeof(ppacket);
+    char* p = reinterpret_cast<char*>(ppacket);  /* we really write the packet address */
+    int len = sizeof(apacket*);
     while(len > 0) {
-        r = adb_write(fd, p, len);
+        int r = adb_write(fd, p, len);
         if(r > 0) {
             len -= r;
             p += r;
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 0dc9581..db9bedb 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -100,7 +100,7 @@
     }
 #endif
     if (fd < 0) {
-        fd = socket_loopback_client(adb_port, SOCK_STREAM);
+        fd = network_loopback_client(adb_port, SOCK_STREAM, error);
     }
 
     if (fd >= 0) {
@@ -144,9 +144,10 @@
     serverfd = -1;
     for(;;) {
         if(serverfd == -1) {
-            serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
+            std::string error;
+            serverfd = network_inaddr_any_server(port, SOCK_STREAM, &error);
             if(serverfd < 0) {
-                D("server: cannot bind socket yet: %s\n", strerror(errno));
+                D("server: cannot bind socket yet: %s\n", error.c_str());
                 adb_sleep_ms(1000);
                 continue;
             }
diff --git a/base/Android.mk b/base/Android.mk
index 7bd317b..4e135f6 100644
--- a/base/Android.mk
+++ b/base/Android.mk
@@ -21,6 +21,7 @@
     logging.cpp \
     stringprintf.cpp \
     strings.cpp \
+    test_utils.cpp \
 
 libbase_test_src_files := \
     file_test.cpp \
@@ -28,7 +29,6 @@
     stringprintf_test.cpp \
     strings_test.cpp \
     test_main.cpp \
-    test_utils.cpp \
 
 libbase_cppflags := \
     -Wall \
diff --git a/base/file_test.cpp b/base/file_test.cpp
index b138094..4056684 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -24,7 +24,7 @@
 
 #include <string>
 
-#include "test_utils.h"
+#include "base/test_utils.h"
 
 TEST(file, ReadFileToString_ENOENT) {
   std::string s("hello");
@@ -47,10 +47,10 @@
 TEST(file, WriteStringToFile) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
-  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.filename))
+  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path))
     << strerror(errno);
   std::string s;
-  ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s))
+  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
     << strerror(errno);
   EXPECT_EQ("abc", s);
 }
@@ -61,16 +61,16 @@
 TEST(file, WriteStringToFile2) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
-  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.filename, 0660,
+  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path, 0660,
                                                getuid(), getgid()))
       << strerror(errno);
   struct stat sb;
-  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(0, stat(tf.path, &sb));
   ASSERT_EQ(0660U, static_cast<unsigned int>(sb.st_mode & ~S_IFMT));
   ASSERT_EQ(getuid(), sb.st_uid);
   ASSERT_EQ(getgid(), sb.st_gid);
   std::string s;
-  ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s))
+  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
     << strerror(errno);
   EXPECT_EQ("abc", s);
 }
@@ -109,7 +109,7 @@
   ASSERT_TRUE(tf.fd != -1);
   ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
   std::string s;
-  ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s))
+  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
     << strerror(errno);
   EXPECT_EQ("abc", s);
 }
diff --git a/base/test_utils.h b/base/include/base/test_utils.h
similarity index 68%
rename from base/test_utils.h
rename to base/include/base/test_utils.h
index 132d3a7..83f0f1c 100644
--- a/base/test_utils.h
+++ b/base/include/base/test_utils.h
@@ -17,16 +17,37 @@
 #ifndef TEST_UTILS_H
 #define TEST_UTILS_H
 
+#include <string>
+
+#include <base/macros.h>
+
 class TemporaryFile {
  public:
   TemporaryFile();
   ~TemporaryFile();
 
   int fd;
-  char filename[1024];
+  char path[1024];
 
  private:
-  void init(const char* tmp_dir);
+  void init(const std::string& tmp_dir);
+
+  DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
 };
 
+#if !defined(_WIN32)
+class TemporaryDir {
+ public:
+  TemporaryDir();
+  ~TemporaryDir();
+
+  char path[1024];
+
+ private:
+  bool init(const std::string& tmp_dir);
+
+  DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
+};
+#endif
+
 #endif // TEST_UTILS_H
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index c91857a..1a92c94 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -21,7 +21,7 @@
 
 #include "base/file.h"
 #include "base/stringprintf.h"
-#include "test_utils.h"
+#include "base/test_utils.h"
 
 #include <gtest/gtest.h>
 
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 0517bc7..dceb8b7 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "test_utils.h"
+#include "base/test_utils.h"
 
 #include <fcntl.h>
 #include <stdio.h>
@@ -26,34 +26,55 @@
 #include <windows.h>
 #endif
 
-TemporaryFile::TemporaryFile() {
+#include <string>
+
+static std::string GetSystemTempDir() {
 #if defined(__ANDROID__)
-  init("/data/local/tmp");
+  return "/data/local/tmp";
 #elif defined(_WIN32)
   char wd[MAX_PATH] = {};
   _getcwd(wd, sizeof(wd));
-  init(wd);
+  return wd;
 #else
-  init("/tmp");
+  return "/tmp";
 #endif
 }
 
+TemporaryFile::TemporaryFile() {
+  init(GetSystemTempDir());
+}
+
 TemporaryFile::~TemporaryFile() {
   close(fd);
-  unlink(filename);
+  unlink(path);
 }
 
-void TemporaryFile::init(const char* tmp_dir) {
-  snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
+void TemporaryFile::init(const std::string& tmp_dir) {
+  snprintf(path, sizeof(path), "%s/TemporaryFile-XXXXXX", tmp_dir.c_str());
 #if !defined(_WIN32)
-  fd = mkstemp(filename);
+  fd = mkstemp(path);
 #else
   // Windows doesn't have mkstemp, and tmpfile creates the file in the root
   // directory, requiring root (?!) permissions. We have to settle for mktemp.
-  if (mktemp(filename) == nullptr) {
+  if (mktemp(path) == nullptr) {
     abort();
   }
 
-  fd = open(filename, O_RDWR | O_NOINHERIT | O_CREAT, _S_IREAD | _S_IWRITE);
+  fd = open(path, O_RDWR | O_NOINHERIT | O_CREAT, _S_IREAD | _S_IWRITE);
 #endif
 }
+
+#if !defined(_WIN32)
+TemporaryDir::TemporaryDir() {
+  init(GetSystemTempDir());
+}
+
+TemporaryDir::~TemporaryDir() {
+  rmdir(path);
+}
+
+bool TemporaryDir::init(const std::string& tmp_dir) {
+  snprintf(path, sizeof(path), "%s/TemporaryDir-XXXXXX", tmp_dir.c_str());
+  return (mkdtemp(path) != nullptr);
+}
+#endif