Skip to content

Commit

Permalink
simple_file: Compact the array of filesystem entries
Browse files Browse the repository at this point in the history
If HandleProtocol or OpenVolume fails, the entries array will
become non-contiguous, i.e. will have NULL pointers between valid
volume names in the array. Because of that count_lines may return
a lower number of entries than expected. As a result one may not
browse all valid filesystems in the file explorer.

Compact the array by locating the holes in filesystem entries array
and fill them with valid entries from higher indices, if any.
As a result, count_lines should return proper length and there
won't be any accesses to invalid entries or lost partitions.

Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com>
  • Loading branch information
miczyg1 committed Dec 16, 2023
1 parent 4b0b46c commit ff0a509
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 1 deletion.
13 changes: 13 additions & 0 deletions include/console.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
25 changes: 24 additions & 1 deletion lib/simple_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit ff0a509

Please sign in to comment.