File:  [Qemu by Fabrice Bellard] / qemu / path.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:56:08 2018 UTC (23 months, 2 weeks ago) by root
Branches: qemu, MAIN
CVS tags: qemu1101, qemu1001, qemu1000, qemu0151, HEAD
qemu 0.15.1

    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:                                   unsigned char type);
   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:     if (asprintf(&new->pathname, "%s/%s", root, name) == -1) {
   51:         printf("Cannot allocate memory\n");
   52:         exit(1);
   53:     }
   54:     new->num_entries = 0;
   55:     return new;
   56: }
   57: 
   58: #define streq(a,b) (strcmp((a), (b)) == 0)
   59: 
   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: 
   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,"..")){
   78:                 path = add_entry(path, dirent->d_name, dirent_type(dirent));
   79:             }
   80:         }
   81:         closedir(dir);
   82:     }
   83:     return path;
   84: }
   85: 
   86: static struct pathelem *add_entry(struct pathelem *root, const char *name,
   87:                                   unsigned char type)
   88: {
   89:     struct pathelem **e;
   90: 
   91:     root->num_entries++;
   92: 
   93:     root = realloc(root, sizeof(*root)
   94:                    + sizeof(root->entries[0])*root->num_entries);
   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:     }
  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