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 * 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