qemu/util/path.c
Richard Henderson f3a8bdc1d5 util/path: Do not cache all filenames at startup
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>
2019-06-24 22:19:30 +02:00

71 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;
}