diff options
Diffstat (limited to 'util/path.c')
-rw-r--r-- | util/path.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/util/path.c b/util/path.c new file mode 100644 index 000000000..8e174eb43 --- /dev/null +++ b/util/path.c @@ -0,0 +1,70 @@ +/* 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; +} |