mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-02 22:41:07 +00:00
f3a8bdc1d5
If one uses -L $PATH to point to a full chroot, the startup time is significant. In addition, the existing probing algorithm fails to handle symlink loops. Instead, probe individual paths on demand. Cache both positive and negative results within $PATH, so that any one filename is probed only once. Use glib filename functions for clarity. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Tested-by: Laurent Vivier <laurent@vivier.eu> Message-Id: <20190519201953.20161-2-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
70 lines
1.8 KiB
C
70 lines
1.8 KiB
C
/* Code to mangle pathnames into those matching a given prefix.
|
|
eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so");
|
|
|
|
The assumption is that this area does not change.
|
|
*/
|
|
#include "qemu/osdep.h"
|
|
#include <sys/param.h>
|
|
#include <dirent.h>
|
|
#include "qemu/cutils.h"
|
|
#include "qemu/path.h"
|
|
#include "qemu/thread.h"
|
|
|
|
static const char *base;
|
|
static GHashTable *hash;
|
|
static QemuMutex lock;
|
|
|
|
void init_paths(const char *prefix)
|
|
{
|
|
if (prefix[0] == '\0' || !strcmp(prefix, "/")) {
|
|
return;
|
|
}
|
|
|
|
if (prefix[0] == '/') {
|
|
base = g_strdup(prefix);
|
|
} else {
|
|
char *cwd = g_get_current_dir();
|
|
base = g_build_filename(cwd, prefix, NULL);
|
|
g_free(cwd);
|
|
}
|
|
|
|
hash = g_hash_table_new(g_str_hash, g_str_equal);
|
|
qemu_mutex_init(&lock);
|
|
}
|
|
|
|
/* Look for path in emulation dir, otherwise return name. */
|
|
const char *path(const char *name)
|
|
{
|
|
gpointer key, value;
|
|
const char *ret;
|
|
|
|
/* Only do absolute paths: quick and dirty, but should mostly be OK. */
|
|
if (!base || !name || name[0] != '/') {
|
|
return name;
|
|
}
|
|
|
|
qemu_mutex_lock(&lock);
|
|
|
|
/* Have we looked up this file before? */
|
|
if (g_hash_table_lookup_extended(hash, name, &key, &value)) {
|
|
ret = value ? value : name;
|
|
} else {
|
|
char *save = g_strdup(name);
|
|
char *full = g_build_filename(base, name, NULL);
|
|
|
|
/* Look for the path; record the result, pass or fail. */
|
|
if (access(full, F_OK) == 0) {
|
|
/* Exists. */
|
|
g_hash_table_insert(hash, save, full);
|
|
ret = full;
|
|
} else {
|
|
/* Does not exist. */
|
|
g_free(full);
|
|
g_hash_table_insert(hash, save, NULL);
|
|
ret = name;
|
|
}
|
|
}
|
|
|
|
qemu_mutex_unlock(&lock);
|
|
return ret;
|
|
}
|