1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2009 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 * K. P. Vo 25 * G. S. Fowler 26 * AT&T Research 27 */ 28 29 #include <ast.h> 30 #include <error.h> 31 #include <stk.h> 32 33 #if DEBUG 34 35 #undef PATH_MAX 36 37 #define PATH_MAX 16 38 39 static int 40 vchdir(const char* path) 41 { 42 int n; 43 44 if (strlen(path) >= PATH_MAX) 45 { 46 errno = ENAMETOOLONG; 47 n = -1; 48 } 49 else n = chdir(path); 50 return n; 51 } 52 53 #define chdir(p) vchdir(p) 54 55 #endif 56 57 /* 58 * set the current directory to path 59 * if path is long and home!=0 then pathcd(home,0) 60 * is called on intermediate chdir errors 61 */ 62 63 int 64 pathcd(const char* path, const char* home) 65 { 66 register char* p = (char*)path; 67 register char* s; 68 register int n; 69 int i; 70 int r; 71 72 r = 0; 73 for (;;) 74 { 75 /* 76 * this should work 99% of the time 77 */ 78 79 if (!chdir(p)) 80 return r; 81 82 /* 83 * chdir failed 84 */ 85 86 if ((n = strlen(p)) < PATH_MAX) 87 return -1; 88 #ifdef ENAMETOOLONG 89 if (errno != ENAMETOOLONG) 90 return -1; 91 #endif 92 93 /* 94 * path is too long -- copy so it can be modified in place 95 */ 96 97 i = stktell(stkstd); 98 sfputr(stkstd, p, 0); 99 stkseek(stkstd, i); 100 p = stkptr(stkstd, i); 101 for (;;) 102 { 103 /* 104 * get a short prefix component 105 */ 106 107 s = p + PATH_MAX; 108 while (--s >= p && *s != '/'); 109 if (s <= p) 110 break; 111 112 /* 113 * chdir to the prefix 114 */ 115 116 *s++ = 0; 117 if (chdir(p)) 118 break; 119 120 /* 121 * do the remainder 122 */ 123 124 if ((n -= s - p) < PATH_MAX) 125 { 126 if (chdir(s)) 127 break; 128 return r; 129 } 130 p = s; 131 } 132 133 /* 134 * try to recover back to home 135 */ 136 137 if (!(p = (char*)home)) 138 return -1; 139 home = 0; 140 r = -1; 141 } 142 } 143