1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2010 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #pragma prototyped 23 /* 24 * Glenn Fowler 25 * AT&T Research 26 * 27 * in-place path name canonicalization -- preserves the logical view 28 * pointer to trailing 0 in path returned 29 * 30 * remove redundant .'s and /'s 31 * move ..'s to the front 32 * /.. preserved (for pdu and newcastle hacks) 33 * FS_3D handles ... 34 * if (flags&PATH_PHYSICAL) then symlinks resolved at each component 35 * if (flags&PATH_DOTDOT) then each .. checked for access 36 * if (flags&PATH_EXISTS) then path must exist at each component 37 * if (flags&PATH_VERIFIED(n)) then first n chars of path exist 38 * 39 * longer pathname possible if (flags&PATH_PHYSICAL) or FS_3D ... involved 40 * 0 returned on error and if (flags&(PATH_DOTDOT|PATH_EXISTS)) then path 41 * will contain the components following the failure point 42 */ 43 44 #include <ast.h> 45 #include <ls.h> 46 #include <fs3d.h> 47 #include <error.h> 48 49 char* 50 pathcanon(char* path, int flags) 51 { 52 register char* p; 53 register char* r; 54 register char* s; 55 register char* t; 56 register int dots; 57 char* phys; 58 char* v; 59 int loop; 60 int oerrno; 61 #if defined(FS_3D) 62 long visits = 0; 63 #endif 64 65 oerrno = errno; 66 dots = loop = 0; 67 phys = path; 68 v = path + ((flags >> 5) & 01777); 69 if (*path == '/') 70 { 71 if (*(path + 1) == '/' && *astconf("PATH_LEADING_SLASHES", NiL, NiL) == '1') 72 do path++; while (*path == '/' && *(path + 1) == '/'); 73 if (!*(path + 1)) 74 return path + 1; 75 } 76 p = r = s = t = path; 77 for (;;) switch (*t++ = *s++) 78 { 79 case '.': 80 dots++; 81 break; 82 case 0: 83 s--; 84 /*FALLTHROUGH*/ 85 case '/': 86 while (*s == '/') s++; 87 switch (dots) 88 { 89 case 1: 90 t -= 2; 91 break; 92 case 2: 93 if ((flags & (PATH_DOTDOT|PATH_EXISTS)) == PATH_DOTDOT && (t - 2) >= v) 94 { 95 struct stat st; 96 97 *(t - 2) = 0; 98 if (stat(phys, &st)) 99 { 100 strcpy(path, s); 101 return 0; 102 } 103 *(t - 2) = '.'; 104 } 105 #if PRESERVE_TRAILING_SLASH 106 if (t - 5 < r) r = t; 107 #else 108 if (t - 5 < r) 109 { 110 if (t - 4 == r) t = r + 1; 111 else r = t; 112 } 113 #endif 114 else for (t -= 5; t > r && *(t - 1) != '/'; t--); 115 break; 116 case 3: 117 #if defined(FS_3D) 118 { 119 char* x; 120 char* o; 121 int c; 122 123 o = t; 124 if ((t -= 5) <= path) t = path + 1; 125 c = *t; 126 *t = 0; 127 if (x = pathnext(phys, s - (*s != 0), &visits)) 128 { 129 r = path; 130 if (t == r + 1) x = r; 131 v = s = t = x; 132 } 133 else 134 { 135 *t = c; 136 t = o; 137 } 138 } 139 #else 140 r = t; 141 #endif 142 break; 143 default: 144 if ((flags & PATH_PHYSICAL) && loop < 32 && (t - 1) > path) 145 { 146 int c; 147 char buf[PATH_MAX]; 148 149 c = *(t - 1); 150 *(t - 1) = 0; 151 dots = pathgetlink(phys, buf, sizeof(buf)); 152 *(t - 1) = c; 153 if (dots > 0) 154 { 155 loop++; 156 strcpy(buf + dots, s - (*s != 0)); 157 if (*buf == '/') p = r = path; 158 v = s = t = p; 159 strcpy(p, buf); 160 } 161 else if (dots < 0 && errno == ENOENT) 162 { 163 if (flags & PATH_EXISTS) 164 { 165 strcpy(path, s); 166 return 0; 167 } 168 flags &= ~(PATH_PHYSICAL|PATH_DOTDOT); 169 } 170 dots = 4; 171 } 172 break; 173 } 174 if (dots >= 4 && (flags & PATH_EXISTS) && (t - 1) >= v && (t > path + 1 || t > path && *(t - 1) && *(t - 1) != '/')) 175 { 176 struct stat st; 177 178 *(t - 1) = 0; 179 if (stat(phys, &st)) 180 { 181 strcpy(path, s); 182 return 0; 183 } 184 v = t; 185 if (*s) *(t - 1) = '/'; 186 } 187 if (!*s) 188 { 189 if (t > path && !*(t - 1)) t--; 190 if (t == path) *t++ = '.'; 191 #if DONT_PRESERVE_TRAILING_SLASH 192 else if (t > path + 1 && *(t - 1) == '/') t--; 193 #else 194 else if ((s <= path || *(s - 1) != '/') && t > path + 1 && *(t - 1) == '/') t--; 195 #endif 196 *t = 0; 197 errno = oerrno; 198 return t; 199 } 200 dots = 0; 201 p = t; 202 break; 203 default: 204 dots = 4; 205 break; 206 } 207 } 208