📄 paxdir.c
字号:
* 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 + -