1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
46 #define ERROR(e) { errno = e; goto error; }
48 struct dirlist
/* long path chdir(2) component */
50 struct dirlist
* next
; /* next component */
51 int index
; /* index from end of buf */
55 * pop long dir component chdir stack
59 popdir(register struct dirlist
* d
, register char* end
)
61 register struct dirlist
* dp
;
70 if (d
) *(end
- d
->index
- 1) = 0;
71 v
= chdir(end
- dp
->index
);
72 if (d
) *(end
- d
->index
- 1) = '/';
80 * push long dir component onto stack
83 static struct dirlist
*
84 pushdir(register struct dirlist
* d
, char* dots
, char* path
, char* end
)
86 register struct dirlist
* p
;
88 if (!(p
= newof(0, struct dirlist
, 1, 0)) || chdir(dots
))
91 if (d
) popdir(d
, end
);
94 p
->index
= end
- path
;
100 * return a pointer to the absolute path name of .
101 * this path name may be longer than PATH_MAX
103 * a few environment variables are checked before the search algorithm
104 * return value is placed in buf of len chars
105 * if buf is 0 then space is allocated via malloc() with
106 * len extra chars after the path name
107 * 0 is returned on error with errno set as appropriate
111 getcwd(char* buf
, size_t len
)
121 struct dirent
* entry
;
122 struct dirlist
* dirstk
= 0;
144 if (buf
&& !len
) ERROR(EINVAL
);
145 if (fs3d(FS3D_TEST
) && (namlen
= mount(".", dots
, FS3D_GET
|FS3D_VIEW
|FS3D_SIZE(sizeof(dots
)), NiL
)) > 1 && namlen
< sizeof(dots
))
152 if (len
< namlen
) ERROR(ERANGE
);
154 else if (!(buf
= newof(0, char, namlen
, len
))) ERROR(ENOMEM
);
155 return (char*)memcpy(buf
, p
, namlen
);
159 if (stat(".", par
)) ERROR(errno
);
160 for (n
= 0; n
< elementsof(env
); n
++)
162 if ((env
[n
].name
&& (p
= getenv(env
[n
].name
)) || (p
= env
[n
].path
)) && *p
== '/' && !stat(p
, cur
))
165 env
[n
].dev
= cur
->st_dev
;
166 env
[n
].ino
= cur
->st_ino
;
167 if (cur
->st_ino
== par
->st_ino
&& cur
->st_dev
== par
->st_dev
)
178 if (!(buf
= newof(0, char, len
, extra
))) ERROR(ENOMEM
);
189 if ((d
- dots
) > (PATH_MAX
- 4))
191 if (!(dirstk
= pushdir(dirstk
, dots
, p
, buf
+ len
- 1))) ERROR(ERANGE
);
197 if (!(dirp
= opendir(dots
))) ERROR(errno
);
198 #if !_dir_ok || _mem_dd_fd_DIR
199 if (fstat(dirp
->dd_fd
, par
)) ERROR(errno
);
201 if (stat(dots
, par
)) ERROR(errno
);
204 if (par
->st_dev
== cur
->st_dev
)
206 if (par
->st_ino
== cur
->st_ino
)
216 if (extra
>= 0 && !(buf
= newof(buf
, char, len
, extra
))) ERROR(ENOMEM
);
218 if (dirstk
&& popdir(dirstk
, buf
+ len
- 1))
225 env
[0].path
= strdup(buf
);
229 while (entry
= readdir(dirp
))
230 if (D_FILENO(entry
) == cur
->st_ino
)
232 namlen
= D_NAMLEN(entry
);
238 * this fallthrough handles logical naming
245 if (!(entry
= readdir(dirp
))) ERROR(ENOENT
);
246 namlen
= D_NAMLEN(entry
);
247 if ((d
- dots
) > (PATH_MAX
- 1 - namlen
))
250 if (namlen
>= PATH_MAX
|| !(dirstk
= pushdir(dirstk
, dots
+ 3, p
, buf
+ len
- 1))) ERROR(ERANGE
);
253 memcpy(d
, entry
->d_name
, namlen
+ 1);
254 } while (stat(dots
, &tstst
) || tstst
.st_ino
!= cur
->st_ino
|| tstst
.st_dev
!= cur
->st_dev
);
257 while ((p
-= namlen
) <= (buf
+ 1))
259 x
= (buf
+ len
- 1) - (p
+= namlen
);
261 if (extra
< 0 || !(buf
= newof(buf
, char, len
+= PATH_MAX
, extra
))) ERROR(ERANGE
);
263 while (p
> buf
+ len
- 1 - x
) *--p
= *--s
;
265 if (n
< elementsof(env
))
267 memcpy(p
, env
[n
].path
, namlen
);
270 memcpy(p
, entry
->d_name
, namlen
);
273 for (n
= 0; n
< elementsof(env
); n
++)
274 if (env
[n
].ino
== par
->st_ino
&& env
[n
].dev
== par
->st_dev
)
276 namlen
= strlen(env
[n
].path
);
283 if (dirstk
) popdir(dirstk
, buf
+ len
- 1);
284 if (extra
>= 0) free(buf
);
286 if (dirp
) closedir(dirp
);