[comp.unix.sysv386] Need a getwd call.

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.