fix the symlink() command to create directories if needed

Full OTAs currently fail if the build contains a directory containing
only symlinks, because nothing creates that directory.  Change the
symlink() command to create any ancestor directories that don't exist.
They're created as owner root perms 0700 because we assume that in
practice subsequent set_perm_recursive() calls will fix up their
ownership and permissions.

Change-Id: I4681cbc85863d9778e36b924f0532b2b3ef14310
diff --git a/updater/install.c b/updater/install.c
index f981017..ba27e9f 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -456,6 +456,26 @@
     }
 }
 
+// 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) fprintf(stderr, "symlink(): created [%s]\n", name);
+        *p = '/';
+        if (result == 0 || errno == EEXIST) {
+            // successfully created or already existed; we're done
+            return 0;
+        } else {
+            fprintf(stderr, "failed to mkdir %s: %s\n", name, strerror(errno));
+            return -1;
+        }
+    }
+    return 0;
+}
 
 // symlink target src1 src2 ...
 //    unlinks any previously existing src1, src2, etc before creating symlinks.
@@ -483,6 +503,11 @@
                 ++bad;
             }
         }
+        if (make_parents(srcs[i])) {
+            fprintf(stderr, "%s: failed to symlink %s to %s: making parents failed\n",
+                    name, srcs[i], target);
+            ++bad;
+        }
         if (symlink(target, srcs[i]) < 0) {
             fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
                     name, srcs[i], target, strerror(errno));
@@ -504,7 +529,8 @@
 
     int min_args = 4 + (recursive ? 1 : 0);
     if (argc < min_args) {
-        return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
+        return ErrorAbort(state, "%s() expects %d+ args, got %d",
+                          name, min_args, argc);
     }
 
     char** args = ReadVarArgs(state, argc, argv);
@@ -626,7 +652,7 @@
 
     buffer = malloc(st.st_size+1);
     if (buffer == NULL) {
-        ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1);
+        ErrorAbort(state, "%s: failed to alloc %lld bytes", name, st.st_size+1);
         goto done;
     }
 
@@ -638,7 +664,7 @@
     }
 
     if (fread(buffer, 1, st.st_size, f) != st.st_size) {
-        ErrorAbort(state, "%s: failed to read %d bytes from %s",
+        ErrorAbort(state, "%s: failed to read %lld bytes from %s",
                    name, st.st_size+1, filename);
         fclose(f);
         goto done;