utils.cpp revision a836c472f017f09cf16fa68176df461a4958d22a
194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/* 294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood** Copyright 2008, The Android Open Source Project 394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood** 4d93707342a61e66bc3eb2145628158452f577f42Dave Allison** Licensed under the Apache License, Version 2.0 (the "License"); 5d93707342a61e66bc3eb2145628158452f577f42Dave Allison** you may not use this file except in compliance with the License. 6d93707342a61e66bc3eb2145628158452f577f42Dave Allison** You may obtain a copy of the License at 794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood** 8d93707342a61e66bc3eb2145628158452f577f42Dave Allison** http://www.apache.org/licenses/LICENSE-2.0 994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood** 10d93707342a61e66bc3eb2145628158452f577f42Dave Allison** Unless required by applicable law or agreed to in writing, software 11d93707342a61e66bc3eb2145628158452f577f42Dave Allison** distributed under the License is distributed on an "AS IS" BASIS, 12d93707342a61e66bc3eb2145628158452f577f42Dave Allison** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d93707342a61e66bc3eb2145628158452f577f42Dave Allison** See the License for the specific language governing permissions and 1494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood** limitations under the License. 1594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood*/ 1694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 1702d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include "utils.h" 1802d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe 1902d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <errno.h> 2002d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <fcntl.h> 213dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey#include <fts.h> 2202d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <stdlib.h> 2302d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <sys/stat.h> 2402d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <sys/wait.h> 259a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey#include <sys/xattr.h> 26ed909ae8db2f44ce7fe7003c6fee457f13669702Jeff Sharkey#include <sys/statvfs.h> 2794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 28e4ec9eb7b4c452493589983970ba5ccc501728d1Elliott Hughes#include <android-base/logging.h> 2902d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <android-base/stringprintf.h> 3002d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <cutils/fs.h> 31871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkey#include <cutils/properties.h> 327823e124e00576e20e47ec717cbe8bc89f0f2bf2Mark Salyzyn#include <log/log.h> 3302d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include <private/android_filesystem_config.h> 3402d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe 3502d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#include "globals.h" // extern variables. 3694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 3702d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#ifndef LOG_TAG 3802d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#define LOG_TAG "installd" 3902d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe#endif 409a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey 419a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey#define DEBUG_XATTRS 0 4294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 43c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkeyusing android::base::StringPrintf; 4494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 4502d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampenamespace android { 4602d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampenamespace installd { 4702d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe 4894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/** 49c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey * Check that given string is valid filename, and that it attempts no 50c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey * parent or child directory traversal. 5194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood */ 52423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkeybool is_valid_filename(const std::string& name) { 53c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey if (name.empty() || (name == ".") || (name == "..") 54c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey || (name.find('/') != std::string::npos)) { 55c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey return false; 5694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } else { 57c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey return true; 5894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 59c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey} 6094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 616a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravlestatic void check_package_name(const char* package_name) { 626a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle CHECK(is_valid_filename(package_name)); 63423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey CHECK(is_valid_package_name(package_name)); 646a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle} 656a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle 66c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey/** 67d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey * Create the path name where package app contents should be stored for 68d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey * the given volume UUID and package name. An empty UUID is assumed to 69d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey * be internal storage. 70d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey */ 71d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkeystd::string create_data_app_package_path(const char* volume_uuid, 72d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey const char* package_name) { 736a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle check_package_name(package_name); 74d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey return StringPrintf("%s/%s", 75d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey create_data_app_path(volume_uuid).c_str(), package_name); 76d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey} 77d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey 78d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey/** 79c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey * Create the path name where package data should be stored for the given 80c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey * volume UUID, package name, and user ID. An empty UUID is assumed to be 81c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey * internal storage. 82c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey */ 832f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkeystd::string create_data_user_ce_package_path(const char* volume_uuid, 84d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey userid_t user, const char* package_name) { 856a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle check_package_name(package_name); 86d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey return StringPrintf("%s/%s", 872f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey create_data_user_ce_path(volume_uuid, user).c_str(), package_name); 882f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey} 892f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey 902f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkeystd::string create_data_user_ce_package_path(const char* volume_uuid, userid_t user, 912f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey const char* package_name, ino_t ce_data_inode) { 922f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey // For testing purposes, rely on the inode when defined; this could be 932f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey // optimized to use access() in the future. 942f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey auto fallback = create_data_user_ce_package_path(volume_uuid, user, package_name); 952f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey if (ce_data_inode != 0) { 962f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey auto user_path = create_data_user_ce_path(volume_uuid, user); 972f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey DIR* dir = opendir(user_path.c_str()); 982f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey if (dir == nullptr) { 992f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey PLOG(ERROR) << "Failed to opendir " << user_path; 1002f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey return fallback; 1012f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey } 1022f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey 1032f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey struct dirent* ent; 1042f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey while ((ent = readdir(dir))) { 1052f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey if (ent->d_ino == ce_data_inode) { 1061d992f9f7886f98e46f98430d6c1d061cc31fdb3Jeff Sharkey auto resolved = StringPrintf("%s/%s", user_path.c_str(), ent->d_name); 1079a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey#if DEBUG_XATTRS 1081d992f9f7886f98e46f98430d6c1d061cc31fdb3Jeff Sharkey if (resolved != fallback) { 1091d992f9f7886f98e46f98430d6c1d061cc31fdb3Jeff Sharkey LOG(DEBUG) << "Resolved path " << resolved << " for inode " << ce_data_inode 1101d992f9f7886f98e46f98430d6c1d061cc31fdb3Jeff Sharkey << " instead of " << fallback; 1111d992f9f7886f98e46f98430d6c1d061cc31fdb3Jeff Sharkey } 1129a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey#endif 1132f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey closedir(dir); 1141d992f9f7886f98e46f98430d6c1d061cc31fdb3Jeff Sharkey return resolved; 1152f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey } 1162f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey } 1171d992f9f7886f98e46f98430d6c1d061cc31fdb3Jeff Sharkey LOG(WARNING) << "Failed to resolve inode " << ce_data_inode << "; using " << fallback; 1182f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey closedir(dir); 1192f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey return fallback; 1202f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey } else { 1212f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey return fallback; 1222f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey } 123c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey} 12494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 12563ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkeystd::string create_data_user_de_package_path(const char* volume_uuid, 12663ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkey userid_t user, const char* package_name) { 1276a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle check_package_name(package_name); 12863ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkey return StringPrintf("%s/%s", 12963ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkey create_data_user_de_path(volume_uuid, user).c_str(), package_name); 13063ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkey} 13163ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkey 132c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkeyint create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname, 133c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey const char *postfix, userid_t userid) { 134423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey if (!is_valid_package_name(pkgname)) { 135c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey path[0] = '\0'; 13694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 13794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 13894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 1392f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkey std::string _tmp(create_data_user_ce_package_path(nullptr, userid, pkgname) + postfix); 140c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey const char* tmp = _tmp.c_str(); 141c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey if (strlen(tmp) >= PKG_PATH_MAX) { 142c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey path[0] = '\0'; 143c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey return -1; 144c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey } else { 145c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey strcpy(path, tmp); 146c03de09173f98506e73e7cf7df21fe11795d4b24Jeff Sharkey return 0; 14794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 14894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 14994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 15041ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkeystd::string create_data_path(const char* volume_uuid) { 15141ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey if (volume_uuid == nullptr) { 15241ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey return "/data"; 153871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkey } else if (!strcmp(volume_uuid, "TEST")) { 154871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkey CHECK(property_get_bool("ro.debuggable", false)); 155871a8f236ef2a055b9955b47a342b2c44c020ef7Jeff Sharkey return "/data/local/tmp"; 15694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } else { 15741ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey CHECK(is_valid_filename(volume_uuid)); 15841ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey return StringPrintf("/mnt/expand/%s", volume_uuid); 15994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 16041ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey} 16194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 16241ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey/** 163d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey * Create the path name for app data. 164d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey */ 165d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkeystd::string create_data_app_path(const char* volume_uuid) { 166d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey return StringPrintf("%s/app", create_data_path(volume_uuid).c_str()); 167d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey} 168d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey 169d792118c493806eeb24a8203f508e6e18fe93bd7Jeff Sharkey/** 17041ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey * Create the path name for user data for a certain userid. 17141ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey */ 1722f720f7ec5c9d0b91defc85878e7330b10f8e89aJeff Sharkeystd::string create_data_user_ce_path(const char* volume_uuid, userid_t userid) { 17341ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey std::string data(create_data_path(volume_uuid)); 17441ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey if (volume_uuid == nullptr) { 17541ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey if (userid == 0) { 17641ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey return StringPrintf("%s/data", data.c_str()); 17741ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey } else { 17841ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey return StringPrintf("%s/user/%u", data.c_str(), userid); 17994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 18041ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey } else { 18141ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey return StringPrintf("%s/user/%u", data.c_str(), userid); 18294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 18394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 18494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 18594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/** 18663ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkey * Create the path name for device encrypted user data for a certain userid. 18763ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkey */ 18863ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkeystd::string create_data_user_de_path(const char* volume_uuid, userid_t userid) { 18963ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkey std::string data(create_data_path(volume_uuid)); 19063ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkey return StringPrintf("%s/user_de/%u", data.c_str(), userid); 19163ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkey} 19263ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkey 19363ec2d64196144b2d15d2baffedccfa011d6494fJeff Sharkey/** 194abe4fe5b46157ecd2a52d28abf938c816c3ce878Jeff Sharkey * Create the path name for media for a certain userid. 19594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood */ 19641ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkeystd::string create_data_media_path(const char* volume_uuid, userid_t userid) { 19741ea424413c0381ef2aa15fc5bd5d4b88abd23c4Jeff Sharkey return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid); 19894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 19994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 200df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkeystd::string create_data_media_obb_path(const char* volume_uuid, const char* package_name) { 201df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey return StringPrintf("%s/media/obb/%s", create_data_path(volume_uuid).c_str(), package_name); 202df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey} 203df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey 2043dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkeystd::string create_data_media_package_path(const char* volume_uuid, userid_t userid, 2053dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey const char* data_type, const char* package_name) { 2063dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey return StringPrintf("%s/Android/%s/%s", create_data_media_path(volume_uuid, userid).c_str(), 2073dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey data_type, package_name); 2083dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey} 2093dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey 210379a12b0072b322c7f86e690a8e8a220e500861cJeff Sharkeystd::string create_data_misc_legacy_path(userid_t userid) { 211379a12b0072b322c7f86e690a8e8a220e500861cJeff Sharkey return StringPrintf("%s/misc/user/%u", create_data_path(nullptr).c_str(), userid); 212379a12b0072b322c7f86e690a8e8a220e500861cJeff Sharkey} 213379a12b0072b322c7f86e690a8e8a220e500861cJeff Sharkey 214114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravlestd::string create_primary_cur_profile_dir_path(userid_t userid) { 2156a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid); 2166a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle} 2176a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle 218114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravlestd::string create_primary_current_profile_package_dir_path(userid_t user, 219114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle const std::string& package_name) { 22076268c56febde9a77183387fbd4baabe6694e6b5Calin Juravle check_package_name(package_name.c_str()); 221114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle return StringPrintf("%s/%s", 222114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle create_primary_cur_profile_dir_path(user).c_str(), package_name.c_str()); 223df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey} 224df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey 225114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravlestd::string create_primary_ref_profile_dir_path() { 226df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey return StringPrintf("%s/ref", android_profiles_dir.path); 2276a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle} 2286a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle 229114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravlestd::string create_primary_reference_profile_package_dir_path(const std::string& package_name) { 23076268c56febde9a77183387fbd4baabe6694e6b5Calin Juravle check_package_name(package_name.c_str()); 23176268c56febde9a77183387fbd4baabe6694e6b5Calin Juravle return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name.c_str()); 2326a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle} 2336a1648e2f161cb1d7c46aa9d27e8062521a9f314Calin Juravle 2343dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkeystd::string create_data_dalvik_cache_path() { 2353dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey return "/data/dalvik-cache"; 2363dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey} 2373dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey 238114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle// Keep profile paths in sync with ActivityThread and LoadedApk. 239114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravleconst std::string PROFILE_EXT = ".prof"; 240114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravleconst std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT; 24190aff26f0135379db19432ae90c40c0831ba5954Jeff Sharkey 242114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravlestd::string create_current_profile_path(userid_t user, const std::string& location, 243114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle bool is_secondary_dex) { 244114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle if (is_secondary_dex) { 245114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle // Secondary dex profiles are stored next to the dex files using .prof extension. 246114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle return StringPrintf("%s%s", location.c_str(), PROFILE_EXT.c_str()); 247114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle } else { 248114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle // Profiles for primary apks are under /data/misc/profiles/cur. 249114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle std::string profile_dir = create_primary_current_profile_package_dir_path(user, location); 250114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME.c_str()); 251114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle } 252114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle} 253114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle 254114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravlestd::string create_reference_profile_path(const std::string& location, bool is_secondary_dex) { 255114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle if (is_secondary_dex) { 256114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle // Secondary dex reference profiles are stored next to the dex files under the oat folder. 257114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle size_t dirIndex = location.rfind('/'); 258114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle CHECK(dirIndex != std::string::npos) 259114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle << "Unexpected dir structure for secondary dex " << location; 260114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle 261114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle std::string dex_dir = location.substr(0, dirIndex); 262114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle std::string dex_name = location.substr(dirIndex +1); 263114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle return StringPrintf("%s/oat/%s%s", 264114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle dex_dir.c_str(), dex_name.c_str(), PROFILE_EXT.c_str()); 265114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle } else { 266114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle // Reference profiles for primary apks are stored in /data/misc/profile/ref. 267114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle std::string profile_dir = create_primary_reference_profile_package_dir_path(location); 268114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME.c_str()); 269114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle } 27090aff26f0135379db19432ae90c40c0831ba5954Jeff Sharkey} 27190aff26f0135379db19432ae90c40c0831ba5954Jeff Sharkey 272e36372423000a906bafae68844ebc6c42d09335aJeff Sharkeystd::vector<userid_t> get_known_users(const char* volume_uuid) { 273e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey std::vector<userid_t> users; 274e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey 275e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey // We always have an owner 276e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey users.push_back(0); 277e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey 278e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey std::string path(create_data_path(volume_uuid) + "/" + SECONDARY_USER_PREFIX); 279e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey DIR* dir = opendir(path.c_str()); 280e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey if (dir == NULL) { 281e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey // Unable to discover other users, but at least return owner 282e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey PLOG(ERROR) << "Failed to opendir " << path; 283e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey return users; 284e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey } 285e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey 286e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey struct dirent* ent; 287e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey while ((ent = readdir(dir))) { 288e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey if (ent->d_type != DT_DIR) { 289e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey continue; 290e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey } 291e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey 292e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey char* end; 293e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey userid_t user = strtol(ent->d_name, &end, 10); 294e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey if (*end == '\0' && user != 0) { 295e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey LOG(DEBUG) << "Found valid user " << user; 296e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey users.push_back(user); 297e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey } 298e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey } 299e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey closedir(dir); 300e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey 301e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey return users; 302e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey} 303e36372423000a906bafae68844ebc6c42d09335aJeff Sharkey 3043dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkeyint calculate_tree_size(const std::string& path, int64_t* size, 305df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey int32_t include_gid, int32_t exclude_gid, bool exclude_apps) { 3063dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey FTS *fts; 3073dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey FTSENT *p; 308df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey int64_t matchedSize = 0; 3093dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey char *argv[] = { (char*) path.c_str(), nullptr }; 310b26786d647b624498c11405075e5223d1853f30aJeff Sharkey if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) { 3113dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey if (errno != ENOENT) { 3123dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey PLOG(ERROR) << "Failed to fts_open " << path; 3133dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey } 3143dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey return -1; 3153dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey } 3163dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey while ((p = fts_read(fts)) != NULL) { 3173dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey switch (p->fts_info) { 3183dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey case FTS_D: 3193dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey case FTS_DEFAULT: 3203dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey case FTS_F: 3213dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey case FTS_SL: 3223dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey case FTS_SLNONE: 323df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey int32_t uid = p->fts_statp->st_uid; 324df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey int32_t gid = p->fts_statp->st_gid; 325df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey int32_t user_uid = multiuser_get_app_id(uid); 326df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey int32_t user_gid = multiuser_get_app_id(gid); 327df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey if (exclude_apps && ((user_uid >= AID_APP_START && user_uid <= AID_APP_END) 328df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey || (user_gid >= AID_CACHE_GID_START && user_gid <= AID_CACHE_GID_END) 329df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey || (user_gid >= AID_SHARED_GID_START && user_gid <= AID_SHARED_GID_END))) { 330df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey // Don't traverse inside or measure 331df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey fts_set(fts, p, FTS_SKIP); 3323dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey break; 3333dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey } 334df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey if (include_gid != -1 && gid != include_gid) { 3353dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey break; 3363dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey } 337df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey if (exclude_gid != -1 && gid == exclude_gid) { 338df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey break; 339df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey } 340df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey matchedSize += (p->fts_statp->st_blocks * 512); 3413dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey break; 3423dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey } 3433dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey } 3443dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey fts_close(fts); 345df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#if MEASURE_DEBUG 346df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey if ((include_gid == -1) && (exclude_gid == -1)) { 347df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey LOG(DEBUG) << "Measured " << path << " size " << matchedSize; 348df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey } else { 349df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey LOG(DEBUG) << "Measured " << path << " size " << matchedSize << "; include " << include_gid 350df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey << " exclude " << exclude_gid; 351df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey } 352df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey#endif 353df2d754b38796e0c49c70e0a67f7d383e3079ff2Jeff Sharkey *size += matchedSize; 3543dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey return 0; 3553dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey} 3563dfae0c008576c873c4039bb4c2e54a6adf3720aJeff Sharkey 35794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodint create_move_path(char path[PKG_PATH_MAX], 35894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood const char* pkgname, 35994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood const char* leaf, 36002d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe userid_t userid ATTRIBUTE_UNUSED) 36194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{ 36294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1) 36394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood >= PKG_PATH_MAX) { 36494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 36594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 36694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 36794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf); 36894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return 0; 36994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 37094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 37194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/** 37294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * Checks whether the package name is valid. Returns -1 on error and 37394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * 0 on success. 37494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood */ 375423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkeybool is_valid_package_name(const std::string& packageName) { 376367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey // This logic is borrowed from PackageParser.java 377367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey bool hasSep = false; 378367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey bool front = true; 379367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey 380367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey auto it = packageName.begin(); 381367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey for (; it != packageName.end() && *it != '-'; it++) { 382367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey char c = *it; 383367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { 384367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey front = false; 385367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey continue; 386367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey } 387367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey if (!front) { 388367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey if ((c >= '0' && c <= '9') || c == '_') { 389367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey continue; 39094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 39194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 392367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey if (c == '.') { 393367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey hasSep = true; 394367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey front = true; 395367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey continue; 396367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey } 397367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey LOG(WARNING) << "Bad package character " << c << " in " << packageName; 398367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey return false; 399367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey } 40094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 401ab7ac8d5a04bd3f38b85ce20ae5bb382f2a26585Jeff Sharkey if (front) { 402367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey LOG(WARNING) << "Missing separator in " << packageName; 403367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey return false; 40494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 40594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 406367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey for (; it != packageName.end(); it++) { 407367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey char c = *it; 408367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) continue; 409367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey if ((c >= '0' && c <= '9') || c == '_' || c == '-' || c == '=') continue; 410367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey LOG(WARNING) << "Bad suffix character " << c << " in " << packageName; 411367ace2f77105f7a09b34a50bc875fd4fa591177Jeff Sharkey return false; 41294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 41394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 414423e746ac7d4b3a3d772dd0e01bdb9fd6029d439Jeff Sharkey return true; 41594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 41694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 4173aee2c5c749dc2589f001b26fae1ec958ec89524Narayan Kamathstatic int _delete_dir_contents(DIR *d, 4183aee2c5c749dc2589f001b26fae1ec958ec89524Narayan Kamath int (*exclusion_predicate)(const char *name, const int is_dir)) 41994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{ 42094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int result = 0; 42194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood struct dirent *de; 42294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int dfd; 42394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 42494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood dfd = dirfd(d); 42594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 42694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (dfd < 0) return -1; 42794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 42894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood while ((de = readdir(d))) { 42994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood const char *name = de->d_name; 43094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 4313aee2c5c749dc2589f001b26fae1ec958ec89524Narayan Kamath /* check using the exclusion predicate, if provided */ 4323aee2c5c749dc2589f001b26fae1ec958ec89524Narayan Kamath if (exclusion_predicate && exclusion_predicate(name, (de->d_type == DT_DIR))) { 4333aee2c5c749dc2589f001b26fae1ec958ec89524Narayan Kamath continue; 4343aee2c5c749dc2589f001b26fae1ec958ec89524Narayan Kamath } 43594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 43694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (de->d_type == DT_DIR) { 43799d9fb15b4a1eb534261ae81b2cf25aec4447bd0Chih-Hung Hsieh int subfd; 43894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood DIR *subdir; 43994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 44094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood /* always skip "." and ".." */ 44194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (name[0] == '.') { 44294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (name[1] == 0) continue; 44394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if ((name[1] == '.') && (name[2] == 0)) continue; 44494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 44594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 4468b7acacc93930df9fa9e1ebea4a4394195b2332eNick Kralevich subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); 44794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (subfd < 0) { 44894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("Couldn't openat %s: %s\n", name, strerror(errno)); 44994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood result = -1; 45094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood continue; 45194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 45294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood subdir = fdopendir(subfd); 45394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (subdir == NULL) { 45494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); 45594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood close(subfd); 45694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood result = -1; 45794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood continue; 45894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 4593aee2c5c749dc2589f001b26fae1ec958ec89524Narayan Kamath if (_delete_dir_contents(subdir, exclusion_predicate)) { 46094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood result = -1; 46194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 46294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood closedir(subdir); 46394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) { 46494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); 46594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood result = -1; 46694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 46794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } else { 46894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (unlinkat(dfd, name, 0) < 0) { 46994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); 47094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood result = -1; 47194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 47294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 47394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 47494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 47594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return result; 47694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 47794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 478b06f98aabc5381fd6366526d9b31b5d0345481b6Calin Juravleint delete_dir_contents(const std::string& pathname, bool ignore_if_missing) { 479b06f98aabc5381fd6366526d9b31b5d0345481b6Calin Juravle return delete_dir_contents(pathname.c_str(), 0, NULL, ignore_if_missing); 480ebf728fd43ab5c7d11a1f9e5fdc775d6740fae0aJeff Sharkey} 481ebf728fd43ab5c7d11a1f9e5fdc775d6740fae0aJeff Sharkey 482b06f98aabc5381fd6366526d9b31b5d0345481b6Calin Juravleint delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) { 483b06f98aabc5381fd6366526d9b31b5d0345481b6Calin Juravle return delete_dir_contents(pathname.c_str(), 1, NULL, ignore_if_missing); 484ebf728fd43ab5c7d11a1f9e5fdc775d6740fae0aJeff Sharkey} 485ebf728fd43ab5c7d11a1f9e5fdc775d6740fae0aJeff Sharkey 48694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodint delete_dir_contents(const char *pathname, 48794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int also_delete_dir, 488b06f98aabc5381fd6366526d9b31b5d0345481b6Calin Juravle int (*exclusion_predicate)(const char*, const int), 489b06f98aabc5381fd6366526d9b31b5d0345481b6Calin Juravle bool ignore_if_missing) 49094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{ 49194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int res = 0; 49294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood DIR *d; 49394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 49494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood d = opendir(pathname); 49594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (d == NULL) { 496b06f98aabc5381fd6366526d9b31b5d0345481b6Calin Juravle if (ignore_if_missing && (errno == ENOENT)) { 497b06f98aabc5381fd6366526d9b31b5d0345481b6Calin Juravle return 0; 498b06f98aabc5381fd6366526d9b31b5d0345481b6Calin Juravle } 49994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno)); 50094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -errno; 50194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 5023aee2c5c749dc2589f001b26fae1ec958ec89524Narayan Kamath res = _delete_dir_contents(d, exclusion_predicate); 50394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood closedir(d); 50494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (also_delete_dir) { 50594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (rmdir(pathname)) { 50694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno)); 50794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood res = -1; 50894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 50994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 51094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return res; 51194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 51294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 51394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodint delete_dir_contents_fd(int dfd, const char *name) 51494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{ 51594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int fd, res; 51694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood DIR *d; 51794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 5188b7acacc93930df9fa9e1ebea4a4394195b2332eNick Kralevich fd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); 51994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (fd < 0) { 52094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("Couldn't openat %s: %s\n", name, strerror(errno)); 52194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 52294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 52394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood d = fdopendir(fd); 52494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (d == NULL) { 52594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); 52694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood close(fd); 52794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 52894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 52994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood res = _delete_dir_contents(d, 0); 53094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood closedir(d); 53194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return res; 53294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 53394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 53460fd3feecab4336d964ca8e31c7c3220e1afb558Robin Leestatic int _copy_owner_permissions(int srcfd, int dstfd) 53560fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee{ 53660fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee struct stat st; 53760fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (fstat(srcfd, &st) != 0) { 53860fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee return -1; 53960fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 54060fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (fchmod(dstfd, st.st_mode) != 0) { 54160fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee return -1; 54260fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 54360fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee return 0; 54460fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee} 54560fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee 54660fd3feecab4336d964ca8e31c7c3220e1afb558Robin Leestatic int _copy_dir_files(int sdfd, int ddfd, uid_t owner, gid_t group) 54760fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee{ 54860fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee int result = 0; 54960fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (_copy_owner_permissions(sdfd, ddfd) != 0) { 55060fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee ALOGE("_copy_dir_files failed to copy dir permissions\n"); 55160fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 55260fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (fchown(ddfd, owner, group) != 0) { 55360fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee ALOGE("_copy_dir_files failed to change dir owner\n"); 55460fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 55560fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee 55660fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee DIR *ds = fdopendir(sdfd); 55760fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (ds == NULL) { 55860fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee ALOGE("Couldn't fdopendir: %s\n", strerror(errno)); 55960fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee return -1; 56060fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 56160fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee struct dirent *de; 56260fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee while ((de = readdir(ds))) { 56360fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (de->d_type != DT_REG) { 56460fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee continue; 56560fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 56660fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee 56760fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee const char *name = de->d_name; 56860fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee int fsfd = openat(sdfd, name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); 56960fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee int fdfd = openat(ddfd, name, O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_CREAT, 0600); 57060fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (fsfd == -1 || fdfd == -1) { 57160fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee ALOGW("Couldn't copy %s: %s\n", name, strerror(errno)); 57260fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } else { 57360fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (_copy_owner_permissions(fsfd, fdfd) != 0) { 57460fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee ALOGE("Failed to change file permissions\n"); 57560fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 57660fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (fchown(fdfd, owner, group) != 0) { 57760fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee ALOGE("Failed to change file owner\n"); 57860fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 57960fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee 58060fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee char buf[8192]; 58160fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee ssize_t size; 58260fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee while ((size = read(fsfd, buf, sizeof(buf))) > 0) { 58360fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee write(fdfd, buf, size); 58460fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 58560fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (size < 0) { 58660fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee ALOGW("Couldn't copy %s: %s\n", name, strerror(errno)); 58760fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee result = -1; 58860fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 58960fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 59060fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee close(fdfd); 59160fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee close(fsfd); 59260fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 59360fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee 59460fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee return result; 59560fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee} 59660fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee 59760fd3feecab4336d964ca8e31c7c3220e1afb558Robin Leeint copy_dir_files(const char *srcname, 59860fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee const char *dstname, 59960fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee uid_t owner, 60060fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee uid_t group) 60160fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee{ 60260fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee int res = 0; 60360fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee DIR *ds = NULL; 60460fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee DIR *dd = NULL; 60560fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee 60660fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee ds = opendir(srcname); 60760fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (ds == NULL) { 60860fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee ALOGE("Couldn't opendir %s: %s\n", srcname, strerror(errno)); 60960fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee return -errno; 61060fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 61160fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee 61260fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee mkdir(dstname, 0600); 61360fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee dd = opendir(dstname); 61460fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (dd == NULL) { 61560fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee ALOGE("Couldn't opendir %s: %s\n", dstname, strerror(errno)); 61660fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee closedir(ds); 61760fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee return -errno; 61860fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 61960fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee 62060fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee int sdfd = dirfd(ds); 62160fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee int ddfd = dirfd(dd); 62260fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee if (sdfd != -1 && ddfd != -1) { 62360fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee res = _copy_dir_files(sdfd, ddfd, owner, group); 62460fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } else { 62560fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee res = -errno; 62660fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee } 62760fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee closedir(dd); 62860fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee closedir(ds); 62960fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee return res; 63060fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee} 63160fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee 632a836c472f017f09cf16fa68176df461a4958d22aJeff Sharkeyint64_t data_disk_free(const std::string& data_path) { 633ed909ae8db2f44ce7fe7003c6fee457f13669702Jeff Sharkey struct statvfs sfs; 634ed909ae8db2f44ce7fe7003c6fee457f13669702Jeff Sharkey if (statvfs(data_path.c_str(), &sfs) == 0) { 635a836c472f017f09cf16fa68176df461a4958d22aJeff Sharkey return sfs.f_bavail * sfs.f_frsize; 63694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } else { 637ed909ae8db2f44ce7fe7003c6fee457f13669702Jeff Sharkey PLOG(ERROR) << "Couldn't statvfs " << data_path; 63894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 63994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 64094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 64194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 6429a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkeyint get_path_inode(const std::string& path, ino_t *inode) { 6439a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey struct stat buf; 6449a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey memset(&buf, 0, sizeof(buf)); 6459a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey if (stat(path.c_str(), &buf) != 0) { 6469a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey PLOG(WARNING) << "Failed to stat " << path; 6479a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey return -1; 6489a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } else { 6499a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey *inode = buf.st_ino; 6509a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey return 0; 6519a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } 6529a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey} 6539a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey 6549a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey/** 6559a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey * Write the inode of a specific child file into the given xattr on the 6569a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey * parent directory. This allows you to find the child later, even if its 6579a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey * name is encrypted. 6589a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey */ 6599a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkeyint write_path_inode(const std::string& parent, const char* name, const char* inode_xattr) { 6609a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey ino_t inode = 0; 6619a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey uint64_t inode_raw = 0; 6629a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey auto path = StringPrintf("%s/%s", parent.c_str(), name); 6639a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey 6649a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey if (get_path_inode(path, &inode) != 0) { 6659a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey // Path probably doesn't exist yet; ignore 6669a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey return 0; 6679a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } 6689a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey 6699a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey // Check to see if already set correctly 6709a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey if (getxattr(parent.c_str(), inode_xattr, &inode_raw, sizeof(inode_raw)) == sizeof(inode_raw)) { 6719a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey if (inode_raw == inode) { 6729a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey // Already set correctly; skip writing 6739a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey return 0; 6749a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } else { 6759a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey PLOG(WARNING) << "Mismatched inode value; found " << inode 6769a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey << " on disk but marked value was " << inode_raw << "; overwriting"; 6779a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } 6789a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } 6799a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey 6809a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey inode_raw = inode; 6814ed6507cfb4f0fae8567b42037e74a07f7dd28baJeff Sharkey if (setxattr(parent.c_str(), inode_xattr, &inode_raw, sizeof(inode_raw), 0) != 0 && errno != EOPNOTSUPP) { 6829a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey PLOG(ERROR) << "Failed to write xattr " << inode_xattr << " at " << parent; 6839a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey return -1; 6849a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } else { 6859a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey return 0; 6869a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } 6879a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey} 6889a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey 6899a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey/** 6909a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey * Read the inode of a specific child file from the given xattr on the 6919a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey * parent directory. Returns a currently valid path for that child, which 6929a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey * might have an encrypted name. 6939a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey */ 6949a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkeystd::string read_path_inode(const std::string& parent, const char* name, const char* inode_xattr) { 6959a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey ino_t inode = 0; 6969a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey uint64_t inode_raw = 0; 6979a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey auto fallback = StringPrintf("%s/%s", parent.c_str(), name); 6989a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey 6999a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey // Lookup the inode value written earlier 7009a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey if (getxattr(parent.c_str(), inode_xattr, &inode_raw, sizeof(inode_raw)) == sizeof(inode_raw)) { 7019a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey inode = inode_raw; 7029a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } 7039a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey 7049a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey // For testing purposes, rely on the inode when defined; this could be 7059a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey // optimized to use access() in the future. 7069a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey if (inode != 0) { 7079a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey DIR* dir = opendir(parent.c_str()); 7089a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey if (dir == nullptr) { 7099a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey PLOG(ERROR) << "Failed to opendir " << parent; 7109a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey return fallback; 7119a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } 7129a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey 7139a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey struct dirent* ent; 7149a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey while ((ent = readdir(dir))) { 7159a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey if (ent->d_ino == inode) { 7169a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey auto resolved = StringPrintf("%s/%s", parent.c_str(), ent->d_name); 7179a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey#if DEBUG_XATTRS 7189a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey if (resolved != fallback) { 7199a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey LOG(DEBUG) << "Resolved path " << resolved << " for inode " << inode 7209a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey << " instead of " << fallback; 7219a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } 7229a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey#endif 7239a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey closedir(dir); 7249a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey return resolved; 7259a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } 7269a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } 7279a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey LOG(WARNING) << "Failed to resolve inode " << inode << "; using " << fallback; 7289a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey closedir(dir); 7299a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey return fallback; 7309a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } else { 7319a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey return fallback; 7329a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey } 7339a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey} 7349a998f4762cb5ad71c786229be748ea0ab9eb7a0Jeff Sharkey 73594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/** 736c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle * Validate that the path is valid in the context of the provided directory. 737c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle * The path is allowed to have at most one subdirectory and no indirections 738c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle * to top level directories (i.e. have ".."). 739c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle */ 740e23a13299a4f6f2488935b4786cdbb46f46e3d3cJeff Sharkeystatic int validate_path(const dir_rec_t* dir, const char* path, int maxSubdirs) { 741c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle size_t dir_len = dir->len; 742c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle const char* subdir = strchr(path + dir_len, '/'); 743c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle 744c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle // Only allow the path to have at most one subdirectory. 745c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle if (subdir != NULL) { 746c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle ++subdir; 747e23a13299a4f6f2488935b4786cdbb46f46e3d3cJeff Sharkey if ((--maxSubdirs == 0) && strchr(subdir, '/') != NULL) { 748c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle ALOGE("invalid apk path '%s' (subdir?)\n", path); 749c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle return -1; 750c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle } 751c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle } 752c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle 753c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle // Directories can't have a period directly after the directory markers to prevent "..". 754c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle if ((path[dir_len] == '.') || ((subdir != NULL) && (*subdir == '.'))) { 755c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle ALOGE("invalid apk path '%s' (trickery)\n", path); 756c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle return -1; 757c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle } 758c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle 759c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle return 0; 760c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle} 761c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle 762c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle/** 76394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * Checks whether a path points to a system app (.apk file). Returns 0 76494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * if it is a system app or -1 if it is not. 76594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood */ 76694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodint validate_system_app_path(const char* path) { 76794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood size_t i; 76894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 76994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood for (i = 0; i < android_system_dirs.count; i++) { 77094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood const size_t dir_len = android_system_dirs.dirs[i].len; 77194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) { 772e23a13299a4f6f2488935b4786cdbb46f46e3d3cJeff Sharkey return validate_path(android_system_dirs.dirs + i, path, 1); 77394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 77494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 77594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 77694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 77794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 77894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 779114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravlebool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path, 78042451c029b0e87990e5833daea2286bb12c21df5Calin Juravle const char* volume_uuid, int uid, int storage_flag) { 78142451c029b0e87990e5833daea2286bb12c21df5Calin Juravle CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE); 78242451c029b0e87990e5833daea2286bb12c21df5Calin Juravle 78342451c029b0e87990e5833daea2286bb12c21df5Calin Juravle std::string app_private_dir = storage_flag == FLAG_STORAGE_CE 784114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle ? create_data_user_ce_package_path( 785114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle volume_uuid, multiuser_get_user_id(uid), pkgname.c_str()) 786114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle : create_data_user_de_package_path( 787114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle volume_uuid, multiuser_get_user_id(uid), pkgname.c_str()); 78842451c029b0e87990e5833daea2286bb12c21df5Calin Juravle dir_rec_t dir; 78942451c029b0e87990e5833daea2286bb12c21df5Calin Juravle if (get_path_from_string(&dir, app_private_dir.c_str()) != 0) { 79042451c029b0e87990e5833daea2286bb12c21df5Calin Juravle LOG(WARNING) << "Could not get dir rec for " << app_private_dir; 79142451c029b0e87990e5833daea2286bb12c21df5Calin Juravle return false; 79242451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } 79342451c029b0e87990e5833daea2286bb12c21df5Calin Juravle // Usually secondary dex files have a nested directory structure. 79442451c029b0e87990e5833daea2286bb12c21df5Calin Juravle // Pick at most 10 subdirectories when validating (arbitrary value). 79542451c029b0e87990e5833daea2286bb12c21df5Calin Juravle // If the secondary dex file is >10 directory nested then validation will 79642451c029b0e87990e5833daea2286bb12c21df5Calin Juravle // fail and the file will not be compiled. 797114f08107be384a3f9cc954bdec2b6b7619354aeCalin Juravle return validate_path(&dir, dex_path.c_str(), /*max_subdirs*/ 10) == 0; 79842451c029b0e87990e5833daea2286bb12c21df5Calin Juravle} 79942451c029b0e87990e5833daea2286bb12c21df5Calin Juravle 80094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/** 80194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * Get the contents of a environment variable that contains a path. Caller 80294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * owns the string that is inserted into the directory record. Returns 80394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * 0 on success and -1 on error. 80494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood */ 80594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodint get_path_from_env(dir_rec_t* rec, const char* var) { 80694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood const char* path = getenv(var); 80794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int ret = get_path_from_string(rec, path); 80894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (ret < 0) { 80994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGW("Problem finding value for environment variable %s\n", var); 81094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 81194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return ret; 81294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 81394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 81494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/** 81594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * Puts the string into the record as a directory. Appends '/' to the end 81694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * of all paths. Caller owns the string that is inserted into the directory 81794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * record. A null value will result in an error. 81894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * 81994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood * Returns 0 on success and -1 on error. 82094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood */ 82194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodint get_path_from_string(dir_rec_t* rec, const char* path) { 82294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (path == NULL) { 82394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 82494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } else { 82594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood const size_t path_len = strlen(path); 82694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (path_len <= 0) { 82794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 82894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 82994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 83094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood // Make sure path is absolute. 83194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (path[0] != '/') { 83294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 83394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 83494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 83594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (path[path_len - 1] == '/') { 83694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood // Path ends with a forward slash. Make our own copy. 83794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 83894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood rec->path = strdup(path); 83994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (rec->path == NULL) { 84094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 84194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 84294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 84394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood rec->len = path_len; 84494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } else { 84594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood // Path does not end with a slash. Generate a new string. 84694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood char *dst; 84794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 84894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood // Add space for slash and terminating null. 84994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood size_t dst_size = path_len + 2; 85094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 85119803807cd7ae01868fcfa50305f4a7dd13765e2Jeff Sharkey rec->path = (char*) malloc(dst_size); 85294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (rec->path == NULL) { 85394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 85494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 85594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 85694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood dst = rec->path; 85794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 85894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (append_and_increment(&dst, path, &dst_size) < 0 85994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood || append_and_increment(&dst, "/", &dst_size)) { 86094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("Error canonicalizing path"); 86194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 86294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 86394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 86494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood rec->len = dst - rec->path; 86594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 86694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 86794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return 0; 86894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 86994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 87094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodint copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) { 87194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood dst->len = src->len + strlen(suffix); 87294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood const size_t dstSize = dst->len + 1; 87394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood dst->path = (char*) malloc(dstSize); 87494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 87594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (dst->path == NULL 87694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood || snprintf(dst->path, dstSize, "%s%s", src->path, suffix) 87794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood != (ssize_t) dst->len) { 87894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("Could not allocate memory to hold appended path; aborting\n"); 87994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 88094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 88194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 88294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return 0; 88394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 88494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 88594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/** 886d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath * Check whether path points to a valid path for an APK file. The path must 887d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath * begin with a whitelisted prefix path and must be no deeper than |maxSubdirs| within 888d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath * that path. Returns -1 when an invalid path is encountered and 0 when a valid path 889d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath * is encountered. 89094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood */ 891d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamathstatic int validate_apk_path_internal(const char *path, int maxSubdirs) { 892c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle const dir_rec_t* dir = NULL; 89394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (!strncmp(path, android_app_dir.path, android_app_dir.len)) { 894c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle dir = &android_app_dir; 89594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) { 896c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle dir = &android_app_private_dir; 8975c1a910e6a2d2c42002dc6ed88ff770336afcb3fTodd Kennedy } else if (!strncmp(path, android_app_ephemeral_dir.path, android_app_ephemeral_dir.len)) { 8985c1a910e6a2d2c42002dc6ed88ff770336afcb3fTodd Kennedy dir = &android_app_ephemeral_dir; 89994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) { 900c597b6dd895dbb2b28c757ce7a2651b3cdc9b00cCalin Juravle dir = &android_asec_dir; 901e23a13299a4f6f2488935b4786cdbb46f46e3d3cJeff Sharkey } else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) { 902e23a13299a4f6f2488935b4786cdbb46f46e3d3cJeff Sharkey dir = &android_mnt_expand_dir; 903d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath if (maxSubdirs < 2) { 904d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath maxSubdirs = 2; 905d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath } 90694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } else { 90794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 90894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 90994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 910e23a13299a4f6f2488935b4786cdbb46f46e3d3cJeff Sharkey return validate_path(dir, path, maxSubdirs); 91194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 91294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 913d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamathint validate_apk_path(const char* path) { 914d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath return validate_apk_path_internal(path, 1 /* maxSubdirs */); 915d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath} 916d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath 917d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamathint validate_apk_path_subdirs(const char* path) { 918d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath return validate_apk_path_internal(path, 3 /* maxSubdirs */); 919d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath} 920d845c96128a40ca5802c0840ae190fa0af7d4735Narayan Kamath 92194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodint append_and_increment(char** dst, const char* src, size_t* dst_size) { 92294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ssize_t ret = strlcpy(*dst, src, *dst_size); 92394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (ret < 0 || (size_t) ret >= *dst_size) { 92494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return -1; 92594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 92694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood *dst += ret; 92794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood *dst_size -= ret; 92894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return 0; 92994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 93094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 93119803807cd7ae01868fcfa50305f4a7dd13765e2Jeff Sharkeychar *build_string2(const char *s1, const char *s2) { 93294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (s1 == NULL || s2 == NULL) return NULL; 93394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 93494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int len_s1 = strlen(s1); 93594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int len_s2 = strlen(s2); 93694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int len = len_s1 + len_s2 + 1; 93719803807cd7ae01868fcfa50305f4a7dd13765e2Jeff Sharkey char *result = (char *) malloc(len); 93894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (result == NULL) return NULL; 93994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 94094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood strcpy(result, s1); 94194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood strcpy(result + len_s1, s2); 94294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 94394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return result; 94494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 94594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 94619803807cd7ae01868fcfa50305f4a7dd13765e2Jeff Sharkeychar *build_string3(const char *s1, const char *s2, const char *s3) { 94794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL; 94894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 94994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int len_s1 = strlen(s1); 95094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int len_s2 = strlen(s2); 95194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int len_s3 = strlen(s3); 95294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int len = len_s1 + len_s2 + len_s3 + 1; 95319803807cd7ae01868fcfa50305f4a7dd13765e2Jeff Sharkey char *result = (char *) malloc(len); 95494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (result == NULL) return NULL; 95594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 95694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood strcpy(result, s1); 95794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood strcpy(result + len_s1, s2); 95894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood strcpy(result + len_s1 + len_s2, s3); 95994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 96094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return result; 96194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 96294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 963095c763dd9aa26a206d10ab7c1d7e1c569298fb3Robin Leeint ensure_config_user_dirs(userid_t userid) { 964095c763dd9aa26a206d10ab7c1d7e1c569298fb3Robin Lee // writable by system, readable by any app within the same user 96560fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee const int uid = multiuser_get_uid(userid, AID_SYSTEM); 96660fd3feecab4336d964ca8e31c7c3220e1afb558Robin Lee const int gid = multiuser_get_uid(userid, AID_EVERYBODY); 967095c763dd9aa26a206d10ab7c1d7e1c569298fb3Robin Lee 968095c763dd9aa26a206d10ab7c1d7e1c569298fb3Robin Lee // Ensure /data/misc/user/<userid> exists 969379a12b0072b322c7f86e690a8e8a220e500861cJeff Sharkey auto path = create_data_misc_legacy_path(userid); 970379a12b0072b322c7f86e690a8e8a220e500861cJeff Sharkey return fs_prepare_dir(path.c_str(), 0750, uid, gid); 971095c763dd9aa26a206d10ab7c1d7e1c569298fb3Robin Lee} 97202d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe 97302d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampeint wait_child(pid_t pid) 97402d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe{ 97502d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe int status; 97602d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe pid_t got_pid; 97702d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe 97802d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe while (1) { 97902d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe got_pid = waitpid(pid, &status, 0); 98002d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe if (got_pid == -1 && errno == EINTR) { 98102d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe printf("waitpid interrupted, retrying\n"); 98202d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe } else { 98302d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe break; 98402d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe } 98502d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe } 98602d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe if (got_pid != pid) { 98702d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe ALOGW("waitpid failed: wanted %d, got %d: %s\n", 98802d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe (int) pid, (int) got_pid, strerror(errno)); 98902d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe return 1; 99002d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe } 99102d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe 99202d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 99302d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe return 0; 99402d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe } else { 99502d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe return status; /* always nonzero */ 99602d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe } 99702d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe} 99802d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe 99942451c029b0e87990e5833daea2286bb12c21df5Calin Juravle/** 100042451c029b0e87990e5833daea2286bb12c21df5Calin Juravle * Prepare an app cache directory, which offers to fix-up the GID and 100142451c029b0e87990e5833daea2286bb12c21df5Calin Juravle * directory mode flags during a platform upgrade. 100242451c029b0e87990e5833daea2286bb12c21df5Calin Juravle * The app cache directory path will be 'parent'/'name'. 100342451c029b0e87990e5833daea2286bb12c21df5Calin Juravle */ 100442451c029b0e87990e5833daea2286bb12c21df5Calin Juravleint prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode, 100542451c029b0e87990e5833daea2286bb12c21df5Calin Juravle uid_t uid, gid_t gid) { 100642451c029b0e87990e5833daea2286bb12c21df5Calin Juravle auto path = StringPrintf("%s/%s", parent.c_str(), name); 100742451c029b0e87990e5833daea2286bb12c21df5Calin Juravle struct stat st; 100842451c029b0e87990e5833daea2286bb12c21df5Calin Juravle if (stat(path.c_str(), &st) != 0) { 100942451c029b0e87990e5833daea2286bb12c21df5Calin Juravle if (errno == ENOENT) { 101042451c029b0e87990e5833daea2286bb12c21df5Calin Juravle // This is fine, just create it 101142451c029b0e87990e5833daea2286bb12c21df5Calin Juravle if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) { 101242451c029b0e87990e5833daea2286bb12c21df5Calin Juravle PLOG(ERROR) << "Failed to prepare " << path; 101342451c029b0e87990e5833daea2286bb12c21df5Calin Juravle return -1; 101442451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } else { 101542451c029b0e87990e5833daea2286bb12c21df5Calin Juravle return 0; 101642451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } 101742451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } else { 101842451c029b0e87990e5833daea2286bb12c21df5Calin Juravle PLOG(ERROR) << "Failed to stat " << path; 101942451c029b0e87990e5833daea2286bb12c21df5Calin Juravle return -1; 102042451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } 102142451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } 102242451c029b0e87990e5833daea2286bb12c21df5Calin Juravle 102342451c029b0e87990e5833daea2286bb12c21df5Calin Juravle mode_t actual_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID); 102442451c029b0e87990e5833daea2286bb12c21df5Calin Juravle if (st.st_uid != uid) { 102542451c029b0e87990e5833daea2286bb12c21df5Calin Juravle // Mismatched UID is real trouble; we can't recover 102642451c029b0e87990e5833daea2286bb12c21df5Calin Juravle LOG(ERROR) << "Mismatched UID at " << path << ": found " << st.st_uid 102742451c029b0e87990e5833daea2286bb12c21df5Calin Juravle << " but expected " << uid; 102842451c029b0e87990e5833daea2286bb12c21df5Calin Juravle return -1; 102942451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } else if (st.st_gid == gid && actual_mode == target_mode) { 103042451c029b0e87990e5833daea2286bb12c21df5Calin Juravle // Everything looks good! 103142451c029b0e87990e5833daea2286bb12c21df5Calin Juravle return 0; 103242451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } 103342451c029b0e87990e5833daea2286bb12c21df5Calin Juravle 103442451c029b0e87990e5833daea2286bb12c21df5Calin Juravle // Directory is owned correctly, but GID or mode mismatch means it's 103542451c029b0e87990e5833daea2286bb12c21df5Calin Juravle // probably a platform upgrade so we need to fix them 103642451c029b0e87990e5833daea2286bb12c21df5Calin Juravle FTS *fts; 103742451c029b0e87990e5833daea2286bb12c21df5Calin Juravle FTSENT *p; 103842451c029b0e87990e5833daea2286bb12c21df5Calin Juravle char *argv[] = { (char*) path.c_str(), nullptr }; 1039b26786d647b624498c11405075e5223d1853f30aJeff Sharkey if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) { 104042451c029b0e87990e5833daea2286bb12c21df5Calin Juravle PLOG(ERROR) << "Failed to fts_open " << path; 104142451c029b0e87990e5833daea2286bb12c21df5Calin Juravle return -1; 104242451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } 104342451c029b0e87990e5833daea2286bb12c21df5Calin Juravle while ((p = fts_read(fts)) != NULL) { 104442451c029b0e87990e5833daea2286bb12c21df5Calin Juravle switch (p->fts_info) { 104542451c029b0e87990e5833daea2286bb12c21df5Calin Juravle case FTS_DP: 104642451c029b0e87990e5833daea2286bb12c21df5Calin Juravle if (chmod(p->fts_accpath, target_mode) != 0) { 104742451c029b0e87990e5833daea2286bb12c21df5Calin Juravle PLOG(WARNING) << "Failed to chmod " << p->fts_path; 104842451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } 104942451c029b0e87990e5833daea2286bb12c21df5Calin Juravle // Intentional fall through to also set GID 105042451c029b0e87990e5833daea2286bb12c21df5Calin Juravle case FTS_F: 105142451c029b0e87990e5833daea2286bb12c21df5Calin Juravle if (chown(p->fts_accpath, -1, gid) != 0) { 105242451c029b0e87990e5833daea2286bb12c21df5Calin Juravle PLOG(WARNING) << "Failed to chown " << p->fts_path; 105342451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } 105442451c029b0e87990e5833daea2286bb12c21df5Calin Juravle break; 105542451c029b0e87990e5833daea2286bb12c21df5Calin Juravle case FTS_SL: 105642451c029b0e87990e5833daea2286bb12c21df5Calin Juravle case FTS_SLNONE: 105742451c029b0e87990e5833daea2286bb12c21df5Calin Juravle if (lchown(p->fts_accpath, -1, gid) != 0) { 105842451c029b0e87990e5833daea2286bb12c21df5Calin Juravle PLOG(WARNING) << "Failed to chown " << p->fts_path; 105942451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } 106042451c029b0e87990e5833daea2286bb12c21df5Calin Juravle break; 106142451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } 106242451c029b0e87990e5833daea2286bb12c21df5Calin Juravle } 106342451c029b0e87990e5833daea2286bb12c21df5Calin Juravle fts_close(fts); 106442451c029b0e87990e5833daea2286bb12c21df5Calin Juravle return 0; 106542451c029b0e87990e5833daea2286bb12c21df5Calin Juravle} 106642451c029b0e87990e5833daea2286bb12c21df5Calin Juravle 106702d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe} // namespace installd 106802d0de56c75347a0cb8d5a8565dc8c4ee7616057Andreas Gampe} // namespace android 1069