Add an installd command to link files

Given a pair of absolute paths {from_path, to_path} , check that
they are both valid apk subpaths (eg. /data/app/package/foo) and
link(2) to_path to from_path. This is required by staged installs,
where we link existing apks and oat files to their staging location.

bug: 20889739
Change-Id: I3b5e3b43677af68be59308121a4409caaa6a72f0
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 3f679a2..7db3fb9 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -1043,15 +1043,13 @@
 }
 
 /**
- * Check whether path points to a valid path for an APK file. Only one level of
- * subdirectory names is allowed. Returns -1 when an invalid path is encountered
- * and 0 when a valid path is encountered.
+ * Check whether path points to a valid path for an APK file. The path must
+ * begin with a whitelisted prefix path and must be no deeper than |maxSubdirs| within
+ * that path. Returns -1 when an invalid path is encountered and 0 when a valid path
+ * is encountered.
  */
-int validate_apk_path(const char *path)
-{
+static int validate_apk_path_internal(const char *path, int maxSubdirs) {
     const dir_rec_t* dir = NULL;
-    int maxSubdirs = 1;
-
     if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
         dir = &android_app_dir;
     } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
@@ -1060,7 +1058,9 @@
         dir = &android_asec_dir;
     } else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) {
         dir = &android_mnt_expand_dir;
-        maxSubdirs = 2;
+        if (maxSubdirs < 2) {
+            maxSubdirs = 2;
+        }
     } else {
         return -1;
     }
@@ -1068,6 +1068,14 @@
     return validate_path(dir, path, maxSubdirs);
 }
 
+int validate_apk_path(const char* path) {
+    return validate_apk_path_internal(path, 1 /* maxSubdirs */);
+}
+
+int validate_apk_path_subdirs(const char* path) {
+    return validate_apk_path_internal(path, 3 /* maxSubdirs */);
+}
+
 int append_and_increment(char** dst, const char* src, size_t* dst_size) {
     ssize_t ret = strlcpy(*dst, src, *dst_size);
     if (ret < 0 || (size_t) ret >= *dst_size) {