2
0

path.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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-common.h"
  14. struct pathelem
  15. {
  16. /* Name of this, eg. lib */
  17. char *name;
  18. /* Full path name, eg. /usr/gnemul/x86-linux/lib. */
  19. char *pathname;
  20. struct pathelem *parent;
  21. /* Children */
  22. unsigned int num_entries;
  23. struct pathelem *entries[0];
  24. };
  25. static struct pathelem *base;
  26. /* First N chars of S1 match S2, and S2 is N chars long. */
  27. static int strneq(const char *s1, unsigned int n, const char *s2)
  28. {
  29. unsigned int i;
  30. for (i = 0; i < n; i++)
  31. if (s1[i] != s2[i])
  32. return 0;
  33. return s2[i] == 0;
  34. }
  35. static struct pathelem *add_entry(struct pathelem *root, const char *name,
  36. unsigned char type);
  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. if (asprintf(&new->pathname, "%s/%s", root, name) == -1) {
  44. printf("Cannot allocate memory\n");
  45. exit(1);
  46. }
  47. new->num_entries = 0;
  48. return new;
  49. }
  50. #define streq(a,b) (strcmp((a), (b)) == 0)
  51. /* Not all systems provide this feature */
  52. #if defined(DT_DIR) && defined(DT_UNKNOWN)
  53. # define dirent_type(dirent) ((dirent)->d_type)
  54. # define is_dir_maybe(type) ((type) == DT_DIR || (type) == DT_UNKNOWN)
  55. #else
  56. # define dirent_type(dirent) (1)
  57. # define is_dir_maybe(type) (type)
  58. #endif
  59. static struct pathelem *add_dir_maybe(struct pathelem *path)
  60. {
  61. DIR *dir;
  62. if ((dir = opendir(path->pathname)) != NULL) {
  63. struct dirent *dirent;
  64. while ((dirent = readdir(dir)) != NULL) {
  65. if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
  66. path = add_entry(path, dirent->d_name, dirent_type(dirent));
  67. }
  68. }
  69. closedir(dir);
  70. }
  71. return path;
  72. }
  73. static struct pathelem *add_entry(struct pathelem *root, const char *name,
  74. unsigned char type)
  75. {
  76. struct pathelem **e;
  77. root->num_entries++;
  78. root = realloc(root, sizeof(*root)
  79. + sizeof(root->entries[0])*root->num_entries);
  80. e = &root->entries[root->num_entries-1];
  81. *e = new_entry(root->pathname, root, name);
  82. if (is_dir_maybe(type)) {
  83. *e = add_dir_maybe(*e);
  84. }
  85. return root;
  86. }
  87. /* This needs to be done after tree is stabilized (ie. no more reallocs!). */
  88. static void set_parents(struct pathelem *child, struct pathelem *parent)
  89. {
  90. unsigned int i;
  91. child->parent = parent;
  92. for (i = 0; i < child->num_entries; i++)
  93. set_parents(child->entries[i], child);
  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. name += strspn(name, "/");
  101. namelen = strcspn(name, "/");
  102. if (namelen == 0)
  103. return cursor->pathname;
  104. if (strneq(name, namelen, ".."))
  105. return follow_path(cursor->parent, name + namelen);
  106. if (strneq(name, namelen, "."))
  107. return follow_path(cursor, name + namelen);
  108. for (i = 0; i < cursor->num_entries; i++)
  109. if (strneq(name, namelen, cursor->entries[i]->name))
  110. return follow_path(cursor->entries[i], name + namelen);
  111. /* Not found */
  112. return NULL;
  113. }
  114. void init_paths(const char *prefix)
  115. {
  116. char pref_buf[PATH_MAX];
  117. if (prefix[0] == '\0' ||
  118. !strcmp(prefix, "/"))
  119. return;
  120. if (prefix[0] != '/') {
  121. char *cwd = getcwd(NULL, 0);
  122. size_t pref_buf_len = sizeof(pref_buf);
  123. if (!cwd)
  124. abort();
  125. pstrcpy(pref_buf, sizeof(pref_buf), cwd);
  126. pstrcat(pref_buf, pref_buf_len, "/");
  127. pstrcat(pref_buf, pref_buf_len, prefix);
  128. free(cwd);
  129. } else
  130. pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1);
  131. base = new_entry("", NULL, pref_buf);
  132. base = add_dir_maybe(base);
  133. if (base->num_entries == 0) {
  134. free (base);
  135. base = NULL;
  136. } else {
  137. set_parents(base, base);
  138. }
  139. }
  140. /* Look for path in emulation dir, otherwise return name. */
  141. const char *path(const char *name)
  142. {
  143. /* Only do absolute paths: quick and dirty, but should mostly be OK.
  144. Could do relative by tracking cwd. */
  145. if (!base || !name || name[0] != '/')
  146. return name;
  147. return follow_path(base, name) ?: name;
  148. }