|
|
1.1 ! root 1: /* Code to mangle pathnames into those matching a given prefix. ! 2: eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so"); ! 3: ! 4: The assumption is that this area does not change. ! 5: */ ! 6: #include <sys/types.h> ! 7: #include <sys/param.h> ! 8: #include <dirent.h> ! 9: #include <unistd.h> ! 10: #include <stdlib.h> ! 11: #include <string.h> ! 12: #include <errno.h> ! 13: #include <stdio.h> ! 14: #include "qemu.h" ! 15: #include "qemu-common.h" ! 16: ! 17: struct pathelem ! 18: { ! 19: /* Name of this, eg. lib */ ! 20: char *name; ! 21: /* Full path name, eg. /usr/gnemul/x86-linux/lib. */ ! 22: char *pathname; ! 23: struct pathelem *parent; ! 24: /* Children */ ! 25: unsigned int num_entries; ! 26: struct pathelem *entries[0]; ! 27: }; ! 28: ! 29: static struct pathelem *base; ! 30: ! 31: /* First N chars of S1 match S2, and S2 is N chars long. */ ! 32: static int strneq(const char *s1, unsigned int n, const char *s2) ! 33: { ! 34: unsigned int i; ! 35: ! 36: for (i = 0; i < n; i++) ! 37: if (s1[i] != s2[i]) ! 38: return 0; ! 39: return s2[i] == 0; ! 40: } ! 41: ! 42: static struct pathelem *add_entry(struct pathelem *root, const char *name); ! 43: ! 44: static struct pathelem *new_entry(const char *root, ! 45: struct pathelem *parent, ! 46: const char *name) ! 47: { ! 48: struct pathelem *new = malloc(sizeof(*new)); ! 49: new->name = strdup(name); ! 50: asprintf(&new->pathname, "%s/%s", root, name); ! 51: new->num_entries = 0; ! 52: return new; ! 53: } ! 54: ! 55: #define streq(a,b) (strcmp((a), (b)) == 0) ! 56: ! 57: static struct pathelem *add_dir_maybe(struct pathelem *path) ! 58: { ! 59: DIR *dir; ! 60: ! 61: if ((dir = opendir(path->pathname)) != NULL) { ! 62: struct dirent *dirent; ! 63: ! 64: while ((dirent = readdir(dir)) != NULL) { ! 65: if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){ ! 66: path = add_entry(path, dirent->d_name); ! 67: } ! 68: } ! 69: closedir(dir); ! 70: } ! 71: return path; ! 72: } ! 73: ! 74: static struct pathelem *add_entry(struct pathelem *root, const char *name) ! 75: { ! 76: root->num_entries++; ! 77: ! 78: root = realloc(root, sizeof(*root) ! 79: + sizeof(root->entries[0])*root->num_entries); ! 80: ! 81: root->entries[root->num_entries-1] = new_entry(root->pathname, root, name); ! 82: root->entries[root->num_entries-1] ! 83: = add_dir_maybe(root->entries[root->num_entries-1]); ! 84: return root; ! 85: } ! 86: ! 87: /* This needs to be done after tree is stabilized (ie. no more reallocs!). */ ! 88: static void set_parents(struct pathelem *child, struct pathelem *parent) ! 89: { ! 90: unsigned int i; ! 91: ! 92: child->parent = parent; ! 93: for (i = 0; i < child->num_entries; i++) ! 94: set_parents(child->entries[i], child); ! 95: } ! 96: ! 97: /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */ ! 98: static const char * ! 99: follow_path(const struct pathelem *cursor, const char *name) ! 100: { ! 101: unsigned int i, namelen; ! 102: ! 103: name += strspn(name, "/"); ! 104: namelen = strcspn(name, "/"); ! 105: ! 106: if (namelen == 0) ! 107: return cursor->pathname; ! 108: ! 109: if (strneq(name, namelen, "..")) ! 110: return follow_path(cursor->parent, name + namelen); ! 111: ! 112: if (strneq(name, namelen, ".")) ! 113: return follow_path(cursor, name + namelen); ! 114: ! 115: for (i = 0; i < cursor->num_entries; i++) ! 116: if (strneq(name, namelen, cursor->entries[i]->name)) ! 117: return follow_path(cursor->entries[i], name + namelen); ! 118: ! 119: /* Not found */ ! 120: return NULL; ! 121: } ! 122: ! 123: void init_paths(const char *prefix) ! 124: { ! 125: char pref_buf[PATH_MAX]; ! 126: ! 127: if (prefix[0] == '\0' || ! 128: !strcmp(prefix, "/")) ! 129: return; ! 130: ! 131: if (prefix[0] != '/') { ! 132: char *cwd = getcwd(NULL, 0); ! 133: size_t pref_buf_len = sizeof(pref_buf); ! 134: ! 135: if (!cwd) ! 136: abort(); ! 137: pstrcpy(pref_buf, sizeof(pref_buf), cwd); ! 138: pstrcat(pref_buf, pref_buf_len, "/"); ! 139: pstrcat(pref_buf, pref_buf_len, prefix); ! 140: free(cwd); ! 141: } else ! 142: pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1); ! 143: ! 144: base = new_entry("", NULL, pref_buf); ! 145: base = add_dir_maybe(base); ! 146: if (base->num_entries == 0) { ! 147: free (base); ! 148: base = NULL; ! 149: } else { ! 150: set_parents(base, base); ! 151: } ! 152: } ! 153: ! 154: /* Look for path in emulation dir, otherwise return name. */ ! 155: const char *path(const char *name) ! 156: { ! 157: /* Only do absolute paths: quick and dirty, but should mostly be OK. ! 158: Could do relative by tracking cwd. */ ! 159: if (!base || name[0] != '/') ! 160: return name; ! 161: ! 162: return follow_path(base, name) ?: name; ! 163: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.