File:  [MW Coherent from dump] / coherent / b / lib / libc / ndir / getdents.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:36 2019 UTC (7 years ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
	getdents -- get directory entries in a file system independent format
			(SVR3 system call emulation)

	last edit:	25-Apr-1987	D A Gwyn

	This single source file supports several different methods of
	getting directory entries from the operating system.  Define
	whichever one of the following describes your system:

	UFS	original UNIX filesystem (14-character name limit)
	BFS	4.2BSD (also 4.3BSD) native filesystem (long names)
	NFS	getdirentries() system call

	Also define any of the following that are pertinent:

	BRL	BRL UNIX System V emulation environment on 4.nBSD
	UNK	have _getdents() system call, but kernel may not support it

	If your C library has a getdents() system call interface, but you
	can't count on all kernels on which your application binaries may
	run to support it, change the system call interface name to
	_getdents() and define "UNK" to enable the system-call validity
	test in this "wrapper" around _getdents().

	If your system has a getdents() system call that is guaranteed 
	to always work, you shouldn't be using this source file at all.
*/


#if DBG
#include 	<stdio.h>
#endif

#include	<sys/types.h>

#ifdef COHERENT
#  include	<errno.h>
#else
#  include	<sys/errno.h>
#endif /*Coherent*/

#ifdef BRL
#  include	<sys/_dir.h>		/* BSD flavor, not System V */
#else
#  ifndef COHERENT
#    include	<sys/dir.h>
#  endif
	/* Good thing we don't need to use the DIRSIZ() macro! */
#  ifdef d_ino				/* 4.3BSD/NFS using d_fileno */
#    undef	d_ino			/* (not absolutely necessary) */
#  else
#    define	d_fileno	d_ino		/* (struct direct) member */
#  endif
#endif

/* sys.dirent.h no longer needed for 4.2 */
#if 0
#if DBG
#include	"sys.dirent.h"
#else
#include	"sys.dirent.h"
#endif /*DBG*/
#endif

#include <dirent.h>

#include	<sys/stat.h>
#ifdef UNK
#  ifndef UFS
#    include "***** ERROR ***** UNK applies only to UFS"
/* One could do something similar for getdirentries(), but I didn't bother. */
#  endif
#  include	<signal.h>
#endif



#if defined(UFS) + defined(BFS) + defined(NFS) != 1	/* sanity check */
#include "***** ERROR ***** exactly one of UFS, BFS, or NFS must be defined"
#endif


#define max(a,b) ( ((a)>(b)) ? (a) : (b) )

#ifdef UFS
#define	RecLen( dp )	(sizeof(struct direct))	/* fixed-length entries */
#else	/* BFS || NFS */
#define	RecLen( dp )	((dp)->d_reclen)	/* variable-length entries */
#endif

#ifdef NFS
#  ifdef BRL
#    define getdirentries _getdirentries /* package hides this system call */
#  endif
   extern int	getdirentries();
   static long	dummy;			/* getdirentries() needs basep */
#  define	GetBlock( fd, buf, n )	getdirentries( fd, buf, (unsigned)n, &dummy )
#else	/* UFS || BFS */
#  ifdef BRL
#    define read	_read			/* avoid emulation overhead */
#  endif
   extern int	read();
#  define	GetBlock( fd, buf, n )	read( fd, buf, (unsigned)n )
#endif

#ifdef UNK
extern int	_getdents();		/* actual system call */
#endif

extern char	*strncpy();
extern int	fstat(), strlen();

off_t	lseek();

extern int	errno;

#ifndef DIRBLKSIZ
#define	DIRBLKSIZ	4096		/* directory file read buffer size */
#endif

#ifndef NULL
#define	NULL	0
#endif

#ifndef SEEK_CUR
#define	SEEK_CUR	1
#endif

#ifndef S_ISDIR				/* macro to test for directory file */
#define	S_ISDIR( mode )		(((mode) & S_IFMT) == S_IFDIR)
#endif

#ifdef UNK
static enum	{ maybe, no, yes }	state = maybe;
					/* does _getdents() work? */

/*ARGSUSED*/
static void
sig_catch( sig )
	int	sig;			/* must be SIGSYS */
	{
	state = no;			/* attempted _getdents() faulted */
	}
#endif

int
getdents( fildes, buf, nbyte )		/* returns # bytes read;
					   0 on EOF, -1 on error */
	int			fildes;	/* directory file descriptor */
	char			*buf;	/* where to put the (struct dirent)s */
	unsigned		nbyte;	/* size of buf[] */
	{
	int			serrno;	/* entry errno */
	off_t			offset;	/* initial directory file offset */
	struct stat		statb;	/* fstat() info */
	union	{
		char		dblk[DIRBLKSIZ];
					/* directory file block buffer */
		struct direct	dummy;	/* just for alignment */
		}	u;		/* (avoids having to malloc()) */
	register struct direct	*dp;	/* -> u.dblk[.] */
	register struct dirent	*bp;	/* -> buf[.] */

#ifdef UNK
	switch ( state )
		{
		void		(*shdlr)();	/* entry SIGSYS handler */
		register int	retval;	/* return from _getdents() if any */

	case yes:			/* _getdents() is known to work */
		return _getdents( fildes, buf, nbyte );

	case maybe:			/* first time only */
		shdlr = signal( SIGSYS, sig_catch );
		retval = _getdents( fildes, buf, nbyte );	/* try it */
		(void)signal( SIGSYS, shdlr );

		if ( state == maybe )	/* SIGSYS did not occur */
			{
			state = yes;	/* so _getdents() must have worked */
			return retval;
			}
		/* else fall through into emulation */

	case no:	/* fall through into emulation */
		}
#endif

#if DBG
	printf("\ngetdents: fd= %d; buf=%x; nbytes=%d\n",fildes,buf,nbyte);
#endif

	if ( buf == NULL 
#ifndef BIT_16
	|| (unsigned long)buf % sizeof(long) != 0 ) /* ugh */
#else
	)
#endif /*16bit*/
		{
		errno = EFAULT;		/* invalid pointer */
		return -1;
		}

#if DBG
	printf("fstat says: %d\n",fstat(fildes, &statb));
#endif
	if ( fstat( fildes, &statb ) != 0 )
		return -1;		/* errno set by fstat() */
#if DBG
	printf("fstat OK\n");
#endif
	if ( !S_ISDIR( statb.st_mode ) )
		{
		errno = ENOTDIR;	/* not a directory */
		return -1;
		}
#ifdef DBG
	printf("fd  is a dir.\n");
#endif
	if ( (offset = lseek( fildes, (off_t)0, SEEK_CUR )) < 0 )
		return -1;		/* errno set by lseek() */


#ifdef BFS				/* no telling what remote hosts do */
	if ( (unsigned long)offset % DIRBLKSIZ != 0 )
		{
		errno = ENOENT;		/* file pointer probably misaligned */
		return -1;
		}
#endif

	serrno = errno;			/* save entry errno */

#if DBG
	printf(stderr,"\nIn getdents: \n");
#endif
	for ( bp = (struct dirent *)buf; bp == (struct dirent *)buf; )
		{			/* convert next directory block */
		int	size;

		do	size = GetBlock( fildes, u.dblk, DIRBLKSIZ );
		while ( size == -1 && errno == EINTR );

		if ( size <= 0 )
			return size;	/* EOF or error (EBADF) */

		for ( dp = (struct direct *)u.dblk;
		      (char *)dp < &u.dblk[size];
		      dp = (struct direct *)((char *)dp + RecLen( dp ))
		    )	{
#ifndef UFS
			if ( dp->d_reclen <= 0 )
				{
				errno = EIO;	/* corrupted directory */
				return -1;
				}
#endif

			if ( dp->d_fileno != 0 )
				{	/* non-empty; copy to user buffer */
				register int	reclen, namlen =
					strlen ( dp ->d_name );
#if DBG
	printf("name (%s) is %d long, ",dp->d_name, namlen);
#endif /*DBG*/
				namlen = (namlen > MAXNAMLEN) ? MAXNAMLEN
								: namlen;
#ifdef DBG
	printf("(ultimately %d long) MAXNAMLEN=%d\n", namlen,MAXNAMLEN);
#endif
				reclen = DIRENTSIZ(namlen);

				if ( (char *)bp + reclen > &buf[nbyte] )
					{
					errno = EINVAL;
					return -1;	/* buf too small */
					}

				bp->d_ino = (long) dp->d_fileno;
				bp->d_off = offset + ((char *)dp - u.dblk);
				bp->d_reclen = reclen;

				(void)strncpy( bp->d_name, dp->d_name,
					     namlen);
				(void)memset (bp->d_name + namlen, (char *)0,
					reclen - DIRENTBASESIZ - namlen
					     );	/* adds NUL padding */

#if DBG
	printf("getdents: Name=%s; inode = %D; offset = %D; len=%d\n",bp->d_name,
		bp->d_ino, bp->d_off, bp->d_reclen );
#endif
				bp = (struct dirent *)((char *)bp + reclen);
				}
			}

		if ( (char *)dp > &u.dblk[size] )
			{
			errno = EIO;	/* corrupted directory */
			return -1;
			}
		}

	errno = serrno;			/* restore entry errno */
	return (char *)bp - buf;	/* return # bytes read */
	}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.