(linenum→info "unix/slp.c:2238")

qemu/0.9.1/linux-user/path.c

    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 <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"
   14: 
   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: };
   26: 
   27: static struct pathelem *base;
   28: 
   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;
   33: 
   34:     for (i = 0; i < n; i++)
   35:         if (s1[i] != s2[i])
   36:             return 0;
   37:     return s2[i] == 0;
   38: }
   39: 
   40: static struct pathelem *add_entry(struct pathelem *root, const char *name);
   41: 
   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: }
   52: 
   53: #define streq(a,b) (strcmp((a), (b)) == 0)
   54: 
   55: static struct pathelem *add_dir_maybe(struct pathelem *path)
   56: {
   57:     DIR *dir;
   58: 
   59:     if ((dir = opendir(path->pathname)) != NULL) {
   60:         struct dirent *dirent;
   61: 
   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: }
   71: 
   72: static struct pathelem *add_entry(struct pathelem *root, const char *name)
   73: {
   74:     root->num_entries++;
   75: 
   76:     root = realloc(root, sizeof(*root)
   77:                    + sizeof(root->entries[0])*root->num_entries);
   78: 
   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: }
   84: 
   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;
   89: 
   90:     child->parent = parent;
   91:     for (i = 0; i < child->num_entries; i++)
   92:         set_parents(child->entries[i], child);
   93: }
   94: 
   95: /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
   96: static const char *
   97: follow_path(const struct pathelem *cursor, const char *name)
   98: {
   99:     unsigned int i, namelen;
  100: 
  101:     name += strspn(name, "/");
  102:     namelen = strcspn(name, "/");
  103: 
  104:     if (namelen == 0)
  105:         return cursor->pathname;
  106: 
  107:     if (strneq(name, namelen, ".."))
  108:         return follow_path(cursor->parent, name + namelen);
  109: 
  110:     if (strneq(name, namelen, "."))
  111:         return follow_path(cursor, name + namelen);
  112: 
  113:     for (i = 0; i < cursor->num_entries; i++)
  114:         if (strneq(name, namelen, cursor->entries[i]->name))
  115:             return follow_path(cursor->entries[i], name + namelen);
  116: 
  117:     /* Not found */
  118:     return NULL;
  119: }
  120: 
  121: void init_paths(const char *prefix)
  122: {
  123:     char pref_buf[PATH_MAX];
  124: 
  125:     if (prefix[0] == '\0' ||
  126:         !strcmp(prefix, "/"))
  127:         return;
  128: 
  129:     if (prefix[0] != '/') {
  130:         char *cwd = get_current_dir_name();
  131:         if (!cwd)
  132:             abort();
  133:         strcpy(pref_buf, cwd);
  134:         strcat(pref_buf, "/");
  135:         strcat(pref_buf, prefix);
  136:         free(cwd);
  137:     } else
  138:         strcpy(pref_buf,prefix + 1);
  139: 
  140:     base = new_entry("", NULL, pref_buf);
  141:     base = add_dir_maybe(base);
  142:     if (base->num_entries == 0) {
  143:         free (base);
  144:         base = NULL;
  145:     } else {
  146:         set_parents(base, base);
  147:     }
  148: }
  149: 
  150: /* Look for path in emulation dir, otherwise return name. */
  151: const char *path(const char *name)
  152: {
  153:     /* Only do absolute paths: quick and dirty, but should mostly be OK.
  154:        Could do relative by tracking cwd. */
  155:     if (!base || name[0] != '/')
  156:         return name;
  157: 
  158:     return follow_path(base, name) ?: name;
  159: }
Syntax (Markdown)