steveo@world.std.com (Steven W Orr) (06/25/91)
Does anyone have source code for a routine that will return my
current working directory without calling getcwd? The problem is that
getcwd calls fork, and my calling process is huge. The whole thing
has to swap out just to get from the fork to the exec. (Or for that
matter, is there a callable function provided by any of the libraries
in my SCO ODT 1.1 system?)
Just to start stimulating the discussion, I have heard that there are
two ways to do this and I don't know which one is better/more
appropriate.
1. Do {
read . and find out what our current inode is.
chdir to .. and search . to find last inode. That yields
the rightmost filename of the starting point.
} until current_inode == 0
Keep precatenating (is that a word?) until we get to the root
directory. Then chdir back to where we started from.
2. Read the user area and utilize
struct inode *u_cdir; /* current directory */
struct inode *u_rdir; /* root directory */
caddr_t u_dirp; /* pathname pointer */
struct direct u_dent; /* current directory entry */
struct inode *u_pdir; /* inode of parent directory */
/* of dirp */
from <sys/user.h>
--
----------Time flies like the wind. Fruit flies like bananas.------------------
Steven W. Orr steveo@world.std.com uunet!world!steveo
----------Everybody repeat after me: "We are all individuals."-----------------
cpcahil@virtech.uucp (Conor P. Cahill) (06/25/91)
steveo@world.std.com (Steven W Orr) writes: >Just to start stimulating the discussion, I have heard that there are >two ways to do this and I don't know which one is better/more >appropriate. >1. Do { > read . and find out what our current inode is. > chdir to .. and search . to find last inode. That yields > the rightmost filename of the starting point. > } until current_inode == 0 This won't work because 1) the root inode is not 0 it is 2 2) it doesn't handle crossing mount points 3) you've changed your directory and you may not be able to figure out how to get back to where you are if the directory you are in (or a dir in the path) is searchable, but not readable Here is the source code to BSDs getwd() function. You will probably have to modify the directory processing portion of the code but the changes should be minimal. Have fun. /* * 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: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the University nor the names of its * contributors may 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[] = "@(#)getwd.c 5.8 (Berkeley) 6/1/90"; #endif /* LIBC_SCCS and not lint */ #include <sys/param.h> #include <sys/stat.h> #include <dirent.h> #include <string.h> #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); } -- I guess these are the views of VTI - since it is my consulting company. Conor P. Cahill (703)430-9247 uunet!virtech!cpcahil Virtual Technologies, Inc. 46030 Manekin Plaza Sterling, VA 22170
sef@kithrup.COM (Sean Eric Fagan) (06/25/91)
In article <1991Jun25.001136.3202@virtech.uucp> cpcahil@virtech.uucp (Conor P. Cahill) writes: >Here is the source code to BSDs getwd() function. You will probably have >to modify the directory processing portion of the code but the changes >should be minimal. Have fun. And here are patches to make it work for SCO *nix. They should be pretty generic for SysVr3.2 for the '386, though. *** getwd.c.orig Mon Jun 24 19:13:28 1991 --- getwd.c Mon Jun 24 19:03:31 1991 *************** *** 21,35 **** --- 21,48 ---- static char sccsid[] = "@(#)getwd.c 5.8 (Berkeley) 6/1/90"; #endif /* LIBC_SCCS and not lint */ + #include <sys/types.h> #include <sys/param.h> #include <sys/stat.h> #include <dirent.h> #include <string.h> + #ifdef PATHSIZE + # define MAXPATHLEN PATHSIZE + #endif + #define ISDOT(dp) \ (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ dp->d_name[1] == '.' && dp->d_name[2] == '\0')) + #if defined(USG) && !defined(HAVE_SYMLINKS) + # define lstat stat + #endif + + #if defined(USG) && !defined(dirfd) + # define dirfd(x) ((x)->dd_fd) + #endif + char * getwd(store) char *store; *************** *** 100,112 **** --- 113,133 ---- */ if (s.st_dev == dev) { while (dp = readdir(dir)) + #ifdef USG + if (dp->d_ino == ino) + #else if (dp->d_fileno == ino) + #endif goto hit; } else { while (dp = readdir(dir)) { if (ISDOT(dp)) continue; + #ifdef USG + memcpy(pu, dp->d_name, strlen(dp->d_name) + 1); + #else bcopy(dp->d_name, pu, dp->d_namlen + 1); + #endif if (lstat(up, &s)) { file = dp->d_name; save_errno = errno; *************** *** 116,123 **** --- 137,149 ---- if (s.st_dev == dev && s.st_ino == ino) { hit: if (!first) *--pp = '/'; + #ifdef USG + pp -= strlen(dp->d_name); + memcpy(pp, dp->d_name, strlen(dp->d_name)); + #else pp -= dp->d_namlen; bcopy(dp->d_name, pp, dp->d_namlen); + #endif found = 1; break; } -- Sean Eric Fagan | "What *does* that 33 do? I have no idea." sef@kithrup.COM | -- Chris Torek -----------------+ (torek@ee.lbl.gov) Any opinions expressed are my own, and generally unpopular with others.