Add fixupAppDir() API.

This can be used to fixup application directories in case they have been
created by some other entity besides vold; the main use case for this
API right now is OBB directories, which can be created by installers
outside of vold; on devices without sdcardfs, such directories and the
files contained therein are not setup correctly. This API will make sure
everything is setup the way it needs to be setup.

Bug: 146419093
Test: inspect OBB dir after install
Change-Id: I2e35b7ac2992dbb21cc950e53651ffc07cfca907
diff --git a/Utils.cpp b/Utils.cpp
index 35839ac..9f9b357 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -47,6 +47,7 @@
 #include <sys/xattr.h>
 #include <unistd.h>
 
+#include <filesystem>
 #include <list>
 #include <mutex>
 #include <regex>
@@ -228,7 +229,40 @@
     return ret;
 }
 
-int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid) {
+static int FixupAppDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid, long projectId) {
+    namespace fs = std::filesystem;
+
+    // Setup the directory itself correctly
+    int ret = PrepareDirWithProjectId(path, mode, uid, gid, projectId);
+    if (ret != OK) {
+        return ret;
+    }
+
+    // Fixup all of its file entries
+    for (const auto& itEntry : fs::directory_iterator(path)) {
+        ret = lchown(itEntry.path().c_str(), uid, gid);
+        if (ret != 0) {
+            return ret;
+        }
+
+        ret = chmod(itEntry.path().c_str(), mode);
+        if (ret != 0) {
+            return ret;
+        }
+
+        if (!IsFilesystemSupported("sdcardfs")) {
+            ret = SetQuotaProjectId(itEntry.path(), projectId);
+            if (ret != 0) {
+                return ret;
+            }
+        }
+    }
+
+    return OK;
+}
+
+int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid,
+                          bool fixupExisting) {
     long projectId;
     size_t pos;
     int ret = 0;
@@ -302,7 +336,15 @@
         } else {
             projectId = uid - AID_APP_START + AID_EXT_GID_START;
         }
-        ret = PrepareDirWithProjectId(pathToCreate, mode, uid, gid, projectId);
+
+        if (fixupExisting && access(pathToCreate.c_str(), F_OK) == 0) {
+            // Fixup all files in this existing directory with the correct UID/GID
+            // and project ID.
+            ret = FixupAppDir(pathToCreate, mode, uid, gid, projectId);
+        } else {
+            ret = PrepareDirWithProjectId(pathToCreate, mode, uid, gid, projectId);
+        }
+
         if (ret != 0) {
             return ret;
         }