Annotation of qemu/path.c, revision 1.1

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: 
        !            41: static struct pathelem *add_entry(struct pathelem *root, const char *name);
        !            42: 
        !            43: static struct pathelem *new_entry(const char *root,
        !            44:                                   struct pathelem *parent,
        !            45:                                   const char *name)
        !            46: {
        !            47:     struct pathelem *new = malloc(sizeof(*new));
        !            48:     new->name = strdup(name);
        !            49:     asprintf(&new->pathname, "%s/%s", root, name);
        !            50:     new->num_entries = 0;
        !            51:     return new;
        !            52: }
        !            53: 
        !            54: #define streq(a,b) (strcmp((a), (b)) == 0)
        !            55: 
        !            56: static struct pathelem *add_dir_maybe(struct pathelem *path)
        !            57: {
        !            58:     DIR *dir;
        !            59: 
        !            60:     if ((dir = opendir(path->pathname)) != NULL) {
        !            61:         struct dirent *dirent;
        !            62: 
        !            63:         while ((dirent = readdir(dir)) != NULL) {
        !            64:             if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
        !            65:                 path = add_entry(path, dirent->d_name);
        !            66:             }
        !            67:         }
        !            68:         closedir(dir);
        !            69:     }
        !            70:     return path;
        !            71: }
        !            72: 
        !            73: static struct pathelem *add_entry(struct pathelem *root, const char *name)
        !            74: {
        !            75:     root->num_entries++;
        !            76: 
        !            77:     root = realloc(root, sizeof(*root)
        !            78:                    + sizeof(root->entries[0])*root->num_entries);
        !            79: 
        !            80:     root->entries[root->num_entries-1] = new_entry(root->pathname, root, name);
        !            81:     root->entries[root->num_entries-1]
        !            82:         = add_dir_maybe(root->entries[root->num_entries-1]);
        !            83:     return root;
        !            84: }
        !            85: 
        !            86: /* This needs to be done after tree is stabilized (ie. no more reallocs!). */
        !            87: static void set_parents(struct pathelem *child, struct pathelem *parent)
        !            88: {
        !            89:     unsigned int i;
        !            90: 
        !            91:     child->parent = parent;
        !            92:     for (i = 0; i < child->num_entries; i++)
        !            93:         set_parents(child->entries[i], child);
        !            94: }
        !            95: 
        !            96: /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
        !            97: static const char *
        !            98: follow_path(const struct pathelem *cursor, const char *name)
        !            99: {
        !           100:     unsigned int i, namelen;
        !           101: 
        !           102:     name += strspn(name, "/");
        !           103:     namelen = strcspn(name, "/");
        !           104: 
        !           105:     if (namelen == 0)
        !           106:         return cursor->pathname;
        !           107: 
        !           108:     if (strneq(name, namelen, ".."))
        !           109:         return follow_path(cursor->parent, name + namelen);
        !           110: 
        !           111:     if (strneq(name, namelen, "."))
        !           112:         return follow_path(cursor, name + namelen);
        !           113: 
        !           114:     for (i = 0; i < cursor->num_entries; i++)
        !           115:         if (strneq(name, namelen, cursor->entries[i]->name))
        !           116:             return follow_path(cursor->entries[i], name + namelen);
        !           117: 
        !           118:     /* Not found */
        !           119:     return NULL;
        !           120: }
        !           121: 
        !           122: void init_paths(const char *prefix)
        !           123: {
        !           124:     char pref_buf[PATH_MAX];
        !           125: 
        !           126:     if (prefix[0] == '\0' ||
        !           127:         !strcmp(prefix, "/"))
        !           128:         return;
        !           129: 
        !           130:     if (prefix[0] != '/') {
        !           131:         char *cwd = getcwd(NULL, 0);
        !           132:         size_t pref_buf_len = sizeof(pref_buf);
        !           133: 
        !           134:         if (!cwd)
        !           135:             abort();
        !           136:         pstrcpy(pref_buf, sizeof(pref_buf), cwd);
        !           137:         pstrcat(pref_buf, pref_buf_len, "/");
        !           138:         pstrcat(pref_buf, pref_buf_len, prefix);
        !           139:         free(cwd);
        !           140:     } else
        !           141:         pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1);
        !           142: 
        !           143:     base = new_entry("", NULL, pref_buf);
        !           144:     base = add_dir_maybe(base);
        !           145:     if (base->num_entries == 0) {
        !           146:         free (base);
        !           147:         base = NULL;
        !           148:     } else {
        !           149:         set_parents(base, base);
        !           150:     }
        !           151: }
        !           152: 
        !           153: /* Look for path in emulation dir, otherwise return name. */
        !           154: const char *path(const char *name)
        !           155: {
        !           156:     /* Only do absolute paths: quick and dirty, but should mostly be OK.
        !           157:        Could do relative by tracking cwd. */
        !           158:     if (!base || !name || name[0] != '/')
        !           159:         return name;
        !           160: 
        !           161:     return follow_path(base, name) ?: name;
        !           162: }

unix.superglobalmegacorp.com