[comp.os.minix] getcwd

tholm@uvicctr.UUCP (Terrence W. Holm) (08/26/88)

EFTH MINIX report #38  - August 1988 -  getcwd(3)


There follows an implementation of getcwd(3), derived from
Adri Koppes' pwd(1).

Also included is a pwd(1) which uses getcwd(3). This
should be used, as the MINIX V1.1-V1.3 pwd(1) does not
handle 14 character file names. [Yes, V1.3 had a patch,
but it was wrong.]


----------------------------------------------------------
echo x - getcwd.3
gres '^X' '' > getcwd.3 << '/'
XSUBROUTINES
X    getcwd(3)		- current working directory
X
XINVOCATION
X    char *getcwd( buffer, size )
X      char *buffer;
X      int   size;
X
XEXPLANATION
X    The name of the current working directory is placed into
X    the <buffer>. <size> is the size of the buffer, it should
X    be at least 128 (PATH_MAX+1).
X
XRESULTS
X    NULL : Error.
X    o/w  : Pointer to name at <buffer>.
/
echo x - pwd.1
gres '^X' '' > pwd.1 << '/'
XCOMMANDS
X    pwd(1)		- print working directory
X
XINVOCATION
X    pwd
X
XEXPLANATION
X    The path name, from the root, of the current directory
X    is written to standard output.
/
echo x - getcwd.c
gres '^X' '' > getcwd.c << '/'
X/*  getcwd(3)
X *
X *  Author: Terrence W. Holm          Aug. 1988
X *
X *  Directly derived from Adri Koppes' pwd(1).
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X#include <errno.h>
X
X#define  NULL         (char *) 0
X#define  O_RDONLY     0
X#define  DIRECT_SIZE  (sizeof (struct direct))
X#define  PATH_MAX     127
X
Xextern char *rindex();
X
Xextern int errno;
X
X
Xchar *getcwd( buffer, size )
X  char *buffer;
X  int   size;
X
X  {
X  static char path[ PATH_MAX + 1 ];
X  struct stat current;
X
X  if ( buffer == NULL  ||  size == 0 )
X    {
X    errno = EINVAL;
X    return( NULL );
X    }
X
X  path[0] = '\0';
X
X  /*  Get the inode for the current directory  */
X   
X  if ( stat( ".", &current ) == -1 )
X    return( NULL );
X
X  if ( (current.st_mode & S_IFMT) != S_IFDIR )
X    return( NULL );
X
X
X  /*  Run backwards up the directory tree, grabbing 	*/
X  /*  directory names on the way.			*/
X
X  while (1)
X    {
X    struct stat parent;
X    struct direct d;
X    int same_device = 0;
X    int found = 0;
X    int fd;
X
X    /*  Get the inode for the parent directory  */
X
X    if ( chdir( ".." ) == -1 )
X	return( NULL );
X
X    if ( stat( ".", &parent ) == -1 )
X	return( NULL );
X
X    if ( (parent.st_mode & S_IFMT) != S_IFDIR )
X	return( NULL );
X
X    if ( current.st_dev == parent.st_dev )
X	same_device = 1;
X
X
X    /*  At the root, "." is the same as ".."  */
X
X    if ( same_device  &&  current.st_ino == parent.st_ino )
X	break;
X
X
X    /*  Search the parent directory for the current entry  */
X
X    if ( (fd = open( ".", O_RDONLY )) == -1 )
X	return( NULL );
X
X    while ( ! found  &&  read(fd, &d, DIRECT_SIZE) == DIRECT_SIZE )
X	{
X	if ( same_device )
X	    {
X	    if ( current.st_ino == d.d_ino )
X		found = 1;
X	    }
X	else
X	    {
X	    static char temp_name[ DIRSIZ + 1 ];
X	    static struct stat dir_entry;
X
X	    temp_name[0] = '\0';
X	    strncat( temp_name, d.d_name, DIRSIZ );
X
X	    if ( stat( temp_name, &dir_entry ) == -1 )
X		{
X		close( fd );
X		return( NULL );
X		}
X
X	    if ( current.st_dev == dir_entry.st_dev  &&
X	         current.st_ino == dir_entry.st_ino )
X		found = 1;
X	    }
X	}
X
X    close( fd );
X
X    if ( ! found )
X    	return( NULL );
X
X    if ( strlen(path) + DIRSIZ + 1 > PATH_MAX )
X	{
X	errno = ERANGE;
X	return( NULL );
X	}
X
X    strcat( path, "/" );
X    strncat( path, d.d_name, DIRSIZ );
X 
X    current.st_dev = parent.st_dev;
X    current.st_ino = parent.st_ino;
X    }
X
X
X  /*  Copy the reversed path name into <buffer>  */
X
X  if ( strlen(path) + 1 > size )
X    {
X    errno = ERANGE;
X    return( NULL );
X    }
X
X  if ( strlen(path) == 0 )
X    {
X    strcpy( buffer, "/" );
X    return( buffer );
X    }
X
X  *buffer = '\0';
X
X  {
X  char *r;
X
X  while ( (r = rindex( path, '/' )) != NULL )
X    {
X    strcat( buffer, r );
X    *r = '\0';
X    }
X  }
X
X  return( buffer );
X  }
/
echo x - pwd.c
gres '^X' '' > pwd.c << '/'
X/*  pwd(1)
X *
X *  Author: Terrence W. Holm          Aug. 1988
X */
X
X#define  NULL  		(char *) 0
X#define  PATH_MAX	127
X
Xextern char *getcwd();
X
X
Xmain()
X  {
X  char buffer[ PATH_MAX + 1 ];
X  char *path;
X
X  path = getcwd( buffer, PATH_MAX + 1 );
X
X  if ( path == NULL )
X    {
X    perror( ".." );
X    exit( 1 );
X    }
X
X  write( 1, path, strlen(path) );
X  write( 1, "\n", 1 );
X
X  exit( 0 );
X  }
/
----------------------------------------------------------

		Edwin L. Froese
		  uw-beaver!ubc-cs!mprg!handel!froese

		Terrence W. Holm
		  uw-beaver!uvicctr!tholm

tholm@uvicctr.UUCP (Terrence W. Holm) (09/09/88)

> EFTH MINIX report #38  - August 1988 -  getcwd(3)

My implementation of getcwd(3) has a bug. Thanks to
Earl Chew for funding it. (Is there a prize for finding
the first V1.4 bug?) The problem arises because getcwd(3)
does not reset the current directory before returning.

Earl supplied the following fix to set the directory
on NON-ERROR returns. Just change the last return() on
line 157 to:
  
  return( chdir( buffer ) ? NULL : buffer );