xref: /plan9-contrib/sys/src/ape/lib/ap/plan9/getcwd.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include "lib.h"
2 #include <stddef.h>
3 #include <unistd.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include "sys9.h"
8 #include "dir.h"
9 
10 #define DBG(s)
11 #define MAXDEPTH	100
12 
13 static void namedev(Dir *);
14 static int  samefile(Dir *, Dir *);
15 
16 char *
17 getcwd(char *s , size_t size)
18 {
19 	Dir *p, db[MAXDEPTH], root;
20 	int depth, l;
21 	char *x, *v;
22 	char cd[DIRLEN];
23 
24 	if(size == 0) {
25 		errno = EINVAL;
26 		return 0;
27 	}
28 	x = s;
29 	if(_STAT("/", cd) < 0) {
30 		errno = EACCES;
31 		return 0;
32 	}
33 	convM2D(cd, &root);
34 
35 	for(depth = 0; depth < MAXDEPTH; depth++) {
36 		p = &db[depth];
37 		if(_STAT(".", cd) < 0) {
38 			errno = EACCES;
39 			return 0;
40 		}
41 		convM2D(cd, p);
42 
43 		DBG(print("stat: %s %lux\n", p->name, p->qid);)
44 
45 		if(samefile(p, &root)) {
46 			depth--;
47 			break;
48 		}
49 
50 		if(depth > 1 && samefile(p, &db[depth-1])) {
51 			p->name[0] = '#';
52 			p->name[1] = p->type;
53 			p->name[2] = '\0';
54 			break;
55 		}
56 
57 		if((p->name[0] == '.' || p->name[0] == '/') &&
58 		    p->name[1] == '\0')
59 			namedev(p);
60 
61 		if(chdir("..") < 0) {
62 			errno = EACCES;
63 			return 0;
64 		}
65 	}
66 
67 	while(depth >= 0) {
68 		v = db[depth--].name;
69 		if(v[0] == '.' && v[1] == '\0')
70 			continue;
71 		if(v[0] != '#')
72 			*x++ = '/';
73 		l = strlen(v);
74 		size -= l+1;
75 		if(size <= 0) {
76 			errno = ERANGE;
77 			return 0;
78 		}
79 		strcpy(x, v);
80 		x += l;
81 	}
82 	DBG(print("chdir %s\n", s);)
83 	if(chdir(s) < 0) {
84 		errno = EACCES;
85 		return 0;
86 	}
87 	return s;
88 }
89 
90 static void
91 namedev(Dir *p)
92 {
93 	Dir dirb, tdirb;
94 	char buf[DIRLEN*50], sd[NAMELEN*2];
95 	char cd[DIRLEN];
96 	int fd, n;
97 	char *t, *e;
98 
99 	fd = _OPEN("..", OREAD);
100 	if(fd < 0)
101 		return;
102 
103 	for(;;) {
104 		n = _READ(fd, buf, sizeof(buf));
105 		if(n <= 0) {
106 			_CLOSE(fd);
107 			return;
108 		}
109 		e = &buf[n];
110 
111 		for(t = buf; t < e; t += DIRLEN) {
112 			convM2D(t, &dirb);
113 			if((dirb.qid.path&CHDIR) == 0)
114 				continue;
115 			sprintf(sd, "../%s/.", dirb.name);
116 			if(_STAT(sd, cd) < 0)
117 				continue;
118 			convM2D(cd, &tdirb);
119 
120 			if(samefile(&tdirb, p) == 0)
121 				continue;
122 			_CLOSE(fd);
123 			DBG(print("%s->%s\n", p->name, dirb.name);)
124 			strcpy(p->name, dirb.name);
125 			return;
126 		}
127 	}
128 	_CLOSE(fd);
129 }
130 
131 static int
132 samefile(Dir *a, Dir *b)
133 {
134 	if(a->type != b->type)
135 		return 0;
136 	if(a->dev != b->dev)
137 		return 0;
138 	if(a->qid.path != b->qid.path)
139 		return 0;
140 	return 1;
141 }
142