otautil: Clean up dirCreateHierarchy().

- Changed to std::string based implementation (mostly moved from the
  former make_parents() in updater/install.cpp);
- Removed the timestamp parameter, which is only neeed by file-based OTA;
- Changed the type of mode from int to mode_t;
- Renamed dirCreateHierarchy() to mkdir_recursively().

Test: recovery_unit_test passes.
Test: No external user of dirCreateHierarchy() in code search.
Change-Id: I71f8c4b29bab625513bbc3af6d0d1ecdc3a2719a
diff --git a/otautil/DirUtil.cpp b/otautil/DirUtil.cpp
index ad344de..fffc822 100644
--- a/otautil/DirUtil.cpp
+++ b/otautil/DirUtil.cpp
@@ -16,147 +16,101 @@
 
 #include "DirUtil.h"
 
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
 #include <dirent.h>
-#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include <string>
 
 #include <selinux/label.h>
 #include <selinux/selinux.h>
 
-typedef enum { DMISSING, DDIR, DILLEGAL } DirStatus;
+enum class DirStatus { DMISSING, DDIR, DILLEGAL };
 
-static DirStatus
-getPathDirStatus(const char *path)
-{
-    struct stat st;
-    int err;
-
-    err = stat(path, &st);
-    if (err == 0) {
-        /* Something's there; make sure it's a directory.
-         */
-        if (S_ISDIR(st.st_mode)) {
-            return DDIR;
-        }
-        errno = ENOTDIR;
-        return DILLEGAL;
-    } else if (errno != ENOENT) {
-        /* Something went wrong, or something in the path
-         * is bad.  Can't do anything in this situation.
-         */
-        return DILLEGAL;
+static DirStatus dir_status(const std::string& path) {
+  struct stat sb;
+  if (stat(path.c_str(), &sb) == 0) {
+    // Something's there; make sure it's a directory.
+    if (S_ISDIR(sb.st_mode)) {
+      return DirStatus::DDIR;
     }
-    return DMISSING;
+    errno = ENOTDIR;
+    return DirStatus::DILLEGAL;
+  } else if (errno != ENOENT) {
+    // Something went wrong, or something in the path is bad. Can't do anything in this situation.
+    return DirStatus::DILLEGAL;
+  }
+  return DirStatus::DMISSING;
 }
 
-int
-dirCreateHierarchy(const char *path, int mode,
-        const struct utimbuf *timestamp, bool stripFileName,
-        struct selabel_handle *sehnd)
-{
-    DirStatus ds;
+int mkdir_recursively(const std::string& input_path, mode_t mode, bool strip_filename,
+                      const selabel_handle* sehnd) {
+  // Check for an empty string before we bother making any syscalls.
+  if (input_path.empty()) {
+    errno = ENOENT;
+    return -1;
+  }
 
-    /* Check for an empty string before we bother
-     * making any syscalls.
-     */
-    if (path[0] == '\0') {
-        errno = ENOENT;
-        return -1;
+  // Allocate a path that we can modify; stick a slash on the end to make things easier.
+  std::string path = input_path;
+  if (strip_filename) {
+    // Strip everything after the last slash.
+    size_t pos = path.rfind('/');
+    if (pos == std::string::npos) {
+      errno = ENOENT;
+      return -1;
     }
-    // Allocate a path that we can modify; stick a slash on
-    // the end to make things easier.
-    std::string cpath = path;
-    if (stripFileName) {
-        // Strip everything after the last slash.
-        size_t pos = cpath.rfind('/');
-        if (pos == std::string::npos) {
-            errno = ENOENT;
-            return -1;
-        }
-        cpath.resize(pos + 1);
-    } else {
-        // Make sure that the path ends in a slash.
-        cpath.push_back('/');
-    }
+    path.resize(pos + 1);
+  } else {
+    // Make sure that the path ends in a slash.
+    path.push_back('/');
+  }
 
-    /* See if it already exists.
-     */
-    ds = getPathDirStatus(cpath.c_str());
-    if (ds == DDIR) {
-        return 0;
-    } else if (ds == DILLEGAL) {
-        return -1;
-    }
-
-    /* Walk up the path from the root and make each level.
-     * If a directory already exists, no big deal.
-     */
-    const char *path_start = &cpath[0];
-    char *p = &cpath[0];
-    while (*p != '\0') {
-        /* Skip any slashes, watching out for the end of the string.
-         */
-        while (*p != '\0' && *p == '/') {
-            p++;
-        }
-        if (*p == '\0') {
-            break;
-        }
-
-        /* Find the end of the next path component.
-         * We know that we'll see a slash before the NUL,
-         * because we added it, above.
-         */
-        while (*p != '/') {
-            p++;
-        }
-        *p = '\0';
-
-        /* Check this part of the path and make a new directory
-         * if necessary.
-         */
-        ds = getPathDirStatus(path_start);
-        if (ds == DILLEGAL) {
-            /* Could happen if some other process/thread is
-             * messing with the filesystem.
-             */
-            return -1;
-        } else if (ds == DMISSING) {
-            int err;
-
-            char *secontext = NULL;
-
-            if (sehnd) {
-                selabel_lookup(sehnd, &secontext, path_start, mode);
-                setfscreatecon(secontext);
-            }
-
-            err = mkdir(path_start, mode);
-
-            if (secontext) {
-                freecon(secontext);
-                setfscreatecon(NULL);
-            }
-
-            if (err != 0) {
-                return -1;
-            }
-            if (timestamp != NULL && utime(path_start, timestamp)) {
-                return -1;
-            }
-        }
-        // else, this directory already exists.
-
-        // Repair the path and continue.
-        *p = '/';
-    }
+  // See if it already exists.
+  DirStatus ds = dir_status(path);
+  if (ds == DirStatus::DDIR) {
     return 0;
+  } else if (ds == DirStatus::DILLEGAL) {
+    return -1;
+  }
+
+  // Walk up the path from the root and make each level.
+  size_t prev_end = 0;
+  while (prev_end < path.size()) {
+    size_t next_end = path.find('/', prev_end + 1);
+    if (next_end == std::string::npos) {
+      break;
+    }
+    std::string dir_path = path.substr(0, next_end);
+    // Check this part of the path and make a new directory if necessary.
+    switch (dir_status(dir_path)) {
+      case DirStatus::DILLEGAL:
+        // Could happen if some other process/thread is messing with the filesystem.
+        return -1;
+      case DirStatus::DMISSING: {
+        char* secontext = nullptr;
+        if (sehnd) {
+          selabel_lookup(const_cast<selabel_handle*>(sehnd), &secontext, dir_path.c_str(), mode);
+          setfscreatecon(secontext);
+        }
+        int err = mkdir(dir_path.c_str(), mode);
+        if (secontext) {
+          freecon(secontext);
+          setfscreatecon(nullptr);
+        }
+        if (err != 0) {
+          return -1;
+        }
+        break;
+      }
+      default:
+        // Already exists.
+        break;
+    }
+    prev_end = next_end;
+  }
+  return 0;
 }