diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c index efb44c25e..d5117baef 100644 --- a/grub-core/commands/search.c +++ b/grub-core/commands/search.c @@ -33,11 +33,21 @@ GRUB_MOD_LICENSE ("GPLv3+"); +struct cache_entry +{ + struct cache_entry *next; + char *key; + char *value; +}; + +static struct cache_entry *cache; + void FUNC_NAME (const char *key, const char *var, int no_floppy, char **hints, unsigned nhints) { int count = 0; + int is_cache = 0; grub_fs_autoload_hook_t saved_autoload; auto int iterate_device (const char *name); @@ -50,6 +60,12 @@ FUNC_NAME (const char *key, const char *var, int no_floppy, name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9') return 0; +#ifdef DO_SEARCH_FS_UUID +#define compare_fn grub_strcasecmp +#else +#define compare_fn grub_strcmp +#endif + #ifdef DO_SEARCH_FILE { char *buf; @@ -81,10 +97,8 @@ FUNC_NAME (const char *key, const char *var, int no_floppy, fs = grub_fs_probe (dev); #ifdef DO_SEARCH_FS_UUID -#define compare_fn grub_strcasecmp #define read_fn uuid #else -#define compare_fn grub_strcmp #define read_fn label #endif @@ -106,6 +120,31 @@ FUNC_NAME (const char *key, const char *var, int no_floppy, } #endif + if (!is_cache && found && count == 0) + { + struct cache_entry *cache_ent; + cache_ent = grub_malloc (sizeof (*cache_ent)); + if (cache_ent) + { + cache_ent->key = grub_strdup (key); + cache_ent->value = grub_strdup (name); + if (cache_ent->value && cache_ent->key) + { + cache_ent->next = cache; + cache = cache_ent; + } + else + { + grub_free (cache_ent->value); + grub_free (cache_ent->key); + grub_free (cache_ent); + grub_errno = GRUB_ERR_NONE; + } + } + else + grub_errno = GRUB_ERR_NONE; + } + if (found) { count++; @@ -143,6 +182,32 @@ FUNC_NAME (const char *key, const char *var, int no_floppy, void try (void) { unsigned i; + struct cache_entry **prev; + struct cache_entry *cache_ent; + + for (prev = &cache, cache_ent = *prev; cache_ent; + prev = &cache_ent->next, cache_ent = *prev) + if (compare_fn (cache_ent->key, key) == 0) + break; + if (cache_ent) + { + is_cache = 1; + if (iterate_device (cache_ent->value)) + { + is_cache = 0; + return; + } + is_cache = 0; + /* Cache entry was outdated. Remove it. */ + if (!count) + { + grub_free (cache_ent->key); + grub_free (cache_ent->value); + grub_free (cache_ent); + *prev = cache_ent->next; + } + } + for (i = 0; i < nhints; i++) { char *end;