aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTao Bao2017-02-10 02:13:30 -0600
committerTao Bao2017-02-10 23:21:52 -0600
commitc4a18efa84e4618820ea58dcfce68d607b5825ad (patch)
tree9f4225b5783fc88710736391939a392a0a374c75 /recovery.cpp
parentdf464dbe79202b62f8b2cf73f45e52d9f32e5e5e (diff)
downloadplatform-bootable-recovery-c4a18efa84e4618820ea58dcfce68d607b5825ad.tar.gz
platform-bootable-recovery-c4a18efa84e4618820ea58dcfce68d607b5825ad.tar.xz
platform-bootable-recovery-c4a18efa84e4618820ea58dcfce68d607b5825ad.zip
recovery: Clean up browse_directory().
Get rid of the malloc/realloc/free'd menus. browse_directory() will only be called on devices with SD card. Tested the CL by temporarily setting SDCARD_ROOT to a different location. Test: See above. Change-Id: I935e1bf4bad0273e3dff87fa2536924f1219adb5
Diffstat (limited to 'recovery.cpp')
-rw-r--r--recovery.cpp147
1 files changed, 55 insertions, 92 deletions
diff --git a/recovery.cpp b/recovery.cpp
index 29d7ab88..9dfe5d1b 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -34,7 +34,9 @@
34#include <time.h> 34#include <time.h>
35#include <unistd.h> 35#include <unistd.h>
36 36
37#include <algorithm>
37#include <chrono> 38#include <chrono>
39#include <memory>
38#include <string> 40#include <string>
39#include <vector> 41#include <vector>
40 42
@@ -656,108 +658,69 @@ get_menu_selection(const char* const * headers, const char* const * items,
656 return chosen_item; 658 return chosen_item;
657} 659}
658 660
659static int compare_string(const void* a, const void* b) { 661// Returns the selected filename, or an empty string.
660 return strcmp(*(const char**)a, *(const char**)b); 662static std::string browse_directory(const std::string& path, Device* device) {
661} 663 ensure_path_mounted(path.c_str());
662 664
663// Returns a malloc'd path, or NULL. 665 std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
664static char* browse_directory(const char* path, Device* device) { 666 if (!d) {
665 ensure_path_mounted(path); 667 PLOG(ERROR) << "error opening " << path;
668 return "";
669 }
666 670
667 DIR* d = opendir(path); 671 std::vector<std::string> dirs;
668 if (d == NULL) { 672 std::vector<std::string> zips = { "../" }; // "../" is always the first entry.
669 PLOG(ERROR) << "error opening " << path;
670 return NULL;
671 }
672 673
673 int d_size = 0; 674 dirent* de;
674 int d_alloc = 10; 675 while ((de = readdir(d.get())) != nullptr) {
675 char** dirs = (char**)malloc(d_alloc * sizeof(char*)); 676 std::string name(de->d_name);
676 int z_size = 1;
677 int z_alloc = 10;
678 char** zips = (char**)malloc(z_alloc * sizeof(char*));
679 zips[0] = strdup("../");
680 677
681 struct dirent* de; 678 if (de->d_type == DT_DIR) {
682 while ((de = readdir(d)) != NULL) { 679 // Skip "." and ".." entries.
683 int name_len = strlen(de->d_name); 680 if (name == "." || name == "..") continue;
684 681 dirs.push_back(name + "/");
685 if (de->d_type == DT_DIR) { 682 } else if (de->d_type == DT_REG && android::base::EndsWithIgnoreCase(name, ".zip")) {
686 // skip "." and ".." entries 683 zips.push_back(name);
687 if (name_len == 1 && de->d_name[0] == '.') continue;
688 if (name_len == 2 && de->d_name[0] == '.' &&
689 de->d_name[1] == '.') continue;
690
691 if (d_size >= d_alloc) {
692 d_alloc *= 2;
693 dirs = (char**)realloc(dirs, d_alloc * sizeof(char*));
694 }
695 dirs[d_size] = (char*)malloc(name_len + 2);
696 strcpy(dirs[d_size], de->d_name);
697 dirs[d_size][name_len] = '/';
698 dirs[d_size][name_len+1] = '\0';
699 ++d_size;
700 } else if (de->d_type == DT_REG &&
701 name_len >= 4 &&
702 strncasecmp(de->d_name + (name_len-4), ".zip", 4) == 0) {
703 if (z_size >= z_alloc) {
704 z_alloc *= 2;
705 zips = (char**)realloc(zips, z_alloc * sizeof(char*));
706 }
707 zips[z_size++] = strdup(de->d_name);
708 }
709 } 684 }
710 closedir(d); 685 }
711
712 qsort(dirs, d_size, sizeof(char*), compare_string);
713 qsort(zips, z_size, sizeof(char*), compare_string);
714 686
715 // append dirs to the zips list 687 std::sort(dirs.begin(), dirs.end());
716 if (d_size + z_size + 1 > z_alloc) { 688 std::sort(zips.begin(), zips.end());
717 z_alloc = d_size + z_size + 1;
718 zips = (char**)realloc(zips, z_alloc * sizeof(char*));
719 }
720 memcpy(zips + z_size, dirs, d_size * sizeof(char*));
721 free(dirs);
722 z_size += d_size;
723 zips[z_size] = NULL;
724 689
725 const char* headers[] = { "Choose a package to install:", path, NULL }; 690 // Append dirs to the zips list.
691 zips.insert(zips.end(), dirs.begin(), dirs.end());
726 692
727 char* result; 693 const char* entries[zips.size() + 1];
728 int chosen_item = 0; 694 entries[zips.size()] = nullptr;
729 while (true) { 695 for (size_t i = 0; i < zips.size(); i++) {
730 chosen_item = get_menu_selection(headers, zips, 1, chosen_item, device); 696 entries[i] = zips[i].c_str();
697 }
731 698
732 char* item = zips[chosen_item]; 699 const char* headers[] = { "Choose a package to install:", path.c_str(), nullptr };
733 int item_len = strlen(item);
734 if (chosen_item == 0) { // item 0 is always "../"
735 // go up but continue browsing (if the caller is update_directory)
736 result = NULL;
737 break;
738 }
739 700
740 char new_path[PATH_MAX]; 701 int chosen_item = 0;
741 strlcpy(new_path, path, PATH_MAX); 702 while (true) {
742 strlcat(new_path, "/", PATH_MAX); 703 chosen_item = get_menu_selection(headers, entries, 1, chosen_item, device);
743 strlcat(new_path, item, PATH_MAX);
744 704
745 if (item[item_len-1] == '/') { 705 const std::string& item = zips[chosen_item];
746 // recurse down into a subdirectory 706 if (chosen_item == 0) {
747 new_path[strlen(new_path)-1] = '\0'; // truncate the trailing '/' 707 // Go up but continue browsing (if the caller is browse_directory).
748 result = browse_directory(new_path, device); 708 return "";
749 if (result) break;
750 } else {
751 // selected a zip file: return the malloc'd path to the caller.
752 result = strdup(new_path);
753 break;
754 }
755 } 709 }
756 710
757 for (int i = 0; i < z_size; ++i) free(zips[i]); 711 std::string new_path = path + "/" + item;
758 free(zips); 712 if (new_path.back() == '/') {
713 // Recurse down into a subdirectory.
714 new_path.pop_back();
715 std::string result = browse_directory(new_path, device);
716 if (!result.empty()) return result;
717 } else {
718 // Selected a zip file: return the path to the caller.
719 return new_path;
720 }
721 }
759 722
760 return result; 723 // Unreachable.
761} 724}
762 725
763static bool yes_no(Device* device, const char* question1, const char* question2) { 726static 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) {
1065 return INSTALL_ERROR; 1028 return INSTALL_ERROR;
1066 } 1029 }
1067 1030
1068 char* path = browse_directory(SDCARD_ROOT, device); 1031 std::string path = browse_directory(SDCARD_ROOT, device);
1069 if (path == NULL) { 1032 if (path.empty()) {
1070 ui->Print("\n-- No package file selected.\n"); 1033 ui->Print("\n-- No package file selected.\n");
1071 ensure_path_unmounted(SDCARD_ROOT); 1034 ensure_path_unmounted(SDCARD_ROOT);
1072 return INSTALL_ERROR; 1035 return INSTALL_ERROR;
1073 } 1036 }
1074 1037
1075 ui->Print("\n-- Install %s ...\n", path); 1038 ui->Print("\n-- Install %s ...\n", path.c_str());
1076 set_sdcard_update_bootloader_message(); 1039 set_sdcard_update_bootloader_message();
1077 1040
1078 // We used to use fuse in a thread as opposed to a process. Since accessing 1041 // 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) {
1080 // to deadlock when a page fault occurs. (Bug: 26313124) 1043 // to deadlock when a page fault occurs. (Bug: 26313124)
1081 pid_t child; 1044 pid_t child;
1082 if ((child = fork()) == 0) { 1045 if ((child = fork()) == 0) {
1083 bool status = start_sdcard_fuse(path); 1046 bool status = start_sdcard_fuse(path.c_str());
1084 1047
1085 _exit(status ? EXIT_SUCCESS : EXIT_FAILURE); 1048 _exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
1086 } 1049 }