ia64/xen-unstable

view tools/ioemu/path.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 8e5fc5fe636c
children
line source
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");
4 The assumption is that this area does not change.
5 */
6 #include <sys/types.h>
7 #include <dirent.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <errno.h>
12 #include <stdio.h>
13 #include "qemu.h"
15 struct pathelem
16 {
17 /* Name of this, eg. lib */
18 char *name;
19 /* Full path name, eg. /usr/gnemul/x86-linux/lib. */
20 char *pathname;
21 struct pathelem *parent;
22 /* Children */
23 unsigned int num_entries;
24 struct pathelem *entries[0];
25 };
27 static struct pathelem *base;
29 /* First N chars of S1 match S2, and S2 is N chars long. */
30 static int strneq(const char *s1, unsigned int n, const char *s2)
31 {
32 unsigned int i;
34 for (i = 0; i < n; i++)
35 if (s1[i] != s2[i])
36 return 0;
37 return s2[i] == 0;
38 }
40 static struct pathelem *add_entry(struct pathelem *root, const char *name);
42 static struct pathelem *new_entry(const char *root,
43 struct pathelem *parent,
44 const char *name)
45 {
46 struct pathelem *new = malloc(sizeof(*new));
47 new->name = strdup(name);
48 asprintf(&new->pathname, "%s/%s", root, name);
49 new->num_entries = 0;
50 return new;
51 }
53 #define streq(a,b) (strcmp((a), (b)) == 0)
55 static struct pathelem *add_dir_maybe(struct pathelem *path)
56 {
57 DIR *dir;
59 if ((dir = opendir(path->pathname)) != NULL) {
60 struct dirent *dirent;
62 while ((dirent = readdir(dir)) != NULL) {
63 if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
64 path = add_entry(path, dirent->d_name);
65 }
66 }
67 closedir(dir);
68 }
69 return path;
70 }
72 static struct pathelem *add_entry(struct pathelem *root, const char *name)
73 {
74 root->num_entries++;
76 root = realloc(root, sizeof(*root)
77 + sizeof(root->entries[0])*root->num_entries);
79 root->entries[root->num_entries-1] = new_entry(root->pathname, root, name);
80 root->entries[root->num_entries-1]
81 = add_dir_maybe(root->entries[root->num_entries-1]);
82 return root;
83 }
85 /* This needs to be done after tree is stabalized (ie. no more reallocs!). */
86 static void set_parents(struct pathelem *child, struct pathelem *parent)
87 {
88 unsigned int i;
90 child->parent = parent;
91 for (i = 0; i < child->num_entries; i++)
92 set_parents(child->entries[i], child);
93 }
95 void init_paths(const char *prefix)
96 {
97 if (prefix[0] != '/' ||
98 prefix[0] == '\0' ||
99 !strcmp(prefix, "/"))
100 return;
102 base = new_entry("", NULL, prefix+1);
103 base = add_dir_maybe(base);
104 if (base->num_entries == 0) {
105 free (base);
106 base = NULL;
107 } else {
108 set_parents(base, base);
109 }
110 }
112 /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
113 static const char *
114 follow_path(const struct pathelem *cursor, const char *name)
115 {
116 unsigned int i, namelen;
118 name += strspn(name, "/");
119 namelen = strcspn(name, "/");
121 if (namelen == 0)
122 return cursor->pathname;
124 if (strneq(name, namelen, ".."))
125 return follow_path(cursor->parent, name + namelen);
127 if (strneq(name, namelen, "."))
128 return follow_path(cursor, name + namelen);
130 for (i = 0; i < cursor->num_entries; i++)
131 if (strneq(name, namelen, cursor->entries[i]->name))
132 return follow_path(cursor->entries[i], name + namelen);
134 /* Not found */
135 return NULL;
136 }
138 /* Look for path in emulation dir, otherwise return name. */
139 const char *path(const char *name)
140 {
141 /* Only do absolute paths: quick and dirty, but should mostly be OK.
142 Could do relative by tracking cwd. */
143 if (!base || name[0] != '/')
144 return name;
146 return follow_path(base, name) ?: name;
147 }