POSIX/SVID/X3J11 standard routines (libposix.a) (Part 3 of 5)
Lenny Tropiano
lenny at icus.islp.ny.us
Thu Aug 3 11:52:23 AEST 1989
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 3 (of 5)."
# Contents: DIRENT.INSTALL DIRENT.NOTES bsearch.3c directory.3c
# getcwd.c mkdir.c tsearch.c
# Wrapped by lenny at icus on Wed Aug 2 21:40:29 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f DIRENT.INSTALL -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"DIRENT.INSTALL\"
else
echo shar: Extracting \"DIRENT.INSTALL\" \(5490 characters\)
sed "s/^X//" >DIRENT.INSTALL <<'END_OF_DIRENT.INSTALL'
X
X
X INSTALLATION INSTRUCTIONS
X
X
XThe following instructions are for systems resembling Ninth Edition UNIX, with
Xhints about dealing with variations you may encounter for your specific system.
XInstallation should be done only by someone who is comfortable with modifying
Xthe standard C library and header files.
X
XIf your system already includes directory access routines, you should replace
Xthem with this package. We're trying to get this standardized; see the
Xdiscussion in the NOTES file.
X
XI have tried to make the source code as generic as possible, but if your system
Xpredates Seventh Edition UNIX you will have problems.
X
XDISCLAIMER: Although I believe the code and procedures described here to be
Xcorrect, I make no warranty of any kind, and you are advised to perform your
Xown careful testing before making any substantial change like this to your
Xprogramming environment.
X
X
X0) For antique systems that do not support C's "void" data type, edit the file
X sys.dirent.h to add the following:
X
X typedef int void; /* good enough for govt work */
X
X If for some reason your <sys/types.h> doesn't define them, add the
X following to sys.dirent.h:
X
X typedef unsigned short ino_t; /* (assuming original UFS) */
X typedef long off_t; /* long is forced by lseek() */
X
X None of this should be necessary for any modern UNIX system.
X
X1) Copy the file dirent.h to /usr/include/dirent.h and copy the file
X sys.dirent.h to /usr/include/sys/dirent.h. (The file sys._dir.h is also
X provided for the BRL UNIX System V emulation for 4.nBSD. That environment
X uses different directory names for everything.)
X
X2) Copy the file directory.3c to /usr/man/man3/directory.3 and copy the file
X dirent.4 to /usr/man/man5/dirent.5; edit the new file
X /usr/man/man3/directory.3 to change the "SEE ALSO" reference from dirent(4)
X to dirent(5) and to change the 3C on the first line to 3; edit the new file
X /usr/man/man5/dirent.5 to change the 4 on the first line to 5; then print
X the manual pages via the command
X
X man directory dirent
X
X to see what the new routines are like. (If you have a "catman" style of
X on-line manual, adapt these instructions accordingly. Manual entries are
X kept in directories with other names on some systems such as UNIX System V.
X On systems that already had a directory library documented in some other
X manual entry, remove the superseded manual entry; if the description of the
X native filesystem directory format found by "man dir" refers to a directory
X library, modify it to simply refer to the entry for "dirent".)
X
X3) Copy the files closedir.c, opendir.c, readdir.c, rewinddir.c, seekdir.c,
X and telldir.c to the "gen" or "port/gen" subdirectory of your C library
X source directory. If you do not have a getdents() system call, copy the
X file getdents.c to the "sys" or "port/sys" subdirectory and copy the file
X getdents.2 to /usr/man/man2/getdents.2 (actually you may prefer to put this
X file in section 3 and adjust the references in the other manual entries
X accordingly; also adjust the references to dirent(4) to be to dirent(5) if
X that's where the entry is). Edit the C library makefile(s) to include the
X new object modules in the C library. (See the comments at the beginning of
X getdents.c for symbols that must be defined to configure getdents.c.) Then
X remake and reinstall the C library. Alternatively, you can just compile
X the new sources and insert their objects near the front of the C library
X /lib/libc.a using the "ar" utility (seekdir.o should precede readdir.o,
X which in turn should precede getdents.o). On some systems you then need to
X use the "ranlib" utility to update the archive symbol table.
X
X4) After the C library has been updated, delete /usr/include/ndir.h or any
X other header used with a previous directory library to prevent inadvertent
X use of the superseded directory access interface. Also delete any
X corresponding library such as /usr/lib/libndir.a.
X
X5) To verify installation, try compiling, linking, and running the program
X testdir.c. This program searches the current directory "." for each file
X named as a program argument and prints `"FOO" found.' or `"FOO" not found.'
X where FOO is of course replaced by the name being sought in the directory.
X Try something like
X
X cd /usr/bin # a multi-block directory
X WHEREVER/testdir FOO lint BAR f77 XYZZY
X
X which should produce the output
X
X "FOO" not found.
X "lint" found.
X "BAR" not found.
X "f77" found.
X "XYZZY" not found.
X
X A more thorough test would be
X
X cd /usr/bin # a multi-block directory
X WHEREVER/testdir `ls -a` | grep 'not found'
X
X This program does not test the seekdir() and telldir() functions.
X
X6) Notify your programmers that all directory access must be made through the
X new interface, and that documentation is available via
X
X man directory dirent
X
X Make the NOTES file available to those programmers who might want to
X understand what this is all about.
X
X7) Change all system sources that were accessing directories to use the new
X routines. Nearly all such sources contain the line
X
X #include <sys/dir.h>
X or
X #include <ndir.h>
X
X so they should be easy to find. (If you earlier removed some other header
X file, that is, if this package superseded an earlier version of the
X directory access library, look for its name too. See the conversion
X instructions in the NOTES file.)
END_OF_DIRENT.INSTALL
if test 5490 -ne `wc -c <DIRENT.INSTALL`; then
echo shar: \"DIRENT.INSTALL\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f DIRENT.NOTES -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"DIRENT.NOTES\"
else
echo shar: Extracting \"DIRENT.NOTES\" \(5314 characters\)
sed "s/^X//" >DIRENT.NOTES <<'END_OF_DIRENT.NOTES'
X
X
XNOTES FOR NEARLY-POSIX-COMPATIBLE C LIBRARY DIRECTORY-ACCESS ROUTINES
X
X
XOlder UNIX C libraries lacked support for reading directories, so historically
Xprograms had knowledge of UNIX directory structure hard-coded into them. When
XBerkeley changed the format of directories for 4.2BSD, it became necessary to
Xchange programs to work with the new structure. Fortunately, Berkeley designed
Xa small set of directory access routines to encapsulate knowledge of the new
Xdirectory format so that user programs could deal with directory entries as an
Xabstract data type. (Unfortunately, they didn't get it quite right.) The
Xinterface to these routines was nearly independent of the particular
Ximplementation of directories on any given UNIX system; this has become a
Xparticularly important requirement with the advent of heterogeneous network
Xfilesystems such as NFS.
X
XIt has consequently become possible to write portable applications that search
Xdirectories by restricting all directory access to use these new interface
Xroutines. The sources supplied here are a total rewrite of Berkeley's code,
Xincorporating ideas from a variety of sources and conforming as closely to
Xpublished standards as possible, and are in the PUBLIC DOMAIN to encourage
Xtheir widespread adoption. They support four methods of access to system
Xdirectories: the original UNIX filesystem via read(), the 4.2BSD filesystem via
Xread(), NFS and native filesystems via getdirentries(), and SVR3 getdents().
XThe other three types are accomplished by appropriate emulation of the SVR3
Xgetdents() system call, which attains portability at the cost of slightly more
Xdata movement than absolutely necessary for some systems. These routines
Xshould be added to the standard C library on all UNIX systems, and all existing
Xand future applications should be changed to use this interface. Once this is
Xdone, there should be no portability problems due to differences in underlying
Xdirectory structures among UNIX systems. (When porting your applications to
Xother UNIX systems, you can always carry this package around with you.)
X
XAn additional benefit of these routines is that they buffer directory input,
Xwhich provides improved access speed over raw read()s of one entry at a time.
X
XOne annoying compatibility problem has arisen along the way, namely that the
Xoriginal Berkeley interface used the same name, struct direct, for the new data
Xstructure as had been used for the original UNIX filesystem directory record
Xstructure. This name was changed by the IEEE 1003.1 (POSIX) Working Group to
X"struct dirent" and was picked up for SVR3 under the new name; it is also the
Xname used in this portable package. I believe it is necessary to bite the
Xbullet and adopt the new non-conflicting name. Code using a 4.2BSD-compatible
Xpackage needs to be slightly revised to work with this new package, as follows:
X Change
X #include <ndir.h> /* Ninth Edition UNIX */
X or
X #include <sys/dir.h> /* 4.2BSD */
X or
X #include <dir.h> /* BRL System V emulation */
X to
X #include <sys/types.h> /* if not already #included */
X #include <dirent.h>
X
X Change
X struct direct
X to
X struct dirent
X
X Change
X (anything)->d_namlen
X to
X strlen( (anything)->d_name )
X
XThere is a minor compatibility problem in that the closedir() function was
Xoriginally defined to have type void, but IEEE 1003.1 changed this to type int,
Xwhich is what this implementation supports (even though I disagree with the
Xchange). However, the difference does not affect most applications.
X
XAnother minor problem is that IEEE 1003.1 defined the d_name member of a struct
Xdirent to be an array of maximum length; this does not permit use of compact
Xvariable-length entries directly from a directory block buffer. This part of
Xthe specification is incompatible with efficient use of the getdents() system
Xcall, and I have therefore chosen to follow the SVID specification instead of
XIEEE 1003.1 (which I hope is changed for the final-use standard). This
Xdeviation should have little or no impact on sensibly-coded applications, since
Xthe relevant d_name length is that given by strlen(), not the declared array
Xsize.
X
XError handling is not completely satisfactory, due to the variety of possible
Xfailure modes in a general setting. For example, the rewinddir() function
Xmight fail, but there is no good way to indicate this. I have tried to
Xfollow the specifications in IEEE 1003.1 and the SVID as closely as possible,
Xbut there are minor deviations in this regard. Applications should not rely
Xtoo heavily on exact failure mode semantics.
X
XPlease do not change the new standard interface in any way, as that would
Xdefeat the major purpose of this package! (It's okay to alter the internal
Ximplementation if you really have to, although I tried to make this unnecessary
Xfor the vast majority of UNIX variants.)
X
XInstallation instructions can be found in the file named INSTALL.
X
XThis implementation is provided by:
X
X Douglas A. Gwyn
X U.S. Army Ballistic Research Laboratory
X SLCBR-VL-V
X Aberdeen Proving Ground, MD 21005-5066
X
X (301)278-6647
X
X Gwyn at BRL.MIL or seismo!brl!gwyn
X
XThis is UNSUPPORTED, use-at-your-own-risk, free software in the public domain.
XHowever, I would appreciate hearing of any actual bugs you find in this
Ximplementation and/or any improvements you come up with.
END_OF_DIRENT.NOTES
if test 5314 -ne `wc -c <DIRENT.NOTES`; then
echo shar: \"DIRENT.NOTES\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f bsearch.3c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"bsearch.3c\"
else
echo shar: Extracting \"bsearch.3c\" \(3005 characters\)
sed "s/^X//" >bsearch.3c <<'END_OF_bsearch.3c'
X.TH BSEARCH 3C "Standard Extension"
X.SH NAME
Xbsearch \- binary search a sorted table
X.SH SYNOPSIS
X.B #include <search.h>
X.PP
X.B "char \(**bsearch ((char \(**) key, (char \(**) base, nel, sizeof (\(**key), compar)"
X.br
X.B unsigned nel;
X.br
X.B int (\(**compar)( );
X.SH DESCRIPTION
X.I Bsearch
Xis a binary search routine generalized from Knuth (6.2.1) Algorithm B.
XIt returns a pointer into a table indicating where a datum may be found.
XThe table must be previously sorted in increasing order according to a
Xprovided comparison function.
X.I Key
Xpoints to a datum instance to be sought in the table.
X.I Base
Xpoints to the element at the base of the table.
X.I Nel
Xis the number of elements in the table.
X.I Compar
Xis the name of the comparison function, which is called with two arguments
Xthat point to the elements being compared. The function must return
Xan integer less than, equal to, or greater than zero as accordinly the first
Xargument is to be considered less than, equal to, or greater than the second.
X.SH EXAMPLE
XThe example below searches a table containing pointers to nodes consisting of
Xa string and its length. The table is ordered alphabetically on the string in
Xthe node pointed to by each entry.
X.PP
XThis code fragment reads in strings and either finds the corresponding node
Xand prints out the string and its length, or prints an error message.
X.PP
X.RS
X.nf
X.ss 18
X#include <stdio.h>
X#include <search.h>
X
X#define \s-1TABSIZE\s+1 1000
X
Xstruct node { /\(** these are stored in the table \(**/
X char \(**string;
X int length;
X};
Xstruct node table[\s-1TABSIZE\s+1]; /\(** table to be searched \(**/
X .
X .
X .
X{
X struct node \(**node_ptr, node;
X int node_compare( ); /\(** routine to compare 2 nodes \(**/
X char str_space[20]; /\(** space to read string into \(**/
X .
X .
X .
X node.string = str_space;
X while (scanf("%s", node.string) != \s-1EOF\s+1) {
X node_ptr = (struct node \(**)bsearch((char \(**)(&node),
X (char \(**)table, \s-1TABSIZE\s+1,
X sizeof(struct node), node_compare);
X if (node_ptr != \s-1NULL\s+1) {
X (void)printf("string = %20s, length = %d\en",
X node_ptr\(mi>string, node_ptr\(mi>length);
X } else {
X (void)printf("not found: %s\en", node.string);
X }
X }
X}
X/\(**
X This routine compares two nodes based on an
X alphabetical ordering of the string field.
X\(**/
Xint
Xnode_compare(node1, node2)
Xstruct node \(**node1, \(**node2;
X{
X return strcmp(node1\(mi>string, node2\(mi>string);
X}
X.fe
X.SH NOTES
XThe pointers to the key and the element at the base of
Xthe table should be of type pointer-to-element,
Xand cast to type pointer-to-character.
X.br
XThe comparison function need not compare every byte,
Xso arbitrary data may be contained in the elements in addition to the values
Xbeing compared.
X.br
XAlthough declared as type pointer-to-character,
Xthe value returned should be cast into type pointer-to-element.
X.SH SEE ALSO
Xhsearch(3C), lsearch(3C), qsort(3C), tsearch(3C).
X.SH DIAGNOSTICS
XA
X\s-1NULL\s+1
Xpointer is returned if the key cannot be found in the table.
END_OF_bsearch.3c
if test 3005 -ne `wc -c <bsearch.3c`; then
echo shar: \"bsearch.3c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f directory.3c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"directory.3c\"
else
echo shar: Extracting \"directory.3c\" \(4136 characters\)
sed "s/^X//" >directory.3c <<'END_OF_directory.3c'
X.TH DIRECTORY 3C "Standard Extension"
X.SH NAME
Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- directory operations
X.SH SYNOPSIS
X.B "#include <sys/types.h>"
X.br
X.B "#include <dirent.h>"
X.P
X.B "DIR \(**opendir (dirname)"
X.br
X.B "char \(**dirname;"
X.P
X.B "struct dirent \(**readdir (dirp)"
X.br
X.B "DIR \(**dirp;"
X.P
X.B "off_t telldir (dirp)"
X.br
X.B "DIR \(**dirp;"
X.P
X.B "void seekdir (dirp, loc)"
X.br
X.B "DIR \(**dirp;"
X.br
X.B "off_t loc;"
X.P
X.B "void rewinddir (dirp)"
X.br
X.B "DIR \(**dirp;"
X.P
X.B "int closedir (dirp)"
X.br
X.B "DIR \(**dirp;"
X.SH DESCRIPTION
X.I Opendir
Xestablishes a connection between
Xthe directory named by
X.I dirname
Xand a unique object of type
X.SM DIR
Xknown as a
X.I "directory stream"
Xthat it creates.
X.I Opendir
Xreturns a pointer to be used to identify the
Xdirectory stream
Xin subsequent operations.
XA
X.SM NULL
Xpointer is returned if
X.I dirname
Xcannot be accessed or is not a directory,
Xor if
X.I opendir
Xis unable to create the
X.SM DIR
Xobject
X(perhaps due to insufficient memory).
X.P
X.I Readdir
Xreturns a pointer to an internal structure
Xcontaining information about the next active directory entry.
XNo inactive entries are reported.
XThe internal structure may be overwritten by
Xanother operation on the same
Xdirectory stream;
Xthe amount of storage needed to hold a copy
Xof the internal structure is given by the value of a macro,
X.IR DIRENTSIZ(strlen(direntp\->d_name)) ,
Xnot by
X.I "sizeof(struct\ dirent)"
Xas one might expect.
XA
X.SM NULL
Xpointer is returned
Xupon reaching the end of the directory,
Xupon detecting an invalid location in the directory,
Xor upon occurrence of an error while reading the directory.
X.P
X.I Telldir
Xreturns the current position associated with the named
Xdirectory stream
Xfor later use as an argument to
X.IR seekdir .
X.P
X.I Seekdir
Xsets the position of the next
X.I readdir
Xoperation on the named
Xdirectory stream.
XThe new position reverts to the one associated with the
Xdirectory stream
Xwhen the
X.I telldir
Xoperation from which
X.I loc
Xwas obtained was performed.
X.P
X.I Rewinddir
Xresets the position of the named
Xdirectory stream
Xto the beginning of the directory.
XAll buffered data for the directory stream is discarded,
Xthereby guaranteeing that the actual
Xfile system directory will be referred to for the next
X.I readdir
Xon the
Xdirectory stream.
X.P
X.I Closedir
Xcloses the named
Xdirectory stream;
Xinternal resources used for the
Xdirectory stream are liberated,
Xand subsequent use of the associated
X.SM DIR
Xobject is no longer valid.
X.I Closedir
Xreturns a value of zero if no error occurs,
X\-1 otherwise.
X.P
XThere are several possible errors that can occur
Xas a result of these operations;
Xthe external integer variable
X.I errno
Xis set to indicate the specific error.
X.RI ( Readdir 's
Xdetection of the normal end of a directory
Xis not considered to be an error.)
X.SH EXAMPLE
XSample code which searches the current working directory for entry
X.IR name :
X.P
X.ft B
X dirp = opendir( "." );
X.br
X while ( (dp = readdir( dirp )) != NULL )
X.br
X if ( strcmp( dp\->d_name, name ) == 0 )
X.br
X {
X.br
X (void) closedir( dirp );
X.br
X return FOUND;
X.br
X }
X.br
X (void) closedir( dirp );
X.br
X return NOT_FOUND;
X.ft P
X.SH "SEE ALSO"
Xgetdents(2), dirent(4).
X.SH WARNINGS
XEntries for "." and ".."
Xmay not be reported for some file system types.
X.P
XThe value returned by
X.I telldir
Xneed not have any simple interpretation
Xand should only be used as an argument to
X.IR seekdir .
XSimilarly,
Xthe
X.I loc
Xargument to
X.I seekdir
Xmust be obtained from a previous
X.I telldir
Xoperation on the same
Xdirectory stream.
X.P
X.I Telldir
Xand
X.I seekdir
Xare unreliable when used in conjunction with
Xfile systems that perform directory compaction or expansion
Xor when the directory stream has been closed and reopened.
XIt is best to avoid using
X.I telldir
Xand
X.I seekdir
Xaltogether.
X.P
XThe exact set of
X.I errno
Xvalues and meanings may vary among implementations.
X.P
XBecause directory entries can dynamically
Xappear and disappear,
Xand because directory contents are buffered
Xby these routines,
Xan application may need to continually rescan
Xa directory to maintain an accurate picture
Xof its active entries.
END_OF_directory.3c
if test 4136 -ne `wc -c <directory.3c`; then
echo shar: \"directory.3c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f getcwd.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"getcwd.c\"
else
echo shar: Extracting \"getcwd.c\" \(5249 characters\)
sed "s/^X//" >getcwd.c <<'END_OF_getcwd.c'
X/*
X getcwd -- get current working directory name (POSIX and SVID compatible)
X
X last edit: 21-Sep-1987 D A Gwyn
X
X This public-domain getcwd() routine can be used to replace the UNIX
X System V library routine (which uses popen() to capture the output of
X the "pwd" command). Once that is done, "pwd" can be reimplemented as
X just puts(getcwd()).
X
X This implementation depends on every directory having entries for
X "." and "..". It also depends on the internals of the <dirent.h>
X data structures to some degree.
X
X I considered using chdir() to ascend the hierarchy, followed by a
X final chdir() to the path being returned by getcwd() to restore the
X location, but decided that error recovery was too difficult that way.
X The algorithm I settled on was inspired by my rewrite of the "pwd"
X utility, combined with the dotdots[] array trick from the SVR2 shell.
X*/
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <dirent.h>
X#include <errno.h>
X#include <string.h>
X
Xtypedef char *pointer; /* (void *) if you have it */
X
Xextern void free();
Xextern pointer malloc();
Xextern int fstat(), stat();
X
Xextern int errno; /* normally done by <errno.h> */
X
X#ifndef NULL
X#define NULL 0 /* amorphous null pointer constant */
X#endif
X
X#ifndef NAME_MAX
X#define NAME_MAX 255 /* maximum directory entry size */
X#endif
X
Xchar *
Xgetcwd( buf, size ) /* returns pointer to CWD pathname */
X char *buf; /* where to put name (NULL to malloc) */
X int size; /* size of buf[] or malloc()ed memory */
X {
X static char dotdots[] =
X"../../../../../../../../../../../../../../../../../../../../../../../../../..";
X char *dotdot; /* -> dotdots[.], right to left */
X DIR *dirp; /* -> parent directory stream */
X struct dirent *dir; /* -> directory entry */
X struct stat stat1, stat2; /* info from stat() */
X struct stat *d = &stat1; /* -> info about "." */
X struct stat *dd = &stat2; /* -> info about ".." */
X register char *buffer; /* local copy of buf, or malloc()ed */
X char *bufend; /* -> buffer[size] */
X register char *endp; /* -> end of reversed string */
X register char *dname; /* entry name ("" for root) */
X int serrno = errno; /* save entry errno */
X
X if ( size == 0 )
X {
X errno = EINVAL; /* invalid argument */
X return NULL;
X }
X
X if ( (buffer = buf) == NULL /* wants us to malloc() the string */
X && (buffer = (char *)malloc( (unsigned)size )) == NULL
X ) {
X errno = ENOMEM; /* cannot malloc() specified size */
X return NULL;
X }
X
X if ( stat( ".", dd ) != 0 ) /* prime the pump */
X goto error; /* errno already set */
X
X endp = buffer; /* initially, empty string */
X bufend = &buffer[size];
X
X for ( dotdot = &dotdots[sizeof(dotdots)]; dotdot != dotdots; )
X {
X dotdot -= 3; /* include one more "/.." section */
X /* (first time is actually "..") */
X
X /* swap stat() info buffers */
X {
X register struct stat *temp = d;
X
X d = dd; /* new current dir is old parent dir */
X dd = temp;
X }
X
X if ( (dirp = opendir( dotdot )) == NULL ) /* new parent */
X goto error; /* errno already set */
X
X if ( fstat( dirp->dd_fd, dd ) != 0 )
X {
X serrno = errno; /* set by fstat() */
X (void)closedir( dirp );
X errno = serrno; /* in case closedir() clobbered it */
X goto error;
X }
X
X if ( d->st_dev == dd->st_dev )
X { /* not crossing a mount point */
X if ( d->st_ino == dd->st_ino )
X { /* root directory */
X dname = "";
X goto append;
X }
X
X do
X if ( (dir = readdir( dirp )) == NULL )
X {
X (void)closedir( dirp );
X errno = ENOENT; /* missing entry */
X goto error;
X }
X while ( dir->d_ino != d->st_ino );
X }
X else { /* crossing a mount point */
X struct stat t; /* info re. test entry */
X char name[sizeof(dotdots) + 1 + NAME_MAX];
X
X (void)strcpy( name, dotdot );
X dname = &name[strlen( name )];
X *dname++ = '/';
X
X do {
X if ( (dir = readdir( dirp )) == NULL )
X {
X (void)closedir( dirp );
X errno = ENOENT; /* missing entry */
X goto error;
X }
X
X (void)strcpy( dname, dir->d_name );
X /* must fit if NAME_MAX is not a lie */
X }
X while ( stat( name, &t ) != 0
X || t.st_ino != d->st_ino
X || t.st_dev != d->st_dev
X );
X }
X
X dname = dir->d_name;
X
X /* append "/" and reversed dname string onto buffer */
X append:
X if ( endp != buffer /* avoid trailing / in final name */
X || dname[0] == '\0' /* but allow "/" when CWD is root */
X )
X *endp++ = '/';
X
X {
X register char *app; /* traverses dname string */
X
X for ( app = dname; *app != '\0'; ++app )
X ;
X
X if ( app - dname >= bufend - endp )
X {
X (void)closedir( dirp );
X errno = ERANGE; /* won't fit allotted space */
X goto error;
X }
X
X while ( app != dname )
X *endp++ = *--app;
X }
X
X (void)closedir( dirp );
X
X if ( dname[0] == '\0' ) /* reached root; wrap it up */
X {
X register char *startp; /* -> buffer[.] */
X
X *endp = '\0'; /* plant null terminator */
X
X /* straighten out reversed pathname string */
X for ( startp = buffer; --endp > startp; ++startp )
X {
X char temp = *endp;
X
X *endp = *startp;
X *startp = temp;
X }
X
X errno = serrno; /* restore entry errno */
X return buffer;
X }
X }
X
X errno = ENOMEM; /* actually, algorithm failure */
X
X error:
X if ( buf == NULL )
X free( (pointer)buffer );
X
X return NULL;
X }
X
X
END_OF_getcwd.c
if test 5249 -ne `wc -c <getcwd.c`; then
echo shar: \"getcwd.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f mkdir.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"mkdir.c\"
else
echo shar: Extracting \"mkdir.c\" \(4832 characters\)
sed "s/^X//" >mkdir.c <<'END_OF_mkdir.c'
X/****************************************************************************
X
XNAME
X mkdir.c -- emulation of BSD/SVr3-style mkdir(2) system call
X
XSYNOPSIS
X int mkdir(path, perm) -- make a directory with given permissions
X char *path; int perm;
X
XDESCRIPTION
X The mkdir() function is used for making directories on systems that
Xdon't have a mkdir(2) call (that is, V7 and USG systems before V.3). It tries
Xto act as much like mkdir(2) as possible. Due to various bogosities (why, oh
Xwhy wasn't mknod(2) for a directory made a non-privileged call?) it cannot
Xcompletely succeed. It returns 0 on success and -1 on failure but
Xonly detect the following ERRNO conditions; ENOENT, EEXIST, EACCESS, ENOTDIR.
X
X Note: this function emulates the SVr3 behavior (group ID of the directory
Xis the effective group ID of the calling process) rather than the BSD
Xbehavior (group ID of the directory is the group ID of the parent directory).
X
X On USG it will succeed if the real or apparent uid of the calling process
Xhas write privileges in the current directory (the latter case is implemented
Xby a kluge that tries to set the parent directory's permissions to 0777, 'ware
Xsecurity holes!). The new directory will be owned by the effective uid.
X
X On V7 (because it restricts the chown(2) call and mkdir(1) makes
Xdirectories owned by the real ID of its caller) the call will only succeed
Xif the real ID matches, and the new directory will be owned by the real
Xuid.
X
XREVISED BY
X Eric S. Raymond
X
X****************************************************************************/
X/* LINTLIBRARY */
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <errno.h>
X#include <signal.h>
X
Xextern int errno;
X
Xstatic int fwait(pid)
X/* wait on a child process, shielding it from SIGINT and SIGHUP */
Xregister int pid;
X{
X register int w;
X int status;
X
X while ((w = wait(&status)) != pid && w != -1)
X continue;
X if (w == -1)
X status = -1;
X
X return(status);
X}
X
Xint mkdir(path, perm)
Xchar *path;
Xint perm;
X{
X int status, pid;
X int uid = getuid(), gid = getgid();
X#ifndef lint
X int euid = geteuid();
X int egid = getegid();
X#endif /* lint */
X struct stat pstat, sbuf;
X register char *p;
X char parent[200];
X extern char *strrchr();
X
X#ifdef MAIN
X (void) fprintf(stderr, "Attempting to mkdir %s\n", path);
X#endif /* MAIN */
X
X errno = 0;
X
X /*
X * check that the directory doesn't already exist, so that the
X * do loop below must run at least once
X */
X if (stat(path, &sbuf) == 0)
X {
X errno = EEXIST;
X#ifdef MAIN
X (void) fprintf(stderr, "Directory %s exists\n", path);
X#endif /* MAIN */
X return(-1);
X }
X
X /* construct the parent's name */
X if (p = strrchr(path, '/'))
X {
X *p = '\0';
X (void) strcpy(parent, path);
X *p = '/';
X }
X else
X (void) strcpy(parent, ".");
X
X if (stat(parent, &pstat) == -1) /* check that the parent exists */
X {
X errno = ENOENT;
X return(-1);
X }
X else if (!(pstat.st_mode & S_IFDIR)) /* and that it's a directory */
X {
X errno = ENOTDIR;
X return(-1);
X }
X
X#ifdef USG
X /*
X * If the parent directory is 755 (rwxr-xr-x) the mkdir(1) below
X * will probably fail because it will get suid'd to our real uid, which
X * is random (and thus probably won't match the parent owner's).
X * So we have to temporarily chmod the parent to 777 (rwxrwxrwx).
X */
X if (sbuf.st_uid != uid)
X {
X if (chmod(parent, 0777) == -1)
X {
X errno = EACCES;
X return(-1);
X }
X }
X#endif /* USG */
X
X /* now we can make the new directory */
X if (pid = fork()) /* parent side */
X {
X if (pid == -1)
X return(-1);
X
X status = fwait(pid); /* wait till mkdir child is done */
X
X#ifdef USG
X /*
X * Spawn another child to set ownership correctly -- we do this so
X * that it gets set to effective ID even if we're running su. This
X * only works where chown(2) can be called to give files away by a
X * non-superuser.
X */
X if (pid = fork())
X (void) fwait(pid);
X else {
X#ifndef lint
X int oldumask = umask(0777);
X#endif /* lint */
X
X (void) stat(".", &pstat);
X (void) setuid(uid);
X (void) setgid(gid);
X#ifndef lint /* USG lints disagree about 2nd argument types */
X (void) chmod(path, (unsigned)(perm & ~oldumask));
X (void) chown(path, euid, egid);
X (void) umask(oldumask);
X#endif /* lint */
X _exit(0);
X }
X#endif /* USG */
X } else { /* child side */
X (void) close(1); /* stdout */
X (void) close(2); /* stderr */
X (void) execlp("mkdir", "mkdir", path, (char *)0);
X perror(path);
X _exit(1);
X }
X
X#ifndef lint /* USG lints disagree about the type of arg 2 */
X#ifdef USG
X if (sbuf.st_uid != uid)
X (void) chmod(parent, (unsigned) pstat.st_mode); /* put it back */
X#endif /* USG */
X#endif /* lint */
X
X return(status);
X}
X
X/* mkdir.c ends here */
END_OF_mkdir.c
if test 4832 -ne `wc -c <mkdir.c`; then
echo shar: \"mkdir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f tsearch.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"tsearch.c\"
else
echo shar: Extracting \"tsearch.c\" \(3509 characters\)
sed "s/^X//" >tsearch.c <<'END_OF_tsearch.c'
X/*
X * Tree search generalized from Knuth (6.2.2) Algorithm T just like
X * the AT&T man page says.
X *
X * The node_t structure is for internal use only, lint doesn't grok it.
X *
X * Written by reading the System V Interface Definition, not the code.
X *
X * Totally public domain.
X */
X/*LINTLIBRARY*/
X
X#include <search.h>
X
Xtypedef struct node_t
X{
X char *key;
X struct node_t *left, *right;
X}
Xnode;
X
Xnode *tsearch(key, rootp, compar)
X/* find or insert datum into search tree */
Xchar *key; /* key to be located */
Xregister node **rootp; /* address of tree root */
Xint (*compar)(); /* ordering function */
X{
X register node *q;
X
X if (rootp == (struct node_t **)0)
X return ((struct node_t *)0);
X while (*rootp != (struct node_t *)0) /* Knuth's T1: */
X {
X int r;
X
X if ((r = (*compar)(key, (*rootp)->key)) == 0) /* T2: */
X return (*rootp); /* we found it! */
X rootp = (r < 0) ?
X &(*rootp)->left : /* T3: follow left branch */
X &(*rootp)->right; /* T4: follow right branch */
X }
X q = (node *) malloc(sizeof(node)); /* T5: key not found */
X if (q != (struct node_t *)0) /* make new node */
X {
X *rootp = q; /* link new node to old */
X q->key = key; /* initialize new node */
X q->left = q->right = (struct node_t *)0;
X }
X return (q);
X}
X
Xnode *tdelete(key, rootp, compar)
X/* delete node with given key */
Xchar *key; /* key to be deleted */
Xregister node **rootp; /* address of the root of tree */
Xint (*compar)(); /* comparison function */
X{
X node *p;
X register node *q;
X register node *r;
X int cmp;
X
X if (rootp == (struct node_t **)0 || (p = *rootp) == (struct node_t *)0)
X return ((struct node_t *)0);
X while ((cmp = (*compar)(key, (*rootp)->key)) != 0)
X {
X p = *rootp;
X rootp = (cmp < 0) ?
X &(*rootp)->left : /* follow left branch */
X &(*rootp)->right; /* follow right branch */
X if (*rootp == (struct node_t *)0)
X return ((struct node_t *)0); /* key not found */
X }
X r = (*rootp)->right; /* D1: */
X if ((q = (*rootp)->left) == (struct node_t *)0) /* Left (struct node_t *)0? */
X q = r;
X else if (r != (struct node_t *)0) /* Right link is null? */
X {
X if (r->left == (struct node_t *)0) /* D2: Find successor */
X {
X r->left = q;
X q = r;
X }
X else
X { /* D3: Find (struct node_t *)0 link */
X for (q = r->left; q->left != (struct node_t *)0; q = r->left)
X r = q;
X r->left = q->right;
X q->left = (*rootp)->left;
X q->right = (*rootp)->right;
X }
X }
X free((struct node_t *) *rootp); /* D4: Free node */
X *rootp = q; /* link parent to new node */
X return(p);
X}
X
Xstatic void trecurse(root, action, level)
X/* Walk the nodes of a tree */
Xregister node *root; /* Root of the tree to be walked */
Xregister void (*action)(); /* Function to be called at each node */
Xregister int level;
X{
X if (root->left == (struct node_t *)0 && root->right == (struct node_t *)0)
X (*action)(root, leaf, level);
X else
X {
X (*action)(root, preorder, level);
X if (root->left != (struct node_t *)0)
X trecurse(root->left, action, level + 1);
X (*action)(root, postorder, level);
X if (root->right != (struct node_t *)0)
X trecurse(root->right, action, level + 1);
X (*action)(root, endorder, level);
X }
X}
X
Xvoid twalk(root, action) /* Walk the nodes of a tree */
Xnode *root; /* Root of the tree to be walked */
Xvoid (*action)(); /* Function to be called at each node */
X{
X if (root != (node *)0 && action != (void(*)())0)
X trecurse(root, action, 0);
X}
X
X/* tsearch.c ends here */
END_OF_tsearch.c
if test 3509 -ne `wc -c <tsearch.c`; then
echo shar: \"tsearch.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 3 \(of 5\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 5 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Lenny Tropiano ICUS Software Systems [w] +1 (516) 589-7930
lenny at icus.islp.ny.us Telex; 154232428 ICUS [h] +1 (516) 968-8576
{ames,talcott,decuac,hombre,pacbell,sbcs}!icus!lenny attmail!icus!lenny
ICUS Software Systems -- PO Box 1; Islip Terrace, NY 11752
More information about the Unix-pc.sources
mailing list