path.c 3.8 KB

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