_getcwd.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /* getcwd - get current working directory Author: Terrence W. Holm */
  2. /* Directly derived from Adri Koppes' pwd(1).
  3. * Modified by Andy Tanenbaum for POSIX (29 Oct. 1989)
  4. */
  5. #include <lib.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #include <sys/dir.h>
  9. #include <string.h>
  10. #define getcwd _getcwd
  11. #define DIRECT_SIZE (sizeof (struct direct))
  12. PRIVATE _PROTOTYPE(void go_back, (char *path) );
  13. char *getcwd(buffer, size)
  14. char *buffer;
  15. int size;
  16. /* Get current working directory. */
  17. {
  18. int same_device, found, fd;
  19. char *r, path[PATH_MAX + 1], temp_name[NAME_MAX + 1];
  20. struct stat current, parent, dir_entry;
  21. struct direct d;
  22. if (buffer == (char *)NULL || size <= 0) {
  23. errno = EINVAL;
  24. return((char *)NULL);
  25. }
  26. path[0] = '\0';
  27. /* Get the inode for the current directory */
  28. if (stat(".", &current) == -1) return((char *)NULL);
  29. if ((current.st_mode & S_IFMT) != S_IFDIR) return((char *)NULL);
  30. /* Run backwards up the directory tree, grabbing dir names on the way. */
  31. while (1) {
  32. same_device = 0;
  33. found = 0;
  34. /* Get the inode for the parent directory */
  35. if (chdir("..") == -1) return((char *)NULL);
  36. if (stat(".", &parent) == -1) return((char *)NULL);
  37. if ((parent.st_mode & S_IFMT) != S_IFDIR) return((char *)NULL);
  38. if (current.st_dev == parent.st_dev) same_device = 1;
  39. /* At the root, "." is the same as ".." */
  40. if (same_device && current.st_ino == parent.st_ino) break;
  41. /* Search the parent directory for the current entry */
  42. if ((fd = open(".", O_RDONLY)) == -1) return((char *)NULL);
  43. while (!found && read(fd, (char *)&d, DIRECT_SIZE) == DIRECT_SIZE) {
  44. if (d.d_ino == 0L) continue; /* empty slot */
  45. if (same_device) {
  46. if (current.st_ino == d.d_ino) found = 1;
  47. } else {
  48. temp_name[0] = '\0';
  49. strncat(temp_name, d.d_name, NAME_MAX);
  50. if (stat(temp_name, &dir_entry) == -1) {
  51. close(fd);
  52. go_back(path);
  53. return((char *)NULL);
  54. }
  55. if (current.st_dev == dir_entry.st_dev &&
  56. current.st_ino == dir_entry.st_ino)
  57. found = 1;
  58. }
  59. }
  60. close(fd);
  61. if (!found) {
  62. go_back(path);
  63. return((char *)NULL);
  64. }
  65. if (strlen(path) + NAME_MAX + 1 > PATH_MAX) {
  66. errno = ERANGE;
  67. go_back(path);
  68. return((char *)NULL);
  69. }
  70. strcat(path, "/");
  71. strncat(path, d.d_name, NAME_MAX);
  72. current.st_dev = parent.st_dev;
  73. current.st_ino = parent.st_ino;
  74. }
  75. /* Copy the reversed path name into <buffer> */
  76. if (strlen(path) + 1 > size) {
  77. errno = ERANGE;
  78. go_back(path);
  79. return((char *)NULL);
  80. }
  81. if (strlen(path) == 0) {
  82. strcpy(buffer, "/");
  83. return(buffer);
  84. }
  85. *buffer = '\0';
  86. while ((r = strrchr(path, '/')) != (char *)NULL) {
  87. strcat(buffer, r);
  88. *r = '\0';
  89. }
  90. return(chdir(buffer) ? (char *)NULL : buffer);
  91. }
  92. PRIVATE void go_back(path)
  93. char *path;
  94. {
  95. /* If getcwd() gets in trouble and can't complete normally, reverse the
  96. * path built so far and change there so we end up in the directory that
  97. * we started in.
  98. */
  99. char *r;
  100. while ((r = strrchr(path, '/')) != (char *)NULL) {
  101. chdir(r+1);
  102. *r = '\0';
  103. }
  104. }