Loading cmds/installd/commands.cpp +65 −122 Original line number Original line Diff line number Diff line Loading @@ -49,46 +49,17 @@ int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const c return -1; return -1; } } std::string ce_package_path(create_data_user_package_path(uuid, 0, pkgname)); return make_user_data(uuid, pkgname, uid, 0, seinfo); std::string de_package_path(create_data_user_de_package_path(uuid, 0, pkgname)); const char* c_ce_package_path = ce_package_path.c_str(); const char* c_de_package_path = de_package_path.c_str(); if (fs_prepare_dir(c_ce_package_path, 0751, uid, gid) == -1) { PLOG(ERROR) << "Failed to prepare " << ce_package_path; unlink(c_ce_package_path); return -1; } if (selinux_android_setfilecon(c_ce_package_path, pkgname, seinfo, uid) < 0) { PLOG(ERROR) << "Failed to setfilecon " << ce_package_path; unlink(c_ce_package_path); return -1; } if (property_get_bool("vold.has_fbe", false)) { if (fs_prepare_dir(c_de_package_path, 0751, uid, gid) == -1) { PLOG(ERROR) << "Failed to prepare " << de_package_path; unlink(c_de_package_path); return -1; } if (selinux_android_setfilecon(c_de_package_path, pkgname, seinfo, uid) < 0) { PLOG(ERROR) << "Failed to setfilecon " << de_package_path; unlink(c_de_package_path); return -1; } } return 0; } } int uninstall(const char *uuid, const char *pkgname, userid_t userid) int uninstall(const char *uuid, const char *pkgname, userid_t userid) { { std::string ce_package_path(create_data_user_package_path(uuid, userid, pkgname)); std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname)); std::string de_package_path(create_data_user_de_package_path(uuid, userid, pkgname)); const char* pkgdir = _pkgdir.c_str(); /* delete contents AND directory, no exceptions */ int res = 0; return delete_dir_contents(pkgdir, 1, NULL); res |= delete_dir_contents_and_dir(ce_package_path); res |= delete_dir_contents_and_dir(de_package_path); return res; } } int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid) int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid) Loading @@ -100,6 +71,7 @@ int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid) return -1; return -1; } } // TODO: handle user_de paths std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname)); std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname)); const char* pkgdir = _pkgdir.c_str(); const char* pkgdir = _pkgdir.c_str(); Loading @@ -124,39 +96,44 @@ int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid) return 0; return 0; } } int delete_user_data(const char *uuid, const char *pkgname, userid_t userid) int delete_user_data(const char *uuid, const char *pkgname, userid_t userid) { { std::string ce_package_path(create_data_user_package_path(uuid, userid, pkgname)); std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname)); std::string de_package_path(create_data_user_de_package_path(uuid, userid, pkgname)); const char* pkgdir = _pkgdir.c_str(); return delete_dir_contents(pkgdir, 0, NULL); int res = 0; res |= delete_dir_contents(ce_package_path); res |= delete_dir_contents(de_package_path); return res; } } int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid, const char* seinfo) int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid, { const char* seinfo) { std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname)); std::string ce_package_path(create_data_user_package_path(uuid, userid, pkgname)); const char* pkgdir = _pkgdir.c_str(); std::string de_package_path(create_data_user_de_package_path(uuid, userid, pkgname)); if (mkdir(pkgdir, 0751) < 0) { const char* c_ce_package_path = ce_package_path.c_str(); ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno)); const char* c_de_package_path = de_package_path.c_str(); return -errno; if (fs_prepare_dir(c_ce_package_path, 0751, uid, uid) == -1) { PLOG(ERROR) << "Failed to prepare " << ce_package_path; unlink(c_ce_package_path); return -1; } } if (chmod(pkgdir, 0751) < 0) { if (selinux_android_setfilecon(c_ce_package_path, pkgname, seinfo, uid) < 0) { ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno)); PLOG(ERROR) << "Failed to setfilecon " << ce_package_path; unlink(pkgdir); unlink(c_ce_package_path); return -errno; return -1; } } if (selinux_android_setfilecon(pkgdir, pkgname, seinfo, uid) < 0) { if (fs_prepare_dir(c_de_package_path, 0751, uid, uid) == -1) { ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno)); PLOG(ERROR) << "Failed to prepare " << de_package_path; unlink(pkgdir); unlink(c_de_package_path); return -errno; return -1; } } if (selinux_android_setfilecon(c_de_package_path, pkgname, seinfo, uid) < 0) { if (chown(pkgdir, uid, uid) < 0) { PLOG(ERROR) << "Failed to setfilecon " << de_package_path; ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno)); unlink(c_de_package_path); unlink(pkgdir); return -1; return -errno; } } return 0; return 0; Loading Loading @@ -200,6 +177,7 @@ int copy_complete_app(const char *from_uuid, const char *to_uuid, } } // Copy private data for all known users // Copy private data for all known users // TODO: handle user_de paths for (auto user : users) { for (auto user : users) { std::string from(create_data_user_package_path(from_uuid, user, package_name)); std::string from(create_data_user_package_path(from_uuid, user, package_name)); std::string to(create_data_user_package_path(to_uuid, user, package_name)); std::string to(create_data_user_package_path(to_uuid, user, package_name)); Loading Loading @@ -280,30 +258,27 @@ int make_user_config(userid_t userid) return 0; return 0; } } int delete_user(const char *uuid, userid_t userid) int delete_user(const char *uuid, userid_t userid) { { int res = 0; int status = 0; std::string data_path(create_data_user_path(uuid, userid)); std::string data_path(create_data_user_path(uuid, userid)); if (delete_dir_contents(data_path.c_str(), 1, NULL) != 0) { std::string data_de_path(create_data_user_de_path(uuid, userid)); status = -1; } std::string media_path(create_data_media_path(uuid, userid)); std::string media_path(create_data_media_path(uuid, userid)); if (delete_dir_contents(media_path.c_str(), 1, NULL) != 0) { status = -1; res |= delete_dir_contents_and_dir(data_path); } res |= delete_dir_contents_and_dir(data_de_path); res |= delete_dir_contents_and_dir(media_path); // Config paths only exist on internal storage // Config paths only exist on internal storage if (uuid == nullptr) { if (uuid == nullptr) { char config_path[PATH_MAX]; char config_path[PATH_MAX]; if ((create_user_config_path(config_path, userid) != 0) if ((create_user_config_path(config_path, userid) != 0) || (delete_dir_contents(config_path, 1, NULL) != 0)) { || (delete_dir_contents(config_path, 1, NULL) != 0)) { status = -1; res = -1; } } } } return status; return res; } } int delete_cache(const char *uuid, const char *pkgname, userid_t userid) int delete_cache(const char *uuid, const char *pkgname, userid_t userid) Loading Loading @@ -546,6 +521,7 @@ int get_size(const char *uuid, const char *pkgname, int userid, const char *apkp } } for (auto user : users) { for (auto user : users) { // TODO: handle user_de directories std::string _pkgdir(create_data_user_package_path(uuid, user, pkgname)); std::string _pkgdir(create_data_user_package_path(uuid, user, pkgname)); const char* pkgdir = _pkgdir.c_str(); const char* pkgdir = _pkgdir.c_str(); Loading Loading @@ -1681,13 +1657,8 @@ fail: return -1; return -1; } } int restorecon_data(const char* uuid, const char* pkgName, int restorecon_data(const char* uuid, const char* pkgName, const char* seinfo, appid_t appid) { const char* seinfo, uid_t uid) int res = 0; { struct dirent *entry; DIR *d; struct stat s; int ret = 0; // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here. // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here. unsigned int flags = SELINUX_ANDROID_RESTORECON_RECURSE; unsigned int flags = SELINUX_ANDROID_RESTORECON_RECURSE; Loading @@ -1697,53 +1668,25 @@ int restorecon_data(const char* uuid, const char* pkgName, return -1; return -1; } } // Special case for owner on internal storage // Relabel package directory for all users if (uuid == nullptr) { std::vector<userid_t> users = get_known_users(uuid); std::string path(create_data_user_package_path(nullptr, 0, pkgName)); for (auto user : users) { uid_t uid = multiuser_get_uid(user, appid); if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, flags) < 0) { PLOG(ERROR) << "restorecon failed for " << path; ret |= -1; } } // Relabel package directory for all secondary users. std::string userdir(create_data_path(uuid) + "/" + SECONDARY_USER_PREFIX); d = opendir(userdir.c_str()); if (d == NULL) { return -1; } while ((entry = readdir(d))) { if (entry->d_type != DT_DIR) { continue; } const char *user = entry->d_name; std::string ce_package_path(create_data_user_package_path(uuid, user, pkgName)); // Ignore "." and ".." std::string de_package_path(create_data_user_de_package_path(uuid, user, pkgName)); if (!strcmp(user, ".") || !strcmp(user, "..")) { continue; } // user directories start with a number if (selinux_android_restorecon_pkgdir(ce_package_path.c_str(), seinfo, uid, flags) < 0) { if (user[0] < '0' || user[0] > '9') { PLOG(ERROR) << "restorecon failed for " << ce_package_path; ALOGE("Expecting numbered directory during restorecon. Instead got '%s'.", user); res = -1; continue; } } if (selinux_android_restorecon_pkgdir(de_package_path.c_str(), seinfo, uid, flags) < 0) { std::string pkgdir(StringPrintf("%s%s/%s", userdir.c_str(), user, pkgName)); PLOG(ERROR) << "restorecon failed for " << de_package_path; if (stat(pkgdir.c_str(), &s) < 0) { res = -1; continue; } if (selinux_android_restorecon_pkgdir(pkgdir.c_str(), seinfo, s.st_uid, flags) < 0) { PLOG(ERROR) << "restorecon failed for " << pkgdir; ret |= -1; } } } } closedir(d); return res; return ret; } } int create_oat_dir(const char* oat_dir, const char* instruction_set) int create_oat_dir(const char* oat_dir, const char* instruction_set) Loading cmds/installd/installd.h +3 −0 Original line number Original line Diff line number Diff line Loading @@ -196,6 +196,9 @@ int is_valid_package_name(const char* pkgname); int create_cache_path(char path[PKG_PATH_MAX], const char *src, int create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set); const char *instruction_set); int delete_dir_contents(const std::string& pathname); int delete_dir_contents_and_dir(const std::string& pathname); int delete_dir_contents(const char *pathname, int delete_dir_contents(const char *pathname, int also_delete_dir, int also_delete_dir, int (*exclusion_predicate)(const char *name, const int is_dir)); int (*exclusion_predicate)(const char *name, const int is_dir)); Loading cmds/installd/utils.cpp +8 −0 Original line number Original line Diff line number Diff line Loading @@ -305,6 +305,14 @@ static int _delete_dir_contents(DIR *d, return result; return result; } } int delete_dir_contents(const std::string& pathname) { return delete_dir_contents(pathname.c_str(), 0, NULL); } int delete_dir_contents_and_dir(const std::string& pathname) { return delete_dir_contents(pathname.c_str(), 1, NULL); } int delete_dir_contents(const char *pathname, int delete_dir_contents(const char *pathname, int also_delete_dir, int also_delete_dir, int (*exclusion_predicate)(const char*, const int)) int (*exclusion_predicate)(const char*, const int)) Loading Loading
cmds/installd/commands.cpp +65 −122 Original line number Original line Diff line number Diff line Loading @@ -49,46 +49,17 @@ int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const c return -1; return -1; } } std::string ce_package_path(create_data_user_package_path(uuid, 0, pkgname)); return make_user_data(uuid, pkgname, uid, 0, seinfo); std::string de_package_path(create_data_user_de_package_path(uuid, 0, pkgname)); const char* c_ce_package_path = ce_package_path.c_str(); const char* c_de_package_path = de_package_path.c_str(); if (fs_prepare_dir(c_ce_package_path, 0751, uid, gid) == -1) { PLOG(ERROR) << "Failed to prepare " << ce_package_path; unlink(c_ce_package_path); return -1; } if (selinux_android_setfilecon(c_ce_package_path, pkgname, seinfo, uid) < 0) { PLOG(ERROR) << "Failed to setfilecon " << ce_package_path; unlink(c_ce_package_path); return -1; } if (property_get_bool("vold.has_fbe", false)) { if (fs_prepare_dir(c_de_package_path, 0751, uid, gid) == -1) { PLOG(ERROR) << "Failed to prepare " << de_package_path; unlink(c_de_package_path); return -1; } if (selinux_android_setfilecon(c_de_package_path, pkgname, seinfo, uid) < 0) { PLOG(ERROR) << "Failed to setfilecon " << de_package_path; unlink(c_de_package_path); return -1; } } return 0; } } int uninstall(const char *uuid, const char *pkgname, userid_t userid) int uninstall(const char *uuid, const char *pkgname, userid_t userid) { { std::string ce_package_path(create_data_user_package_path(uuid, userid, pkgname)); std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname)); std::string de_package_path(create_data_user_de_package_path(uuid, userid, pkgname)); const char* pkgdir = _pkgdir.c_str(); /* delete contents AND directory, no exceptions */ int res = 0; return delete_dir_contents(pkgdir, 1, NULL); res |= delete_dir_contents_and_dir(ce_package_path); res |= delete_dir_contents_and_dir(de_package_path); return res; } } int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid) int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid) Loading @@ -100,6 +71,7 @@ int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid) return -1; return -1; } } // TODO: handle user_de paths std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname)); std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname)); const char* pkgdir = _pkgdir.c_str(); const char* pkgdir = _pkgdir.c_str(); Loading @@ -124,39 +96,44 @@ int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid) return 0; return 0; } } int delete_user_data(const char *uuid, const char *pkgname, userid_t userid) int delete_user_data(const char *uuid, const char *pkgname, userid_t userid) { { std::string ce_package_path(create_data_user_package_path(uuid, userid, pkgname)); std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname)); std::string de_package_path(create_data_user_de_package_path(uuid, userid, pkgname)); const char* pkgdir = _pkgdir.c_str(); return delete_dir_contents(pkgdir, 0, NULL); int res = 0; res |= delete_dir_contents(ce_package_path); res |= delete_dir_contents(de_package_path); return res; } } int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid, const char* seinfo) int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid, { const char* seinfo) { std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname)); std::string ce_package_path(create_data_user_package_path(uuid, userid, pkgname)); const char* pkgdir = _pkgdir.c_str(); std::string de_package_path(create_data_user_de_package_path(uuid, userid, pkgname)); if (mkdir(pkgdir, 0751) < 0) { const char* c_ce_package_path = ce_package_path.c_str(); ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno)); const char* c_de_package_path = de_package_path.c_str(); return -errno; if (fs_prepare_dir(c_ce_package_path, 0751, uid, uid) == -1) { PLOG(ERROR) << "Failed to prepare " << ce_package_path; unlink(c_ce_package_path); return -1; } } if (chmod(pkgdir, 0751) < 0) { if (selinux_android_setfilecon(c_ce_package_path, pkgname, seinfo, uid) < 0) { ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno)); PLOG(ERROR) << "Failed to setfilecon " << ce_package_path; unlink(pkgdir); unlink(c_ce_package_path); return -errno; return -1; } } if (selinux_android_setfilecon(pkgdir, pkgname, seinfo, uid) < 0) { if (fs_prepare_dir(c_de_package_path, 0751, uid, uid) == -1) { ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno)); PLOG(ERROR) << "Failed to prepare " << de_package_path; unlink(pkgdir); unlink(c_de_package_path); return -errno; return -1; } } if (selinux_android_setfilecon(c_de_package_path, pkgname, seinfo, uid) < 0) { if (chown(pkgdir, uid, uid) < 0) { PLOG(ERROR) << "Failed to setfilecon " << de_package_path; ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno)); unlink(c_de_package_path); unlink(pkgdir); return -1; return -errno; } } return 0; return 0; Loading Loading @@ -200,6 +177,7 @@ int copy_complete_app(const char *from_uuid, const char *to_uuid, } } // Copy private data for all known users // Copy private data for all known users // TODO: handle user_de paths for (auto user : users) { for (auto user : users) { std::string from(create_data_user_package_path(from_uuid, user, package_name)); std::string from(create_data_user_package_path(from_uuid, user, package_name)); std::string to(create_data_user_package_path(to_uuid, user, package_name)); std::string to(create_data_user_package_path(to_uuid, user, package_name)); Loading Loading @@ -280,30 +258,27 @@ int make_user_config(userid_t userid) return 0; return 0; } } int delete_user(const char *uuid, userid_t userid) int delete_user(const char *uuid, userid_t userid) { { int res = 0; int status = 0; std::string data_path(create_data_user_path(uuid, userid)); std::string data_path(create_data_user_path(uuid, userid)); if (delete_dir_contents(data_path.c_str(), 1, NULL) != 0) { std::string data_de_path(create_data_user_de_path(uuid, userid)); status = -1; } std::string media_path(create_data_media_path(uuid, userid)); std::string media_path(create_data_media_path(uuid, userid)); if (delete_dir_contents(media_path.c_str(), 1, NULL) != 0) { status = -1; res |= delete_dir_contents_and_dir(data_path); } res |= delete_dir_contents_and_dir(data_de_path); res |= delete_dir_contents_and_dir(media_path); // Config paths only exist on internal storage // Config paths only exist on internal storage if (uuid == nullptr) { if (uuid == nullptr) { char config_path[PATH_MAX]; char config_path[PATH_MAX]; if ((create_user_config_path(config_path, userid) != 0) if ((create_user_config_path(config_path, userid) != 0) || (delete_dir_contents(config_path, 1, NULL) != 0)) { || (delete_dir_contents(config_path, 1, NULL) != 0)) { status = -1; res = -1; } } } } return status; return res; } } int delete_cache(const char *uuid, const char *pkgname, userid_t userid) int delete_cache(const char *uuid, const char *pkgname, userid_t userid) Loading Loading @@ -546,6 +521,7 @@ int get_size(const char *uuid, const char *pkgname, int userid, const char *apkp } } for (auto user : users) { for (auto user : users) { // TODO: handle user_de directories std::string _pkgdir(create_data_user_package_path(uuid, user, pkgname)); std::string _pkgdir(create_data_user_package_path(uuid, user, pkgname)); const char* pkgdir = _pkgdir.c_str(); const char* pkgdir = _pkgdir.c_str(); Loading Loading @@ -1681,13 +1657,8 @@ fail: return -1; return -1; } } int restorecon_data(const char* uuid, const char* pkgName, int restorecon_data(const char* uuid, const char* pkgName, const char* seinfo, appid_t appid) { const char* seinfo, uid_t uid) int res = 0; { struct dirent *entry; DIR *d; struct stat s; int ret = 0; // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here. // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here. unsigned int flags = SELINUX_ANDROID_RESTORECON_RECURSE; unsigned int flags = SELINUX_ANDROID_RESTORECON_RECURSE; Loading @@ -1697,53 +1668,25 @@ int restorecon_data(const char* uuid, const char* pkgName, return -1; return -1; } } // Special case for owner on internal storage // Relabel package directory for all users if (uuid == nullptr) { std::vector<userid_t> users = get_known_users(uuid); std::string path(create_data_user_package_path(nullptr, 0, pkgName)); for (auto user : users) { uid_t uid = multiuser_get_uid(user, appid); if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, flags) < 0) { PLOG(ERROR) << "restorecon failed for " << path; ret |= -1; } } // Relabel package directory for all secondary users. std::string userdir(create_data_path(uuid) + "/" + SECONDARY_USER_PREFIX); d = opendir(userdir.c_str()); if (d == NULL) { return -1; } while ((entry = readdir(d))) { if (entry->d_type != DT_DIR) { continue; } const char *user = entry->d_name; std::string ce_package_path(create_data_user_package_path(uuid, user, pkgName)); // Ignore "." and ".." std::string de_package_path(create_data_user_de_package_path(uuid, user, pkgName)); if (!strcmp(user, ".") || !strcmp(user, "..")) { continue; } // user directories start with a number if (selinux_android_restorecon_pkgdir(ce_package_path.c_str(), seinfo, uid, flags) < 0) { if (user[0] < '0' || user[0] > '9') { PLOG(ERROR) << "restorecon failed for " << ce_package_path; ALOGE("Expecting numbered directory during restorecon. Instead got '%s'.", user); res = -1; continue; } } if (selinux_android_restorecon_pkgdir(de_package_path.c_str(), seinfo, uid, flags) < 0) { std::string pkgdir(StringPrintf("%s%s/%s", userdir.c_str(), user, pkgName)); PLOG(ERROR) << "restorecon failed for " << de_package_path; if (stat(pkgdir.c_str(), &s) < 0) { res = -1; continue; } if (selinux_android_restorecon_pkgdir(pkgdir.c_str(), seinfo, s.st_uid, flags) < 0) { PLOG(ERROR) << "restorecon failed for " << pkgdir; ret |= -1; } } } } closedir(d); return res; return ret; } } int create_oat_dir(const char* oat_dir, const char* instruction_set) int create_oat_dir(const char* oat_dir, const char* instruction_set) Loading
cmds/installd/installd.h +3 −0 Original line number Original line Diff line number Diff line Loading @@ -196,6 +196,9 @@ int is_valid_package_name(const char* pkgname); int create_cache_path(char path[PKG_PATH_MAX], const char *src, int create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set); const char *instruction_set); int delete_dir_contents(const std::string& pathname); int delete_dir_contents_and_dir(const std::string& pathname); int delete_dir_contents(const char *pathname, int delete_dir_contents(const char *pathname, int also_delete_dir, int also_delete_dir, int (*exclusion_predicate)(const char *name, const int is_dir)); int (*exclusion_predicate)(const char *name, const int is_dir)); Loading
cmds/installd/utils.cpp +8 −0 Original line number Original line Diff line number Diff line Loading @@ -305,6 +305,14 @@ static int _delete_dir_contents(DIR *d, return result; return result; } } int delete_dir_contents(const std::string& pathname) { return delete_dir_contents(pathname.c_str(), 0, NULL); } int delete_dir_contents_and_dir(const std::string& pathname) { return delete_dir_contents(pathname.c_str(), 1, NULL); } int delete_dir_contents(const char *pathname, int delete_dir_contents(const char *pathname, int also_delete_dir, int also_delete_dir, int (*exclusion_predicate)(const char*, const int)) int (*exclusion_predicate)(const char*, const int)) Loading