1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 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 == '/' && *(path + 1) == '/' && *astconf("PATH_LEADING_SLASHES", NiL, NiL) == '1') 70 do path++; while (*path == '/' && *(path + 1) == '/'); 71 p = r = s = t = path; 72 for (;;) switch (*t++ = *s++) 73 { 74 case '.': 75 dots++; 76 break; 77 case 0: 78 s--; 79 /*FALLTHROUGH*/ 80 case '/': 81 while (*s == '/') s++; 82 switch (dots) 83 { 84 case 1: 85 t -= 2; 86 break; 87 case 2: 88 if ((flags & (PATH_DOTDOT|PATH_EXISTS)) == PATH_DOTDOT && (t - 2) >= v) 89 { 90 struct stat st; 91 92 *(t - 2) = 0; 93 if (stat(phys, &st)) 94 { 95 strcpy(path, s); 96 return 0; 97 } 98 *(t - 2) = '.'; 99 } 100 #if PRESERVE_TRAILING_SLASH 101 if (t - 5 < r) r = t; 102 #else 103 if (t - 5 < r) 104 { 105 if (t - 4 == r) t = r + 1; 106 else r = t; 107 } 108 #endif 109 else for (t -= 5; t > r && *(t - 1) != '/'; t--); 110 break; 111 case 3: 112 #if defined(FS_3D) 113 { 114 char* x; 115 char* o; 116 int c; 117 118 o = t; 119 if ((t -= 5) <= path) t = path + 1; 120 c = *t; 121 *t = 0; 122 if (x = pathnext(phys, s - (*s != 0), &visits)) 123 { 124 r = path; 125 if (t == r + 1) x = r; 126 v = s = t = x; 127 } 128 else 129 { 130 *t = c; 131 t = o; 132 } 133 } 134 #else 135 r = t; 136 #endif 137 break; 138 default: 139 if ((flags & PATH_PHYSICAL) && loop < 32 && (t - 1) > path) 140 { 141 int c; 142 char buf[PATH_MAX]; 143 144 c = *(t - 1); 145 *(t - 1) = 0; 146 dots = pathgetlink(phys, buf, sizeof(buf)); 147 *(t - 1) = c; 148 if (dots > 0) 149 { 150 loop++; 151 strcpy(buf + dots, s - (*s != 0)); 152 if (*buf == '/') p = r = path; 153 v = s = t = p; 154 strcpy(p, buf); 155 } 156 else if (dots < 0 && errno == ENOENT) 157 { 158 if (flags & PATH_EXISTS) 159 { 160 strcpy(path, s); 161 return 0; 162 } 163 flags &= ~(PATH_PHYSICAL|PATH_DOTDOT); 164 } 165 dots = 4; 166 } 167 break; 168 } 169 if (dots >= 4 && (flags & PATH_EXISTS) && (t - 1) >= v && (t > path + 1 || t > path && *(t - 1) && *(t - 1) != '/')) 170 { 171 struct stat st; 172 173 *(t - 1) = 0; 174 if (stat(phys, &st)) 175 { 176 strcpy(path, s); 177 return 0; 178 } 179 v = t; 180 if (*s) *(t - 1) = '/'; 181 } 182 if (!*s) 183 { 184 if (t > path && !*(t - 1)) t--; 185 if (t == path) *t++ = '.'; 186 #if DONT_PRESERVE_TRAILING_SLASH 187 else if (t > path + 1 && *(t - 1) == '/') t--; 188 #else 189 else if ((s <= path || *(s - 1) != '/') && t > path + 1 && *(t - 1) == '/') t--; 190 #endif 191 *t = 0; 192 errno = oerrno; 193 return t; 194 } 195 dots = 0; 196 p = t; 197 break; 198 default: 199 dots = 4; 200 break; 201 } 202 } 203