Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / lib / libast / misc / getcwd.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: getcwd.c /main/3 1995/11/01 17:56:20 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
29 *                          AT&T CORP.                          *
30 *                                                              *
31 *                Copyright (c) 1995 AT&T Corp.                 *
32 *                     All Rights Reserved                      *
33 *                                                              *
34 *           This software is licensed by AT&T Corp.            *
35 *       under the terms and conditions of the license in       *
36 *       http://www.research.att.com/orgs/ssr/book/reuse        *
37 *                                                              *
38 *               This software was created by the               *
39 *           Software Engineering Research Department           *
40 *                    AT&T Bell Laboratories                    *
41 *                                                              *
42 *               For further information contact                *
43 *                     gsf@research.att.com                     *
44 *                                                              *
45 ***************************************************************/
46
47 /* : : generated by proto : : */
48
49 #if !defined(__PROTO__)
50 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
51 #if defined(__cplusplus)
52 #define __MANGLE__      "C"
53 #else
54 #define __MANGLE__
55 #endif
56 #define __STDARG__
57 #define __PROTO__(x)    x
58 #define __OTORP__(x)
59 #define __PARAM__(n,o)  n
60 #if !defined(__STDC__) && !defined(__cplusplus)
61 #if !defined(c_plusplus)
62 #define const
63 #endif
64 #define signed
65 #define void            int
66 #define volatile
67 #define __V_            char
68 #else
69 #define __V_            void
70 #endif
71 #else
72 #define __PROTO__(x)    ()
73 #define __OTORP__(x)    x
74 #define __PARAM__(n,o)  o
75 #define __MANGLE__
76 #define __V_            char
77 #define const
78 #define signed
79 #define void            int
80 #define volatile
81 #endif
82 #if defined(__cplusplus) || defined(c_plusplus)
83 #define __VARARG__      ...
84 #else
85 #define __VARARG__
86 #endif
87 #if defined(__STDARG__)
88 #define __VA_START__(p,a)       va_start(p,a)
89 #else
90 #define __VA_START__(p,a)       va_start(p)
91 #endif
92 #endif
93 #include "dirlib.h"
94
95 #include <fs3d.h>
96
97 #ifndef ERANGE
98 #define ERANGE          E2BIG
99 #endif
100
101 #define ERROR(e)        { errno = e; goto error; }
102
103 struct dirlist                          /* long path chdir(2) component */
104 {
105         struct dirlist* next;           /* next component               */
106         int             index;          /* index from end of buf        */
107 };
108
109 /*
110  * pop long dir component chdir stack
111  */
112
113 static int
114 popdir __PARAM__((register struct dirlist* d, register char* end), (d, end)) __OTORP__(register struct dirlist* d; register char* end;){
115         register struct dirlist*        dp;
116         int                             v;
117
118         v = 0;
119         while (dp = d)
120         {
121                 d = d->next;
122                 if (!v)
123                 {
124                         if (d) *(end - d->index - 1) = 0;
125                         v = chdir(end - dp->index);
126                         if (d) *(end - d->index - 1) = '/';
127                 }
128                 free(dp);
129         }
130         return(v);
131 }
132
133 /*
134  * push long dir component onto stack
135  */
136
137 static struct dirlist*
138 pushdir __PARAM__((register struct dirlist* d, char* dots, char* path, char* end), (d, dots, path, end)) __OTORP__(register struct dirlist* d; char* dots; char* path; char* end;){
139         register struct dirlist*        p;
140
141         if (!(p = newof(0, struct dirlist, 1, 0)) || chdir(dots))
142         {
143                 if (p) free(p);
144                 if (d) popdir(d, end);
145                 return(0);
146         }
147         p->index = end - path;
148         p->next = d;
149         return(p);
150 }
151
152 /*
153  * return a pointer to the absolute path name of .
154  * this path name may be longer than PATH_MAX
155  *
156  * a few environment variables are checked before the search algorithm
157  * return value is placed in buf of len chars
158  * if buf is 0 then space is allocated via malloc() with
159  * len extra chars after the path name
160  * 0 is returned on error with errno set as appropriate
161  */
162
163 char*
164 getcwd __PARAM__((char* buf, size_t len), (buf, len)) __OTORP__(char* buf; size_t len;){
165         register char*  d;
166         register char*  p;
167         register char*  s;
168         DIR*            dirp = 0;
169         int             n;
170         int             x;
171         size_t          namlen;
172         ssize_t         extra = -1;
173         struct dirent*  entry;
174         struct dirlist* dirstk = 0;
175         struct stat*    cur;
176         struct stat*    par;
177         struct stat*    tmp;
178         struct stat     curst;
179         struct stat     parst;
180         struct stat     tstst;
181         char            dots[PATH_MAX];
182
183         static struct
184         {
185                 char*   name;
186                 char*   path;
187                 dev_t   dev;
188                 ino_t   ino;
189         }               env[] =
190         {
191                 { "PWD",        0, 0, 0 },
192                 { "HOME",       0, 0, 0 },
193         };
194
195         if (buf && !len) ERROR(EINVAL);
196         if (fs3d(FS3D_TEST) && (namlen = mount(".", dots, FS3D_GET|FS3D_VIEW|FS3D_SIZE(sizeof(dots)), NiL)) > 1 && namlen < sizeof(dots))
197         {
198                 p = dots;
199         easy:
200                 namlen++;
201                 if (buf)
202                 {
203                         if (len < namlen) ERROR(ERANGE);
204                 }
205                 else if (!(buf = newof(0, char, namlen, len))) ERROR(ENOMEM);
206                 return((char*)memcpy(buf, p, namlen));
207         }
208         cur = &curst;
209         par = &parst;
210         if (stat(".", par)) ERROR(errno);
211         for (n = 0; n < elementsof(env); n++)
212         {
213                 if ((p = getenv(env[n].name)) && *p == '/' && !stat(p, cur))
214                 {
215                         env[n].path = p;
216                         env[n].dev = cur->st_dev;
217                         env[n].ino = cur->st_ino;
218                         if (cur->st_ino == par->st_ino && cur->st_dev == par->st_dev)
219                         {
220                                 namlen = strlen(p);
221                                 goto easy;
222                         }
223                 }
224         }
225         if (!buf)
226         {
227                 extra = len;
228                 len = PATH_MAX;
229                 if (!(buf = newof(0, char, len, extra))) ERROR(ENOMEM);
230         }
231         d = dots;
232         p = buf + len - 1;
233         *p = 0;
234         n = elementsof(env);
235         for (;;)
236         {
237                 tmp = cur;
238                 cur = par;
239                 par = tmp;
240                 if ((d - dots) > (PATH_MAX - 4))
241                 {
242                         if (!(dirstk = pushdir(dirstk, dots, p, buf + len - 1))) ERROR(ERANGE);
243                         d = dots;
244                 }
245                 *d++ = '.';
246                 *d++ = '.';
247                 *d = 0;
248                 if (!(dirp = opendir(dots))) ERROR(errno);
249 #if !_dir_ok || _mem_dd_fd_DIR
250                 if (fstat(dirp->dd_fd, par)) ERROR(errno);
251 #else
252                 if (stat(dots, par)) ERROR(errno);
253 #endif
254                 *d++ = '/';
255                 if (par->st_dev == cur->st_dev)
256                 {
257                         if (par->st_ino == cur->st_ino)
258                         {
259                                 closedir(dirp);
260                                 *--p = '/';
261                         pop:
262                                 if (p != buf)
263                                 {
264                                         d = buf;
265                                         while (*d++ = *p++);
266                                         len = d - buf;
267                                         if (extra >= 0 && !(buf = newof(buf, char, len, extra))) ERROR(ENOMEM);
268                                 }
269                                 if (dirstk && popdir(dirstk, buf + len - 1))
270                                 {
271                                         dirstk = 0;
272                                         ERROR(errno);
273                                 }
274                                 return(buf);
275                         }
276 #if _mem_d_fileno_dirent || _mem_d_ino_dirent
277 #if !_mem_d_fileno_dirent
278 #define d_fileno        d_ino
279 #endif
280                         while (entry = readdir(dirp))
281                                 if (entry->d_fileno == cur->st_ino)
282                                 {
283 #if _mem_d_namlen_dirent
284                                         namlen = entry->d_namlen;
285 #else
286                                         namlen = strlen(entry->d_name);
287 #endif
288                                         goto found;
289                                 }
290 #endif
291
292                         /*
293                          * this fallthrough handles logical naming
294                          */
295
296                         rewinddir(dirp);
297                 }
298                 do
299                 {
300                         if (!(entry = readdir(dirp))) ERROR(ENOENT);
301 #if _mem_d_namlen_dirent
302                         namlen = entry->d_namlen;
303 #else
304                         namlen = strlen(entry->d_name);
305 #endif
306                         if ((d - dots) > (PATH_MAX - 1 - namlen))
307                         {
308                                 *d = 0;
309                                 if (namlen >= PATH_MAX || !(dirstk = pushdir(dirstk, dots + 3, p, buf + len - 1))) ERROR(ERANGE);
310                                 d = dots + 3;
311                         }
312                         memcpy(d, entry->d_name, namlen + 1);
313                 } while (stat(dots, &tstst) || tstst.st_ino != cur->st_ino || tstst.st_dev != cur->st_dev);
314         found:
315                 if (*p) *--p = '/';
316                 while ((p -= namlen) <= (buf + 1))
317                 {
318                         x = (buf + len - 1) - (p += namlen);
319                         s = buf + len;
320                         if (extra < 0 || !(buf = newof(buf, char, len += PATH_MAX, extra))) ERROR(ERANGE);
321                         p = buf + len;
322                         while (p > buf + len - 1 - x) *--p = *--s;
323                 }
324                 if (n < elementsof(env))
325                 {
326                         memcpy(p, env[n].path, namlen);
327                         goto pop;
328                 }
329                 memcpy(p, entry->d_name, namlen);
330                 closedir(dirp);
331                 dirp = 0;
332                 for (n = 0; n < elementsof(env); n++)
333                         if (env[n].ino == par->st_ino && env[n].dev == par->st_dev)
334                         {
335                                 namlen = strlen(env[n].path);
336                                 goto found;
337                         }
338         }
339  error:
340         if (buf)
341         {
342                 if (dirstk) popdir(dirstk, buf + len - 1);
343                 if (extra >= 0) free(buf);
344         }
345         if (dirp) closedir(dirp);
346         return(0);
347 }