Index: unix/tcl.m4
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tcl.m4,v
retrieving revision 1.158
diff -u -p -u -p -r1.158 tcl.m4
--- unix/tcl.m4	1 Dec 2005 02:14:18 -0000	1.158
+++ unix/tcl.m4	5 Dec 2005 07:34:39 -0000
@@ -1497,6 +1497,17 @@ dnl AC_CHECK_TOOL(AR, ar)
 	    AC_CHECK_FUNCS(OSSpinLockLock)
 	    AC_CHECK_HEADERS(copyfile.h)
 	    AC_CHECK_FUNCS(copyfile)
+	    AC_CACHE_CHECK([for fts], tcl_cv_api_fts, [
+		AC_TRY_LINK([#include <sys/param.h>
+			#include <sys/stat.h>
+			#include <fts.h>], 
+		    [char*const p[2] = {"/", NULL};
+		    	FTS *f = fts_open(p, FTS_PHYSICAL|FTS_NOCHDIR|FTS_NOSTAT, NULL);
+			FTSENT *e = fts_read(f); fts_close(f);], 
+		    tcl_cv_api_fts=yes, tcl_cv_api_fts=no)])
+	    if test $tcl_cv_api_fts = yes; then
+		AC_DEFINE(HAVE_FTS, 1, [Do we have fts functions?])
+	    fi
 	    AC_DEFINE(MAC_OSX_TCL, 1, [Is this a Mac I see before me?])
 	    AC_DEFINE(USE_VFORK, 1, [Should we use vfork() instead of fork()?])
 	    AC_DEFINE(TCL_DEFAULT_ENCODING,"utf-8",
Index: unix/tclUnixFCmd.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixFCmd.c,v
retrieving revision 1.49
diff -u -p -u -p -r1.49 tclUnixFCmd.c
--- unix/tclUnixFCmd.c	27 Nov 2005 02:33:50 -0000	1.49
+++ unix/tclUnixFCmd.c	5 Dec 2005 07:34:39 -0000
@@ -54,6 +54,9 @@
 #include <sys/statfs.h>
 #endif
 #endif
+#ifdef HAVE_FTS
+#include <fts.h>
+#endif
 
 /*
  * The following constants specify the type of callback when
@@ -178,7 +181,8 @@ CONST TclFileAttrProcs tclpFileAttrProcs
 
 static int		CopyFileAtts(CONST char *src,
 			    CONST char *dst, CONST Tcl_StatBuf *statBufPtr);
-static int		DoCopyFile(CONST char *srcPtr, CONST char *dstPtr);
+static int		DoCopyFile(CONST char *srcPtr, CONST char *dstPtr,
+			    CONST Tcl_StatBuf *statBufPtr);
 static int		DoCreateDirectory(CONST char *pathPtr);
 static int		DoRemoveDirectory(Tcl_DString *pathPtr,
 			    int recursive, Tcl_DString *errorPtr);
@@ -370,25 +374,26 @@ TclpObjCopyFile(
     Tcl_Obj *srcPathPtr,
     Tcl_Obj *destPathPtr)
 {
-    return DoCopyFile(Tcl_FSGetNativePath(srcPathPtr),
-	    Tcl_FSGetNativePath(destPathPtr));
+    CONST char *src = Tcl_FSGetNativePath(srcPathPtr);
+    Tcl_StatBuf srcStatBuf;
+
+    if (TclOSlstat(src, &srcStatBuf) != 0) {		/* INTL: Native. */
+	return TCL_ERROR;
+    }
+
+    return DoCopyFile(src, Tcl_FSGetNativePath(destPathPtr), &srcStatBuf);
 }
 
 static int
 DoCopyFile(
     CONST char *src,		/* Pathname of file to be copied (native). */
-    CONST char *dst)		/* Pathname of file to copy to (native). */
+    CONST char *dst,		/* Pathname of file to copy to (native). */
+    CONST Tcl_StatBuf *statBufPtr)
+				/* Used to determine filetype. */
 {
-    Tcl_StatBuf srcStatBuf, dstStatBuf;
-
-    /*
-     * Have to do a stat() to determine the filetype.
-     */
+    Tcl_StatBuf dstStatBuf;
 
-    if (TclOSlstat(src, &srcStatBuf) != 0) {		/* INTL: Native. */
-	return TCL_ERROR;
-    }
-    if (S_ISDIR(srcStatBuf.st_mode)) {
+    if (S_ISDIR(statBufPtr->st_mode)) {
 	errno = EISDIR;
 	return TCL_ERROR;
     }
@@ -410,7 +415,7 @@ DoCopyFile(
 	}
     }
 
-    switch ((int) (srcStatBuf.st_mode & S_IFMT)) {
+    switch ((int) (statBufPtr->st_mode & S_IFMT)) {
 #ifndef DJGPP
     case S_IFLNK: {
 	char link[MAXPATHLEN];
@@ -425,25 +430,25 @@ DoCopyFile(
 	    return TCL_ERROR;
 	}
 #ifdef MAC_OSX_TCL
-	TclMacOSXCopyFileAttributes(src, dst, &srcStatBuf);
+	TclMacOSXCopyFileAttributes(src, dst, statBufPtr);
 #endif
 	break;
     }
 #endif
     case S_IFBLK:
     case S_IFCHR:
-	if (mknod(dst, srcStatBuf.st_mode,		/* INTL: Native. */
-		srcStatBuf.st_rdev) < 0) {
+	if (mknod(dst, statBufPtr->st_mode,		/* INTL: Native. */
+		statBufPtr->st_rdev) < 0) {
 	    return TCL_ERROR;
 	}
-	return CopyFileAtts(src, dst, &srcStatBuf);
+	return CopyFileAtts(src, dst, statBufPtr);
     case S_IFIFO:
-	if (mkfifo(dst, srcStatBuf.st_mode) < 0) {	/* INTL: Native. */
+	if (mkfifo(dst, statBufPtr->st_mode) < 0) {	/* INTL: Native. */
 	    return TCL_ERROR;
 	}
-	return CopyFileAtts(src, dst, &srcStatBuf);
+	return CopyFileAtts(src, dst, statBufPtr);
     default:
-	return TclUnixCopyFile(src, dst, &srcStatBuf, 0);
+	return TclUnixCopyFile(src, dst, statBufPtr, 0);
     }
     return TCL_OK;
 }
@@ -873,9 +878,15 @@ TraverseUnixTree(
     CONST char *source, *errfile;
     int result, sourceLen;
     int targetLen;
+#ifndef HAVE_FTS
     int numProcessed = 0;
     Tcl_DirEntry *dirEntPtr;
     DIR *dirPtr;
+#else
+    CONST char *paths[2] = {NULL, NULL};
+    FTS *fts;
+    FTSENT *ent;
+#endif
 
     errfile = NULL;
     result = TCL_OK;
@@ -894,6 +905,7 @@ TraverseUnixTree(
 	return (*traverseProc)(sourcePtr, targetPtr, &statBuf, DOTREE_F,
 		errorPtr);
     }
+#ifndef HAVE_FTS
     dirPtr = opendir(source);				/* INTL: Native. */
     if (dirPtr == NULL) {
 	/*
@@ -988,6 +1000,67 @@ TraverseUnixTree(
 	}
 	result = TCL_ERROR;
     }
+#else /* HAVE_FTS */
+    paths[0] = source;
+    fts = fts_open((char**)paths, FTS_PHYSICAL|FTS_NOCHDIR|
+	    (doRewind ? FTS_NOSTAT : 0), NULL); /* no need to stat for delete */
+    if (fts == NULL) {
+	errfile = source;
+	goto end;
+    }
+
+    sourceLen = Tcl_DStringLength(sourcePtr);
+    if (targetPtr != NULL) {
+	targetLen = Tcl_DStringLength(targetPtr);
+    }
+
+    while ((ent = fts_read(fts)) != NULL) {
+	unsigned short info = ent->fts_info;
+	char * path = ent->fts_path + sourceLen;
+	unsigned short pathlen = ent->fts_pathlen - sourceLen;
+	int type;
+	
+	if (info == FTS_DNR || info == FTS_ERR || info == FTS_NS) {
+	    errfile = ent->fts_path;
+	    break;
+	}
+	Tcl_DStringAppend(sourcePtr, path, pathlen);
+	if (targetPtr != NULL) {
+	    Tcl_DStringAppend(targetPtr, path, pathlen);
+	}
+	switch (info) {
+	    case FTS_D:
+		type = DOTREE_PRED;
+		break;
+	    case FTS_DP:
+		type = DOTREE_POSTD;
+		break;
+	    default:
+		type = DOTREE_F;
+		break;
+	}
+	result = (*traverseProc)(sourcePtr, targetPtr, ent->fts_statp, type,
+		errorPtr);
+	if (result != TCL_OK) {
+	    break;
+	}
+	Tcl_DStringSetLength(sourcePtr, sourceLen);
+	if (targetPtr != NULL) {
+	    Tcl_DStringSetLength(targetPtr, targetLen);
+	}
+    }
+
+  end:
+    if (errfile != NULL) {
+	if (errorPtr != NULL) {
+	    Tcl_ExternalToUtfDString(NULL, errfile, -1, errorPtr);
+	}
+	result = TCL_ERROR;
+    }
+    if (fts != NULL) {
+	fts_close(fts);
+    }
+#endif /* HAVE_FTS */
 
     return result;
 }
@@ -1023,8 +1096,8 @@ TraversalCopy(
 {
     switch (type) {
     case DOTREE_F:
-	if (DoCopyFile(Tcl_DStringValue(srcPtr),
-		Tcl_DStringValue(dstPtr)) == TCL_OK) {
+	if (DoCopyFile(Tcl_DStringValue(srcPtr), Tcl_DStringValue(dstPtr),
+		statBufPtr) == TCL_OK) {
 	    return TCL_OK;
 	}
 	break;
