|
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 /* |
|
6 ** Pathname subroutines. |
|
7 ** |
|
8 ** Brendan Eich, 8/29/95 |
|
9 */ |
|
10 #include <assert.h> |
|
11 #include <sys/types.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/stat.h> |
|
20 #include "pathsub.h" |
|
21 |
|
22 #ifdef USE_REENTRANT_LIBC |
|
23 #include <libc_r.h> |
|
24 #endif |
|
25 |
|
26 #ifdef SUNOS4 |
|
27 #include "sunos4.h" |
|
28 #endif |
|
29 |
|
30 #ifndef D_INO |
|
31 #define D_INO d_ino |
|
32 #endif |
|
33 |
|
34 char *program; |
|
35 |
|
36 void |
|
37 fail(char *format, ...) |
|
38 { |
|
39 int error; |
|
40 va_list ap; |
|
41 |
|
42 #ifdef USE_REENTRANT_LIBC |
|
43 R_STRERROR_INIT_R(); |
|
44 #endif |
|
45 |
|
46 error = errno; |
|
47 fprintf(stderr, "%s: ", program); |
|
48 va_start(ap, format); |
|
49 vfprintf(stderr, format, ap); |
|
50 va_end(ap); |
|
51 if (error) { |
|
52 |
|
53 #ifdef USE_REENTRANT_LIBC |
|
54 R_STRERROR_R(errno); |
|
55 fprintf(stderr, ": %s", r_strerror_r); |
|
56 #else |
|
57 fprintf(stderr, ": %s", strerror(errno)); |
|
58 #endif |
|
59 } |
|
60 |
|
61 putc('\n', stderr); |
|
62 exit(1); |
|
63 } |
|
64 |
|
65 char * |
|
66 getcomponent(char *path, char *name) |
|
67 { |
|
68 if (*path == '\0') |
|
69 return 0; |
|
70 if (*path == '/') { |
|
71 *name++ = '/'; |
|
72 } else { |
|
73 do { |
|
74 *name++ = *path++; |
|
75 } while (*path != '/' && *path != '\0'); |
|
76 } |
|
77 *name = '\0'; |
|
78 while (*path == '/') |
|
79 path++; |
|
80 return path; |
|
81 } |
|
82 |
|
83 #ifdef LAME_READDIR |
|
84 #include <sys/param.h> |
|
85 /* |
|
86 ** The static buffer in Unixware's readdir is too small. |
|
87 */ |
|
88 struct dirent *readdir(DIR *d) |
|
89 { |
|
90 static struct dirent *buf = NULL; |
|
91 |
|
92 if(buf == NULL) |
|
93 buf = (struct dirent *) malloc(sizeof(struct dirent) + MAXPATHLEN); |
|
94 return(readdir_r(d, buf)); |
|
95 } |
|
96 #endif |
|
97 |
|
98 char * |
|
99 ino2name(ino_t ino) |
|
100 { |
|
101 DIR *dp; |
|
102 struct dirent *ep; |
|
103 char *name; |
|
104 |
|
105 dp = opendir(".."); |
|
106 if (!dp) |
|
107 fail("cannot read parent directory"); |
|
108 for (;;) { |
|
109 if (!(ep = readdir(dp))) |
|
110 fail("cannot find current directory"); |
|
111 if (ep->D_INO == ino) |
|
112 break; |
|
113 } |
|
114 name = xstrdup(ep->d_name); |
|
115 closedir(dp); |
|
116 return name; |
|
117 } |
|
118 |
|
119 void * |
|
120 xmalloc(size_t size) |
|
121 { |
|
122 void *p = malloc(size); |
|
123 if (!p) |
|
124 fail("cannot allocate %u bytes", size); |
|
125 return p; |
|
126 } |
|
127 |
|
128 char * |
|
129 xstrdup(char *s) |
|
130 { |
|
131 return strcpy(xmalloc(strlen(s) + 1), s); |
|
132 } |
|
133 |
|
134 char * |
|
135 xbasename(char *path) |
|
136 { |
|
137 char *cp; |
|
138 |
|
139 while ((cp = strrchr(path, '/')) && cp[1] == '\0') |
|
140 *cp = '\0'; |
|
141 if (!cp) return path; |
|
142 return cp + 1; |
|
143 } |
|
144 |
|
145 void |
|
146 xchdir(char *dir) |
|
147 { |
|
148 if (chdir(dir) < 0) |
|
149 fail("cannot change directory to %s", dir); |
|
150 } |
|
151 |
|
152 int |
|
153 relatepaths(char *from, char *to, char *outpath) |
|
154 { |
|
155 char *cp, *cp2; |
|
156 int len; |
|
157 char buf[NAME_MAX]; |
|
158 |
|
159 assert(*from == '/' && *to == '/'); |
|
160 for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++) |
|
161 if (*cp == '\0') |
|
162 break; |
|
163 while (cp[-1] != '/') |
|
164 cp--, cp2--; |
|
165 if (cp - 1 == to) { |
|
166 /* closest common ancestor is /, so use full pathname */ |
|
167 len = strlen(strcpy(outpath, to)); |
|
168 if (outpath[len] != '/') { |
|
169 outpath[len++] = '/'; |
|
170 outpath[len] = '\0'; |
|
171 } |
|
172 } else { |
|
173 len = 0; |
|
174 while ((cp2 = getcomponent(cp2, buf)) != 0) { |
|
175 strcpy(outpath + len, "../"); |
|
176 len += 3; |
|
177 } |
|
178 while ((cp = getcomponent(cp, buf)) != 0) { |
|
179 sprintf(outpath + len, "%s/", buf); |
|
180 len += strlen(outpath + len); |
|
181 } |
|
182 } |
|
183 return len; |
|
184 } |
|
185 |
|
186 void |
|
187 reversepath(char *inpath, char *name, int len, char *outpath) |
|
188 { |
|
189 char *cp, *cp2; |
|
190 char buf[NAME_MAX]; |
|
191 struct stat sb; |
|
192 |
|
193 cp = strcpy(outpath + PATH_MAX - (len + 1), name); |
|
194 cp2 = inpath; |
|
195 while ((cp2 = getcomponent(cp2, buf)) != 0) { |
|
196 if (strcmp(buf, ".") == 0) |
|
197 continue; |
|
198 if (strcmp(buf, "..") == 0) { |
|
199 if (stat(".", &sb) < 0) |
|
200 fail("cannot stat current directory"); |
|
201 name = ino2name(sb.st_ino); |
|
202 len = strlen(name); |
|
203 cp -= len + 1; |
|
204 strcpy(cp, name); |
|
205 cp[len] = '/'; |
|
206 free(name); |
|
207 xchdir(".."); |
|
208 } else { |
|
209 cp -= 3; |
|
210 strncpy(cp, "../", 3); |
|
211 xchdir(buf); |
|
212 } |
|
213 } |
|
214 strcpy(outpath, cp); |
|
215 } |