path.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. The assumption is that this area does not change.
  4. */
  5. #include <sys/types.h>
  6. #include <sys/param.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. #include "qemu-common.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. };
  26. static struct pathelem *base;
  27. /* First N chars of S1 match S2, and S2 is N chars long. */
  28. static int strneq(const char *s1, unsigned int n, const char *s2)
  29. {
  30. unsigned int i;
  31. for (i = 0; i < n; i++)
  32. if (s1[i] != s2[i])
  33. return 0;
  34. return s2[i] == 0;
  35. }
  36. static struct pathelem *add_entry(struct pathelem *root, const char *name);
  37. static struct pathelem *new_entry(const char *root,
  38. struct pathelem *parent,
  39. const char *name)
  40. {
  41. struct pathelem *new = malloc(sizeof(*new));
  42. new->name = strdup(name);
  43. asprintf(&new->pathname, "%s/%s", root, name);
  44. new->num_entries = 0;
  45. return new;
  46. }
  47. #define streq(a,b) (strcmp((a), (b)) == 0)
  48. static struct pathelem *add_dir_maybe(struct pathelem *path)
  49. {
  50. DIR *dir;
  51. if ((dir = opendir(path->pathname)) != NULL) {
  52. struct dirent *dirent;
  53. while ((dirent = readdir(dir)) != NULL) {
  54. if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
  55. path = add_entry(path, dirent->d_name);
  56. }
  57. }
  58. closedir(dir);
  59. }
  60. return path;
  61. }
  62. static struct pathelem *add_entry(struct pathelem *root, const char *name)
  63. {
  64. root->num_entries++;
  65. root = realloc(root, sizeof(*root)
  66. + sizeof(root->entries[0])*root->num_entries);
  67. root->entries[root->num_entries-1] = new_entry(root->pathname, root, name);
  68. root->entries[root->num_entries-1]
  69. = add_dir_maybe(root->entries[root->num_entries-1]);
  70. return root;
  71. }
  72. /* This needs to be done after tree is stabilized (ie. no more reallocs!). */
  73. static void set_parents(struct pathelem *child, struct pathelem *parent)
  74. {
  75. unsigned int i;
  76. child->parent = parent;
  77. for (i = 0; i < child->num_entries; i++)
  78. set_parents(child->entries[i], child);
  79. }
  80. /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
  81. static const char *
  82. follow_path(const struct pathelem *cursor, const char *name)
  83. {
  84. unsigned int i, namelen;
  85. name += strspn(name, "/");
  86. namelen = strcspn(name, "/");
  87. if (namelen == 0)
  88. return cursor->pathname;
  89. if (strneq(name, namelen, ".."))
  90. return follow_path(cursor->parent, name + namelen);
  91. if (strneq(name, namelen, "."))
  92. return follow_path(cursor, name + namelen);
  93. for (i = 0; i < cursor->num_entries; i++)
  94. if (strneq(name, namelen, cursor->entries[i]->name))
  95. return follow_path(cursor->entries[i], name + namelen);
  96. /* Not found */
  97. return NULL;
  98. }
  99. void init_paths(const char *prefix)
  100. {
  101. char pref_buf[PATH_MAX];
  102. if (prefix[0] == '\0' ||
  103. !strcmp(prefix, "/"))
  104. return;
  105. if (prefix[0] != '/') {
  106. char *cwd = getcwd(NULL, 0);
  107. size_t pref_buf_len = sizeof(pref_buf);
  108. if (!cwd)
  109. abort();
  110. pstrcpy(pref_buf, sizeof(pref_buf), cwd);
  111. pstrcat(pref_buf, pref_buf_len, "/");
  112. pstrcat(pref_buf, pref_buf_len, prefix);
  113. free(cwd);
  114. } else
  115. pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1);
  116. base = new_entry("", NULL, pref_buf);
  117. base = add_dir_maybe(base);
  118. if (base->num_entries == 0) {
  119. free (base);
  120. base = NULL;
  121. } else {
  122. set_parents(base, base);
  123. }
  124. }
  125. /* Look for path in emulation dir, otherwise return name. */
  126. const char *path(const char *name)
  127. {
  128. /* Only do absolute paths: quick and dirty, but should mostly be OK.
  129. Could do relative by tracking cwd. */
  130. if (!base || name[0] != '/')
  131. return name;
  132. return follow_path(base, name) ?: name;
  133. }