echo x - directory.3 sed "s/^X/ /" >'directory.3'<< 'END OF FILE' XSUBROUTINES X directory(3) - directory operations X XINVOCATION X #include X #include X X DIR *opendir( dirname ) X char *dirname; X X struct dirent *readdir( dirp ) X DIR *dirp; X X off_t telldir( dirp ) X DIR *dirp; X X void seekdir( dirp, loc ) X DIR *dirp; X off_t loc; X X void rewinddir( dirp ) X DIR *dirp; X X int closedir( dirp ) X DIR *dirp; X XEXPLANATION X Opendir(3) establishes a connection between the directory named X by and a unique object of type DIR known as a X directory stream that it creates. Opendir(3) returns a pointer X to be used to identify the directory stream in subsequent X operations. A NULL pointer is returned if cannot be X accessed or is not a directory, or if opendir(3) is unable to X create the DIR object (perhaps due to insufficient memory). X X Readdir(3) returns a pointer to an internal structure containing X information about the next active directory entry. No inactive X entries are reported. The internal structure may be overwritten X by another operation on the same directory stream; the amount of X storage needed to hold a copy of the internal structure is given X by the value of a macro, DIRENTSIZ(strlen(direntp->d_name)), not X by sizeof(struct dirent) as one might expect. A NULL pointer is X returned upon reaching the end of the directory, upon detecting X an invalid location in the directory, or upon occurrence of an X error while reading the directory. X X Telldir(3) returns the current position associated with the named X directory stream for later use as an argument to seekdir(3). X X Seekdir(3) sets the position of the next readdir(3) operation on X the named directory stream. The new position reverts to the one X associated with the directory stream when the telldir(3) operation X from which was obtained was performed. X X Rewinddir(3) resets the position of the named directory stream to X the beginning of the directory. All buffered data for the directory X stream is discarded, thereby guaranteeing that the actual file X system directory will be referred to for the next readdir(3) on the X directory stream. X X Closedir(3) closes the named directory stream; internal resources X used for the directory stream are liberated, and subsequent use of X the associated DIR object is no longer valid. Closedir(3) returns X a value of zero if no error occurs, -1 otherwise. There are several X possible errors that can occur as a result of these operations; the X external integer variable is set to indicate the specific X error. (Readdir's detection of the normal end of a directory is not X considered to be an error.) X XEXAMPLE X Sample code which searches the current working directory for X an entry. Usage: "a.out directory filename". X X #include X #include X #include X X main( argc, argv ) X int argc; X char *argv[]; X X { X DIR *dirp; X struct dirent *dp; X X if ( (dirp = opendir( argv[1] )) == NULL ) X { X fprintf( stderr, "Cannot open directory\n" ); X exit( 1 ); X } X X while ( (dp = readdir( dirp )) != NULL ) X if ( strcmp( dp->d_name, argv[2] ) == 0 ) X { X (void) closedir( dirp ); X printf( "Found\n" ); X exit( 0 ); X } X X (void) closedir( dirp ); X printf( "Not found\n" ); X exit( 1 ); X } X XREFERENCES X dirent(4) X XWARNINGS X The value returned by telldir(3) need not have any simple X interpretation and should only be used as an argument to X seekdir(3). Similarly, the argument to seekdir(3) must X be obtained from a previous telldir(3) operation on the same X directory stream. Telldir(3) and seekdir(3) are unreliable X when the directory stream has been closed and reopened. It X is best to avoid using telldir(3) and seekdir(3) altogether. X X The exact set of values and meanings may vary among X implementations. X X Because directory entries can dynamically appear and disappear, X and because directory contents are buffered by these routines, X an application may need to continually rescan a directory to X maintain an accurate picture of its active entries. X XAUTHOR X Douglas A. Gwyn / echo x - getdents.3 sed "s/^X/ /" > 'getdents.3'<< 'END OF FILE' XSUBROUTINES X getdents(3) - get directory entries X XINVOCATION X int getdents( fildes, buf, nbyte ) X int fildes; X char *buf; X unsigned nbyte; X XEXPLANATION X Getdents(3) reads directory entries in a file system independent X format. This routine is only used by readdir(3) and should X never be used directly by a user's program. X XREFERENCES X directory(3), dirent(4) / echo x - dirent.4 gres '^X' '' > dirent.4 << '/' XSTRUCTURES X dirent(4) - file system independent directory entry X XEXPLANATION X Different file system types may have different directory X entries. The structure defines a file system X independent directory entry, which contains information X common to directory entries in different file system types. X A set of these structures is returned by the getdents(3) X subroutine. The structure is defined below. X X struct dirent X { X long d_ino; X off_t d_off; X unsigned short d_reclen; X char d_name[1]; X }; X X The field d_ino is a number which is unique for each file in X the file system. The field d_off represents an offset of that X directory entry in the actual file system directory. The field X d_name is the beginning of the character array giving the name X of the directory entry. This name is null terminated and may X have at most {NAME_MAX} characters in addition to the null X terminator. This results in file system independent directory X entries being variable-length entities. The value of d_reclen X is the record length of this entry. This length is defined to X be the number of bytes between the beginning of the current entry X and the next one, adjusted so that the next entry will start on X a long boundary. X XFILES X /usr/include/sys/dirent.h X XREFERENCES X getdents(3) X XWARNING X The field d_off does not have a simple interpretation for X some file system types and should not be used directly by X applications. / echo x - dir.h gres '^X' '' > dir.h << '/' X#define DIRBLKSIZ 512 /* size of directory block */ X X#ifndef DIRSIZ X#define DIRSIZ 14 X#endif X Xstruct direct { X ino_t d_ino; X char d_name[DIRSIZ]; X}; / echo x - dirent.h gres '^X' '' > dirent.h << '/' X/* X -- definitions for SVR3 directory access routines X X last edit: 25-Apr-1987 D A Gwyn X X Prerequisite: X*/ X X#include X X#define DIRBUF 1024 /* buffer size for fs-indep. dirs */ X /* must in general be larger than the filesystem buffer size */ X Xtypedef struct X { X int dd_fd; /* file descriptor */ X int dd_loc; /* offset in block */ X int dd_size; /* amount of valid data */ X char *dd_buf; /* -> directory block */ X } DIR; /* stream data from opendir() */ X Xextern DIR *opendir(); Xextern struct dirent *readdir(); Xextern off_t telldir(); Xextern void seekdir(); Xextern void rewinddir(); Xextern int closedir(); X X#ifndef NULL X#define NULL 0 /* DAG -- added for convenience */ X#endif / echo x - sys_dirent.h gres '^X' '' > sys_dirent.h << '/' X/* X -- file system independent directory entry (SVR3) X X last edit: 27-Oct-1988 D A Gwyn X X prerequisite: X*/ X Xstruct dirent /* data from getdents()/readdir() */ X { X long d_ino; /* inode number of entry */ X off_t d_off; /* offset of disk directory entry */ X unsigned short d_reclen; /* length of this record */ X char d_name[1]; /* name of file */ /* non-ANSI */ X }; X X#ifdef BSD_SYSV /* (e.g., when compiling getdents.c) */ Xextern struct dirent __dirent; /* (not actually used) */ X/* The following is portable, although rather silly. */ X#define DIRENTBASESIZ (__dirent.d_name - (char *)&__dirent.d_ino) X X#else X/* The following nonportable ugliness could have been avoided by defining X DIRENTSIZ and DIRENTBASESIZ to also have (struct dirent *) arguments. X There shouldn't be any problem if you avoid using the DIRENTSIZ() macro. */ X X#define DIRENTBASESIZ (((struct dirent *)0)->d_name \ X - (char *)&((struct dirent *)0)->d_ino) X#endif X X#define DIRENTSIZ( namlen ) ((DIRENTBASESIZ + sizeof(long) + (namlen)) \ X / sizeof(long) * sizeof(long)) X X/* DAG -- the following was moved from , which was the wrong place */ X#define MAXNAMLEN 512 /* maximum filename length */ X X#ifndef NAME_MAX X#define NAME_MAX (MAXNAMLEN - 1) /* DAG -- added for POSIX */ X#endif / echo x - closedir.c gres '^X' '' > closedir.c << '/' X/* X closedir -- close a directory stream X X last edit: 11-Nov-1988 D A Gwyn X*/ X X#include X#include X#include X Xtypedef char *pointer; /* (void *) if you have it */ X Xextern void free(); Xextern int close(); X Xextern int errno; X X#ifndef NULL X#define NULL 0 X#endif X Xint Xclosedir( dirp ) X register DIR *dirp; /* stream from opendir() */ X { X register int fd; X X if ( dirp == NULL || dirp->dd_buf == NULL ) X { X errno = EFAULT; X return -1; /* invalid pointer */ X } X X fd = dirp->dd_fd; /* bug fix thanks to R. Salz */ X free( (pointer)dirp->dd_buf ); X free( (pointer)dirp ); X return close( fd ); X } / echo x - getdents.c gres '^X' '' > getdents.c << '/' X/* X getdents -- get directory entries in a file system independent format X (SVR3 system call emulation) X X last edit: 27-Oct-1988 D A Gwyn X X This single source file supports several different methods of X getting directory entries from the operating system. Define X whichever one of the following describes your system: X X UFS original UNIX filesystem (14-character name limit) X BFS 4.2BSD (also 4.3BSD) native filesystem (long names) X NFS getdirentries() system call X X Also define any of the following flags that are pertinent: X X ATT_SPEC check user buffer address for longword alignment X BSD_SYSV BRL UNIX System V emulation environment on 4.nBSD X INT_SIGS thinks that signal handlers have X return type int (rather than the standard void) X NEG_DELS deleted entries have inode number -1 rather than 0 X UNK have _getdents() system call, but kernel may not X support it X X If your C library has a getdents() system call interface, but you X can't count on all kernels on which your application binaries may X run to support it, change the system call interface name to X _getdents() and define "UNK" to enable the system-call validity X test in this "wrapper" around _getdents(). X X If your system has a getdents() system call that is guaranteed X to always work, you shouldn't be using this source file at all. X*/ X X#define UFS X X#include X#include X#ifdef BSD_SYSV X#include /* BSD flavor, not System V */ X#else X#include X#undef MAXNAMLEN /* avoid conflict with SVR3 */ X /* Good thing we don't need to use the DIRSIZ() macro! */ X#ifdef d_ino /* 4.3BSD/NFS using d_fileno */ X#undef d_ino /* (not absolutely necessary) */ X#else X#define d_fileno d_ino /* (struct direct) member */ X#endif X#endif X#include X#include X#ifdef UNK X#ifndef UFS X#include "***** ERROR ***** UNK applies only to UFS" X/* One could do something similar for getdirentries(), but I didn't bother. */ X#endif X#include X#endif X X#ifdef BSD_SYSV Xstruct dirent __dirent; /* (just for the DIRENTBASESIZ macro) */ X#endif X X#ifdef UFS X#define RecLen( dp ) (sizeof(struct direct)) /* fixed-length entries */ X#else /* BFS || NFS */ X#define RecLen( dp ) ((dp)->d_reclen) /* variable-length entries */ X#endif X X#ifdef NFS X#ifdef BSD_SYSV X#define getdirentries _getdirentries /* package hides this system call */ X#endif Xextern int getdirentries(); Xstatic long dummy; /* getdirentries() needs basep */ X#define GetBlock( fd, buf, n ) getdirentries( fd, buf, (unsigned)n, &dummy ) X#else /* UFS || BFS */ X#ifdef BSD_SYSV X#define read _read /* avoid emulation overhead */ X#endif Xextern int read(); X#define GetBlock( fd, buf, n ) read( fd, buf, (unsigned)n ) X#endif X X#ifdef UNK Xextern int _getdents(); /* actual system call */ X#endif X Xextern char *strncpy(); Xextern int fstat(); Xextern off_t lseek(); X Xextern int errno; X X#ifdef NEG_DELS X#define DELETED (-1) X#else X#define DELETED 0 X#endif X X#ifndef DIRBLKSIZ X#define DIRBLKSIZ 4096 /* directory file read buffer size */ X#endif X X#ifndef NULL X#define NULL 0 X#endif X X#ifndef SEEK_CUR X#define SEEK_CUR 1 X#endif X X#ifndef S_ISDIR /* macro to test for directory file */ X#define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR) X#endif X X#ifdef UFS X X/* X The following routine is necessary to handle DIRSIZ-long entry names. X Thanks to Richard Todd for pointing this out. X*/ X Xstatic int XNameLen( name ) /* return # chars in embedded name */ X char name[]; /* -> name embedded in struct direct */ X { X register char *s; /* -> name[.] */ X register char *stop = &name[DIRSIZ]; /* -> past end of name field */ X X for ( s = &name[1]; /* (empty names are impossible) */ X *s != '\0' /* not NUL terminator */ X && ++s < stop; /* < DIRSIZ characters scanned */ X ) X ; X X return s - name; /* # valid characters in name */ X } X X#else /* BFS || NFS */ X Xextern int strlen(); X X#define NameLen( name ) strlen( name ) /* names are always NUL-terminated */ X X#endif X X#ifdef UNK Xstatic enum { maybe, no, yes } state = maybe; X /* does _getdents() work? */ X X#ifdef INT_SIGS X#define RET_SIG int X#else X#define RET_SIG void X#endif X X/*ARGSUSED*/ Xstatic RET_SIG Xsig_catch( sig ) X int sig; /* must be SIGSYS */ X { X state = no; /* attempted _getdents() faulted */ X#ifdef INT_SIGS X return 0; /* telling lies */ X#endif X } X#endif /* UNK */ X Xint Xgetdents( fildes, buf, nbyte ) /* returns # bytes read; X 0 on EOF, -1 on error */ X int fildes; /* directory file descriptor */ X char *buf; /* where to put the (struct dirent)s */ X unsigned nbyte; /* size of buf[] */ X { X int serrno; /* entry errno */ X off_t offset; /* initial directory file offset */ X /* The following are static just to keep the stack small. */ X static struct stat statb; /* fstat() info */ X static union X { X char dblk[DIRBLKSIZ X#ifdef UFS X +1 /* for last entry name terminator */ X#endif X ]; X /* directory file block buffer */ X struct direct dummy; /* just for alignment */ X } u; /* (avoids having to malloc()) */ X register struct direct *dp; /* -> u.dblk[.] */ X register struct dirent *bp; /* -> buf[.] */ X X#ifdef UNK X if ( state == yes ) /* _getdents() is known to work */ X return _getdents( fildes, buf, nbyte ); X X if ( state == maybe ) /* first time only */ X { X RET_SIG (*shdlr)(); /* entry SIGSYS handler */ X register int retval; /* return from _getdents() if any */ X X shdlr = signal( SIGSYS, sig_catch ); X retval = _getdents( fildes, buf, nbyte ); /* try it */ X (void)signal( SIGSYS, shdlr ); X X if ( state == maybe ) /* SIGSYS did not occur */ X { X state = yes; /* so _getdents() must have worked */ X return retval; X } X } X X /* state == no; perform emulation */ X#endif X X if ( buf == NULL X#ifdef ATT_SPEC X || (unsigned long)buf % sizeof(long) != 0 /* ugh */ X#endif X ) { X errno = EFAULT; /* invalid pointer */ X return -1; X } X X if ( fstat( fildes, &statb ) != 0 ) X return -1; /* errno set by fstat() */ X X if ( !S_ISDIR( statb.st_mode ) ) X { X errno = ENOTDIR; /* not a directory */ X return -1; X } X X if ( (offset = lseek( fildes, (off_t)0, SEEK_CUR )) < 0 ) X return -1; /* errno set by lseek() */ X X#ifdef BFS /* no telling what remote hosts do */ X if ( (unsigned long)offset % DIRBLKSIZ != 0 ) X { X errno = ENOENT; /* file pointer probably misaligned */ X return -1; X } X#endif X X serrno = errno; /* save entry errno */ X X for ( bp = (struct dirent *)buf; bp == (struct dirent *)buf; ) X { /* convert next directory block */ X int size; X X do size = GetBlock( fildes, u.dblk, DIRBLKSIZ ); X while ( size == -1 && errno == EINTR ); X X if ( size <= 0 ) X return size; /* EOF or error (EBADF) */ X X for ( dp = (struct direct *)u.dblk; X (char *)dp < &u.dblk[size]; X dp = (struct direct *)((char *)dp + RecLen( dp )) X ) { X#ifndef UFS X if ( dp->d_reclen <= 0 ) X { X errno = EIO; /* corrupted directory */ X return -1; X } X#endif X X if ( dp->d_fileno != DELETED ) X { /* non-empty; copy to user buffer */ X register int reclen = X DIRENTSIZ( NameLen( dp->d_name ) ); X X if ( (char *)bp + reclen > &buf[nbyte] ) X { X errno = EINVAL; X return -1; /* buf too small */ X } X X bp->d_ino = dp->d_fileno; X bp->d_off = offset + ((char *)dp - u.dblk); X bp->d_reclen = reclen; X X { X#ifdef UFS X /* Is the following kludge ugly? You bet. */ X X register char save = dp->d_name[DIRSIZ]; X /* save original data */ X X dp->d_name[DIRSIZ] = '\0'; X /* ensure NUL termination */ X#endif X (void)strncpy( bp->d_name, dp->d_name, X reclen - DIRENTBASESIZ X ); /* adds NUL padding */ X#ifdef UFS X dp->d_name[DIRSIZ] = save; X /* restore original data */ X#endif X } X X bp = (struct dirent *)((char *)bp + reclen); X } X } X X if ( (char *)dp > &u.dblk[size] ) X { X errno = EIO; /* corrupted directory */ X return -1; X } X } X X errno = serrno; /* restore entry errno */ X return (char *)bp - buf; /* return # bytes read */ X } / echo x - opendir.c gres '^X' '' > opendir.c << '/' X/* X opendir -- open a directory stream X X last edit: 27-Oct-1988 D A Gwyn X*/ X X#include X#include X#include X#include X X#ifdef BSD_SYSV X#define open _open /* avoid emulation overhead */ X#endif X Xtypedef char *pointer; /* (void *) if you have it */ X Xextern void free(); Xextern pointer malloc(); Xextern int open(), close(), fstat(); X Xextern int errno; X X#ifndef NULL X#define NULL 0 X#endif X X#ifndef O_RDONLY X#define O_RDONLY 0 X#endif X X#ifndef S_ISDIR /* macro to test for directory file */ X#define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR) X#endif X XDIR * Xopendir( dirname ) X char *dirname; /* name of directory */ X { X register DIR *dirp; /* -> malloc'ed storage */ X register int fd; /* file descriptor for read */ X /* The following is static just to keep the stack small. */ X static struct stat sbuf; /* result of fstat() */ X X if ( (fd = open( dirname, O_RDONLY )) < 0 ) X return NULL; /* errno set by open() */ X X if ( fstat( fd, &sbuf ) != 0 || !S_ISDIR( sbuf.st_mode ) ) X { X (void)close( fd ); X errno = ENOTDIR; X return NULL; /* not a directory */ X } X X if ( (dirp = (DIR *)malloc( sizeof(DIR) )) == NULL X || (dirp->dd_buf = (char *)malloc( (unsigned)DIRBUF )) == NULL X ) { X register int serrno = errno; X /* errno set to ENOMEM by sbrk() */ X X if ( dirp != NULL ) X free( (pointer)dirp ); X X (void)close( fd ); X errno = serrno; X return NULL; /* not enough memory */ X } X X dirp->dd_fd = fd; X dirp->dd_loc = dirp->dd_size = 0; /* refill needed */ X X return dirp; X } / echo x - readdir.c gres '^X' '' > readdir.c << '/' X/* X readdir -- read next entry from a directory stream X X last edit: 25-Apr-1987 D A Gwyn X*/ X X#include X#include X#include X Xextern int getdents(); /* SVR3 system call, or emulation */ X Xextern int errno; X X#ifndef NULL X#define NULL 0 X#endif X Xstruct dirent * Xreaddir( dirp ) X register DIR *dirp; /* stream from opendir() */ X { X register struct dirent *dp; /* -> directory data */ X X if ( dirp == NULL || dirp->dd_buf == NULL ) X { X errno = EFAULT; X return NULL; /* invalid pointer */ X } X X do { X if ( dirp->dd_loc >= dirp->dd_size ) /* empty or obsolete */ X dirp->dd_loc = dirp->dd_size = 0; X X if ( dirp->dd_size == 0 /* need to refill buffer */ X && (dirp->dd_size = X getdents( dirp->dd_fd, dirp->dd_buf, (unsigned)DIRBUF ) X ) <= 0 X ) X return NULL; /* EOF or error */ X X dp = (struct dirent *)&dirp->dd_buf[dirp->dd_loc]; X dirp->dd_loc += dp->d_reclen; X } X while ( dp->d_ino == 0L ); /* don't rely on getdents() */ X X return dp; X } / echo x - rewinddir.c gres '^X' '' > rewinddir.c << '/' X/* X rewinddir -- rewind a directory stream X X last edit: 25-Apr-1987 D A Gwyn X X This is not simply a call to seekdir(), because seekdir() X will use the current buffer whenever possible and we need X rewinddir() to forget about buffered data. X*/ X X#include X#include X#include X Xextern off_t lseek(); X Xextern int errno; X X#ifndef NULL X#define NULL 0 X#endif X X#ifndef SEEK_SET X#define SEEK_SET 0 X#endif X Xvoid Xrewinddir( dirp ) X register DIR *dirp; /* stream from opendir() */ X { X if ( dirp == NULL || dirp->dd_buf == NULL ) X { X errno = EFAULT; X return; /* invalid pointer */ X } X X dirp->dd_loc = dirp->dd_size = 0; /* invalidate buffer */ X (void)lseek( dirp->dd_fd, (off_t)0, SEEK_SET ); /* may set errno */ X } / echo x - seekdir.c gres '^X' '' > seekdir.c << '/' X/* X seekdir -- reposition a directory stream X X last edit: 24-May-1987 D A Gwyn X X An unsuccessful seekdir() will in general alter the current X directory position; beware. X X NOTE: 4.nBSD directory compaction makes seekdir() & telldir() X practically impossible to do right. Avoid using them! X*/ X X#include X#include X#include X Xextern off_t lseek(); X Xextern int errno; X X#ifndef NULL X#define NULL 0 X#endif X X#ifndef SEEK_SET X#define SEEK_SET 0 X#endif X Xtypedef int bool; /* Boolean data type */ X#define false 0 X#define true 1 X Xvoid Xseekdir( dirp, loc ) X register DIR *dirp; /* stream from opendir() */ X register off_t loc; /* position from telldir() */ X { X register bool rewind; /* "start over when stymied" flag */ X X if ( dirp == NULL || dirp->dd_buf == NULL ) X { X errno = EFAULT; X return; /* invalid pointer */ X } X X /* A (struct dirent)'s d_off is an invented quantity on 4.nBSD X NFS-supporting systems, so it is not safe to lseek() to it. */ X X /* Monotonicity of d_off is heavily exploited in the following. */ X X /* This algorithm is tuned for modest directory sizes. For X huge directories, it might be more efficient to read blocks X until the first d_off is too large, then back up one block, X or even to use binary search on the directory blocks. I X doubt that the extra code for that would be worthwhile. */ X X if ( dirp->dd_loc >= dirp->dd_size /* invalid index */ X || ((struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off > loc X /* too far along in buffer */ X ) X dirp->dd_loc = 0; /* reset to beginning of buffer */ X /* else save time by starting at current dirp->dd_loc */ X X for ( rewind = true; ; ) X { X register struct dirent *dp; X X /* See whether the matching entry is in the current buffer. */ X X if ( (dirp->dd_loc < dirp->dd_size /* valid index */ X || readdir( dirp ) != NULL /* next buffer read */ X && (dirp->dd_loc = 0, true) /* beginning of buffer set */ X ) X && (dp = (struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off X <= loc /* match possible in this buffer */ X ) { X for ( /* dp initialized above */ ; X (char *)dp < &dirp->dd_buf[dirp->dd_size]; X dp = (struct dirent *)((char *)dp + dp->d_reclen) X ) X if ( dp->d_off == loc ) X { /* found it! */ X dirp->dd_loc = X (char *)dp - dirp->dd_buf; X return; X } X X rewind = false; /* no point in backing up later */ X dirp->dd_loc = dirp->dd_size; /* set end of buffer */ X } X else /* whole buffer past matching entry */ X if ( !rewind ) X { /* no point in searching further */ X errno = EINVAL; X return; /* no entry at specified loc */ X } X else { /* rewind directory and start over */ X rewind = false; /* but only once! */ X X dirp->dd_loc = dirp->dd_size = 0; X X if ( lseek( dirp->dd_fd, (off_t)0, SEEK_SET ) X != 0 X ) X return; /* errno already set (EBADF) */ X X if ( loc == 0 ) X return; /* save time */ X } X } X } / echo x - telldir.c gres '^X' '' > telldir.c << '/' X/* X telldir -- report directory stream position X X last edit: 25-Apr-1987 D A Gwyn X X NOTE: 4.nBSD directory compaction makes seekdir() & telldir() X practically impossible to do right. Avoid using them! X*/ X X#include X#include X#include X Xextern off_t lseek(); X Xextern int errno; X X#ifndef SEEK_CUR X#define SEEK_CUR 1 X#endif X Xoff_t Xtelldir( dirp ) /* return offset of next entry */ X DIR *dirp; /* stream from opendir() */ X { X if ( dirp == NULL || dirp->dd_buf == NULL ) X { X errno = EFAULT; X return -1; /* invalid pointer */ X } X X if ( dirp->dd_loc < dirp->dd_size ) /* valid index */ X return ((struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off; X else /* beginning of next directory block */ X return lseek( dirp->dd_fd, (off_t)0, SEEK_CUR ); X } / exit ---------------------------------------------------------- Terrence W. Holm uunet!uw-beaver!uvicctr!tholm tholm%uvunix.bitnet tholm@uvicctr.UVic.ca