xref: /original-bsd/lib/libc/gen/getcwd.c (revision 6570ed16)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static char sccsid[] = "@(#)getcwd.c	5.7 (Berkeley) 05/27/90";
20 #endif /* LIBC_SCCS and not lint */
21 
22 #include <sys/param.h>
23 #include <sys/stat.h>
24 #include <dirent.h>
25 #include <string.h>
26 
27 #define	ISDOT(dp) \
28 	(dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
29 	    dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
30 
31 char *
32 getwd(store)
33 	char *store;
34 {
35 	extern int errno;
36 	register struct dirent *dp;
37 	register DIR *dir;
38 	register ino_t ino;
39 	register char *pp, *pu;
40 	register int first;
41 	struct stat s;
42 	dev_t root_dev, dev;
43 	ino_t root_ino;
44 	int save_errno, found;
45 	char path[MAXPATHLEN], up[MAXPATHLEN], *file;
46 
47 	/* save root values */
48 	if (stat("/", &s)) {
49 		file = "/";
50 		goto err;
51 	}
52 	root_dev = s.st_dev;
53 	root_ino = s.st_ino;
54 
55 	/* init path pointer; built from the end of the buffer */
56 	pp = path + sizeof(path) - 1;
57 	*pp = '\0';
58 
59 	/* special case first stat, it's ".", not ".." */
60 	up[0] = '.';
61 	up[1] = '\0';
62 
63 	for (pu = up, first = 1;; first = 0) {
64 		/* stat current level */
65 		if (lstat(up, &s)) {
66 			file = up;
67 			goto err;
68 		}
69 
70 		/* save current node values */
71 		ino = s.st_ino;
72 		dev = s.st_dev;
73 
74 		/* check for root */
75 		if (root_dev == dev && root_ino == ino) {
76 			*store = '/';
77 			(void) strcpy(store + 1, pp);
78 			return (store);
79 		}
80 
81 		*pu++ = '.';
82 		*pu++ = '.';
83 		*pu = '\0';
84 
85 		/* open and stat parent */
86 		if (!(dir = opendir(up)) || fstat(dirfd(dir), &s)) {
87 			file = up;
88 			goto err;
89 		}
90 		found = save_errno = 0;
91 
92 		*pu++ = '/';
93 
94 		/*
95 		 * if it's a mount point you have to stat each element because
96 		 * the inode number in the directory is for the entry in the
97 		 * parent directory, not the inode number of the mounted file.
98 		 */
99 		if (s.st_dev == dev) {
100 			while (dp = readdir(dir))
101 				if (dp->d_fileno == ino)
102 					goto hit;
103 		} else {
104 			while (dp = readdir(dir)) {
105 				if (ISDOT(dp))
106 					continue;
107 				bcopy(dp->d_name, pu, dp->d_namlen + 1);
108 				if (lstat(up, &s)) {
109 					file = dp->d_name;
110 					save_errno = errno;
111 					errno = 0;
112 					continue;
113 				}
114 				if (s.st_dev == dev && s.st_ino == ino) {
115 hit:					if (!first)
116 						*--pp = '/';
117 					pp -= dp->d_namlen;
118 					bcopy(dp->d_name, pp, dp->d_namlen);
119 					found = 1;
120 					break;
121 				}
122 			}
123 			if (errno) {
124 				file = up;
125 				save_errno = errno;
126 			}
127 		}
128 		(void) closedir(dir);
129 
130 		*pu = '\0';
131 
132 		if (!found) {
133 			/*
134 			 * We didn't find the current level in its parent
135 			 * directory; figure out what to complain about.
136 			 */
137 			if (save_errno) {
138 				errno = save_errno;
139 				goto err;
140 			}
141 			(void) sprintf(store, "%s not found in %s?\n",
142 				first ? "." : pp, up);
143 			return ((char *)NULL);
144 		}
145 	}
146 err:
147 	(void) sprintf(store, "getwd: %s: %s", file, strerror(errno));
148 	return ((char *)NULL);
149 }
150