Mostly sync with CSRG.
This commit is contained in:
parent
1fc62d2108
commit
05fe3ff1f7
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue