pathsub.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. /*
  7. ** Pathname subroutines.
  8. **
  9. ** Brendan Eich, 8/29/95
  10. */
  11. #include <assert.h>
  12. #include <dirent.h>
  13. #include <errno.h>
  14. #include <stdarg.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <unistd.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include "pathsub.h"
  22. #ifdef USE_REENTRANT_LIBC
  23. #include <libc_r.h>
  24. #endif /* USE_REENTRANT_LIBC */
  25. char *program;
  26. void
  27. fail(char *format, ...)
  28. {
  29. int error;
  30. va_list ap;
  31. #ifdef USE_REENTRANT_LIBC
  32. R_STRERROR_INIT_R();
  33. #endif
  34. error = errno;
  35. fprintf(stderr, "%s: ", program);
  36. va_start(ap, format);
  37. vfprintf(stderr, format, ap);
  38. va_end(ap);
  39. if (error)
  40. #ifdef USE_REENTRANT_LIBC
  41. R_STRERROR_R(errno);
  42. fprintf(stderr, ": %s", r_strerror_r);
  43. #else
  44. fprintf(stderr, ": %s", strerror(errno));
  45. #endif
  46. putc('\n', stderr);
  47. exit(1);
  48. }
  49. char *
  50. getcomponent(char *path, char *name)
  51. {
  52. if (*path == '\0')
  53. return 0;
  54. if (*path == '/') {
  55. *name++ = '/';
  56. } else {
  57. do {
  58. *name++ = *path++;
  59. } while (*path != '/' && *path != '\0');
  60. }
  61. *name = '\0';
  62. while (*path == '/')
  63. path++;
  64. return path;
  65. }
  66. #ifdef UNIXWARE
  67. /* Sigh. The static buffer in Unixware's readdir is too small. */
  68. struct dirent * readdir(DIR *d)
  69. {
  70. static struct dirent *buf = NULL;
  71. #define MAX_PATH_LEN 1024
  72. if(buf == NULL)
  73. buf = (struct dirent *) malloc(sizeof(struct dirent) + MAX_PATH_LEN)
  74. ;
  75. return(readdir_r(d, buf));
  76. }
  77. #endif
  78. char *
  79. ino2name(ino_t ino, char *dir)
  80. {
  81. DIR *dp;
  82. struct dirent *ep;
  83. char *name;
  84. dp = opendir("..");
  85. if (!dp)
  86. fail("cannot read parent directory");
  87. for (;;) {
  88. if (!(ep = readdir(dp)))
  89. fail("cannot find current directory");
  90. if (ep->d_ino == ino)
  91. break;
  92. }
  93. name = xstrdup(ep->d_name);
  94. closedir(dp);
  95. return name;
  96. }
  97. void *
  98. xmalloc(size_t size)
  99. {
  100. void *p = malloc(size);
  101. if (!p)
  102. fail("cannot allocate %u bytes", size);
  103. return p;
  104. }
  105. char *
  106. xstrdup(char *s)
  107. {
  108. return strcpy(xmalloc(strlen(s) + 1), s);
  109. }
  110. char *
  111. xbasename(char *path)
  112. {
  113. char *cp;
  114. while ((cp = strrchr(path, '/')) && cp[1] == '\0')
  115. *cp = '\0';
  116. if (!cp) return path;
  117. return cp + 1;
  118. }
  119. void
  120. xchdir(char *dir)
  121. {
  122. if (chdir(dir) < 0)
  123. fail("cannot change directory to %s", dir);
  124. }
  125. int
  126. relatepaths(char *from, char *to, char *outpath)
  127. {
  128. char *cp, *cp2;
  129. int len;
  130. char buf[NAME_MAX];
  131. assert(*from == '/' && *to == '/');
  132. for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++)
  133. if (*cp == '\0')
  134. break;
  135. while (cp[-1] != '/')
  136. cp--, cp2--;
  137. if (cp - 1 == to) {
  138. /* closest common ancestor is /, so use full pathname */
  139. len = strlen(strcpy(outpath, to));
  140. if (outpath[len] != '/') {
  141. outpath[len++] = '/';
  142. outpath[len] = '\0';
  143. }
  144. } else {
  145. len = 0;
  146. while ((cp2 = getcomponent(cp2, buf)) != 0) {
  147. strcpy(outpath + len, "../");
  148. len += 3;
  149. }
  150. while ((cp = getcomponent(cp, buf)) != 0) {
  151. sprintf(outpath + len, "%s/", buf);
  152. len += strlen(outpath + len);
  153. }
  154. }
  155. return len;
  156. }
  157. void
  158. reversepath(char *inpath, char *name, int len, char *outpath)
  159. {
  160. char *cp, *cp2;
  161. char buf[NAME_MAX];
  162. struct stat sb;
  163. cp = strcpy(outpath + PATH_MAX - (len + 1), name);
  164. cp2 = inpath;
  165. while ((cp2 = getcomponent(cp2, buf)) != 0) {
  166. if (strcmp(buf, ".") == 0)
  167. continue;
  168. if (strcmp(buf, "..") == 0) {
  169. if (stat(".", &sb) < 0)
  170. fail("cannot stat current directory");
  171. name = ino2name(sb.st_ino, "..");
  172. len = strlen(name);
  173. cp -= len + 1;
  174. strcpy(cp, name);
  175. cp[len] = '/';
  176. free(name);
  177. xchdir("..");
  178. } else {
  179. cp -= 3;
  180. strncpy(cp, "../", 3);
  181. xchdir(buf);
  182. }
  183. }
  184. strcpy(outpath, cp);
  185. }