Merge "Make make_parent() to take const argument" am: 52e2a97aa7 am: 1fd9f0aff7 am: 260573b3c2
am: cd3513c8dd

Change-Id: I3244b7ff4f67a04b34c3531caae49bb50dc4917f
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index f922933..acc2b40 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -208,4 +208,26 @@
 
     // Already renamed.
     expect(temp_file2.path, script2.c_str(), kNoCause);
+
+    // Parents create successfully.
+    TemporaryFile temp_file3;
+    TemporaryDir td;
+    std::string temp_dir = std::string(td.path) + "/aaa/bbb/a.txt";
+    std::string script3("rename(\"" + std::string(temp_file3.path) + "\", \"" +
+                        temp_dir + "\")");
+    expect(temp_dir.c_str(), script3.c_str(), kNoCause);
+}
+
+TEST_F(UpdaterTest, symlink) {
+    // symlink expects 1+ argument.
+    expect(nullptr, "symlink()", kArgsParsingFailure);
+
+    // symlink should fail if src is an empty string.
+    TemporaryFile temp_file1;
+    std::string script1("symlink(\"" + std::string(temp_file1.path) + "\", \"\")");
+    expect(nullptr, script1.c_str(), kSymlinkFailure);
+
+    // symlink failed to remove old src.
+    std::string script2("symlink(\"" + std::string(temp_file1.path) + "\", \"/proc\")");
+    expect(nullptr, script2.c_str(), kSymlinkFailure);
 }
diff --git a/updater/install.cpp b/updater/install.cpp
index ed55ea5..cba95f5 100644
--- a/updater/install.cpp
+++ b/updater/install.cpp
@@ -95,25 +95,33 @@
     uiPrint(state, error_msg);
 }
 
+static bool is_dir(const std::string& dirpath) {
+  struct stat st;
+  return stat(dirpath.c_str(), &st) == 0 && S_ISDIR(st.st_mode);
+}
+
 // Create all parent directories of name, if necessary.
-static int make_parents(char* name) {
-    char* p;
-    for (p = name + (strlen(name)-1); p > name; --p) {
-        if (*p != '/') continue;
-        *p = '\0';
-        if (make_parents(name) < 0) return -1;
-        int result = mkdir(name, 0700);
-        if (result == 0) printf("created [%s]\n", name);
-        *p = '/';
-        if (result == 0 || errno == EEXIST) {
-            // successfully created or already existed; we're done
-            return 0;
-        } else {
-            printf("failed to mkdir %s: %s\n", name, strerror(errno));
-            return -1;
+static bool make_parents(const std::string& name) {
+    size_t prev_end = 0;
+    while (prev_end < name.size()) {
+        size_t next_end = name.find('/', prev_end + 1);
+        if (next_end == std::string::npos) {
+            break;
         }
+        std::string dir_path = name.substr(0, next_end);
+        if (!is_dir(dir_path)) {
+            int result = mkdir(dir_path.c_str(), 0700);
+            if (result != 0) {
+                printf("failed to mkdir %s when make parents for %s: %s\n", dir_path.c_str(),
+                       name.c_str(), strerror(errno));
+                return false;
+            }
+
+            printf("created [%s]\n", dir_path.c_str());
+        }
+        prev_end = next_end;
     }
-    return 0;
+    return true;
 }
 
 // mount(fs_type, partition_type, location, mount_point)
@@ -342,7 +350,7 @@
         return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
     }
     const std::string& src_name = args[0];
-    std::string& dst_name = args[1];
+    const std::string& dst_name = args[1];
 
     if (src_name.empty()) {
         return ErrorAbort(state, kArgsParsingFailure, "src_name argument to %s() can't be empty",
@@ -352,7 +360,7 @@
         return ErrorAbort(state, kArgsParsingFailure, "dst_name argument to %s() can't be empty",
                           name);
     }
-    if (make_parents(&dst_name[0]) != 0) {
+    if (!make_parents(dst_name)) {
         return ErrorAbort(state, kFileRenameFailure, "Creating parent of %s failed, error %s",
                           dst_name.c_str(), strerror(errno));
     } else if (access(dst_name.c_str(), F_OK) == 0 && access(src_name.c_str(), F_OK) != 0) {
@@ -583,7 +591,7 @@
                 ++bad;
             }
         }
-        if (make_parents(&srcs[i][0])) {
+        if (!make_parents(srcs[i])) {
             printf("%s: failed to symlink %s to %s: making parents failed\n",
                     name, srcs[i].c_str(), target.c_str());
             ++bad;