1
0
mirror of git://git.sv.gnu.org/coreutils.git synced 2026-07-26 02:30:35 +02:00

virgin copy from glibc

This commit is contained in:
Jim Meyering
2003-02-24 08:24:59 +00:00
parent 74432ad178
commit f30cda6bd2
2 changed files with 82 additions and 203 deletions
+38 -163
View File
@@ -27,96 +27,29 @@
* SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
#endif /* LIBC_SCCS and not lint */
#if HAVE_SYS_PARAM_H || defined _LIBC
# include <sys/param.h>
#endif
#ifdef _LIBC
# include <include/sys/stat.h>
#else
# include <sys/stat.h>
#endif
#include <sys/param.h>
#include <include/sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <fts_.h>
#include <search.h>
#include <fts.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if defined _LIBC
# include <dirent.h>
# define NAMLEN(dirent) _D_EXACT_NAMLEN (dirent)
#else
# if HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) strlen ((dirent)->d_name)
# else
# define dirent direct
# define NAMLEN(dirent) (dirent)->d_namlen
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
# endif
#endif
#ifndef _LIBC
# undef __close
# define __close close
# undef __closedir
# define __closedir closedir
# undef __fchdir
# define __fchdir fchdir
# undef __open
# define __open open
# undef __opendir
# define __opendir opendir
# undef __readdir
# define __readdir readdir
# undef __tdestroy
# define __tdestroy tdestroy
# undef __tfind
# define __tfind tfind
# undef __tsearch
# define __tsearch tsearch
# undef internal_function
# define internal_function /* empty */
#endif
/* Arrange to make lstat calls go through the wrapper function
on systems with an lstat function that does not dereference symlinks
that are specified with a trailing slash. */
#if ! _LIBC && ! LSTAT_FOLLOWS_SLASHED_SYMLINK
int rpl_lstat (const char *, struct stat *);
# undef lstat
# define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf)
#endif
#ifndef __set_errno
# define __set_errno(Val) errno = (Val)
#endif
/* Largest alignment size needed, minus one.
Usually long double is the worst case. */
#ifndef ALIGNBYTES
# define ALIGNBYTES (__alignof__ (long double) - 1)
#define ALIGNBYTES (__alignof__ (long double) - 1)
#endif
/* Align P to that size. */
#ifndef ALIGN
# define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
#define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
#endif
@@ -133,23 +66,23 @@ static int fts_safe_changedir __P((FTS *, FTSENT *, int, const char *))
internal_function;
#ifndef MAX
# define MAX(a, b) ({ __typeof__ (a) _a = (a); \
#define MAX(a, b) ({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#endif
#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
#define CLR(opt) (sp->fts_options &= ~(opt))
#define ISSET(opt) (sp->fts_options & (opt))
#define SET(opt) (sp->fts_options |= (opt))
#define ISSET(opt) (sp->fts_options & (opt))
#define SET(opt) (sp->fts_options |= (opt))
#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && __fchdir(fd))
#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && __fchdir(fd))
/* fts_build flags */
#define BCHILD 1 /* fts_children */
#define BNAMES 2 /* fts_children, names only */
#define BREAD 3 /* fts_read */
#define BCHILD 1 /* fts_children */
#define BNAMES 2 /* fts_children, names only */
#define BREAD 3 /* fts_read */
FTS *
fts_open(argv, options, compar)
@@ -185,7 +118,7 @@ fts_open(argv, options, compar)
* to hold the user's paths.
*/
#ifndef MAXPATHLEN
# define MAXPATHLEN 1024
#define MAXPATHLEN 1024
#endif
if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
goto mem1;
@@ -203,8 +136,7 @@ fts_open(argv, options, compar)
goto mem3;
}
if ((p = fts_alloc(sp, *argv, len)) == NULL)
goto mem3;
p = fts_alloc(sp, *argv, len);
p->fts_level = FTS_ROOTLEVEL;
p->fts_parent = parent;
p->fts_accpath = p->fts_name;
@@ -244,8 +176,6 @@ fts_open(argv, options, compar)
sp->fts_cur->fts_link = root;
sp->fts_cur->fts_info = FTS_INIT;
sp->fts_dir_info = NULL;
/*
* If using chdir(2), grab a file descriptor pointing to dot to ensure
* that we can get back here; this could be avoided for some paths,
@@ -335,9 +265,6 @@ fts_close(sp)
}
}
/* Free all of the directory fingerprint info. */
__tdestroy (sp->fts_dir_info, free);
/* Free up the stream pointer. */
free(sp);
return (0);
@@ -347,7 +274,7 @@ fts_close(sp)
* Special case of "/" at the end of the path so that slashes aren't
* appended which would cause paths to be written as "....//foo".
*/
#define NAPPEND(p) \
#define NAPPEND(p) \
(p->fts_path[p->fts_pathlen - 1] == '/' \
? p->fts_pathlen - 1 : p->fts_pathlen)
@@ -442,10 +369,6 @@ fts_read(sp)
} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
if (ISSET(FTS_STOP))
return (NULL);
/* If fts_safe_changedir failed because it was not able
to fchdir into a subdirectory, tell the caller. */
if (p->fts_errno)
p->fts_info = FTS_ERR;
return (p);
}
p = sp->fts_child;
@@ -766,11 +689,11 @@ fts_build(sp, type)
if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
continue;
if ((p = fts_alloc(sp, dp->d_name, (int)NAMLEN (dp))) == NULL)
if ((p = fts_alloc(sp, dp->d_name, (int)_D_EXACT_NAMLEN (dp))) == NULL)
goto mem1;
if (NAMLEN (dp) >= maxlen) {/* include space for NUL */
if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */
oldaddr = sp->fts_path;
if (fts_palloc(sp, NAMLEN (dp) + len + 1)) {
if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
/*
* No more memory for path or structures. Save
* errno, free up the current structure and the
@@ -795,7 +718,7 @@ mem1: saved_errno = errno;
maxlen = sp->fts_pathlen - len;
}
if (len + NAMLEN (dp) >= 999999999 /* FIXME SIZE_MAX */) {
if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) {
/*
* In an FTSENT, fts_pathlen is a u_short so it is
* possible to wraparound here. If we do, free up
@@ -812,7 +735,7 @@ mem1: saved_errno = errno;
}
p->fts_level = level;
p->fts_parent = sp->fts_cur;
p->fts_pathlen = len + NAMLEN (dp);
p->fts_pathlen = len + _D_EXACT_NAMLEN (dp);
#if defined FTS_WHITEOUT && 0
if (dp->d_type == DT_WHT)
@@ -827,7 +750,7 @@ mem1: saved_errno = errno;
p->fts_info = FTS_NSOK;
p->fts_accpath = cur->fts_accpath;
} else if (nlinks == 0
#if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE /* FIXME */
#if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE
|| (nostat &&
dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
#endif
@@ -910,52 +833,6 @@ mem1: saved_errno = errno;
return (head);
}
struct known_object
{
dev_t dev;
ino_t ino;
FTSENT *fts_ent;
};
static int
object_compare (const void *p1, const void *p2)
{
/* We don't need a sophisticated and useful comparison. We are only
interested in equality. However, we must be careful not to
accidentally compare `holes' in the structure. */
const struct known_object *kp1 = p1, *kp2 = p2;
int cmp1;
cmp1 = (kp1->ino > kp2->ino) - (kp1->ino < kp2->ino);
if (cmp1 != 0)
return cmp1;
return (kp1->dev > kp2->dev) - (kp1->dev < kp2->dev);
}
static inline int
add_object (FTS *fts, FTSENT *data, struct stat *st)
{
struct known_object *newp = malloc (sizeof (struct known_object));
if (newp == NULL)
return -1;
newp->dev = st->st_dev;
newp->ino = st->st_ino;
newp->fts_ent = data;
return __tsearch (newp, &fts->fts_dir_info, object_compare) ? 0 : -1;
}
static inline FTSENT *
find_object (FTS *fts, struct stat *st)
{
struct known_object obj;
struct known_object const *t;
obj.dev = st->st_dev;
obj.ino = st->st_ino;
t = __tfind (&obj, &fts->fts_dir_info, object_compare);
return t ? t->fts_ent : NULL;
}
static u_short
internal_function
fts_stat(sp, p, follow)
@@ -963,6 +840,9 @@ fts_stat(sp, p, follow)
register FTSENT *p;
int follow;
{
register FTSENT *t;
register dev_t dev;
register ino_t ino;
struct stat *sbp, sb;
int saved_errno;
@@ -1002,7 +882,6 @@ err: memset(sbp, 0, sizeof(struct stat));
}
if (S_ISDIR(sbp->st_mode)) {
register FTSENT *t;
/*
* Set the device/inode. Used to find cycles and check for
* crossing mount points. Also remember the link count, used
@@ -1010,29 +889,25 @@ err: memset(sbp, 0, sizeof(struct stat));
* understood that these fields are only referenced if fts_info
* is set to FTS_D.
*/
p->fts_dev = sbp->st_dev;
p->fts_ino = sbp->st_ino;
dev = p->fts_dev = sbp->st_dev;
ino = p->fts_ino = sbp->st_ino;
p->fts_nlink = sbp->st_nlink;
if (ISDOT(p->fts_name))
return (FTS_DOT);
/*
FIXME
* Cycle detection is done by brute force when the directory
* is first encountered. If the tree gets deep enough or the
* number of symbolic links to directories is high enough,
* something faster might be worthwhile.
*/
if ((t = find_object (sp, sbp))) {
p->fts_cycle = t;
return (FTS_DC);
}
/* Remember the object, ignoring any failure. If we're running
out of memory, detecting cycles isn't a high priority. */
add_object (sp, p, sbp);
for (t = p->fts_parent;
t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
if (ino == t->fts_ino && dev == t->fts_dev) {
p->fts_cycle = t;
return (FTS_DC);
}
return (FTS_D);
}
if (S_ISLNK(sbp->st_mode))
@@ -1154,7 +1029,7 @@ fts_palloc(sp, more)
* a signed int but in an FTSENT it is an unsigned short.
* We limit fts_pathlen to USHRT_MAX to be safe in both cases.
*/
if (sp->fts_pathlen < 0 || sp->fts_pathlen >= INT_MAX) {
if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
if (sp->fts_path) {
free(sp->fts_path);
sp->fts_path = NULL;
@@ -1186,7 +1061,7 @@ fts_padjust(sp, head)
FTSENT *p;
char *addr = sp->fts_path;
#define ADJUST(p) do { \
#define ADJUST(p) do { \
if ((p)->fts_accpath != (p)->fts_name) { \
(p)->fts_accpath = \
(char *)addr + ((p)->fts_accpath - (p)->fts_path); \
@@ -1231,14 +1106,14 @@ fts_safe_changedir(sp, p, fd, path)
const char *path;
{
int ret, oerrno, newfd;
struct stat sb;
struct stat64 sb;
newfd = fd;
if (ISSET(FTS_NOCHDIR))
return (0);
if (fd < 0 && (newfd = __open(path, O_RDONLY, 0)) < 0)
return (-1);
if (fstat(newfd, &sb)) {
if (__fxstat64(_STAT_VER, newfd, &sb)) {
ret = -1;
goto bail;
}
+44 -40
View File
@@ -30,10 +30,17 @@
*/
#ifndef _FTS_H
# define _FTS_H 1
#define _FTS_H 1
#include <features.h>
#include <sys/types.h>
/* The fts interface is incompatible with the LFS interface which
transparently uses the 64-bit file access functions. */
#ifdef __USE_FILE_OFFSET64
# error "<fts.h> cannot be used with -D_FILE_OFFSET_BITS==64"
#endif
# include <features.h>
# include <sys/types.h>
typedef struct {
struct _ftsent *fts_cur; /* current node */
@@ -46,22 +53,19 @@ typedef struct {
int fts_nitems; /* elements in the sort array */
int (*fts_compar) (const void *, const void *); /* compare fn */
# define FTS_COMFOLLOW 0x0001 /* follow command line symlinks */
# define FTS_LOGICAL 0x0002 /* logical walk */
# define FTS_NOCHDIR 0x0004 /* don't change directories */
# define FTS_NOSTAT 0x0008 /* don't get stat info */
# define FTS_PHYSICAL 0x0010 /* physical walk */
# define FTS_SEEDOT 0x0020 /* return dot and dot-dot */
# define FTS_XDEV 0x0040 /* don't cross devices */
# define FTS_WHITEOUT 0x0080 /* return whiteout information */
# define FTS_OPTIONMASK 0x00ff /* valid user option mask */
#define FTS_COMFOLLOW 0x0001 /* follow command line symlinks */
#define FTS_LOGICAL 0x0002 /* logical walk */
#define FTS_NOCHDIR 0x0004 /* don't change directories */
#define FTS_NOSTAT 0x0008 /* don't get stat info */
#define FTS_PHYSICAL 0x0010 /* physical walk */
#define FTS_SEEDOT 0x0020 /* return dot and dot-dot */
#define FTS_XDEV 0x0040 /* don't cross devices */
#define FTS_WHITEOUT 0x0080 /* return whiteout information */
#define FTS_OPTIONMASK 0x00ff /* valid user option mask */
# define FTS_NAMEONLY 0x0100 /* (private) child names only */
# define FTS_STOP 0x0200 /* (private) unrecoverable error */
#define FTS_NAMEONLY 0x0100 /* (private) child names only */
#define FTS_STOP 0x0200 /* (private) unrecoverable error */
int fts_options; /* fts_open options, global flags */
/* Data structure in which to store the fingerprint
of each directory we've encountered. */
void *fts_dir_info;
} FTS;
typedef struct _ftsent {
@@ -74,41 +78,41 @@ typedef struct _ftsent {
char *fts_path; /* root path */
int fts_errno; /* errno for this node */
int fts_symfd; /* fd for symlink */
size_t fts_pathlen; /* strlen(fts_path) */
u_short fts_pathlen; /* strlen(fts_path) */
u_short fts_namelen; /* strlen(fts_name) */
ino_t fts_ino; /* inode */
dev_t fts_dev; /* device */
nlink_t fts_nlink; /* link count */
# define FTS_ROOTPARENTLEVEL -1
# define FTS_ROOTLEVEL 0
#define FTS_ROOTPARENTLEVEL -1
#define FTS_ROOTLEVEL 0
short fts_level; /* depth (-1 to N) */
# define FTS_D 1 /* preorder directory */
# define FTS_DC 2 /* directory that causes cycles */
# define FTS_DEFAULT 3 /* none of the above */
# define FTS_DNR 4 /* unreadable directory */
# define FTS_DOT 5 /* dot or dot-dot */
# define FTS_DP 6 /* postorder directory */
# define FTS_ERR 7 /* error; errno is set */
# define FTS_F 8 /* regular file */
# define FTS_INIT 9 /* initialized only */
# define FTS_NS 10 /* stat(2) failed */
# define FTS_NSOK 11 /* no stat(2) requested */
# define FTS_SL 12 /* symbolic link */
# define FTS_SLNONE 13 /* symbolic link without target */
# define FTS_W 14 /* whiteout object */
#define FTS_D 1 /* preorder directory */
#define FTS_DC 2 /* directory that causes cycles */
#define FTS_DEFAULT 3 /* none of the above */
#define FTS_DNR 4 /* unreadable directory */
#define FTS_DOT 5 /* dot or dot-dot */
#define FTS_DP 6 /* postorder directory */
#define FTS_ERR 7 /* error; errno is set */
#define FTS_F 8 /* regular file */
#define FTS_INIT 9 /* initialized only */
#define FTS_NS 10 /* stat(2) failed */
#define FTS_NSOK 11 /* no stat(2) requested */
#define FTS_SL 12 /* symbolic link */
#define FTS_SLNONE 13 /* symbolic link without target */
#define FTS_W 14 /* whiteout object */
u_short fts_info; /* user flags for FTSENT structure */
# define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
# define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
u_short fts_flags; /* private flags for FTSENT structure */
# define FTS_AGAIN 1 /* read node again */
# define FTS_FOLLOW 2 /* follow symbolic link */
# define FTS_NOINSTR 3 /* no instructions */
# define FTS_SKIP 4 /* discard node */
#define FTS_AGAIN 1 /* read node again */
#define FTS_FOLLOW 2 /* follow symbolic link */
#define FTS_NOINSTR 3 /* no instructions */
#define FTS_SKIP 4 /* discard node */
u_short fts_instr; /* fts_set() instructions */
struct stat *fts_statp; /* stat(2) information */