1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1985-2011 AT&T Intellectual Property * 5* and is licensed under the * 6* Eclipse Public License, Version 1.0 * 7* by AT&T Intellectual Property * 8* * 9* A copy of the License is available at * 10* http://www.eclipse.org/org/documents/epl-v10.html * 11* (with md5 checksum b35adb5213ca9657e911e9befb180842) * 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 39static int 40vchdir(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 63int 64pathcd(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