getcwd.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #include <stdlib.h>
  2. #include <errno.h>
  3. #include <sys/stat.h>
  4. #include <dirent.h>
  5. #include <string.h>
  6. /* #undef FAST_DIR_SEARCH_POSSIBLE on Linux */
  7. /* These functions find the absolute path to the current working directory. */
  8. static char *recurser(); /* Routine to go up tree */
  9. static char *search_dir(); /* Routine to find the step back down */
  10. static char *path_buf;
  11. static int path_size;
  12. static dev_t root_dev;
  13. static ino_t root_ino;
  14. static struct stat st;
  15. char *getcwd( char *buf, int size)
  16. {
  17. path_size = size;
  18. if (size < 3) {
  19. __set_errno(ERANGE);
  20. return NULL;
  21. }
  22. if (buf != NULL)
  23. path_buf = buf;
  24. else
  25. {
  26. path_buf = malloc (size);
  27. if (path_buf == NULL)
  28. return NULL;
  29. }
  30. strcpy(path_buf, ".");
  31. if (stat("/", &st) < 0)
  32. return NULL;
  33. root_dev = st.st_dev;
  34. root_ino = st.st_ino;
  35. return recurser();
  36. }
  37. static char *recurser()
  38. {
  39. dev_t this_dev;
  40. ino_t this_ino;
  41. if (stat(path_buf, &st) < 0)
  42. return 0;
  43. this_dev = st.st_dev;
  44. this_ino = st.st_ino;
  45. if (this_dev == root_dev && this_ino == root_ino) {
  46. strcpy(path_buf, "/");
  47. return path_buf;
  48. }
  49. if (strlen(path_buf) + 4 > path_size) {
  50. __set_errno(ERANGE);
  51. return 0;
  52. }
  53. strcat(path_buf, "/..");
  54. if (recurser() == 0)
  55. return 0;
  56. return search_dir(this_dev, this_ino);
  57. }
  58. static char *search_dir(this_dev, this_ino)
  59. dev_t this_dev;
  60. ino_t this_ino;
  61. {
  62. DIR *dp;
  63. struct dirent *d;
  64. char *ptr;
  65. int slen;
  66. #ifdef FAST_DIR_SEARCH_POSSIBLE
  67. /* The test is for ELKS lib 0.0.9, this should be fixed in the real kernel */
  68. int slow_search = (sizeof(ino_t) != sizeof(d->d_ino));
  69. #endif
  70. if (stat(path_buf, &st) < 0)
  71. return 0;
  72. #ifdef FAST_DIR_SEARCH_POSSIBLE
  73. if (this_dev != st.st_dev)
  74. slow_search = 1;
  75. #endif
  76. slen = strlen(path_buf);
  77. ptr = path_buf + slen - 1;
  78. if (*ptr != '/') {
  79. if (slen + 2 > path_size) {
  80. __set_errno(ERANGE);
  81. return 0;
  82. }
  83. strcpy(++ptr, "/");
  84. slen++;
  85. }
  86. slen++;
  87. dp = opendir(path_buf);
  88. if (dp == 0)
  89. return 0;
  90. while ((d = readdir(dp)) != 0) {
  91. #ifdef FAST_DIR_SEARCH_POSSIBLE
  92. if (slow_search || this_ino == d->d_ino) {
  93. #endif
  94. if (slen + strlen(d->d_name) > path_size) {
  95. __set_errno(ERANGE);
  96. return 0;
  97. }
  98. strcpy(ptr + 1, d->d_name);
  99. if (stat(path_buf, &st) < 0)
  100. continue;
  101. if (st.st_ino == this_ino && st.st_dev == this_dev) {
  102. closedir(dp);
  103. return path_buf;
  104. }
  105. #ifdef FAST_DIR_SEARCH_POSSIBLE
  106. }
  107. #endif
  108. }
  109. closedir(dp);
  110. __set_errno(ENOENT);
  111. return 0;
  112. }