Refine directory traversing: registering callback 66/103266/4
authorKyungwook Tak <k.tak@samsung.com>
Thu, 8 Dec 2016 01:12:11 +0000 (10:12 +0900)
committerKyungwook Tak <k.tak@samsung.com>
Thu, 8 Dec 2016 08:20:04 +0000 (17:20 +0900)
There's two part of directory traversing(removing all files in directory
and loading preloaded app deks). So duplicated code can be compressed to
traverse_directory with entry callback registered.

Change-Id: I654bed7f3b4efff75b2853fceb3f9d97b51a85b5
Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
srcs/key_handler.c

index d77016f..cdc96af 100644 (file)
@@ -188,61 +188,87 @@ error:
        return ret;
 }
 
-static void _remove_file(const char *path)
+typedef int(*entry_callback)(const char *path, const struct dirent *entry, void *user_data);
+static int traverse_directory(const char *path, entry_callback ecb, void *user_data)
 {
-       unlink(path);
-}
-
-void _remove_directory(const char *path)
-{
-       char file_path_buff[MAX_PATH_LEN] = {0, };
        DIR *dir = opendir(path);
        if (dir == NULL) {
-               if (errno == ENOENT)
-                       WAE_SLOGI("directory is not exist already(%s)", path);
-               else
+               if (errno == ENOENT) {
+                       // it's not error for current cases of using traverse_directory.
+                       // To open dek store directory for load/remove can be occured in some
+                       // exception(or attacked) cases but we can just ignore it if it isn't the
+                       // first time call load_preloaded_app_deks.
+                       WAE_SLOGI("directory isn't exist(%s).", path);
+                       return WAE_ERROR_NONE;
+               } else {
                        WAE_SLOGE("Failed to open dir(%s)", path);
-
-               return;
+                       return WAE_ERROR_FILE;
+               }
        }
 
+       int ret = WAE_ERROR_NONE;
        struct dirent entry;
        struct dirent *result = NULL;
        while (true) {
                if (readdir_r(dir, &entry, &result) != 0) {
+                       WAE_SLOGE("readdir_r error on dir(%s) errno(%d)", path, errno);
                        break;
                } else if (result == NULL) {
-                       break;
+                       break; // end of directory
                } else if (strcmp(entry.d_name, ".") == 0 || strcmp(entry.d_name, "..") == 0) {
                        continue;
                }
 
-               if (snprintf(file_path_buff, sizeof(file_path_buff), "%s/%s", path, entry.d_name)
-                               < 0)
-                       continue;
+               int _ret = ecb(path, result, user_data);
+               if (_ret != WAE_ERROR_NONE)
+                       ret = _ret;
+       }
 
-               if (entry.d_type == DT_DIR) {
-                       _remove_directory(file_path_buff);
-               } else {
-                       WAE_SLOGD("remove file(%s)", file_path_buff);
-                       _remove_file(file_path_buff);
-               }
+       closedir(dir);
+       return ret;
+}
+
+static void _remove_file(const char *path)
+{
+       unlink(path);
+}
+
+static int _entry_callback_remove_all(
+       const char *path, const struct dirent *entry, void *user_data)
+{
+       (void) user_data; // TODO: use UNUSED macro
+
+       char file_path_buff[MAX_PATH_LEN] = {0, };
+       if (snprintf(file_path_buff, sizeof(file_path_buff), "%s/%s", path, entry->d_name) < 0)
+               return WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */
+
+       int ret = WAE_ERROR_NONE;
+       if (entry->d_type == DT_DIR) {
+               int _ret = traverse_directory(file_path_buff, _entry_callback_remove_all, NULL);
+               if (_ret != WAE_ERROR_NONE)
+                       ret = _ret;
+               rmdir(file_path_buff);
+       } else {
+               _remove_file(file_path_buff);
        }
+       return ret;
+}
+
+void _remove_directory(const char *path)
+{
+       traverse_directory(path, _entry_callback_remove_all, NULL);
 
        WAE_SLOGD("remove directory(%s)", path);
-       closedir(dir);
        rmdir(path);
 }
 
 int _get_preloaded_app_dek_file_path(const char *pkg_id, size_t size, char *path)
 {
-       int ret = snprintf(path, size, "%s/%s_%s.adek",
-                                  _get_dek_store_path(), APP_DEK_FILE_PFX, pkg_id);
-
-       if (ret < 0)
+       if (snprintf(path, size, "%s/%s_%s.adek",
+                               _get_dek_store_path(), APP_DEK_FILE_PFX, pkg_id) < 0)
                return WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */
-
-       return WAE_ERROR_NONE;
+       else
+               return WAE_ERROR_NONE;
 }
 
 static int _extract_pkg_id_from_file_name(const char *file_name, char *pkg_id)
@@ -574,18 +600,56 @@ int _get_app_dek_kek(raw_buffer_s **pdek_kek)
 #endif
 }
 
-int load_preloaded_app_deks()
+static int _entry_callback_load_preloaded_adeks(
+       const char *path, const struct dirent *entry, void *prikey)
 {
-       WAE_SLOGI("load_preloaded_app_deks start");
+       const char *pub_key_path = _get_dek_kek_pub_key_path();
+       const char *pri_key_path = _get_dek_kek_pri_key_path();
+
+       char file_path_buff[MAX_PATH_LEN] = {0, };
+       if (snprintf(file_path_buff, sizeof(file_path_buff), "%s/%s", path, entry->d_name) < 0)
+               return WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */
+
+       if (strcmp(file_path_buff, pub_key_path) == 0 ||
+               strcmp(file_path_buff, pri_key_path) == 0)
+               return WAE_ERROR_NONE; /* skip KEK files */
 
-       int global_ret = WAE_ERROR_NONE;
+       if (entry->d_type != DT_REG || strstr(entry->d_name, APP_DEK_FILE_PFX) == NULL) {
+               if (entry->d_type == DT_DIR)
+                       WAE_SLOGW(
+                               "Invalid file in dek store(%s). Directory shouldn't be here.", path);
+               else
+                       WAE_SLOGW(
+                               "Invalid file in dek store(%s). "
+                               "Not regular file or prefix(%s) is invalid.", path, APP_DEK_FILE_PFX);
+
+               return WAE_ERROR_FILE;
+       }
 
        char pkg_id[MAX_PKGID_LEN] = {0, };
-       char file_path_buff[MAX_PATH_LEN] = {0, };
+       int ret = _extract_pkg_id_from_file_name(entry->d_name, pkg_id);
+       if (ret != WAE_ERROR_NONE) {
+               WAE_SLOGW("Failed to extract pkgid from file(%s). It will be ignored.", file_path_buff);
+               return ret;
+       }
+
+       ret = _load_preloaded_app_dek((raw_buffer_s *)prikey, file_path_buff, pkg_id);
+       if (ret == WAE_ERROR_NONE || ret == WAE_ERROR_KEY_EXISTS) {
+               WAE_SLOGI("Successfully load app dek(%s)", file_path_buff);
+               return WAE_ERROR_NONE;
+       } else {
+               WAE_SLOGW("Failed to load app dek(%s) ret(%d)", file_path_buff, ret);
+               return ret;
+       }
+}
+
+int load_preloaded_app_deks()
+{
+       WAE_SLOGI("load_preloaded_app_deks start");
+
+       int ret = WAE_ERROR_NONE;
 
        const char *dek_store_path = _get_dek_store_path();
-       const char *dek_kek_pub_key_path = _get_dek_kek_pub_key_path();
-       const char *dek_kek_pri_key_path = _get_dek_kek_pri_key_path();
 
        raw_buffer_s *prikey = NULL;
        DIR *dir = NULL;
@@ -602,86 +666,24 @@ int load_preloaded_app_deks()
                        return WAE_ERROR_NONE;
                } else {
                        WAE_SLOGE("Fail to open dir. dir=%s", dek_store_path);
-                       global_ret = WAE_ERROR_FILE;
+                       ret = WAE_ERROR_FILE;
                        goto out;
                }
        }
 
-       global_ret = _get_app_dek_kek(&prikey);
-
-       if (global_ret != WAE_ERROR_NONE) {
-               WAE_SLOGE("Fail to get APP_DEK_KEK Private Key");
+       ret = _get_app_dek_kek(&prikey);
+       if (ret != WAE_ERROR_NONE) {
+               WAE_SLOGE("Fail to get APP_DEK_KEK Private Key. ret(%d)", ret);
                goto out;
        }
 
-       struct dirent entry;
-       struct dirent *result = NULL;
-
-       while (true) {
-               int ret = WAE_ERROR_NONE;
-               if (readdir_r(dir, &entry, &result) != 0) {
-                       global_ret = WAE_ERROR_FILE;
-                       break;
-               }
-
-               // readdir_r returns NULL in *result if the end
-               // of the directory stream is reached
-               if (result == NULL)
-                       break;
-
-               if (strcmp(entry.d_name, ".") == 0 || strcmp(entry.d_name, "..") == 0)
-                       continue;
-
-               if (snprintf(file_path_buff, sizeof(file_path_buff), "%s/%s",
-                                          dek_store_path, entry.d_name) < 0) {
-                       WAE_SLOGE("Failed to make file path by snprintf.");
-                       global_ret = WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */
-                       break;
-               }
-
-               // skip for KEKs. They'll be deleted after all akek loaded to key-manager.
-               if (strcmp(file_path_buff, dek_kek_pub_key_path) == 0 ||
-                       strcmp(file_path_buff, dek_kek_pri_key_path) == 0) {
-                       WAE_SLOGD("Skip KEK file...(%s)", file_path_buff);
-                       continue;
-               }
-
-               // regular file && start with KEY_MANAGER_INITIAL_VALUE_FILE_PFX
-               // clear all invalid cases silently
-               if (entry.d_type != DT_REG || strstr(entry.d_name, APP_DEK_FILE_PFX) == NULL) {
-                       if (entry.d_type == DT_DIR) {
-                               WAE_SLOGW(
-                                       "Invalid file in dek store(%s). Directory shouldn't be here.",
-                                       dek_store_path);
-                               global_ret = WAE_ERROR_FILE;
-                       } else {
-                               WAE_SLOGW(
-                                       "Invalid file in dek store(%s). "
-                                       "Not regular file or prefix(%s) is invalid.",
-                                       dek_store_path, APP_DEK_FILE_PFX);
-                               global_ret = WAE_ERROR_FILE;
-                       }
-
-                       continue;
-               }
-
-               ret = _extract_pkg_id_from_file_name(entry.d_name, pkg_id);
-
-               if (ret != WAE_ERROR_NONE) {
-                       WAE_SLOGW("Failed to extract pkgid from file. It will be ignored. file=%s",
-                                         file_path_buff);
-                       global_ret = ret;
-                       continue;
-               }
+       // close dek store dir fd not to affect the traverse_directory call
+       closedir(dir);
+       dir = NULL;
 
-               ret = _load_preloaded_app_dek(prikey, file_path_buff, pkg_id);
-               if (ret != WAE_ERROR_NONE && ret != WAE_ERROR_KEY_EXISTS) {
-                       WAE_SLOGW("Failed to load app dek(%s) ret(%d)", file_path_buff, ret);
-                       global_ret = ret;
-               } else {
-                       WAE_SLOGI("Successfully load app dek(%s)", file_path_buff);
-               }
-       }
+       ret = traverse_directory(dek_store_path, _entry_callback_load_preloaded_adeks, prikey);
+       if (ret != WAE_ERROR_NONE)
+               WAE_SLOGE("Fail when traverse dek store directory. ret(%d)", ret);
 
 out:
        if (prikey != NULL)
@@ -699,7 +701,7 @@ out:
        // initializer service failure.
        _remove_directory(dek_store_path);
 
-       return global_ret;
+       return ret;
 }
 
 int remove_app_ce(uid_t uid, const char *pkg_id, wae_app_type_e app_type)