source: trunk/minix/lib/posix/_getcwd.c@ 10

Last change on this file since 10 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 3.0 KB
Line 
1/* getcwd() - get the name of the current working directory.
2 * Author: Kees J. Bot
3 * 30 Apr 1989
4 */
5#define nil 0
6#define chdir _chdir
7#define closedir _closedir
8#define getcwd _getcwd
9#define opendir _opendir
10#define readdir _readdir
11#define rewinddir _rewinddir
12#define stat _stat
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <errno.h>
16#include <unistd.h>
17#include <dirent.h>
18#include <limits.h>
19#include <string.h>
20
21static int addpath(const char *path, char **ap, const char *entry)
22/* Add the name of a directory entry at the front of the path being built.
23 * Note that the result always starts with a slash.
24 */
25{
26 const char *e= entry;
27 char *p= *ap;
28
29 while (*e != 0) e++;
30
31 while (e > entry && p > path) *--p = *--e;
32
33 if (p == path) return -1;
34 *--p = '/';
35 *ap= p;
36 return 0;
37}
38
39static int recover(char *p)
40/* Undo all those chdir("..")'s that have been recorded by addpath. This
41 * has to be done entry by entry, because the whole pathname may be too long.
42 */
43{
44 int e= errno, slash;
45 char *p0;
46
47 while (*p != 0) {
48 p0= ++p;
49
50 do p++; while (*p != 0 && *p != '/');
51 slash= *p; *p= 0;
52
53 if (chdir(p0) < 0) return -1;
54 *p= slash;
55 }
56 errno= e;
57 return 0;
58}
59
60char *getcwd(char *path, size_t size)
61{
62 struct stat above, current, tmp;
63 struct dirent *entry;
64 DIR *d;
65 char *p, *up, *dotdot;
66 int cycle;
67
68 if (path == nil || size <= 1) { errno= EINVAL; return nil; }
69
70 p= path + size;
71 *--p = 0;
72
73 if (stat(".", &current) < 0) return nil;
74
75 while (1) {
76 dotdot= "..";
77 if (stat(dotdot, &above) < 0) { recover(p); return nil; }
78
79 if (above.st_dev == current.st_dev
80 && above.st_ino == current.st_ino)
81 break; /* Root dir found */
82
83 if ((d= opendir(dotdot)) == nil) { recover(p); return nil; }
84
85 /* Cycle is 0 for a simple inode nr search, or 1 for a search
86 * for inode *and* device nr.
87 */
88 cycle= above.st_dev == current.st_dev ? 0 : 1;
89
90 do {
91 char name[3 + NAME_MAX + 1];
92
93 tmp.st_ino= 0;
94 if ((entry= readdir(d)) == nil) {
95 switch (++cycle) {
96 case 1:
97 rewinddir(d);
98 continue;
99 case 2:
100 closedir(d);
101 errno= ENOENT;
102 recover(p);
103 return nil;
104 }
105 }
106 if (strcmp(entry->d_name, ".") == 0) continue;
107 if (strcmp(entry->d_name, "..") == 0) continue;
108
109 switch (cycle) {
110 case 0:
111 /* Simple test on inode nr. */
112 if (entry->d_ino != current.st_ino) continue;
113 /*FALL THROUGH*/
114
115 case 1:
116 /* Current is mounted. */
117 strcpy(name, "../");
118 strcpy(name+3, entry->d_name);
119 if (stat(name, &tmp) < 0) continue;
120 break;
121 }
122 } while (tmp.st_ino != current.st_ino
123 || tmp.st_dev != current.st_dev);
124
125 up= p;
126 if (addpath(path, &up, entry->d_name) < 0) {
127 closedir(d);
128 errno = ERANGE;
129 recover(p);
130 return nil;
131 }
132 closedir(d);
133
134 if (chdir(dotdot) < 0) { recover(p); return nil; }
135 p= up;
136
137 current= above;
138 }
139 if (recover(p) < 0) return nil; /* Undo all those chdir("..")'s. */
140 if (*p == 0) *--p = '/'; /* Cwd is "/" if nothing added */
141 if (p > path) strcpy(path, p); /* Move string to start of path. */
142 return path;
143}
Note: See TracBrowser for help on using the repository browser.