--- ../qemu/linux-user/path.c 2007-03-20 12:54:22 +0200 +++ qemu-0.9.0.cvs20070320/linux-user/path.c 2007-03-20 16:02:43 +0200 @@ -1,147 +1,75 @@ /* 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]; -}; - -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; +struct path_list_head { + struct path_list_head *next; - 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; + char* orig_path; + char* dest_path; +}; - 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); - } -} - -/* 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; + list_head = malloc(sizeof(struct path_list_head)); - 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->orig_path = strdup("/"); + list_head->dest_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 *tmp = list_head; + /* Only do absolute paths: quick and dirty, but should mostly be OK. Could do relative by tracking cwd. */ - if (!base || name[0] != '/') - return name; + if (!list_head || name[0] != '/') + return name; + + /* look for place where path should be present */ + while ( tmp->next && (strcmp(tmp->next->orig_path, name) < 0) ) + tmp = tmp->next; + + /* if there is no path in list */ + if ( !tmp->next || strcmp(tmp->next->orig_path, name) ) + { + struct stat buf; + struct path_list_head *new; + int path_length = strlen(list_head->dest_path) + strlen(name) + 1; + char *newname = malloc(path_length); + + strncpy(newname, list_head->dest_path, path_length); + strncat(newname, name, path_length); + + new = malloc(sizeof(struct path_list_head)); + + new->orig_path = strdup(name); + /* new->dest_path contains path in emulation dir, otherwise NULL */ + new->dest_path = stat(newname, &buf) ? NULL : newname; + + /* freeing memory if no path in emulation dir */ + if (new->dest_path == NULL) + free(newname); + + new->next = tmp->next; + tmp->next = new; + } - return follow_path(base, name) ?: name; + return tmp->next->dest_path ? tmp->next->dest_path : name; }