⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 paxdir.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
     * A (struct dirent)'s d_off is an invented quantity on 4.nBSD     * NFS-supporting systems, so it is not safe to lseek() to it.      */    /* Monotonicity of d_off is heavily exploited in the following. */    /*     * This algorithm is tuned for modest directory sizes.  For huge     * directories, it might be more efficient to read blocks until the first     * d_off is too large, then back up one block, or even to use binary     * search on the directory blocks.  I doubt that the extra code for that     * would be worthwhile.      */    if (dirp->dd_loc >= dirp->dd_size	/* invalid index */	|| ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off > loc    /* too far along in buffer */	)	dirp->dd_loc = 0;	/* reset to beginning of buffer */    /* else save time by starting at current dirp->dd_loc */    for (rewind = true;;) {	register struct dirent *dp;	/* See whether the matching entry is in the current buffer. */	if ((dirp->dd_loc < dirp->dd_size	/* valid index */	     || readdir(dirp) != (struct dirent *)NULL	/* next buffer read */	     && (dirp->dd_loc = 0, true)	/* beginning of buffer set */	     )	    && (dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off	    <= loc		/* match possible in this buffer */	    ) {	    for ( /* dp initialized above */ ;		 (char *) dp < &dirp->dd_buf[dirp->dd_size];		 dp = (struct dirent *) ((char *) dp + dp->d_reclen)		)		if (dp->d_off == loc) {	/* found it! */		    dirp->dd_loc =			(char *) dp - dirp->dd_buf;		    return;		}	    rewind = false;	/* no point in backing up later */	    dirp->dd_loc = dirp->dd_size;	/* set end of buffer */	} else	 /* whole buffer past matching entry */ if (!rewind) {	/* no point in searching								 * further */	    errno = EINVAL;	    return;		/* no entry at specified loc */	} else {		/* rewind directory and start over */	    rewind = false;	/* but only once! */	    dirp->dd_loc = dirp->dd_size = 0;	    if (lseek(dirp->dd_fd, (OFFSET) 0, SEEK_SET)		!= 0		)		return;		/* errno already set (EBADF) */	    if (loc == 0)		return;		/* save time */	}    }}/* telldir - report directory stream position * * DESCRIPTION * *	Returns the offset of the next directory entry in the *	directory associated with dirp. * *	NOTE:	4.nBSD directory compaction makes seekdir() & telldir() *		practically impossible to do right.  Avoid using them! * * PARAMETERS * *	DIR	*dirp	- stream from opendir() * * RETURNS * * 	Return offset of next entry  */#ifdef __STDC__OFFSET telldir(DIR *dirp)#else    OFFSET telldir(dirp)			DIR            *dirp;		/* stream from opendir() */#endif{    if (dirp == (DIR *)NULL || dirp->dd_buf == (char *)NULL) {	errno = EFAULT;	return -1;		/* invalid pointer */    }    if (dirp->dd_loc < dirp->dd_size)	/* valid index */	return ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off;    else			/* beginning of next directory block */	return lseek(dirp->dd_fd, (OFFSET) 0, SEEK_CUR);}#ifdef UFS/*	The following routine is necessary to handle DIRSIZ-long entry names.	Thanks to Richard Todd for pointing this out.*//* return # chars in embedded name */#ifdef __STDC__static int NameLen(char *name)#else    static int NameLen(name)char            *name;		/* -> name embedded in struct direct */#endif{    register char  *s;		/* -> name[.] */    register char  *stop = &name[DIRSIZ];	/* -> past end of name field */    for (s = &name[1];		/* (empty names are impossible) */	 *s != '\0'		/* not NUL terminator */	 && ++s < stop;		/* < DIRSIZ characters scanned */	);    return s - name;		/* # valid characters in name */}#else				/* BFS || NFS */extern int      strlen();#define	NameLen( name )	strlen( name )	/* names are always NUL-terminated */#endif#ifdef UNKstatic enum {    maybe, no, yes} state = maybe;/* sig_catch - used to catch signals * * DESCRIPTION * *	Used to catch signals. *//*ARGSUSED*/#ifdef __STDC__static void sig_catch(int sig)#else    static void sig_catch(sig)int             sig;		/* must be SIGSYS */#endif{    state = no;			/* attempted _getdents() faulted */}#endif/* getdents - get directory entries * * DESCRIPTION * *	Gets directory entries from the filesystem in an implemenation *	defined way. * * PARAMETERS * *	int             fildes	- directory file descriptor  *	char           *buf	- where to put the (struct dirent)s  *	unsigned	nbyte	- size of buf[]  * * RETURNS *  *	Returns number of bytes read; 0 on EOF, -1 on error  */#ifdef __STDC__int getdents(int fildes, char *buf, unsigned nbyte)#else    int getdents(fildes, buf, nbyte)	int             fildes;		/* directory file descriptor */char           *buf;		/* where to put the (struct dirent)s */unsigned        nbyte;		/* size of buf[] */#endif{    int             serrno;	/* entry errno */    OFFSET          offset;	/* initial directory file offset */    struct stat     statb;	/* fstat() info */    union {	/* directory file block buffer */#ifdef UFS	char		dblk[DIRBLKSIZ + 1];#else	char            dblk[DIRBLKSIZ];#endif	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) {	SIG_T         (*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 */	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 (buf == (char *)NULL#ifdef ATT_SPEC	|| (unsigned long) buf % sizeof(long) != 0	/* ugh */#endif	) {	errno = EFAULT;		/* invalid pointer */	return -1;    }    if (fstat(fildes, &statb) != 0) {	return -1;		/* errno set by fstat() */    }    if (!S_ISDIR(statb.st_mode)) {	errno = ENOTDIR;	/* not a directory */	return -1;    }    if ((offset = lseek(fildes, (OFFSET) 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 */    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 =		DIRENTSIZ(NameLen(dp->d_name));		if ((char *) bp + reclen > &buf[nbyte]) {		    errno = EINVAL;		    return -1;	/* buf too small */		}		bp->d_ino = dp->d_fileno;		bp->d_off = offset + ((char *) dp - u.dblk);		bp->d_reclen = reclen;		{#ifdef UFS		    /* Is the following kludge ugly?  You bet. */		    register char   save = dp->d_name[DIRSIZ];		    /* save original data */		    dp->d_name[DIRSIZ] = '\0';		    /* ensure NUL termination */#endif		    /* adds NUL padding */		    strncpy(bp->d_name, dp->d_name, reclen - DIRENTBASESIZ);#ifdef UFS		    dp->d_name[DIRSIZ] = save;		    /* restore original data */#endif		}		bp = (struct dirent *) ((char *) bp + reclen);	    }	}#ifndef BFS			/* 4.2BSD screwed up; fixed in 4.3BSD */	if ((char *) dp > &u.dblk[size]) {	    errno = EIO;	/* corrupted directory */	    return -1;	}#endif    }    errno = serrno;		/* restore entry errno */    return (char *) bp - buf;	/* return # bytes read */}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -