Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libast/misc/getcwd.c
1810 views
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 <[email protected]> *
18
* David Korn <[email protected]> *
19
* Phong Vo <[email protected]> *
20
* *
21
***********************************************************************/
22
#pragma prototyped
23
/*
24
* Glenn Fowler
25
* AT&T Research
26
*
27
* pwd library support
28
*/
29
30
#include <ast.h>
31
32
#if _WINIX
33
34
NoN(getcwd)
35
36
#else
37
38
#include "FEATURE/syscall"
39
40
#if defined(SYSGETCWD)
41
42
#include <error.h>
43
44
#define ERROR(e) { errno = e; return 0; }
45
46
char*
47
getcwd(char* buf, size_t len)
48
{
49
size_t n;
50
size_t r;
51
int oerrno;
52
53
if (buf)
54
return SYSGETCWD(buf, len) < 0 ? 0 : buf;
55
oerrno = errno;
56
n = PATH_MAX;
57
for (;;)
58
{
59
if (!(buf = newof(buf, char, n, 0)))
60
ERROR(ENOMEM);
61
if (SYSGETCWD(buf, n) >= 0)
62
{
63
if ((r = strlen(buf) + len + 1) != n && !(buf = newof(buf, char, r, 0)))
64
ERROR(ENOMEM);
65
break;
66
}
67
if (errno != ERANGE)
68
{
69
free(buf);
70
return 0;
71
}
72
n += PATH_MAX / 4;
73
}
74
errno = oerrno;
75
return buf;
76
}
77
78
#else
79
80
#include <ast_dir.h>
81
#include <error.h>
82
#include <fs3d.h>
83
84
#ifndef ERANGE
85
#define ERANGE E2BIG
86
#endif
87
88
#define ERROR(e) { errno = e; goto error; }
89
90
struct dirlist /* long path chdir(2) component */
91
{
92
struct dirlist* next; /* next component */
93
int index; /* index from end of buf */
94
};
95
96
/*
97
* pop long dir component chdir stack
98
*/
99
100
static int
101
popdir(register struct dirlist* d, register char* end)
102
{
103
register struct dirlist* dp;
104
int v;
105
106
v = 0;
107
while (dp = d)
108
{
109
d = d->next;
110
if (!v)
111
{
112
if (d) *(end - d->index - 1) = 0;
113
v = chdir(end - dp->index);
114
if (d) *(end - d->index - 1) = '/';
115
}
116
free(dp);
117
}
118
return v;
119
}
120
121
/*
122
* push long dir component onto stack
123
*/
124
125
static struct dirlist*
126
pushdir(register struct dirlist* d, char* dots, char* path, char* end)
127
{
128
register struct dirlist* p;
129
130
if (!(p = newof(0, struct dirlist, 1, 0)) || chdir(dots))
131
{
132
if (p) free(p);
133
if (d) popdir(d, end);
134
return 0;
135
}
136
p->index = end - path;
137
p->next = d;
138
return p;
139
}
140
141
/*
142
* return a pointer to the absolute path name of .
143
* this path name may be longer than PATH_MAX
144
*
145
* a few environment variables are checked before the search algorithm
146
* return value is placed in buf of len chars
147
* if buf is 0 then space is allocated via malloc() with
148
* len extra chars after the path name
149
* 0 is returned on error with errno set as appropriate
150
*/
151
152
char*
153
getcwd(char* buf, size_t len)
154
{
155
register char* d;
156
register char* p;
157
register char* s;
158
DIR* dirp = 0;
159
int n;
160
int x;
161
size_t namlen;
162
ssize_t extra = -1;
163
struct dirent* entry;
164
struct dirlist* dirstk = 0;
165
struct stat* cur;
166
struct stat* par;
167
struct stat* tmp;
168
struct stat curst;
169
struct stat parst;
170
struct stat tstst;
171
char dots[PATH_MAX];
172
173
static struct
174
{
175
char* name;
176
char* path;
177
dev_t dev;
178
ino_t ino;
179
} env[] =
180
{
181
{ /*previous*/0 },
182
{ "PWD" },
183
{ "HOME" },
184
};
185
186
if (buf && !len) ERROR(EINVAL);
187
if (fs3d(FS3D_TEST) && (namlen = mount(".", dots, FS3D_GET|FS3D_VIEW|FS3D_SIZE(sizeof(dots)), NiL)) > 1 && namlen < sizeof(dots))
188
{
189
p = dots;
190
easy:
191
namlen++;
192
if (buf)
193
{
194
if (len < namlen) ERROR(ERANGE);
195
}
196
else if (!(buf = newof(0, char, namlen, len))) ERROR(ENOMEM);
197
return (char*)memcpy(buf, p, namlen);
198
}
199
cur = &curst;
200
par = &parst;
201
if (stat(".", par)) ERROR(errno);
202
for (n = 0; n < elementsof(env); n++)
203
{
204
if ((env[n].name && (p = getenv(env[n].name)) || (p = env[n].path)) && *p == '/' && !stat(p, cur))
205
{
206
env[n].path = p;
207
env[n].dev = cur->st_dev;
208
env[n].ino = cur->st_ino;
209
if (cur->st_ino == par->st_ino && cur->st_dev == par->st_dev)
210
{
211
namlen = strlen(p);
212
goto easy;
213
}
214
}
215
}
216
if (!buf)
217
{
218
extra = len;
219
len = PATH_MAX;
220
if (!(buf = newof(0, char, len, extra))) ERROR(ENOMEM);
221
}
222
d = dots;
223
p = buf + len - 1;
224
*p = 0;
225
n = elementsof(env);
226
for (;;)
227
{
228
tmp = cur;
229
cur = par;
230
par = tmp;
231
if ((d - dots) > (PATH_MAX - 4))
232
{
233
if (!(dirstk = pushdir(dirstk, dots, p, buf + len - 1))) ERROR(ERANGE);
234
d = dots;
235
}
236
*d++ = '.';
237
*d++ = '.';
238
*d = 0;
239
if (!(dirp = opendir(dots))) ERROR(errno);
240
#if !_dir_ok || _mem_dd_fd_DIR
241
if (fstat(dirp->dd_fd, par)) ERROR(errno);
242
#else
243
if (stat(dots, par)) ERROR(errno);
244
#endif
245
*d++ = '/';
246
if (par->st_dev == cur->st_dev)
247
{
248
if (par->st_ino == cur->st_ino)
249
{
250
closedir(dirp);
251
*--p = '/';
252
pop:
253
if (p != buf)
254
{
255
d = buf;
256
while (*d++ = *p++);
257
len = d - buf;
258
if (extra >= 0 && !(buf = newof(buf, char, len, extra))) ERROR(ENOMEM);
259
}
260
if (dirstk && popdir(dirstk, buf + len - 1))
261
{
262
dirstk = 0;
263
ERROR(errno);
264
}
265
if (env[0].path)
266
free(env[0].path);
267
env[0].path = strdup(buf);
268
return buf;
269
}
270
#ifdef D_FILENO
271
while (entry = readdir(dirp))
272
if (D_FILENO(entry) == cur->st_ino)
273
{
274
namlen = D_NAMLEN(entry);
275
goto found;
276
}
277
#endif
278
279
/*
280
* this fallthrough handles logical naming
281
*/
282
283
rewinddir(dirp);
284
}
285
do
286
{
287
if (!(entry = readdir(dirp))) ERROR(ENOENT);
288
namlen = D_NAMLEN(entry);
289
if ((d - dots) > (PATH_MAX - 1 - namlen))
290
{
291
*d = 0;
292
if (namlen >= PATH_MAX || !(dirstk = pushdir(dirstk, dots + 3, p, buf + len - 1))) ERROR(ERANGE);
293
d = dots + 3;
294
}
295
memcpy(d, entry->d_name, namlen + 1);
296
} while (stat(dots, &tstst) || tstst.st_ino != cur->st_ino || tstst.st_dev != cur->st_dev);
297
found:
298
if (*p) *--p = '/';
299
while ((p -= namlen) <= (buf + 1))
300
{
301
x = (buf + len - 1) - (p += namlen);
302
s = buf + len;
303
if (extra < 0 || !(buf = newof(buf, char, len += PATH_MAX, extra))) ERROR(ERANGE);
304
p = buf + len;
305
while (p > buf + len - 1 - x) *--p = *--s;
306
}
307
if (n < elementsof(env))
308
{
309
memcpy(p, env[n].path, namlen);
310
goto pop;
311
}
312
memcpy(p, entry->d_name, namlen);
313
closedir(dirp);
314
dirp = 0;
315
for (n = 0; n < elementsof(env); n++)
316
if (env[n].ino == par->st_ino && env[n].dev == par->st_dev)
317
{
318
namlen = strlen(env[n].path);
319
goto found;
320
}
321
}
322
error:
323
if (buf)
324
{
325
if (dirstk) popdir(dirstk, buf + len - 1);
326
if (extra >= 0) free(buf);
327
}
328
if (dirp) closedir(dirp);
329
return 0;
330
}
331
332
#endif
333
334
#endif
335
336