19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Copyright 2008, The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project*/ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "installd.h" 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1986c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint create_pkg_path_in_dir(char path[PKG_PATH_MAX], 2086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root const dir_rec_t* dir, 2186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root const char* pkgname, 2286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root const char* postfix) 2386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root{ 2486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root const size_t postfix_len = strlen(postfix); 2586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 2686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root const size_t pkgname_len = strlen(pkgname); 2786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (pkgname_len > PKG_NAME_MAX) { 2886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 2986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 3086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 3186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (is_valid_package_name(pkgname) < 0) { 3286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 3386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 3486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 3586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if ((pkgname_len + dir->len + postfix_len) >= PKG_PATH_MAX) { 3686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 3786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 3886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 3986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root char *dst = path; 4086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root size_t dst_size = PKG_PATH_MAX; 4186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 4286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (append_and_increment(&dst, dir->path, &dst_size) < 0 4386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root || append_and_increment(&dst, pkgname, &dst_size) < 0 4486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root || append_and_increment(&dst, postfix, &dst_size) < 0) { 4586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root LOGE("Error building APK path"); 4686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 4786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 4886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 4986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return 0; 5086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root} 5186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 5286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root/** 5386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Create the package path name for a given package name with a postfix for 5486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * a certain persona. Returns 0 on success, and -1 on failure. 5586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */ 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint create_pkg_path(char path[PKG_PATH_MAX], 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const char *pkgname, 5886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root const char *postfix, 5986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root uid_t persona) 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 6186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root size_t uid_len; 6286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root char* persona_prefix; 6386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (persona == 0) { 6486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root persona_prefix = PRIMARY_USER_PREFIX; 6586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root uid_len = 0; 6686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } else { 6786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root persona_prefix = SECONDARY_USER_PREFIX; 6886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root uid_len = snprintf(NULL, 0, "%d", persona); 6986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 7086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 7186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root const size_t prefix_len = android_data_dir.len + strlen(persona_prefix) + uid_len + 1 /*slash*/; 7286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root char prefix[prefix_len + 1]; 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root char *dst = prefix; 7586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root size_t dst_size = sizeof(prefix); 7686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 7786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0 7886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root || append_and_increment(&dst, persona_prefix, &dst_size) < 0) { 7986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root LOGE("Error building prefix for APK path"); 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 8386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (persona != 0) { 8486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root int ret = snprintf(dst, dst_size, "%d/", persona); 8586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (ret < 0 || (size_t) ret != uid_len + 1) { 8686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root LOGW("Error appending UID to APK path"); 8786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 8886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root dir_rec_t dir; 9286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root dir.path = prefix; 9386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root dir.len = prefix_len; 9486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 9586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return create_pkg_path_in_dir(path, &dir, pkgname, postfix); 9686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root} 9786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 9886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root/** 990b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * Create the path name for user data for a certain persona. 1000b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * Returns 0 on success, and -1 on failure. 1010b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani */ 1020b285499db739ba50f2f839d633e763c70e67f96Amith Yamasaniint create_persona_path(char path[PKG_PATH_MAX], 1030b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani uid_t persona) 1040b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani{ 1050b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani size_t uid_len; 1060b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani char* persona_prefix; 1070b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (persona == 0) { 1080b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani persona_prefix = PRIMARY_USER_PREFIX; 1090b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani uid_len = 0; 1100b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } else { 1110b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani persona_prefix = SECONDARY_USER_PREFIX; 112ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root uid_len = snprintf(NULL, 0, "%d/", persona); 1130b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 1140b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 1150b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani char *dst = path; 1160b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani size_t dst_size = PKG_PATH_MAX; 1170b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 1180b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0 1190b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani || append_and_increment(&dst, persona_prefix, &dst_size) < 0) { 1200b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani LOGE("Error building prefix for user path"); 1210b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani return -1; 1220b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 1230b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 1240b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (persona != 0) { 1250b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (dst_size < uid_len + 1) { 1260b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani LOGE("Error building user path"); 1270b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani return -1; 1280b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 129ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root int ret = snprintf(dst, dst_size, "%d/", persona); 1300b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (ret < 0 || (size_t) ret != uid_len) { 1310b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani LOGE("Error appending persona id to path"); 1320b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani return -1; 1330b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 1340b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 1350b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani return 0; 1360b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani} 1370b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 138ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Rootint create_move_path(char path[PKG_PATH_MAX], 139ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root const char* pkgname, 140ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root const char* leaf, 141ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root uid_t persona) 142ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root{ 143ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1) 144ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root >= PKG_PATH_MAX) { 145ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root return -1; 146ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root } 147ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root 148ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf); 149ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root return 0; 150ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root} 151ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root 1520b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani/** 15386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Checks whether the package name is valid. Returns -1 on error and 15486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * 0 on success. 15586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */ 15686c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint is_valid_package_name(const char* pkgname) { 15786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root const char *x = pkgname; 158c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu int alpha = -1; 15986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (*x) { 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isalnum(*x) || (*x == '_')) { 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* alphanumeric or underscore are fine */ 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (*x == '.') { 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((x == pkgname) || (x[1] == '.') || (x[1] == 0)) { 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* periods must not be first, last, or doubled */ 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("invalid package name '%s'\n", pkgname); 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 169c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } else if (*x == '-') { 170c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu /* Suffix -X is fine to let versioning of packages. 171c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu But whatever follows should be alphanumeric.*/ 172c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu alpha = 1; 17386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } else { 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* anything not A-Z, a-z, 0-9, _, or . is invalid */ 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("invalid package name '%s'\n", pkgname); 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x++; 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 182c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu if (alpha == 1) { 183c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu // Skip current character 184c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu x++; 185c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu while (*x) { 186c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu if (!isalnum(*x)) { 187c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu LOGE("invalid package name '%s' should include only numbers after -\n", pkgname); 188c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return -1; 189c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 190c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu x++; 191c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 192c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int _delete_dir_contents(DIR *d, const char *ignore) 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int result = 0; 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct dirent *de; 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dfd; 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dfd = dirfd(d); 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dfd < 0) return -1; 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while ((de = readdir(d))) { 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const char *name = de->d_name; 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* skip the ignore name if provided */ 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ignore && !strcmp(name, ignore)) continue; 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (de->d_type == DT_DIR) { 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int r, subfd; 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DIR *subdir; 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* always skip "." and ".." */ 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (name[0] == '.') { 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (name[1] == 0) continue; 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((name[1] == '.') && (name[2] == 0)) continue; 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (subfd < 0) { 225508715259c332613240b2399c77d35ea7214f91aKenny Root LOGE("Couldn't openat %s: %s\n", name, strerror(errno)); 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = -1; 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project subdir = fdopendir(subfd); 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (subdir == NULL) { 231508715259c332613240b2399c77d35ea7214f91aKenny Root LOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project close(subfd); 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = -1; 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (_delete_dir_contents(subdir, 0)) { 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = -1; 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closedir(subdir); 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) { 241508715259c332613240b2399c77d35ea7214f91aKenny Root LOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = -1; 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (unlinkat(dfd, name, 0) < 0) { 246508715259c332613240b2399c77d35ea7214f91aKenny Root LOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = -1; 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint delete_dir_contents(const char *pathname, 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int also_delete_dir, 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const char *ignore) 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int res = 0; 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DIR *d; 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project d = opendir(pathname); 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (d == NULL) { 264508715259c332613240b2399c77d35ea7214f91aKenny Root LOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno)); 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -errno; 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project res = _delete_dir_contents(d, ignore); 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closedir(d); 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (also_delete_dir) { 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rmdir(pathname)) { 271508715259c332613240b2399c77d35ea7214f91aKenny Root LOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno)); 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project res = -1; 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return res; 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint delete_dir_contents_fd(int dfd, const char *name) 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fd, res; 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DIR *d; 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fd = openat(dfd, name, O_RDONLY | O_DIRECTORY); 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fd < 0) { 285508715259c332613240b2399c77d35ea7214f91aKenny Root LOGE("Couldn't openat %s: %s\n", name, strerror(errno)); 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project d = fdopendir(fd); 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (d == NULL) { 290508715259c332613240b2399c77d35ea7214f91aKenny Root LOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project close(fd); 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project res = _delete_dir_contents(d, 0); 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closedir(d); 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return res; 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 29886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 29986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root/** 30086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Checks whether a path points to a system app (.apk file). Returns 0 30186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * if it is a system app or -1 if it is not. 30286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */ 30386c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint validate_system_app_path(const char* path) { 30486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root size_t i; 30586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 30686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root for (i = 0; i < android_system_dirs.count; i++) { 30786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root const size_t dir_len = android_system_dirs.dirs[i].len; 30886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) { 30986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (path[dir_len] == '.' || strchr(path + dir_len, '/') != NULL) { 31086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root LOGE("invalid system apk path '%s' (trickery)\n", path); 31186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 31286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 31386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return 0; 31486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 31586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 31686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 31786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 31886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root} 31986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 32086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root/** 32186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Get the contents of a environment variable that contains a path. Caller 32286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * owns the string that is inserted into the directory record. Returns 32386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * 0 on success and -1 on error. 32486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */ 32586c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint get_path_from_env(dir_rec_t* rec, const char* var) { 32686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root const char* path = getenv(var); 32786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root int ret = get_path_from_string(rec, path); 32886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (ret < 0) { 32986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root LOGW("Problem finding value for environment variable %s\n", var); 33086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 33186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return ret; 33286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root} 33386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 33486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root/** 33586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Puts the string into the record as a directory. Appends '/' to the end 33686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * of all paths. Caller owns the string that is inserted into the directory 33786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * record. A null value will result in an error. 33886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * 33986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Returns 0 on success and -1 on error. 34086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */ 34186c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint get_path_from_string(dir_rec_t* rec, const char* path) { 34286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (path == NULL) { 34386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 34486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } else { 34586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root const size_t path_len = strlen(path); 34686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (path_len <= 0) { 34786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 34886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 34986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 35086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root // Make sure path is absolute. 35186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (path[0] != '/') { 35286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 35386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 35486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 35586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (path[path_len - 1] == '/') { 35686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root // Path ends with a forward slash. Make our own copy. 35786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 35886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root rec->path = strdup(path); 35986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (rec->path == NULL) { 36086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 36186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 36286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 36386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root rec->len = path_len; 36486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } else { 36586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root // Path does not end with a slash. Generate a new string. 36686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root char *dst; 36786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 36886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root // Add space for slash and terminating null. 36986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root size_t dst_size = path_len + 2; 37086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 37186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root rec->path = malloc(dst_size); 37286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (rec->path == NULL) { 37386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 37486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 37586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 37686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root dst = rec->path; 37786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 37886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (append_and_increment(&dst, path, &dst_size) < 0 37986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root || append_and_increment(&dst, "/", &dst_size)) { 38086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root LOGE("Error canonicalizing path"); 38186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 38286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 38386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 38486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root rec->len = dst - rec->path; 38586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 38686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 38786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return 0; 38886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root} 38986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 39086c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) { 39186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root dst->len = src->len + strlen(suffix); 39286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root const size_t dstSize = dst->len + 1; 39386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root dst->path = (char*) malloc(dstSize); 39486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 39586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (dst->path == NULL 39686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root || snprintf(dst->path, dstSize, "%s%s", src->path, suffix) 39786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root != (ssize_t) dst->len) { 39886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root LOGE("Could not allocate memory to hold appended path; aborting\n"); 39986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 40086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 40186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 40286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return 0; 40386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root} 40486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 40586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root/** 40686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Check whether path points to a valid path for an APK file. An ASEC 40786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * directory is allowed to have one level of subdirectory names. Returns -1 40886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * when an invalid path is encountered and 0 when a valid path is encountered. 40986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */ 41086c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint validate_apk_path(const char *path) 41186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root{ 41286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root int allowsubdir = 0; 41386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root char *subdir = NULL; 41486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root size_t dir_len; 41586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root size_t path_len; 41686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 41786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (!strncmp(path, android_app_dir.path, android_app_dir.len)) { 41886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root dir_len = android_app_dir.len; 41986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) { 42086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root dir_len = android_app_private_dir.len; 42186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) { 42286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root dir_len = android_asec_dir.len; 42386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root allowsubdir = 1; 42486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } else { 42586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root LOGE("invalid apk path '%s' (bad prefix)\n", path); 42686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 42786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 42886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 42986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root path_len = strlen(path); 43086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 43186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root /* 43286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Only allow the path to have a subdirectory if it's been marked as being allowed. 43386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */ 43486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if ((subdir = strchr(path + dir_len, '/')) != NULL) { 43586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root ++subdir; 43686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (!allowsubdir 43786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root || (path_len > (size_t) (subdir - path) && (strchr(subdir, '/') != NULL))) { 43886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root LOGE("invalid apk path '%s' (subdir?)\n", path); 43986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 44086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 44186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 44286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 44386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root /* 44486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Directories can't have a period directly after the directory markers 44586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * to prevent ".." 44686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */ 44786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (path[dir_len] == '.' 44886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root || (subdir != NULL && ((*subdir == '.') || (strchr(subdir, '/') != NULL)))) { 44986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root LOGE("invalid apk path '%s' (trickery)\n", path); 45086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 45186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 45286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 45386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return 0; 45486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root} 45586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root 45686c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint append_and_increment(char** dst, const char* src, size_t* dst_size) { 45786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root ssize_t ret = strlcpy(*dst, src, *dst_size); 45886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root if (ret < 0 || (size_t) ret >= *dst_size) { 45986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return -1; 46086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root } 46186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root *dst += ret; 46286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root *dst_size -= ret; 46386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root return 0; 46486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root} 4650b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4660b285499db739ba50f2f839d633e763c70e67f96Amith Yamasanichar *build_string2(char *s1, char *s2) { 4670b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (s1 == NULL || s2 == NULL) return NULL; 4680b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4690b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani int len_s1 = strlen(s1); 4700b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani int len_s2 = strlen(s2); 4710b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani int len = len_s1 + len_s2 + 1; 4720b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani char *result = malloc(len); 4730b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (result == NULL) return NULL; 4740b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4750b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani strcpy(result, s1); 4760b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani strcpy(result + len_s1, s2); 4770b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4780b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani return result; 4790b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani} 4800b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4810b285499db739ba50f2f839d633e763c70e67f96Amith Yamasanichar *build_string3(char *s1, char *s2, char *s3) { 4820b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL; 4830b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4840b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani int len_s1 = strlen(s1); 4850b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani int len_s2 = strlen(s2); 4860b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani int len_s3 = strlen(s3); 4870b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani int len = len_s1 + len_s2 + len_s3 + 1; 4880b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani char *result = malloc(len); 4890b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (result == NULL) return NULL; 4900b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4910b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani strcpy(result, s1); 4920b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani strcpy(result + len_s1, s2); 4930b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani strcpy(result + len_s1 + len_s2, s3); 4940b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4950b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani return result; 4960b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani} 497