Merge "recovery: Clean up browse_directory()." am: 635eb1c83e
am: c42d44bbeb
Change-Id: I462259ea96248f253e161065a17b0098add83716
This commit is contained in:
+63
-100
@@ -34,7 +34,9 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -656,108 +658,69 @@ get_menu_selection(const char* const * headers, const char* const * items,
|
|||||||
return chosen_item;
|
return chosen_item;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compare_string(const void* a, const void* b) {
|
// Returns the selected filename, or an empty string.
|
||||||
return strcmp(*(const char**)a, *(const char**)b);
|
static std::string browse_directory(const std::string& path, Device* device) {
|
||||||
}
|
ensure_path_mounted(path.c_str());
|
||||||
|
|
||||||
// Returns a malloc'd path, or NULL.
|
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
|
||||||
static char* browse_directory(const char* path, Device* device) {
|
if (!d) {
|
||||||
ensure_path_mounted(path);
|
PLOG(ERROR) << "error opening " << path;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
DIR* d = opendir(path);
|
std::vector<std::string> dirs;
|
||||||
if (d == NULL) {
|
std::vector<std::string> zips = { "../" }; // "../" is always the first entry.
|
||||||
PLOG(ERROR) << "error opening " << path;
|
|
||||||
return NULL;
|
dirent* de;
|
||||||
|
while ((de = readdir(d.get())) != nullptr) {
|
||||||
|
std::string name(de->d_name);
|
||||||
|
|
||||||
|
if (de->d_type == DT_DIR) {
|
||||||
|
// Skip "." and ".." entries.
|
||||||
|
if (name == "." || name == "..") continue;
|
||||||
|
dirs.push_back(name + "/");
|
||||||
|
} else if (de->d_type == DT_REG && android::base::EndsWithIgnoreCase(name, ".zip")) {
|
||||||
|
zips.push_back(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(dirs.begin(), dirs.end());
|
||||||
|
std::sort(zips.begin(), zips.end());
|
||||||
|
|
||||||
|
// Append dirs to the zips list.
|
||||||
|
zips.insert(zips.end(), dirs.begin(), dirs.end());
|
||||||
|
|
||||||
|
const char* entries[zips.size() + 1];
|
||||||
|
entries[zips.size()] = nullptr;
|
||||||
|
for (size_t i = 0; i < zips.size(); i++) {
|
||||||
|
entries[i] = zips[i].c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* headers[] = { "Choose a package to install:", path.c_str(), nullptr };
|
||||||
|
|
||||||
|
int chosen_item = 0;
|
||||||
|
while (true) {
|
||||||
|
chosen_item = get_menu_selection(headers, entries, 1, chosen_item, device);
|
||||||
|
|
||||||
|
const std::string& item = zips[chosen_item];
|
||||||
|
if (chosen_item == 0) {
|
||||||
|
// Go up but continue browsing (if the caller is browse_directory).
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
int d_size = 0;
|
std::string new_path = path + "/" + item;
|
||||||
int d_alloc = 10;
|
if (new_path.back() == '/') {
|
||||||
char** dirs = (char**)malloc(d_alloc * sizeof(char*));
|
// Recurse down into a subdirectory.
|
||||||
int z_size = 1;
|
new_path.pop_back();
|
||||||
int z_alloc = 10;
|
std::string result = browse_directory(new_path, device);
|
||||||
char** zips = (char**)malloc(z_alloc * sizeof(char*));
|
if (!result.empty()) return result;
|
||||||
zips[0] = strdup("../");
|
} else {
|
||||||
|
// Selected a zip file: return the path to the caller.
|
||||||
struct dirent* de;
|
return new_path;
|
||||||
while ((de = readdir(d)) != NULL) {
|
|
||||||
int name_len = strlen(de->d_name);
|
|
||||||
|
|
||||||
if (de->d_type == DT_DIR) {
|
|
||||||
// skip "." and ".." entries
|
|
||||||
if (name_len == 1 && de->d_name[0] == '.') continue;
|
|
||||||
if (name_len == 2 && de->d_name[0] == '.' &&
|
|
||||||
de->d_name[1] == '.') continue;
|
|
||||||
|
|
||||||
if (d_size >= d_alloc) {
|
|
||||||
d_alloc *= 2;
|
|
||||||
dirs = (char**)realloc(dirs, d_alloc * sizeof(char*));
|
|
||||||
}
|
|
||||||
dirs[d_size] = (char*)malloc(name_len + 2);
|
|
||||||
strcpy(dirs[d_size], de->d_name);
|
|
||||||
dirs[d_size][name_len] = '/';
|
|
||||||
dirs[d_size][name_len+1] = '\0';
|
|
||||||
++d_size;
|
|
||||||
} else if (de->d_type == DT_REG &&
|
|
||||||
name_len >= 4 &&
|
|
||||||
strncasecmp(de->d_name + (name_len-4), ".zip", 4) == 0) {
|
|
||||||
if (z_size >= z_alloc) {
|
|
||||||
z_alloc *= 2;
|
|
||||||
zips = (char**)realloc(zips, z_alloc * sizeof(char*));
|
|
||||||
}
|
|
||||||
zips[z_size++] = strdup(de->d_name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
closedir(d);
|
}
|
||||||
|
|
||||||
qsort(dirs, d_size, sizeof(char*), compare_string);
|
// Unreachable.
|
||||||
qsort(zips, z_size, sizeof(char*), compare_string);
|
|
||||||
|
|
||||||
// append dirs to the zips list
|
|
||||||
if (d_size + z_size + 1 > z_alloc) {
|
|
||||||
z_alloc = d_size + z_size + 1;
|
|
||||||
zips = (char**)realloc(zips, z_alloc * sizeof(char*));
|
|
||||||
}
|
|
||||||
memcpy(zips + z_size, dirs, d_size * sizeof(char*));
|
|
||||||
free(dirs);
|
|
||||||
z_size += d_size;
|
|
||||||
zips[z_size] = NULL;
|
|
||||||
|
|
||||||
const char* headers[] = { "Choose a package to install:", path, NULL };
|
|
||||||
|
|
||||||
char* result;
|
|
||||||
int chosen_item = 0;
|
|
||||||
while (true) {
|
|
||||||
chosen_item = get_menu_selection(headers, zips, 1, chosen_item, device);
|
|
||||||
|
|
||||||
char* item = zips[chosen_item];
|
|
||||||
int item_len = strlen(item);
|
|
||||||
if (chosen_item == 0) { // item 0 is always "../"
|
|
||||||
// go up but continue browsing (if the caller is update_directory)
|
|
||||||
result = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
char new_path[PATH_MAX];
|
|
||||||
strlcpy(new_path, path, PATH_MAX);
|
|
||||||
strlcat(new_path, "/", PATH_MAX);
|
|
||||||
strlcat(new_path, item, PATH_MAX);
|
|
||||||
|
|
||||||
if (item[item_len-1] == '/') {
|
|
||||||
// recurse down into a subdirectory
|
|
||||||
new_path[strlen(new_path)-1] = '\0'; // truncate the trailing '/'
|
|
||||||
result = browse_directory(new_path, device);
|
|
||||||
if (result) break;
|
|
||||||
} else {
|
|
||||||
// selected a zip file: return the malloc'd path to the caller.
|
|
||||||
result = strdup(new_path);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < z_size; ++i) free(zips[i]);
|
|
||||||
free(zips);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool yes_no(Device* device, const char* question1, const char* question2) {
|
static bool yes_no(Device* device, const char* question1, const char* question2) {
|
||||||
@@ -1065,14 +1028,14 @@ static int apply_from_sdcard(Device* device, bool* wipe_cache) {
|
|||||||
return INSTALL_ERROR;
|
return INSTALL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* path = browse_directory(SDCARD_ROOT, device);
|
std::string path = browse_directory(SDCARD_ROOT, device);
|
||||||
if (path == NULL) {
|
if (path.empty()) {
|
||||||
ui->Print("\n-- No package file selected.\n");
|
ui->Print("\n-- No package file selected.\n");
|
||||||
ensure_path_unmounted(SDCARD_ROOT);
|
ensure_path_unmounted(SDCARD_ROOT);
|
||||||
return INSTALL_ERROR;
|
return INSTALL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->Print("\n-- Install %s ...\n", path);
|
ui->Print("\n-- Install %s ...\n", path.c_str());
|
||||||
set_sdcard_update_bootloader_message();
|
set_sdcard_update_bootloader_message();
|
||||||
|
|
||||||
// We used to use fuse in a thread as opposed to a process. Since accessing
|
// We used to use fuse in a thread as opposed to a process. Since accessing
|
||||||
@@ -1080,7 +1043,7 @@ static int apply_from_sdcard(Device* device, bool* wipe_cache) {
|
|||||||
// to deadlock when a page fault occurs. (Bug: 26313124)
|
// to deadlock when a page fault occurs. (Bug: 26313124)
|
||||||
pid_t child;
|
pid_t child;
|
||||||
if ((child = fork()) == 0) {
|
if ((child = fork()) == 0) {
|
||||||
bool status = start_sdcard_fuse(path);
|
bool status = start_sdcard_fuse(path.c_str());
|
||||||
|
|
||||||
_exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
|
_exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user