|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 /* |
|
6 ** Pathname subroutines. |
|
7 */ |
|
8 #include <assert.h> |
|
9 #if defined(FREEBSD) || defined(BSDI) || defined(DARWIN) |
|
10 #include <sys/types.h> |
|
11 #endif /* FREEBSD */ |
|
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 |
|
26 char *program; |
|
27 |
|
28 void |
|
29 fail(char *format, ...) |
|
30 { |
|
31 int error; |
|
32 va_list ap; |
|
33 |
|
34 #ifdef USE_REENTRANT_LIBC |
|
35 R_STRERROR_INIT_R(); |
|
36 #endif |
|
37 |
|
38 error = errno; |
|
39 fprintf(stderr, "%s: ", program); |
|
40 va_start(ap, format); |
|
41 vfprintf(stderr, format, ap); |
|
42 va_end(ap); |
|
43 if (error) { |
|
44 |
|
45 #ifdef USE_REENTRANT_LIBC |
|
46 R_STRERROR_R(errno); |
|
47 fprintf(stderr, ": %s", r_strerror_r); |
|
48 #else |
|
49 fprintf(stderr, ": %s", strerror(errno)); |
|
50 #endif |
|
51 } |
|
52 |
|
53 putc('\n', stderr); |
|
54 abort(); |
|
55 exit(1); |
|
56 } |
|
57 |
|
58 char * |
|
59 getcomponent(char *path, char *name) |
|
60 { |
|
61 if (*path == '\0') |
|
62 return 0; |
|
63 if (*path == '/') { |
|
64 *name++ = '/'; |
|
65 } else { |
|
66 do { |
|
67 *name++ = *path++; |
|
68 } while (*path != '/' && *path != '\0'); |
|
69 } |
|
70 *name = '\0'; |
|
71 while (*path == '/') |
|
72 path++; |
|
73 return path; |
|
74 } |
|
75 |
|
76 #ifdef UNIXWARE |
|
77 /* The static buffer in Unixware's readdir is too small. */ |
|
78 struct dirent * readdir(DIR *d) |
|
79 { |
|
80 static struct dirent *buf = NULL; |
|
81 #define MAX_PATH_LEN 1024 |
|
82 |
|
83 if (buf == NULL) |
|
84 buf = (struct dirent *)xmalloc(sizeof(struct dirent) + MAX_PATH_LEN) ; |
|
85 return readdir_r(d, buf); |
|
86 } |
|
87 #endif |
|
88 |
|
89 /* APPARENT BUG - ignores argument "dir", uses ".." instead. */ |
|
90 char * |
|
91 ino2name(ino_t ino, char *dir) |
|
92 { |
|
93 DIR *dp; |
|
94 struct dirent *ep; |
|
95 char *name; |
|
96 |
|
97 dp = opendir(".."); /* XXX */ |
|
98 if (!dp) |
|
99 fail("cannot read parent directory"); |
|
100 for (;;) { |
|
101 if (!(ep = readdir(dp))) |
|
102 fail("cannot find current directory"); |
|
103 if (ep->d_ino == ino) |
|
104 break; |
|
105 } |
|
106 name = xstrdup(ep->d_name); |
|
107 closedir(dp); |
|
108 return name; |
|
109 } |
|
110 |
|
111 void * |
|
112 xmalloc(size_t size) |
|
113 { |
|
114 void *p; |
|
115 |
|
116 if (size <= 0) |
|
117 fail("attempted to allocate %u bytes", size); |
|
118 p = malloc(size); |
|
119 if (!p) |
|
120 fail("cannot allocate %u bytes", size); |
|
121 return p; |
|
122 } |
|
123 |
|
124 char * |
|
125 xstrdup(char *s) |
|
126 { |
|
127 if (!s || !s[0]) |
|
128 fail("Null pointer or empty string passed to xstrdup()"); |
|
129 return strcpy((char*)xmalloc(strlen(s) + 1), s); |
|
130 } |
|
131 |
|
132 char * |
|
133 xbasename(char *path) |
|
134 { |
|
135 char *cp; |
|
136 |
|
137 if (!path || !path[0]) |
|
138 fail("Null pointer or empty string passed to xbasename()"); |
|
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 (!dir || !dir[0]) |
|
149 fail("Null pointer or empty string passed to xchdir()"); |
|
150 if (chdir(dir) < 0) |
|
151 fail("cannot change directory to %s", dir); |
|
152 } |
|
153 |
|
154 int |
|
155 relatepaths(char *from, char *to, char *outpath) |
|
156 { |
|
157 char *cp, *cp2; |
|
158 int len; |
|
159 char buf[NAME_MAX]; |
|
160 |
|
161 assert(*from == '/' && *to == '/'); |
|
162 if (!from || *from != '/') |
|
163 fail("relatepaths: from path does not start with /"); |
|
164 if (!to || *to != '/') |
|
165 fail("relatepaths: to path does not start with /"); |
|
166 |
|
167 for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++) |
|
168 if (*cp == '\0') |
|
169 break; |
|
170 while (cp[-1] != '/') |
|
171 cp--, cp2--; |
|
172 if (cp - 1 == to) { |
|
173 /* closest common ancestor is /, so use full pathname */ |
|
174 len = strlen(strcpy(outpath, to)); |
|
175 if (outpath[len] != '/') { |
|
176 outpath[len++] = '/'; |
|
177 outpath[len] = '\0'; |
|
178 } |
|
179 } else { |
|
180 len = 0; |
|
181 while ((cp2 = getcomponent(cp2, buf)) != 0) { |
|
182 strcpy(outpath + len, "../"); |
|
183 len += 3; |
|
184 } |
|
185 while ((cp = getcomponent(cp, buf)) != 0) { |
|
186 sprintf(outpath + len, "%s/", buf); |
|
187 len += strlen(outpath + len); |
|
188 } |
|
189 } |
|
190 return len; |
|
191 } |
|
192 |
|
193 void |
|
194 reversepath(char *inpath, char *name, int len, char *outpath) |
|
195 { |
|
196 char *cp, *cp2; |
|
197 char buf[NAME_MAX]; |
|
198 struct stat sb; |
|
199 |
|
200 cp = strcpy(outpath + PATH_MAX - (len + 1), name); |
|
201 cp2 = inpath; |
|
202 while ((cp2 = getcomponent(cp2, buf)) != 0) { |
|
203 if (strcmp(buf, ".") == 0) |
|
204 continue; |
|
205 if (strcmp(buf, "..") == 0) { |
|
206 if (stat(".", &sb) < 0) |
|
207 fail("cannot stat current directory"); |
|
208 name = ino2name(sb.st_ino, ".."); |
|
209 len = strlen(name); |
|
210 cp -= len + 1; |
|
211 strcpy(cp, name); |
|
212 cp[len] = '/'; |
|
213 free(name); |
|
214 xchdir(".."); |
|
215 } else { |
|
216 cp -= 3; |
|
217 strncpy(cp, "../", 3); |
|
218 xchdir(buf); |
|
219 } |
|
220 } |
|
221 strcpy(outpath, cp); |
|
222 } |
|
223 |
|
224 void |
|
225 diagnosePath(const char * path) |
|
226 { |
|
227 char * myPath; |
|
228 char * slash; |
|
229 int rv; |
|
230 struct stat sb; |
|
231 char buf[BUFSIZ]; |
|
232 |
|
233 if (!path || !path[0]) |
|
234 fail("Null pointer or empty string passed to mkdirs()"); |
|
235 myPath = strdup(path); |
|
236 if (!myPath) |
|
237 fail("strdup() failed!"); |
|
238 do { |
|
239 rv = lstat(myPath, &sb); |
|
240 if (rv < 0) { |
|
241 perror(myPath); |
|
242 } else if (S_ISLNK(sb.st_mode)) { |
|
243 rv = readlink(myPath, buf, sizeof(buf) - 1); |
|
244 if (rv < 0) { |
|
245 perror("readlink"); |
|
246 buf[0] = 0; |
|
247 } else { |
|
248 buf[rv] = 0; |
|
249 } |
|
250 fprintf(stderr, "%s is a link to %s\n", myPath, buf); |
|
251 } else if (S_ISDIR(sb.st_mode)) { |
|
252 fprintf(stderr, "%s is a directory\n", myPath); |
|
253 rv = access(myPath, X_OK); |
|
254 if (rv < 0) { |
|
255 fprintf(stderr, "%s: no search permission\n", myPath); |
|
256 } |
|
257 } else { |
|
258 fprintf(stderr, "%s is a file !?!\n", myPath); |
|
259 rv = access(myPath, F_OK); |
|
260 if (rv < 0) { |
|
261 fprintf(stderr, "%s does not exist\n", myPath); |
|
262 } |
|
263 } |
|
264 |
|
265 /* chop path off one level. */ |
|
266 slash = strrchr(myPath, '/'); |
|
267 if (!slash) |
|
268 slash = strrchr(myPath, '\\'); |
|
269 if (!slash) |
|
270 slash = myPath; |
|
271 *slash = 0; |
|
272 } while (myPath[0]); |
|
273 free(myPath); |
|
274 } |