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
19197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn#define CACHE_NOISY(x) //x
20197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
2186c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint create_pkg_path_in_dir(char path[PKG_PATH_MAX],
2286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root                                const dir_rec_t* dir,
2386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root                                const char* pkgname,
2486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root                                const char* postfix)
2586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root{
2686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     const size_t postfix_len = strlen(postfix);
2786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
2886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     const size_t pkgname_len = strlen(pkgname);
2986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     if (pkgname_len > PKG_NAME_MAX) {
3086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root         return -1;
3186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     }
3286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
3386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     if (is_valid_package_name(pkgname) < 0) {
3486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root         return -1;
3586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     }
3686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
3786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     if ((pkgname_len + dir->len + postfix_len) >= PKG_PATH_MAX) {
3886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root         return -1;
3986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     }
4086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
4186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     char *dst = path;
4286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     size_t dst_size = PKG_PATH_MAX;
4386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
4486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     if (append_and_increment(&dst, dir->path, &dst_size) < 0
4586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root             || append_and_increment(&dst, pkgname, &dst_size) < 0
4686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root             || append_and_increment(&dst, postfix, &dst_size) < 0) {
473762c311729fe9f3af085c14c5c1fb471d994c03Steve Block         ALOGE("Error building APK path");
4886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root         return -1;
4986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     }
5086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
5186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     return 0;
5286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root}
5386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
5486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root/**
5586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Create the package path name for a given package name with a postfix for
5686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * a certain persona. Returns 0 on success, and -1 on failure.
5786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint create_pkg_path(char path[PKG_PATH_MAX],
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    const char *pkgname,
6086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root                    const char *postfix,
6186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root                    uid_t persona)
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
6386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    size_t uid_len;
6486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    char* persona_prefix;
6586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    if (persona == 0) {
6686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        persona_prefix = PRIMARY_USER_PREFIX;
6786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        uid_len = 0;
6886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    } else {
6986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        persona_prefix = SECONDARY_USER_PREFIX;
7086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        uid_len = snprintf(NULL, 0, "%d", persona);
7186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    }
7286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
7386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    const size_t prefix_len = android_data_dir.len + strlen(persona_prefix) + uid_len + 1 /*slash*/;
7486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    char prefix[prefix_len + 1];
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    char *dst = prefix;
7786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    size_t dst_size = sizeof(prefix);
7886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
7986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
8086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            || append_and_increment(&dst, persona_prefix, &dst_size) < 0) {
813762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Error building prefix for APK path");
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
8586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    if (persona != 0) {
8686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        int ret = snprintf(dst, dst_size, "%d/", persona);
8786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        if (ret < 0 || (size_t) ret != uid_len + 1) {
888564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Error appending UID to APK path");
8986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            return -1;
9086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        }
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    dir_rec_t dir;
9486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    dir.path = prefix;
9586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    dir.len = prefix_len;
9686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
9786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    return create_pkg_path_in_dir(path, &dir, pkgname, postfix);
9886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root}
9986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
10086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root/**
1010b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * Create the path name for user data for a certain persona.
1020b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * Returns 0 on success, and -1 on failure.
1030b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani */
1040b285499db739ba50f2f839d633e763c70e67f96Amith Yamasaniint create_persona_path(char path[PKG_PATH_MAX],
1050b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani                    uid_t persona)
1060b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani{
1070b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    size_t uid_len;
1080b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    char* persona_prefix;
1090b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    if (persona == 0) {
1100b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani        persona_prefix = PRIMARY_USER_PREFIX;
1110b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani        uid_len = 0;
1120b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    } else {
1130b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani        persona_prefix = SECONDARY_USER_PREFIX;
114ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root        uid_len = snprintf(NULL, 0, "%d/", persona);
1150b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    }
1160b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani
1170b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    char *dst = path;
1180b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    size_t dst_size = PKG_PATH_MAX;
1190b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani
1200b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
1210b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani            || append_and_increment(&dst, persona_prefix, &dst_size) < 0) {
1223762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Error building prefix for user path");
1230b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani        return -1;
1240b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    }
1250b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani
1260b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    if (persona != 0) {
1270b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani        if (dst_size < uid_len + 1) {
1283762c311729fe9f3af085c14c5c1fb471d994c03Steve Block            ALOGE("Error building user path");
1290b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani            return -1;
1300b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani        }
131ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root        int ret = snprintf(dst, dst_size, "%d/", persona);
1320b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani        if (ret < 0 || (size_t) ret != uid_len) {
1333762c311729fe9f3af085c14c5c1fb471d994c03Steve Block            ALOGE("Error appending persona id to path");
1340b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani            return -1;
1350b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani        }
1360b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    }
1370b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    return 0;
1380b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani}
1390b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani
1405b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey/**
1415b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey * Create the path name for media for a certain persona.
1425b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey * Returns 0 on success, and -1 on failure.
1435b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey */
1445b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkeyint create_persona_media_path(char path[PATH_MAX], userid_t userid) {
1455b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey    if (snprintf(path, PATH_MAX, "%s%d", android_media_dir.path, userid) > PATH_MAX) {
1465b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey        return -1;
1475b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey    }
1485b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey    return 0;
1495b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey}
1505b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey
151ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Rootint create_move_path(char path[PKG_PATH_MAX],
152ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root    const char* pkgname,
153ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root    const char* leaf,
154ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root    uid_t persona)
155ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root{
156ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root    if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
157ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root            >= PKG_PATH_MAX) {
158ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root        return -1;
159ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root    }
160ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root
161ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root    sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
162ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root    return 0;
163ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root}
164ad757e9b36d6bc6b8e39be00612d0e60863aaafcKenny Root
1650b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani/**
16686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Checks whether the package name is valid. Returns -1 on error and
16786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * 0 on success.
16886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */
16986c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint is_valid_package_name(const char* pkgname) {
17086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    const char *x = pkgname;
171c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu    int alpha = -1;
17286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (*x) {
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isalnum(*x) || (*x == '_')) {
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /* alphanumeric or underscore are fine */
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (*x == '.') {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((x == pkgname) || (x[1] == '.') || (x[1] == 0)) {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    /* periods must not be first, last, or doubled */
1793762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("invalid package name '%s'\n", pkgname);
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return -1;
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
182c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu        } else if (*x == '-') {
183c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu            /* Suffix -X is fine to let versioning of packages.
184c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu               But whatever follows should be alphanumeric.*/
185c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu            alpha = 1;
18686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        } else {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /* anything not A-Z, a-z, 0-9, _, or . is invalid */
1883762c311729fe9f3af085c14c5c1fb471d994c03Steve Block            ALOGE("invalid package name '%s'\n", pkgname);
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        x++;
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
195c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu    if (alpha == 1) {
196c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu        // Skip current character
197c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu        x++;
198c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu        while (*x) {
199c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu            if (!isalnum(*x)) {
2003762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("invalid package name '%s' should include only numbers after -\n", pkgname);
201c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu                return -1;
202c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu            }
203c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu            x++;
204c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu        }
205c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu    }
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0;
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int _delete_dir_contents(DIR *d, const char *ignore)
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int result = 0;
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct dirent *de;
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int dfd;
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    dfd = dirfd(d);
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (dfd < 0) return -1;
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while ((de = readdir(d))) {
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const char *name = de->d_name;
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* skip the ignore name if provided */
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ignore && !strcmp(name, ignore)) continue;
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (de->d_type == DT_DIR) {
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int r, subfd;
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            DIR *subdir;
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /* always skip "." and ".." */
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (name[0] == '.') {
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (name[1] == 0) continue;
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if ((name[1] == '.') && (name[2] == 0)) continue;
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (subfd < 0) {
2383762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result = -1;
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            subdir = fdopendir(subfd);
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (subdir == NULL) {
2443762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                close(subfd);
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result = -1;
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (_delete_dir_contents(subdir, 0)) {
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result = -1;
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            closedir(subdir);
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
2543762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result = -1;
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (unlinkat(dfd, name, 0) < 0) {
2593762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result = -1;
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return result;
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint delete_dir_contents(const char *pathname,
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        int also_delete_dir,
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        const char *ignore)
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int res = 0;
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    DIR *d;
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    d = opendir(pathname);
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (d == NULL) {
2773762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno));
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -errno;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    res = _delete_dir_contents(d, ignore);
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    closedir(d);
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (also_delete_dir) {
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (rmdir(pathname)) {
2843762c311729fe9f3af085c14c5c1fb471d994c03Steve Block            ALOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno));
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            res = -1;
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return res;
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint delete_dir_contents_fd(int dfd, const char *name)
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int fd, res;
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    DIR *d;
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fd < 0) {
2983762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    d = fdopendir(fd);
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (d == NULL) {
3033762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        close(fd);
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    res = _delete_dir_contents(d, 0);
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    closedir(d);
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return res;
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
31186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
312197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornint lookup_media_dir(char basepath[PATH_MAX], const char *dir)
313197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
314197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    DIR *d;
315197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    struct dirent *de;
316197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    struct stat s;
317197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    char* dirpos = basepath + strlen(basepath);
318197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
319197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if ((*(dirpos-1)) != '/') {
320197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        *dirpos = '/';
321197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        dirpos++;
322197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
323197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
324197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    CACHE_NOISY(ALOGI("Looking up %s in %s\n", dir, basepath));
325197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // Verify the path won't extend beyond our buffer, to avoid
326197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // repeated checking later.
327197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if ((dirpos-basepath+strlen(dir)) >= (PATH_MAX-1)) {
328197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        ALOGW("Path exceeds limit: %s%s", basepath, dir);
329197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        return -1;
330197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
331197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
332197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // First, can we find this directory with the case that is given?
333197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    strcpy(dirpos, dir);
334197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if (stat(basepath, &s) >= 0) {
335197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        CACHE_NOISY(ALOGI("Found direct: %s\n", basepath));
336197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        return 0;
337197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
338197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
339197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // Not found with that case...  search through all entries to find
340197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // one that matches regardless of case.
341197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    *dirpos = 0;
342197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
343197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    d = opendir(basepath);
344197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if (d == NULL) {
345197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        return -1;
346197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
347197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
348197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    while ((de = readdir(d))) {
349197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (strcasecmp(de->d_name, dir) == 0) {
350197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            strcpy(dirpos, de->d_name);
351197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            closedir(d);
352197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            CACHE_NOISY(ALOGI("Found search: %s\n", basepath));
353197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            return 0;
354197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
355197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
356197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
357197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    ALOGW("Couldn't find %s in %s", dir, basepath);
358197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    closedir(d);
359197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    return -1;
360197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
361197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
362197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornint64_t data_disk_free()
363197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
364197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    struct statfs sfs;
365197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if (statfs(android_data_dir.path, &sfs) == 0) {
366197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        return sfs.f_bavail * sfs.f_bsize;
367197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    } else {
368197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        ALOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno));
369197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        return -1;
370197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
371197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
372197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
373197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborncache_t* start_cache_collection()
374197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
375197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    cache_t* cache = (cache_t*)calloc(1, sizeof(cache_t));
376197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    return cache;
377197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
378197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
379197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn#define CACHE_BLOCK_SIZE (512*1024)
380197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
381197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornstatic void* _cache_malloc(cache_t* cache, size_t len)
382197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
383197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    len = (len+3)&~3;
384197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if (len > (CACHE_BLOCK_SIZE/2)) {
385197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        // It doesn't make sense to try to put this allocation into one
386197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        // of our blocks, because it is so big.  Instead, make a new dedicated
387197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        // block for it.
388197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        int8_t* res = (int8_t*)malloc(len+sizeof(void*));
389197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (res == NULL) {
390197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            return NULL;
391197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
392197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        CACHE_NOISY(ALOGI("Allocated large cache mem block: %p size %d", res, len));
393197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        // Link it into our list of blocks, not disrupting the current one.
394197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (cache->memBlocks == NULL) {
395197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            *(void**)res = NULL;
396197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            cache->memBlocks = res;
397197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        } else {
398197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            *(void**)res = *(void**)cache->memBlocks;
399197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            *(void**)cache->memBlocks = res;
400197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
401197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        return res + sizeof(void*);
402197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
403197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    int8_t* res = cache->curMemBlockAvail;
404197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    int8_t* nextPos = res + len;
405197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if (cache->memBlocks == NULL || nextPos > cache->curMemBlockEnd) {
406197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        int8_t* newBlock = malloc(CACHE_BLOCK_SIZE);
407197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (newBlock == NULL) {
408197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            return NULL;
409197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
410197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        CACHE_NOISY(ALOGI("Allocated new cache mem block: %p", newBlock));
411197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        *(void**)newBlock = cache->memBlocks;
412197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        cache->memBlocks = newBlock;
413197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        res = cache->curMemBlockAvail = newBlock + sizeof(void*);
414197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        cache->curMemBlockEnd = newBlock + CACHE_BLOCK_SIZE;
415197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        nextPos = res + len;
416197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
417197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    CACHE_NOISY(ALOGI("cache_malloc: ret %p size %d, block=%p, nextPos=%p",
418197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            res, len, cache->memBlocks, nextPos));
419197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    cache->curMemBlockAvail = nextPos;
420197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    return res;
421197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
422197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
423197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornstatic void* _cache_realloc(cache_t* cache, void* cur, size_t origLen, size_t len)
424197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
425197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // This isn't really a realloc, but it is good enough for our purposes here.
426197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    void* alloc = _cache_malloc(cache, len);
427197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if (alloc != NULL && cur != NULL) {
428197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        memcpy(alloc, cur, origLen < len ? origLen : len);
429197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
430197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    return alloc;
431197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
432197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
433197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornstatic void _inc_num_cache_collected(cache_t* cache)
434197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
435197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    cache->numCollected++;
436197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if ((cache->numCollected%20000) == 0) {
437197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        ALOGI("Collected cache so far: %d directories, %d files",
438197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            cache->numDirs, cache->numFiles);
439197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
440197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
441197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
442197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornstatic cache_dir_t* _add_cache_dir_t(cache_t* cache, cache_dir_t* parent, const char *name)
443197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
444197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    size_t nameLen = strlen(name);
445197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    cache_dir_t* dir = (cache_dir_t*)_cache_malloc(cache, sizeof(cache_dir_t)+nameLen+1);
446197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if (dir != NULL) {
447197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        dir->parent = parent;
448197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        dir->childCount = 0;
449197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        dir->hiddenCount = 0;
450197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        dir->deleted = 0;
451197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        strcpy(dir->name, name);
452197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (cache->numDirs >= cache->availDirs) {
453197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            size_t newAvail = cache->availDirs < 1000 ? 1000 : cache->availDirs*2;
454197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            cache_dir_t** newDirs = (cache_dir_t**)_cache_realloc(cache, cache->dirs,
455197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    cache->availDirs*sizeof(cache_dir_t*), newAvail*sizeof(cache_dir_t*));
456197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (newDirs == NULL) {
457197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                ALOGE("Failure growing cache dirs array for %s\n", name);
458197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                return NULL;
459197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
460197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            cache->availDirs = newAvail;
461197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            cache->dirs = newDirs;
462197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
463197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        cache->dirs[cache->numDirs] = dir;
464197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        cache->numDirs++;
465197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (parent != NULL) {
466197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            parent->childCount++;
467197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
468197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        _inc_num_cache_collected(cache);
469197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    } else {
470197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        ALOGE("Failure allocating cache_dir_t for %s\n", name);
471197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
472197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    return dir;
473197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
474197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
475197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornstatic cache_file_t* _add_cache_file_t(cache_t* cache, cache_dir_t* dir, time_t modTime,
476197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        const char *name)
477197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
478197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    size_t nameLen = strlen(name);
479197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    cache_file_t* file = (cache_file_t*)_cache_malloc(cache, sizeof(cache_file_t)+nameLen+1);
480197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if (file != NULL) {
481197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        file->dir = dir;
482197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        file->modTime = modTime;
483197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        strcpy(file->name, name);
484197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (cache->numFiles >= cache->availFiles) {
485197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            size_t newAvail = cache->availFiles < 1000 ? 1000 : cache->availFiles*2;
486197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            cache_file_t** newFiles = (cache_file_t**)_cache_realloc(cache, cache->files,
487197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    cache->availFiles*sizeof(cache_file_t*), newAvail*sizeof(cache_file_t*));
488197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (newFiles == NULL) {
489197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                ALOGE("Failure growing cache file array for %s\n", name);
490197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                return NULL;
491197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
492197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            cache->availFiles = newAvail;
493197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            cache->files = newFiles;
494197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
495197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        CACHE_NOISY(ALOGI("Setting file %p at position %d in array %p", file,
496197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                cache->numFiles, cache->files));
497197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        cache->files[cache->numFiles] = file;
498197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        cache->numFiles++;
499197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        dir->childCount++;
500197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        _inc_num_cache_collected(cache);
501197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    } else {
502197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        ALOGE("Failure allocating cache_file_t for %s\n", name);
503197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
504197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    return file;
505197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
506197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
507197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornstatic int _add_cache_files(cache_t *cache, cache_dir_t *parentDir, const char *dirName,
508197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        DIR* dir, char *pathBase, char *pathPos, size_t pathAvailLen)
509197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
510197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    struct dirent *de;
511197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    cache_dir_t* cacheDir = NULL;
512197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    int dfd;
513197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
514197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    CACHE_NOISY(ALOGI("_add_cache_files: parent=%p dirName=%s dir=%p pathBase=%s",
515197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            parentDir, dirName, dir, pathBase));
516197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
517197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    dfd = dirfd(dir);
518197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
519197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if (dfd < 0) return 0;
520197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
521197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // Sub-directories always get added to the data structure, so if they
522197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // are empty we will know about them to delete them later.
523197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
524197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
525197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    while ((de = readdir(dir))) {
526197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        const char *name = de->d_name;
527197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
528197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (de->d_type == DT_DIR) {
529197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            int subfd;
530197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            DIR *subdir;
531197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
532197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                /* always skip "." and ".." */
533197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (name[0] == '.') {
534197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                if (name[1] == 0) continue;
535197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                if ((name[1] == '.') && (name[2] == 0)) continue;
536197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
537197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
538197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
539197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (subfd < 0) {
540197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
541197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                continue;
542197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
543197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            subdir = fdopendir(subfd);
544197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (subdir == NULL) {
545197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
546197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                close(subfd);
547197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                continue;
548197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
549197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (cacheDir == NULL) {
550197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
551197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
552197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (cacheDir != NULL) {
553197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                // Update pathBase for the new path...  this may change dirName
554197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                // if that is also pointing to the path, but we are done with it
555197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                // now.
556197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name);
557197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                CACHE_NOISY(ALOGI("Collecting dir %s\n", pathBase));
558197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                if (finallen < pathAvailLen) {
559197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    _add_cache_files(cache, cacheDir, name, subdir, pathBase,
560197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                            pathPos+finallen, pathAvailLen-finallen);
561197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                } else {
562197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    // Whoops, the final path is too long!  We'll just delete
563197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    // this directory.
564197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    ALOGW("Cache dir %s truncated in path %s; deleting dir\n",
565197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                            name, pathBase);
566197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    _delete_dir_contents(subdir, NULL);
567197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
568197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
569197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    }
570197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                }
571197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
572197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            closedir(subdir);
573197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        } else if (de->d_type == DT_REG) {
574197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            // Skip files that start with '.'; they will be deleted if
575197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            // their entire directory is deleted.  This allows for metadata
576197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            // like ".nomedia" to remain in the directory until the entire
577197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            // directory is deleted.
578197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (cacheDir == NULL) {
579197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
580197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
581197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (name[0] == '.') {
582197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                cacheDir->hiddenCount++;
583197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                continue;
584197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
585197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (cacheDir != NULL) {
586197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                // Build final full path for file...  this may change dirName
587197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                // if that is also pointing to the path, but we are done with it
588197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                // now.
589197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name);
590197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                CACHE_NOISY(ALOGI("Collecting file %s\n", pathBase));
591197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                if (finallen < pathAvailLen) {
592197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    struct stat s;
593197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    if (stat(pathBase, &s) >= 0) {
594197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        _add_cache_file_t(cache, cacheDir, s.st_mtime, name);
595197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    } else {
596197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        ALOGW("Unable to stat cache file %s; deleting\n", pathBase);
597197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        if (unlink(pathBase) < 0) {
598197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                            ALOGE("Couldn't unlink %s: %s\n", pathBase, strerror(errno));
599197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        }
600197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    }
601197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                } else {
602197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    // Whoops, the final path is too long!  We'll just delete
603197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    // this file.
604197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    ALOGW("Cache file %s truncated in path %s; deleting\n",
605197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                            name, pathBase);
606197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    if (unlinkat(dfd, name, 0) < 0) {
607197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        *pathPos = 0;
608197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        ALOGE("Couldn't unlinkat %s in %s: %s\n", name, pathBase,
609197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                                strerror(errno));
610197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    }
611197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                }
612197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
613197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        } else {
614197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            cacheDir->hiddenCount++;
615197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
616197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
617197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    return 0;
618197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
619197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
620197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornvoid add_cache_files(cache_t* cache, const char *basepath, const char *cachedir)
621197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
622197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    DIR *d;
623197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    struct dirent *de;
624197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    char dirname[PATH_MAX];
625197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
626197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    CACHE_NOISY(ALOGI("add_cache_files: base=%s cachedir=%s\n", basepath, cachedir));
627197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
628197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    d = opendir(basepath);
629197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if (d == NULL) {
630197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        return;
631197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
632197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
633197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    while ((de = readdir(d))) {
634197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (de->d_type == DT_DIR) {
635197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            DIR* subdir;
636197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            const char *name = de->d_name;
637197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            char* pathpos;
638197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
639197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                /* always skip "." and ".." */
640197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (name[0] == '.') {
641197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                if (name[1] == 0) continue;
642197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                if ((name[1] == '.') && (name[2] == 0)) continue;
643197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
644197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
645197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            strcpy(dirname, basepath);
646197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            pathpos = dirname + strlen(dirname);
647197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if ((*(pathpos-1)) != '/') {
648197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                *pathpos = '/';
649197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pathpos++;
650197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                *pathpos = 0;
651197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
652197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (cachedir != NULL) {
653197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                snprintf(pathpos, sizeof(dirname)-(pathpos-dirname), "%s/%s", name, cachedir);
654197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            } else {
655197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                snprintf(pathpos, sizeof(dirname)-(pathpos-dirname), "%s", name);
656197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
657197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            CACHE_NOISY(ALOGI("Adding cache files from dir: %s\n", dirname));
658197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            subdir = opendir(dirname);
659197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (subdir != NULL) {
660197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                size_t dirnameLen = strlen(dirname);
661197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                _add_cache_files(cache, NULL, dirname, subdir, dirname, dirname+dirnameLen,
662197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        PATH_MAX - dirnameLen);
663197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                closedir(subdir);
664197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
665197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
666197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
667197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
668197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    closedir(d);
669197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
670197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
671197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornstatic char *create_dir_path(char path[PATH_MAX], cache_dir_t* dir)
672197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
673197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    char *pos = path;
674197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if (dir->parent != NULL) {
675197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        pos = create_dir_path(path, dir->parent);
676197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
677197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // Note that we don't need to worry about going beyond the buffer,
678197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // since when we were constructing the cache entries our maximum
679197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // buffer size for full paths was PATH_MAX.
680197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    strcpy(pos, dir->name);
681197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    pos += strlen(pos);
682197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    *pos = '/';
683197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    pos++;
684197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    *pos = 0;
685197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    return pos;
686197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
687197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
688197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornstatic void delete_cache_dir(char path[PATH_MAX], cache_dir_t* dir)
689197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
690197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    if (dir->parent != NULL) {
691197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        create_dir_path(path, dir);
692197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        ALOGI("DEL DIR %s\n", path);
693197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (dir->hiddenCount <= 0) {
694197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (rmdir(path)) {
695197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                ALOGE("Couldn't rmdir %s: %s\n", path, strerror(errno));
696197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                return;
697197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
698197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        } else {
699197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            // The directory contains hidden files so we need to delete
700197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            // them along with the directory itself.
701197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (delete_dir_contents(path, 1, NULL)) {
702197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                return;
703197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
704197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
705197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        dir->parent->childCount--;
706197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        dir->deleted = 1;
707197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (dir->parent->childCount <= 0) {
708197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            delete_cache_dir(path, dir->parent);
709197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
710197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    } else if (dir->hiddenCount > 0) {
711197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        // This is a root directory, but it has hidden files.  Get rid of
712197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        // all of those files, but not the directory itself.
713197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        create_dir_path(path, dir);
714197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        ALOGI("DEL CONTENTS %s\n", path);
715197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        delete_dir_contents(path, 0, NULL);
716197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
717197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
718197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
719197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornstatic int cache_modtime_sort(const void *lhsP, const void *rhsP)
720197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
721197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    const cache_file_t *lhs = *(const cache_file_t**)lhsP;
722197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    const cache_file_t *rhs = *(const cache_file_t**)rhsP;
723197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    return lhs->modTime < rhs->modTime ? -1 : (lhs->modTime > rhs->modTime ? 1 : 0);
724197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
725197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
726197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornvoid clear_cache_files(cache_t* cache, int64_t free_size)
727197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
728197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    size_t i;
729197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    int skip = 0;
730197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    char path[PATH_MAX];
731197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
732197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    ALOGI("Collected cache files: %d directories, %d files",
733197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        cache->numDirs, cache->numFiles);
734197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
735197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    CACHE_NOISY(ALOGI("Sorting files..."));
736197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    qsort(cache->files, cache->numFiles, sizeof(cache_file_t*),
737197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            cache_modtime_sort);
738197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
739197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    CACHE_NOISY(ALOGI("Cleaning empty directories..."));
740197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    for (i=cache->numDirs; i>0; i--) {
741197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        cache_dir_t* dir = cache->dirs[i-1];
742197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (dir->childCount <= 0 && !dir->deleted) {
743197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            delete_cache_dir(path, dir);
744197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
745197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
746197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
747197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    CACHE_NOISY(ALOGI("Trimming files..."));
748197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    for (i=0; i<cache->numFiles; i++) {
749197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        skip++;
750197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (skip > 10) {
751197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            if (data_disk_free() > free_size) {
752197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                return;
753197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            }
754197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            skip = 0;
755197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
756197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        cache_file_t* file = cache->files[i];
757197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        strcpy(create_dir_path(path, file->dir), file->name);
758197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        ALOGI("DEL (mod %d) %s\n", (int)file->modTime, path);
759197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (unlink(path) < 0) {
760197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            ALOGE("Couldn't unlink %s: %s\n", path, strerror(errno));
761197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
762197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        file->dir->childCount--;
763197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (file->dir->childCount <= 0) {
764197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            delete_cache_dir(path, file->dir);
765197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
766197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
767197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
768197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
769197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornvoid finish_cache_collection(cache_t* cache)
770197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn{
771197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    size_t i;
772197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
773197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    CACHE_NOISY(ALOGI("clear_cache_files: %d dirs, %d files\n", cache->numDirs, cache->numFiles));
774197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    CACHE_NOISY(
775197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        for (i=0; i<cache->numDirs; i++) {
776197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            cache_dir_t* dir = cache->dirs[i];
777197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            ALOGI("dir #%d: %p %s parent=%p\n", i, dir, dir->name, dir->parent);
778197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        })
779197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    CACHE_NOISY(
780197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        for (i=0; i<cache->numFiles; i++) {
781197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            cache_file_t* file = cache->files[i];
782197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            ALOGI("file #%d: %p %s time=%d dir=%p\n", i, file, file->name,
783197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    (int)file->modTime, file->dir);
784197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        })
785197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    void* block = cache->memBlocks;
786197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    while (block != NULL) {
787197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        void* nextBlock = *(void**)block;
788197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        CACHE_NOISY(ALOGI("Freeing cache mem block: %p", block));
789197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        free(block);
790197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        block = nextBlock;
791197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
792197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    free(cache);
793197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn}
794197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
79586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root/**
79686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Checks whether a path points to a system app (.apk file). Returns 0
79786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * if it is a system app or -1 if it is not.
79886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */
79986c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint validate_system_app_path(const char* path) {
80086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    size_t i;
80186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
80286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    for (i = 0; i < android_system_dirs.count; i++) {
80386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        const size_t dir_len = android_system_dirs.dirs[i].len;
80486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) {
80586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            if (path[dir_len] == '.' || strchr(path + dir_len, '/') != NULL) {
8063762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("invalid system apk path '%s' (trickery)\n", path);
80786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root                return -1;
80886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            }
80986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            return 0;
81086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        }
81186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    }
81286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
81386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    return -1;
81486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root}
81586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
81686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root/**
81786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Get the contents of a environment variable that contains a path. Caller
81886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * owns the string that is inserted into the directory record. Returns
81986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * 0 on success and -1 on error.
82086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */
82186c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint get_path_from_env(dir_rec_t* rec, const char* var) {
82286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    const char* path = getenv(var);
82386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    int ret = get_path_from_string(rec, path);
82486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    if (ret < 0) {
8258564c8da817a845353d213acd8636b76f567b234Steve Block        ALOGW("Problem finding value for environment variable %s\n", var);
82686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    }
82786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    return ret;
82886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root}
82986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
83086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root/**
83186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Puts the string into the record as a directory. Appends '/' to the end
83286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * of all paths. Caller owns the string that is inserted into the directory
83386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * record. A null value will result in an error.
83486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root *
83586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Returns 0 on success and -1 on error.
83686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */
83786c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint get_path_from_string(dir_rec_t* rec, const char* path) {
83886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    if (path == NULL) {
83986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        return -1;
84086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    } else {
84186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        const size_t path_len = strlen(path);
84286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        if (path_len <= 0) {
84386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            return -1;
84486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        }
84586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
84686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        // Make sure path is absolute.
84786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        if (path[0] != '/') {
84886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            return -1;
84986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        }
85086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
85186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        if (path[path_len - 1] == '/') {
85286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            // Path ends with a forward slash. Make our own copy.
85386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
85486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            rec->path = strdup(path);
85586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            if (rec->path == NULL) {
85686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root                return -1;
85786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            }
85886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
85986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            rec->len = path_len;
86086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        } else {
86186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            // Path does not end with a slash. Generate a new string.
86286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            char *dst;
86386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
86486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            // Add space for slash and terminating null.
86586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            size_t dst_size = path_len + 2;
86686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
86786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            rec->path = malloc(dst_size);
86886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            if (rec->path == NULL) {
86986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root                return -1;
87086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            }
87186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
87286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            dst = rec->path;
87386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
87486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            if (append_and_increment(&dst, path, &dst_size) < 0
87586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root                    || append_and_increment(&dst, "/", &dst_size)) {
8763762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("Error canonicalizing path");
87786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root                return -1;
87886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            }
87986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
88086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            rec->len = dst - rec->path;
88186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        }
88286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    }
88386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    return 0;
88486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root}
88586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
88686c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) {
88786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    dst->len = src->len + strlen(suffix);
88886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    const size_t dstSize = dst->len + 1;
88986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    dst->path = (char*) malloc(dstSize);
89086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
89186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    if (dst->path == NULL
89286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            || snprintf(dst->path, dstSize, "%s%s", src->path, suffix)
89386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root                    != (ssize_t) dst->len) {
8943762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Could not allocate memory to hold appended path; aborting\n");
89586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        return -1;
89686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    }
89786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
89886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    return 0;
89986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root}
90086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
90186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root/**
90286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * Check whether path points to a valid path for an APK file. An ASEC
90386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * directory is allowed to have one level of subdirectory names. Returns -1
90486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root * when an invalid path is encountered and 0 when a valid path is encountered.
90586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root */
90686c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint validate_apk_path(const char *path)
90786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root{
90886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    int allowsubdir = 0;
90986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    char *subdir = NULL;
91086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    size_t dir_len;
91186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    size_t path_len;
91286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
91386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
91486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        dir_len = android_app_dir.len;
91586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
91686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        dir_len = android_app_private_dir.len;
91786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) {
91886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        dir_len = android_asec_dir.len;
91986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        allowsubdir = 1;
92086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    } else {
9213762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("invalid apk path '%s' (bad prefix)\n", path);
92286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        return -1;
92386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    }
92486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
92586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    path_len = strlen(path);
92686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
92786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    /*
92886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     * Only allow the path to have a subdirectory if it's been marked as being allowed.
92986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     */
93086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    if ((subdir = strchr(path + dir_len, '/')) != NULL) {
93186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        ++subdir;
93286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        if (!allowsubdir
93386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root                || (path_len > (size_t) (subdir - path) && (strchr(subdir, '/') != NULL))) {
9343762c311729fe9f3af085c14c5c1fb471d994c03Steve Block            ALOGE("invalid apk path '%s' (subdir?)\n", path);
93586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            return -1;
93686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        }
93786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    }
93886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
93986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    /*
94086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     *  Directories can't have a period directly after the directory markers
94186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     *  to prevent ".."
94286c9584559439504fc57ece2ccd9b6cbd568430cKenny Root     */
94386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    if (path[dir_len] == '.'
94486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root            || (subdir != NULL && ((*subdir == '.') || (strchr(subdir, '/') != NULL)))) {
9453762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("invalid apk path '%s' (trickery)\n", path);
94686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        return -1;
94786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    }
94886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
94986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    return 0;
95086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root}
95186c9584559439504fc57ece2ccd9b6cbd568430cKenny Root
95286c9584559439504fc57ece2ccd9b6cbd568430cKenny Rootint append_and_increment(char** dst, const char* src, size_t* dst_size) {
95386c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    ssize_t ret = strlcpy(*dst, src, *dst_size);
95486c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    if (ret < 0 || (size_t) ret >= *dst_size) {
95586c9584559439504fc57ece2ccd9b6cbd568430cKenny Root        return -1;
95686c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    }
95786c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    *dst += ret;
95886c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    *dst_size -= ret;
95986c9584559439504fc57ece2ccd9b6cbd568430cKenny Root    return 0;
96086c9584559439504fc57ece2ccd9b6cbd568430cKenny Root}
9610b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani
9620b285499db739ba50f2f839d633e763c70e67f96Amith Yamasanichar *build_string2(char *s1, char *s2) {
9630b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    if (s1 == NULL || s2 == NULL) return NULL;
9640b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani
9650b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    int len_s1 = strlen(s1);
9660b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    int len_s2 = strlen(s2);
9670b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    int len = len_s1 + len_s2 + 1;
9680b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    char *result = malloc(len);
9690b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    if (result == NULL) return NULL;
9700b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani
9710b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    strcpy(result, s1);
9720b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    strcpy(result + len_s1, s2);
9730b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani
9740b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    return result;
9750b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani}
9760b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani
9770b285499db739ba50f2f839d633e763c70e67f96Amith Yamasanichar *build_string3(char *s1, char *s2, char *s3) {
9780b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL;
9790b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani
9800b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    int len_s1 = strlen(s1);
9810b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    int len_s2 = strlen(s2);
9820b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    int len_s3 = strlen(s3);
9830b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    int len = len_s1 + len_s2 + len_s3 + 1;
9840b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    char *result = malloc(len);
9850b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    if (result == NULL) return NULL;
9860b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani
9870b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    strcpy(result, s1);
9880b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    strcpy(result + len_s1, s2);
9890b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    strcpy(result + len_s1 + len_s2, s3);
9900b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani
9910b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani    return result;
9920b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani}
9935b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey
9948ea0dc6a89b011d4f478c0c8192570d69cf7ce79Jeff Sharkey/* Ensure that /data/media directories are prepared for given user. */
9958ea0dc6a89b011d4f478c0c8192570d69cf7ce79Jeff Sharkeyint ensure_media_user_dirs(userid_t userid) {
9968ea0dc6a89b011d4f478c0c8192570d69cf7ce79Jeff Sharkey    char media_user_path[PATH_MAX];
9978ea0dc6a89b011d4f478c0c8192570d69cf7ce79Jeff Sharkey    char path[PATH_MAX];
9985b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey
9998ea0dc6a89b011d4f478c0c8192570d69cf7ce79Jeff Sharkey    // Ensure /data/media/<userid> exists
10008ea0dc6a89b011d4f478c0c8192570d69cf7ce79Jeff Sharkey    create_persona_media_path(media_user_path, userid);
10018ea0dc6a89b011d4f478c0c8192570d69cf7ce79Jeff Sharkey    if (fs_prepare_dir(media_user_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
10025b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey        return -1;
10035b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey    }
10045b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey
10055b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey    return 0;
10065b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey}
1007