Mostly sync with CSRG.

This commit is contained in:
mycroft 1994-12-28 03:06:05 +00:00
parent 1fc62d2108
commit 05fe3ff1f7
4 changed files with 240 additions and 43 deletions

View File

@ -29,10 +29,10 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" from: @(#)fts.3 8.4 (Berkeley) 4/7/94
.\" $Id: fts.3,v 1.9 1994/04/12 03:21:35 cgd Exp $
.\" from: @(#)fts.3 8.5 (Berkeley) 4/16/94
.\" $Id: fts.3,v 1.10 1994/12/28 03:15:06 mycroft Exp $
.\"
.Dd April 7, 1994
.Dd April 16, 1994
.Dt FTS 3
.Os
.Sh NAME

View File

@ -32,8 +32,8 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
/* from: static char sccsid[] = "@(#)fts.c 8.4 (Berkeley) 4/16/94"; */
static char *rcsid = "$Id: fts.c,v 1.10 1994/10/26 20:25:50 mycroft Exp $";
/* from: static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; */
static char *rcsid = "$Id: fts.c,v 1.11 1994/12/28 03:15:09 mycroft Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
@ -558,7 +558,8 @@ fts_build(sp, type)
FTSENT *cur, *tail;
DIR *dirp;
void *adjaddr;
int cderrno, descend, len, level, maxlen, nlinks, saved_errno, nostat;
int cderrno, descend, len, level, maxlen, nlinks, oflag, saved_errno,
nostat;
char *cp;
/* Set current node pointer. */
@ -568,7 +569,15 @@ fts_build(sp, type)
* Open the directory for reading. If this fails, we're done.
* If being called from fts_read, set the fts_info field.
*/
if ((dirp = opendir(cur->fts_accpath)) == NULL) {
#ifdef FTS_WHITEOUT
if (ISSET(FTS_WHITEOUT))
oflag = DTF_NODUP|DTF_REWIND;
else
oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
#else
#define __opendir2(path, flag) opendir(path)
#endif
if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
if (type == BREAD) {
cur->fts_info = FTS_DNR;
cur->fts_errno = errno;
@ -676,6 +685,11 @@ mem1: saved_errno = errno;
p->fts_parent = sp->fts_cur;
p->fts_level = level;
#ifdef FTS_WHITEOUT
if (dp->d_type == DT_WHT)
p->fts_flags |= FTS_ISW;
#endif
if (cderrno) {
if (nlinks) {
p->fts_info = FTS_NS;
@ -779,7 +793,18 @@ fts_stat(sp, p, follow)
/* If user needs stat info, stat buffer already allocated. */
sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
#ifdef FTS_WHITEOUT
/* check for whiteout */
if (p->fts_flags & FTS_ISW) {
if (sbp != &sb) {
memset(sbp, '\0', sizeof (*sbp));
sbp->st_mode = S_IFWHT;
}
return (FTS_W);
}
#endif
/*
* If doing a logical walk, or application requested FTS_FOLLOW, do
* a stat(2). If that fails, check for a non-existent symlink. If

View File

@ -32,43 +32,54 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
/*static char sccsid[] = "from: @(#)opendir.c 8.2 (Berkeley) 2/12/94";*/
static char rcsid[] = "$Id: opendir.c,v 1.4 1994/09/15 10:48:51 pk Exp $";
/*static char sccsid[] = "from: @(#)opendir.c 8.7 (Berkeley) 12/10/94";*/
static char rcsid[] = "$Id: opendir.c,v 1.5 1994/12/28 03:06:05 mycroft Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
/*
* open a directory.
* Open a directory.
*/
DIR *
opendir(name)
const char *name;
{
struct stat statb;
register DIR *dirp;
register int fd;
register int pagesz;
if ((fd = open(name, 0)) == -1)
return NULL;
return (__opendir2(name, DTF_HIDEW|DTF_NODUP));
}
DIR *
__opendir2(name, flags)
const char *name;
int flags;
{
DIR *dirp;
int fd;
int pagesz;
int incr;
int unionstack;
if ((fd = open(name, O_RDONLY)) == -1)
return (NULL);
if (fstat(fd, &statb) || !S_ISDIR(statb.st_mode)) {
errno = ENOTDIR;
close (fd);
return NULL;
close(fd);
return (NULL);
}
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1 ||
(dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
close (fd);
return NULL;
close(fd);
return (NULL);
}
/*
* If the machine's page size is an exact multiple of DIRBLKSIZ,
* use a buffer that is cluster boundary aligned.
@ -76,21 +87,179 @@ opendir(name)
* to user space to be done by getdirentries()
*/
if (((pagesz = getpagesize()) % DIRBLKSIZ) == 0)
dirp->dd_len = pagesz;
incr = pagesz;
else
dirp->dd_len = DIRBLKSIZ;
incr = DIRBLKSIZ;
dirp->dd_buf = malloc(dirp->dd_len);
if (dirp->dd_buf == NULL) {
close (fd);
return NULL;
/*
* Determine whether this directory is the top of a union stack.
*/
if (flags & DTF_NODUP) {
struct statfs sfb;
if (fstatfs(fd, &sfb) < 0) {
free(dirp);
close(fd);
return (NULL);
}
unionstack = !strcmp(sfb.f_fstypename, MOUNT_UNION);
} else {
unionstack = 0;
}
dirp->dd_fd = fd;
if (unionstack) {
int len = 0;
int space = 0;
char *buf = 0;
char *ddptr = 0;
char *ddeptr;
int n;
struct dirent **dpv;
/*
* The strategy here is to read all the directory
* entries into a buffer, sort the buffer, and
* remove duplicate entries by setting the inode
* number to zero.
*/
do {
/*
* Always make at least DIRBLKSIZ bytes
* available to getdirentries
*/
if (space < DIRBLKSIZ) {
space += incr;
len += incr;
buf = realloc(buf, len);
if (buf == NULL) {
free(dirp);
close(fd);
return (NULL);
}
ddptr = buf + (len - space);
}
n = getdirentries(fd, ddptr, space, &dirp->dd_seek);
if (n > 0) {
ddptr += n;
space -= n;
}
} while (n > 0);
ddeptr = ddptr;
flags |= __DTF_READALL;
/*
* Re-open the directory.
* This has the effect of rewinding back to the
* top of the union stack and is needed by
* programs which plan to fchdir to a descriptor
* which has also been read -- see fts.c.
*/
if (flags & DTF_REWIND) {
(void) close(fd);
if ((fd = open(name, O_RDONLY)) == -1) {
free(buf);
free(dirp);
return (NULL);
}
}
/*
* There is now a buffer full of (possibly) duplicate
* names.
*/
dirp->dd_buf = buf;
/*
* Go round this loop twice...
*
* Scan through the buffer, counting entries.
* On the second pass, save pointers to each one.
* Then sort the pointers and remove duplicate names.
*/
for (dpv = 0;;) {
n = 0;
ddptr = buf;
while (ddptr < ddeptr) {
struct dirent *dp;
dp = (struct dirent *) ddptr;
if ((int)dp & 03)
break;
if ((dp->d_reclen <= 0) ||
(dp->d_reclen > (ddeptr + 1 - ddptr)))
break;
ddptr += dp->d_reclen;
if (dp->d_fileno) {
if (dpv)
dpv[n] = dp;
n++;
}
}
if (dpv) {
struct dirent *xp;
/*
* This sort must be stable.
*/
mergesort(dpv, n, sizeof(*dpv), alphasort);
dpv[n] = NULL;
xp = NULL;
/*
* Scan through the buffer in sort order,
* zapping the inode number of any
* duplicate names.
*/
for (n = 0; dpv[n]; n++) {
struct dirent *dp = dpv[n];
if ((xp == NULL) ||
strcmp(dp->d_name, xp->d_name)) {
xp = dp;
} else {
dp->d_fileno = 0;
}
if (dp->d_type == DT_WHT &&
(flags & DTF_HIDEW))
dp->d_fileno = 0;
}
free(dpv);
break;
} else {
dpv = malloc((n+1) * sizeof(struct dirent *));
if (dpv == NULL)
break;
}
}
dirp->dd_len = len;
dirp->dd_size = ddptr - dirp->dd_buf;
} else {
dirp->dd_len = incr;
dirp->dd_buf = malloc(dirp->dd_len);
if (dirp->dd_buf == NULL) {
free(dirp);
close (fd);
return (NULL);
}
dirp->dd_seek = 0;
flags &= ~DTF_REWIND;
}
dirp->dd_loc = 0;
dirp->dd_seek = 0;
dirp->dd_fd = fd;
dirp->dd_flags = flags;
/*
* Set up seek point for rewinddir.
*/
dirp->dd_rewind = telldir(dirp);
return dirp;
return (dirp);
}

View File

@ -32,8 +32,8 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
/*static char sccsid[] = "from: @(#)readdir.c 8.1 (Berkeley) 6/4/93";*/
static char rcsid[] = "$Id: readdir.c,v 1.3 1994/10/19 03:13:42 cgd Exp $";
/*static char sccsid[] = "from: @(#)readdir.c 8.3 (Berkeley) 9/29/94";*/
static char rcsid[] = "$Id: readdir.c,v 1.4 1994/12/28 03:06:06 mycroft Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
@ -49,25 +49,28 @@ readdir(dirp)
register struct dirent *dp;
for (;;) {
if (dirp->dd_loc == 0) {
if (dirp->dd_loc >= dirp->dd_size) {
if (dirp->dd_flags & __DTF_READALL)
return (NULL);
dirp->dd_loc = 0;
}
if (dirp->dd_loc == 0 && !(dirp->dd_flags & __DTF_READALL)) {
dirp->dd_size = getdirentries(dirp->dd_fd,
dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
if (dirp->dd_size <= 0)
return NULL;
}
if (dirp->dd_loc >= dirp->dd_size) {
dirp->dd_loc = 0;
continue;
return (NULL);
}
dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc);
if ((long)dp & 03) /* bogus pointer check */
return NULL;
return (NULL);
if (dp->d_reclen <= 0 ||
dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc)
return NULL;
return (NULL);
dirp->dd_loc += dp->d_reclen;
if (dp->d_ino == 0)
continue;
if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW))
continue;
return (dp);
}
}