1 : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 : /*
38 : ** Pathname subroutines.
39 : **
40 : ** Brendan Eich, 8/29/95
41 : */
42 : #include <assert.h>
43 : #include <sys/types.h>
44 : #include <dirent.h>
45 : #include <errno.h>
46 : #include <stdarg.h>
47 : #include <stdio.h>
48 : #include <stdlib.h>
49 : #include <string.h>
50 : #include <unistd.h>
51 : #include <sys/stat.h>
52 : #include "pathsub.h"
53 :
54 : #ifdef USE_REENTRANT_LIBC
55 : #include <libc_r.h>
56 : #endif
57 :
58 : #ifdef SUNOS4
59 : #include "sunos4.h"
60 : #endif
61 :
62 : #ifndef D_INO
63 : #define D_INO d_ino
64 : #endif
65 :
66 : char *program;
67 :
68 : void
69 0 : fail(char *format, ...)
70 : {
71 : int error;
72 : va_list ap;
73 :
74 : #ifdef USE_REENTRANT_LIBC
75 : R_STRERROR_INIT_R();
76 : #endif
77 :
78 0 : error = errno;
79 0 : fprintf(stderr, "%s: ", program);
80 0 : va_start(ap, format);
81 0 : vfprintf(stderr, format, ap);
82 0 : va_end(ap);
83 0 : if (error) {
84 :
85 : #ifdef USE_REENTRANT_LIBC
86 : R_STRERROR_R(errno);
87 : fprintf(stderr, ": %s", r_strerror_r);
88 : #else
89 0 : fprintf(stderr, ": %s", strerror(errno));
90 : #endif
91 : }
92 :
93 0 : putc('\n', stderr);
94 0 : exit(1);
95 : }
96 :
97 : char *
98 72 : getcomponent(char *path, char *name)
99 : {
100 72 : if (*path == '\0')
101 22 : return 0;
102 50 : if (*path == '/') {
103 0 : *name++ = '/';
104 : } else {
105 : do {
106 178 : *name++ = *path++;
107 178 : } while (*path != '/' && *path != '\0');
108 : }
109 50 : *name = '\0';
110 128 : while (*path == '/')
111 28 : path++;
112 50 : return path;
113 : }
114 :
115 : #ifdef LAME_READDIR
116 : #include <sys/param.h>
117 : /*
118 : ** The static buffer in Unixware's readdir is too small.
119 : */
120 : struct dirent *readdir(DIR *d)
121 : {
122 : static struct dirent *buf = NULL;
123 :
124 : if(buf == NULL)
125 : buf = (struct dirent *) malloc(sizeof(struct dirent) + MAXPATHLEN);
126 : return(readdir_r(d, buf));
127 : }
128 : #endif
129 :
130 : char *
131 0 : ino2name(ino_t ino)
132 : {
133 : DIR *dp;
134 : struct dirent *ep;
135 : char *name;
136 :
137 0 : dp = opendir("..");
138 0 : if (!dp)
139 0 : fail("cannot read parent directory");
140 : for (;;) {
141 0 : if (!(ep = readdir(dp)))
142 0 : fail("cannot find current directory");
143 0 : if (ep->D_INO == ino)
144 : break;
145 0 : }
146 0 : name = xstrdup(ep->d_name);
147 0 : closedir(dp);
148 0 : return name;
149 : }
150 :
151 : void *
152 72 : xmalloc(size_t size)
153 : {
154 72 : void *p = malloc(size);
155 72 : if (!p)
156 0 : fail("cannot allocate %u bytes", size);
157 72 : return p;
158 : }
159 :
160 : char *
161 0 : xstrdup(char *s)
162 : {
163 0 : return strcpy(xmalloc(strlen(s) + 1), s);
164 : }
165 :
166 : char *
167 61 : xbasename(char *path)
168 : {
169 : char *cp;
170 :
171 122 : while ((cp = strrchr(path, '/')) && cp[1] == '\0')
172 0 : *cp = '\0';
173 61 : if (!cp) return path;
174 50 : return cp + 1;
175 : }
176 :
177 : void
178 26 : xchdir(char *dir)
179 : {
180 26 : if (chdir(dir) < 0)
181 0 : fail("cannot change directory to %s", dir);
182 26 : }
183 :
184 : int
185 11 : relatepaths(char *from, char *to, char *outpath)
186 : {
187 : char *cp, *cp2;
188 : int len;
189 : char buf[NAME_MAX];
190 :
191 11 : assert(*from == '/' && *to == '/');
192 578 : for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++)
193 567 : if (*cp == '\0')
194 0 : break;
195 25 : while (cp[-1] != '/')
196 3 : cp--, cp2--;
197 11 : if (cp - 1 == to) {
198 : /* closest common ancestor is /, so use full pathname */
199 0 : len = strlen(strcpy(outpath, to));
200 0 : if (outpath[len] != '/') {
201 0 : outpath[len++] = '/';
202 0 : outpath[len] = '\0';
203 : }
204 : } else {
205 11 : len = 0;
206 45 : while ((cp2 = getcomponent(cp2, buf)) != 0) {
207 23 : strcpy(outpath + len, "../");
208 23 : len += 3;
209 : }
210 49 : while ((cp = getcomponent(cp, buf)) != 0) {
211 27 : sprintf(outpath + len, "%s/", buf);
212 27 : len += strlen(outpath + len);
213 : }
214 : }
215 11 : return len;
216 : }
217 :
218 : void
219 0 : reversepath(char *inpath, char *name, int len, char *outpath)
220 : {
221 : char *cp, *cp2;
222 : char buf[NAME_MAX];
223 : struct stat sb;
224 :
225 0 : cp = strcpy(outpath + PATH_MAX - (len + 1), name);
226 0 : cp2 = inpath;
227 0 : while ((cp2 = getcomponent(cp2, buf)) != 0) {
228 0 : if (strcmp(buf, ".") == 0)
229 0 : continue;
230 0 : if (strcmp(buf, "..") == 0) {
231 0 : if (stat(".", &sb) < 0)
232 0 : fail("cannot stat current directory");
233 0 : name = ino2name(sb.st_ino);
234 0 : len = strlen(name);
235 0 : cp -= len + 1;
236 0 : strcpy(cp, name);
237 0 : cp[len] = '/';
238 0 : free(name);
239 0 : xchdir("..");
240 : } else {
241 0 : cp -= 3;
242 0 : strncpy(cp, "../", 3);
243 0 : xchdir(buf);
244 : }
245 : }
246 0 : strcpy(outpath, cp);
247 0 : }
|