/* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)getcwd.c 5.7 (Berkeley) 05/27/90"; #endif /* LIBC_SCCS and not lint */ #include #include #include #include #define ISDOT(dp) \ (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ dp->d_name[1] == '.' && dp->d_name[2] == '\0')) char * getwd(store) char *store; { extern int errno; register struct dirent *dp; register DIR *dir; register ino_t ino; register char *pp, *pu; register int first; struct stat s; dev_t root_dev, dev; ino_t root_ino; int save_errno, found; char path[MAXPATHLEN], up[MAXPATHLEN], *file; /* save root values */ if (stat("/", &s)) { file = "/"; goto err; } root_dev = s.st_dev; root_ino = s.st_ino; /* init path pointer; built from the end of the buffer */ pp = path + sizeof(path) - 1; *pp = '\0'; /* special case first stat, it's ".", not ".." */ up[0] = '.'; up[1] = '\0'; for (pu = up, first = 1;; first = 0) { /* stat current level */ if (lstat(up, &s)) { file = up; goto err; } /* save current node values */ ino = s.st_ino; dev = s.st_dev; /* check for root */ if (root_dev == dev && root_ino == ino) { *store = '/'; (void) strcpy(store + 1, pp); return (store); } *pu++ = '.'; *pu++ = '.'; *pu = '\0'; /* open and stat parent */ if (!(dir = opendir(up)) || fstat(dirfd(dir), &s)) { file = up; goto err; } found = save_errno = 0; *pu++ = '/'; /* * if it's a mount point you have to stat each element because * the inode number in the directory is for the entry in the * parent directory, not the inode number of the mounted file. */ if (s.st_dev == dev) { while (dp = readdir(dir)) if (dp->d_fileno == ino) goto hit; } else { while (dp = readdir(dir)) { if (ISDOT(dp)) continue; bcopy(dp->d_name, pu, dp->d_namlen + 1); if (lstat(up, &s)) { file = dp->d_name; save_errno = errno; errno = 0; continue; } if (s.st_dev == dev && s.st_ino == ino) { hit: if (!first) *--pp = '/'; pp -= dp->d_namlen; bcopy(dp->d_name, pp, dp->d_namlen); found = 1; break; } } if (errno) { file = up; save_errno = errno; } } (void) closedir(dir); *pu = '\0'; if (!found) { /* * We didn't find the current level in its parent * directory; figure out what to complain about. */ if (save_errno) { errno = save_errno; goto err; } (void) sprintf(store, "%s not found in %s?\n", first ? "." : pp, up); return ((char *)NULL); } } err: (void) sprintf(store, "getwd: %s: %s", file, strerror(errno)); return ((char *)NULL); }