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