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