diff --git a/include/console.h b/include/console.h index 063bc20f1..923ba9796 100644 --- a/include/console.h +++ b/include/console.h @@ -63,6 +63,19 @@ count_lines(CHAR16 *str_arr[]) return i; } +static inline int +find_first_existing_line(CHAR16 *str_arr[], UINTN start, UINTN end) +{ + UINTN i = start; + + while (i < end) { + if (str_arr[i]) + break; + i++; + } + return i; +} + #define NOSEL 0x7fffffff typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL; diff --git a/lib/simple_file.c b/lib/simple_file.c index fc082bed1..530a20c5e 100644 --- a/lib/simple_file.c +++ b/lib/simple_file.c @@ -170,7 +170,7 @@ simple_file_write_all(EFI_FILE *file, UINTN size, void *buffer) EFI_STATUS simple_volume_selector(CHAR16 **title, CHAR16 **selected, EFI_HANDLE *h) { - UINTN count, i; + UINTN count, i, j; EFI_HANDLE *vol_handles = NULL; EFI_STATUS efi_status; CHAR16 **entries; @@ -225,6 +225,29 @@ simple_volume_selector(CHAR16 **title, CHAR16 **selected, EFI_HANDLE *h) } entries[i] = NULL; + /* + * If HandleProtocol or OpenVolume fails, we will end up with non-contiguous array + * and lose some valid partitions to browse because of how count_lines works. + * Compact the array if needed. + */ + if ((UINTN)count_lines(entries) < i) { + UINTN temp; + for (j = (UINTN)count_lines(entries); j < i; j++) { + /* Skip contiguous valid entries */ + if (entries[j]) + continue; + + temp = (UINTN)find_first_existing_line(entries, j, i); + /* If reached the end, there is nothing to compact anymore. */ + if (temp >= i) + break; + + /* Move the entry to the first free slot and remove old entry record. */ + entries[j] = entries[temp]; + entries[temp] = NULL; + } + } + val = console_select(title, entries, 0); if (val >= 0) {