From 403f07fad3a34a8d96e855e42124439774d1b8d3 Mon Sep 17 00:00:00 2001 From: hobbs Date: Mon, 5 Dec 2005 08:19:36 +0000 Subject: * 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) --- ChangeLog | 7 ++++ unix/configure | 66 +++++++++++++++++++++++++++++ unix/tcl.m4 | 11 +++++ unix/tclUnixFCmd.c | 121 ++++++++++++++++++++++++++++++++++++++++++----------- 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 + + * 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 * 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 + #include + #include +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 + #include + #include ], + [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 #endif #endif +#ifdef HAVE_FTS +#include +#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; -- cgit v0.12