summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rwxr-xr-xunix/configure66
-rw-r--r--unix/tcl.m411
-rw-r--r--unix/tclUnixFCmd.c121
4 files changed, 181 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index 496dff8..eb71468 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2005-12-05 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * unix/configure: Use FTS file APIs on Darwin if available.
+ * unix/tcl.m4: Addresses file delete issues in readdir noted
+ * unix/tclUnixFCmd.c: in [Bug 1034337]. (steffen)
+ Reduce on stat call in DoCopyFile. (steffen)
+
2005-12-02 Kevin B. Kenny <kennykb@acm.org>
* generic/tclClock.c: Moved a tiny bit more of [clock format] from
diff --git a/unix/configure b/unix/configure
index be870d8..43d1a82 100755
--- a/unix/configure
+++ b/unix/configure
@@ -7897,6 +7897,72 @@ _ACEOF
fi
done
+ echo "$as_me:$LINENO: checking for fts" >&5
+echo $ECHO_N "checking for fts... $ECHO_C" >&6
+if test "${tcl_cv_api_fts+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/param.h>
+ #include <sys/stat.h>
+ #include <fts.h>
+int
+main ()
+{
+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);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ tcl_cv_api_fts=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_cv_api_fts=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $tcl_cv_api_fts" >&5
+echo "${ECHO_T}$tcl_cv_api_fts" >&6
+ if test $tcl_cv_api_fts = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FTS 1
+_ACEOF
+
+ fi
cat >>confdefs.h <<\_ACEOF
#define MAC_OSX_TCL 1
diff --git a/unix/tcl.m4 b/unix/tcl.m4
index 211dae3..1bc6e31 100644
--- a/unix/tcl.m4
+++ b/unix/tcl.m4
@@ -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",
diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c
index c65bbec..bdb4cef 100644
--- a/unix/tclUnixFCmd.c
+++ b/unix/tclUnixFCmd.c
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclUnixFCmd.c,v 1.49 2005/11/27 02:33:50 das Exp $
+ * RCS: @(#) $Id: tclUnixFCmd.c,v 1.50 2005/12/05 08:19:37 hobbs Exp $
*
* Portions of this code were derived from NetBSD source code which has the
* following copyright notice:
@@ -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 = NULL;
+ 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;