Annotation of qemu/path.c, revision 1.1.1.3
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-common.h"
15:
16: struct pathelem
17: {
18: /* Name of this, eg. lib */
19: char *name;
20: /* Full path name, eg. /usr/gnemul/x86-linux/lib. */
21: char *pathname;
22: struct pathelem *parent;
23: /* Children */
24: unsigned int num_entries;
25: struct pathelem *entries[0];
26: };
27:
28: static struct pathelem *base;
29:
30: /* First N chars of S1 match S2, and S2 is N chars long. */
31: static int strneq(const char *s1, unsigned int n, const char *s2)
32: {
33: unsigned int i;
34:
35: for (i = 0; i < n; i++)
36: if (s1[i] != s2[i])
37: return 0;
38: return s2[i] == 0;
39: }
40:
1.1.1.3 ! root 41: static struct pathelem *add_entry(struct pathelem *root, const char *name,
! 42: unsigned char type);
1.1 root 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);
1.1.1.2 root 50: if (asprintf(&new->pathname, "%s/%s", root, name) == -1) {
51: printf("Cannot allocate memory\n");
52: exit(1);
53: }
1.1 root 54: new->num_entries = 0;
55: return new;
56: }
57:
58: #define streq(a,b) (strcmp((a), (b)) == 0)
59:
1.1.1.3 ! root 60: /* Not all systems provide this feature */
! 61: #if defined(DT_DIR) && defined(DT_UNKNOWN)
! 62: # define dirent_type(dirent) ((dirent)->d_type)
! 63: # define is_dir_maybe(type) ((type) == DT_DIR || (type) == DT_UNKNOWN)
! 64: #else
! 65: # define dirent_type(dirent) (1)
! 66: # define is_dir_maybe(type) (type)
! 67: #endif
! 68:
1.1 root 69: static struct pathelem *add_dir_maybe(struct pathelem *path)
70: {
71: DIR *dir;
72:
73: if ((dir = opendir(path->pathname)) != NULL) {
74: struct dirent *dirent;
75:
76: while ((dirent = readdir(dir)) != NULL) {
77: if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
1.1.1.3 ! root 78: path = add_entry(path, dirent->d_name, dirent_type(dirent));
1.1 root 79: }
80: }
81: closedir(dir);
82: }
83: return path;
84: }
85:
1.1.1.3 ! root 86: static struct pathelem *add_entry(struct pathelem *root, const char *name,
! 87: unsigned char type)
1.1 root 88: {
1.1.1.3 ! root 89: struct pathelem **e;
! 90:
1.1 root 91: root->num_entries++;
92:
93: root = realloc(root, sizeof(*root)
94: + sizeof(root->entries[0])*root->num_entries);
1.1.1.3 ! root 95: e = &root->entries[root->num_entries-1];
! 96:
! 97: *e = new_entry(root->pathname, root, name);
! 98: if (is_dir_maybe(type)) {
! 99: *e = add_dir_maybe(*e);
! 100: }
1.1 root 101:
102: return root;
103: }
104:
105: /* This needs to be done after tree is stabilized (ie. no more reallocs!). */
106: static void set_parents(struct pathelem *child, struct pathelem *parent)
107: {
108: unsigned int i;
109:
110: child->parent = parent;
111: for (i = 0; i < child->num_entries; i++)
112: set_parents(child->entries[i], child);
113: }
114:
115: /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
116: static const char *
117: follow_path(const struct pathelem *cursor, const char *name)
118: {
119: unsigned int i, namelen;
120:
121: name += strspn(name, "/");
122: namelen = strcspn(name, "/");
123:
124: if (namelen == 0)
125: return cursor->pathname;
126:
127: if (strneq(name, namelen, ".."))
128: return follow_path(cursor->parent, name + namelen);
129:
130: if (strneq(name, namelen, "."))
131: return follow_path(cursor, name + namelen);
132:
133: for (i = 0; i < cursor->num_entries; i++)
134: if (strneq(name, namelen, cursor->entries[i]->name))
135: return follow_path(cursor->entries[i], name + namelen);
136:
137: /* Not found */
138: return NULL;
139: }
140:
141: void init_paths(const char *prefix)
142: {
143: char pref_buf[PATH_MAX];
144:
145: if (prefix[0] == '\0' ||
146: !strcmp(prefix, "/"))
147: return;
148:
149: if (prefix[0] != '/') {
150: char *cwd = getcwd(NULL, 0);
151: size_t pref_buf_len = sizeof(pref_buf);
152:
153: if (!cwd)
154: abort();
155: pstrcpy(pref_buf, sizeof(pref_buf), cwd);
156: pstrcat(pref_buf, pref_buf_len, "/");
157: pstrcat(pref_buf, pref_buf_len, prefix);
158: free(cwd);
159: } else
160: pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1);
161:
162: base = new_entry("", NULL, pref_buf);
163: base = add_dir_maybe(base);
164: if (base->num_entries == 0) {
165: free (base);
166: base = NULL;
167: } else {
168: set_parents(base, base);
169: }
170: }
171:
172: /* Look for path in emulation dir, otherwise return name. */
173: const char *path(const char *name)
174: {
175: /* Only do absolute paths: quick and dirty, but should mostly be OK.
176: Could do relative by tracking cwd. */
177: if (!base || !name || name[0] != '/')
178: return name;
179:
180: return follow_path(base, name) ?: name;
181: }
unix.superglobalmegacorp.com