|
|
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.