diff --git a/ChangeLog b/ChangeLog index 92d2ca1cc..7c3b98f63 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-11-01 Vladimir Serbinenko + + * grub-core/kern/efi/efi.c (grub_efi_get_filename): Avoid inefficient + realloc. + 2013-11-01 Vladimir Serbinenko * util/grub-mkrescue.in: Do not use UUID search on EFI. diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c index e8a62ec7b..8be9b01db 100644 --- a/grub-core/kern/efi/efi.c +++ b/grub-core/kern/efi/efi.c @@ -309,7 +309,34 @@ grub_efi_modules_addr (void) char * grub_efi_get_filename (grub_efi_device_path_t *dp) { - char *name = 0; + char *name = 0, *p; + grub_size_t filesize = 0; + + while (1) + { + grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); + grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); + + if (type == GRUB_EFI_END_DEVICE_PATH_TYPE) + break; + if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE + && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE) + { + grub_efi_uint16_t len; + len = ((GRUB_EFI_DEVICE_PATH_LENGTH (dp) - 4) + / sizeof (grub_efi_char16_t)); + filesize += GRUB_MAX_UTF8_PER_UTF16 * len + 1; + } + + dp = GRUB_EFI_NEXT_DEVICE_PATH (dp); + } + + if (!filesize) + return NULL; + + p = name = grub_malloc (filesize); + if (!name) + return NULL; while (1) { @@ -323,45 +350,25 @@ grub_efi_get_filename (grub_efi_device_path_t *dp) { grub_efi_file_path_device_path_t *fp; grub_efi_uint16_t len; - char *p; - grub_size_t size; - if (name) - { - size = grub_strlen (name); - name[size] = '/'; - size++; - } - else - size = 0; + if (p != name) + *p++ = '/'; len = ((GRUB_EFI_DEVICE_PATH_LENGTH (dp) - 4) / sizeof (grub_efi_char16_t)); - p = grub_realloc (name, size + len * 4 + 1); - if (! p) - { - grub_free (name); - return 0; - } - - name = p; fp = (grub_efi_file_path_device_path_t *) dp; - *grub_utf16_to_utf8 ((grub_uint8_t *) name + size, - fp->path_name, len) = '\0'; + p = (char *) grub_utf16_to_utf8 ((unsigned char *) p, fp->path_name, len); } dp = GRUB_EFI_NEXT_DEVICE_PATH (dp); } - if (name) - { - /* EFI breaks paths with backslashes. */ - char *p; + *p = '\0'; - for (p = name; *p; p++) - if (*p == '\\') - *p = '/'; - } + /* EFI breaks paths with backslashes. */ + for (p = name; *p; p++) + if (*p == '\\') + *p = '/'; return name; }