--- qemu/linux-user/path.c +++ qemu/linux-user/path.c @@ -1,147 +1,81 @@ /* 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 -#include +#include #include -#include #include -#include #include #include "qemu.h" -struct pathelem -{ - /* Name of this, eg. lib */ - char *name; - /* Full path name, eg. /usr/gnemul/x86-linux/lib. */ - char *pathname; - struct pathelem *parent; - /* Children */ - unsigned int num_entries; - struct pathelem *entries[0]; +struct path_list_head { + struct path_list_head *next; + char* path; }; -static struct pathelem *base; - -/* First N chars of S1 match S2, and S2 is N chars long. */ -static int strneq(const char *s1, unsigned int n, const char *s2) -{ - unsigned int i; - - for (i = 0; i < n; i++) - if (s1[i] != s2[i]) - return 0; - return s2[i] == 0; -} - -static struct pathelem *add_entry(struct pathelem *root, const char *name); - -static struct pathelem *new_entry(const char *root, - struct pathelem *parent, - const char *name) -{ - struct pathelem *new = malloc(sizeof(*new)); - new->name = strdup(name); - asprintf(&new->pathname, "%s/%s", root, name); - new->num_entries = 0; - return new; -} - -#define streq(a,b) (strcmp((a), (b)) == 0) - -static struct pathelem *add_dir_maybe(struct pathelem *path) -{ - DIR *dir; - - if ((dir = opendir(path->pathname)) != NULL) { - struct dirent *dirent; - - while ((dirent = readdir(dir)) != NULL) { - if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){ - path = add_entry(path, dirent->d_name); - } - } - closedir(dir); - } - return path; -} - -static struct pathelem *add_entry(struct pathelem *root, const char *name) -{ - root->num_entries++; - - root = realloc(root, sizeof(*root) - + sizeof(root->entries[0])*root->num_entries); - - root->entries[root->num_entries-1] = new_entry(root->pathname, root, name); - root->entries[root->num_entries-1] - = add_dir_maybe(root->entries[root->num_entries-1]); - return root; -} - -/* This needs to be done after tree is stabalized (ie. no more reallocs!). */ -static void set_parents(struct pathelem *child, struct pathelem *parent) -{ - unsigned int i; - - child->parent = parent; - for (i = 0; i < child->num_entries; i++) - set_parents(child->entries[i], child); -} +static struct path_list_head* list_head; void init_paths(const char *prefix) { if (prefix[0] != '/' || - prefix[0] == '\0' || - !strcmp(prefix, "/")) + prefix[0] == '\0' || + !strcmp(prefix, "/")) return; - base = new_entry("", NULL, prefix+1); - base = add_dir_maybe(base); - if (base->num_entries == 0) { - free (base); - base = NULL; - } else { - set_parents(base, base); - } -} + list_head = malloc(sizeof(struct path_list_head)); -/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */ -static const char * -follow_path(const struct pathelem *cursor, const char *name) -{ - unsigned int i, namelen; - - name += strspn(name, "/"); - namelen = strcspn(name, "/"); - - if (namelen == 0) - return cursor->pathname; - - if (strneq(name, namelen, "..")) - return follow_path(cursor->parent, name + namelen); - - if (strneq(name, namelen, ".")) - return follow_path(cursor, name + namelen); - - for (i = 0; i < cursor->num_entries; i++) - if (strneq(name, namelen, cursor->entries[i]->name)) - return follow_path(cursor->entries[i], name + namelen); - - /* Not found */ - return NULL; + /* first element of list is prefix */ + list_head->path = strdup(prefix); + list_head->next = NULL; } /* Look for path in emulation dir, otherwise return name. */ const char *path(const char *name) { + struct path_list_head *list = list_head; + int path_length = strlen(list_head->path) + strlen(name) + 1; + char *newname = malloc(path_length); + struct stat buf; + const char * result = name; + /* Only do absolute paths: quick and dirty, but should mostly be OK. Could do relative by tracking cwd. */ - if (!base || name[0] != '/') - return name; - - return follow_path(base, name) ?: name; + if (!list_head || result[0] != '/') + goto exit; + + strncpy(newname, list_head->path, path_length); + strncat(newname, name, path_length); + + /* look for place where path should be present */ + while ( list->next && (strcmp(list->next->path, newname) < 0) ) + list = list->next; + + /* if there is no path in list */ + if ( !list->next || strcmp(list->next->path, newname) ) { + /* add element to list if path exist in emulation dir */ + if ( !stat(newname, &buf) ) + { + struct path_list_head *new; + + new = malloc(sizeof(struct path_list_head)); + new->path = strdup(newname); + new->next = list->next; + list->next = new; + result = new->path; + } + + } else if ( stat(list->next->path, &buf) ) { + /* remove element from list if path doesn't exist in emulation dir */ + struct path_list_head* tmp; + + tmp = list->next; + list->next = tmp->next; + free(tmp->path); + free(tmp); + } else + result = list->next->path; + +exit: + free(newname); + return result; }