Commit | Line | Data |
---|---|---|
bb0cfa24 | 1 | /* |
8a4b7e23 KB |
2 | * Copyright (c) 1989 The Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
269a7923 | 5 | * %sccs.include.redist.c% |
bb0cfa24 DF |
6 | */ |
7 | ||
2ce81398 | 8 | #if defined(LIBC_SCCS) && !defined(lint) |
269a7923 | 9 | static char sccsid[] = "@(#)getcwd.c 5.8 (Berkeley) %G%"; |
8a4b7e23 | 10 | #endif /* LIBC_SCCS and not lint */ |
9b6e6036 | 11 | |
87dccba9 SL |
12 | #include <sys/param.h> |
13 | #include <sys/stat.h> | |
8a4b7e23 | 14 | #include <dirent.h> |
36226ba7 KB |
15 | #include <string.h> |
16 | ||
17 | #define ISDOT(dp) \ | |
18 | (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ | |
19 | dp->d_name[1] == '.' && dp->d_name[2] == '\0')) | |
9b6e6036 SL |
20 | |
21 | char * | |
8a4b7e23 KB |
22 | getwd(store) |
23 | char *store; | |
9b6e6036 | 24 | { |
8a4b7e23 | 25 | extern int errno; |
8a4b7e23 | 26 | register struct dirent *dp; |
36226ba7 KB |
27 | register DIR *dir; |
28 | register ino_t ino; | |
8a4b7e23 | 29 | register char *pp, *pu; |
36226ba7 KB |
30 | register int first; |
31 | struct stat s; | |
32 | dev_t root_dev, dev; | |
8a4b7e23 | 33 | ino_t root_ino; |
1f8e47f9 | 34 | int save_errno, found; |
36226ba7 | 35 | char path[MAXPATHLEN], up[MAXPATHLEN], *file; |
9b6e6036 | 36 | |
36226ba7 | 37 | /* save root values */ |
1f8e47f9 MK |
38 | if (stat("/", &s)) { |
39 | file = "/"; | |
8a4b7e23 | 40 | goto err; |
1f8e47f9 | 41 | } |
8a4b7e23 KB |
42 | root_dev = s.st_dev; |
43 | root_ino = s.st_ino; | |
36226ba7 KB |
44 | |
45 | /* init path pointer; built from the end of the buffer */ | |
8a4b7e23 KB |
46 | pp = path + sizeof(path) - 1; |
47 | *pp = '\0'; | |
36226ba7 KB |
48 | |
49 | /* special case first stat, it's ".", not ".." */ | |
50 | up[0] = '.'; | |
51 | up[1] = '\0'; | |
52 | ||
8a4b7e23 | 53 | for (pu = up, first = 1;; first = 0) { |
36226ba7 KB |
54 | /* stat current level */ |
55 | if (lstat(up, &s)) { | |
56 | file = up; | |
57 | goto err; | |
58 | } | |
59 | ||
60 | /* save current node values */ | |
61 | ino = s.st_ino; | |
62 | dev = s.st_dev; | |
63 | ||
64 | /* check for root */ | |
65 | if (root_dev == dev && root_ino == ino) { | |
8a4b7e23 | 66 | *store = '/'; |
1f8e47f9 MK |
67 | (void) strcpy(store + 1, pp); |
68 | return (store); | |
90432f68 | 69 | } |
36226ba7 | 70 | |
8a4b7e23 KB |
71 | *pu++ = '.'; |
72 | *pu++ = '.'; | |
73 | *pu = '\0'; | |
36226ba7 KB |
74 | |
75 | /* open and stat parent */ | |
76 | if (!(dir = opendir(up)) || fstat(dirfd(dir), &s)) { | |
1f8e47f9 MK |
77 | file = up; |
78 | goto err; | |
8a4b7e23 | 79 | } |
36226ba7 KB |
80 | found = save_errno = 0; |
81 | ||
8a4b7e23 | 82 | *pu++ = '/'; |
36226ba7 KB |
83 | |
84 | /* | |
85 | * if it's a mount point you have to stat each element because | |
86 | * the inode number in the directory is for the entry in the | |
87 | * parent directory, not the inode number of the mounted file. | |
88 | */ | |
89 | if (s.st_dev == dev) { | |
90 | while (dp = readdir(dir)) | |
91 | if (dp->d_fileno == ino) | |
92 | goto hit; | |
93 | } else { | |
94 | while (dp = readdir(dir)) { | |
95 | if (ISDOT(dp)) | |
96 | continue; | |
97 | bcopy(dp->d_name, pu, dp->d_namlen + 1); | |
98 | if (lstat(up, &s)) { | |
99 | file = dp->d_name; | |
100 | save_errno = errno; | |
101 | errno = 0; | |
102 | continue; | |
103 | } | |
104 | if (s.st_dev == dev && s.st_ino == ino) { | |
105 | hit: if (!first) | |
106 | *--pp = '/'; | |
107 | pp -= dp->d_namlen; | |
108 | bcopy(dp->d_name, pp, dp->d_namlen); | |
109 | found = 1; | |
110 | break; | |
111 | } | |
1f8e47f9 | 112 | } |
36226ba7 KB |
113 | if (errno) { |
114 | file = up; | |
115 | save_errno = errno; | |
90432f68 | 116 | } |
8a4b7e23 | 117 | } |
36226ba7 KB |
118 | (void) closedir(dir); |
119 | ||
8a4b7e23 | 120 | *pu = '\0'; |
36226ba7 | 121 | |
1f8e47f9 MK |
122 | if (!found) { |
123 | /* | |
124 | * We didn't find the current level in its parent | |
125 | * directory; figure out what to complain about. | |
126 | */ | |
36226ba7 | 127 | if (save_errno) { |
1f8e47f9 MK |
128 | errno = save_errno; |
129 | goto err; | |
130 | } | |
131 | (void) sprintf(store, "%s not found in %s?\n", | |
132 | first ? "." : pp, up); | |
133 | return ((char *)NULL); | |
134 | } | |
90432f68 | 135 | } |
1f8e47f9 MK |
136 | err: |
137 | (void) sprintf(store, "getwd: %s: %s", file, strerror(errno)); | |
138 | return ((char *)NULL); | |
9b6e6036 | 139 | } |