summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixFCmd.c
diff options
context:
space:
mode:
authorhobbs <hobbs>2005-12-05 08:19:36 (GMT)
committerhobbs <hobbs>2005-12-05 08:19:36 (GMT)
commit403f07fad3a34a8d96e855e42124439774d1b8d3 (patch)
tree641e84ce6d8a5e51a92dc5642880541f0f549f8f /unix/tclUnixFCmd.c
parentf078a958a988281d9fa063f631db04e67d0148e0 (diff)
downloadtcl-403f07fad3a34a8d96e855e42124439774d1b8d3.zip
tcl-403f07fad3a34a8d96e855e42124439774d1b8d3.tar.gz
tcl-403f07fad3a34a8d96e855e42124439774d1b8d3.tar.bz2
* 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)
Diffstat (limited to 'unix/tclUnixFCmd.c')
-rw-r--r--unix/tclUnixFCmd.c121
1 files changed, 97 insertions, 24 deletions
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;