summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixFCmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixFCmd.c')
-rw-r--r--unix/tclUnixFCmd.c130
1 files changed, 107 insertions, 23 deletions
diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c
index f5555b7..02bd513 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.28.2.7 2005/11/27 02:34:42 das Exp $
+ * RCS: @(#) $Id: tclUnixFCmd.c,v 1.28.2.8 2005/12/05 15:10:33 dgp Exp $
*
* Portions of this code were derived from NetBSD source code which has
* the following copyright notice:
@@ -56,6 +56,9 @@
#include <sys/statfs.h>
#endif
#endif
+#ifdef HAVE_FTS
+#include <fts.h>
+#endif
/*
* The following constants specify the type of callback when
@@ -147,7 +150,7 @@ static int CopyFile _ANSI_ARGS_((CONST char *src,
static int CopyFileAtts _ANSI_ARGS_((CONST char *src,
CONST char *dst, CONST Tcl_StatBuf *statBufPtr));
static int DoCopyFile _ANSI_ARGS_((CONST char *srcPtr,
- CONST char *dstPtr));
+ CONST char *dstPtr, CONST Tcl_StatBuf *statBufPtr));
static int DoCreateDirectory _ANSI_ARGS_((CONST char *pathPtr));
static int DoRemoveDirectory _ANSI_ARGS_((Tcl_DString *pathPtr,
int recursive, Tcl_DString *errorPtr));
@@ -343,25 +346,26 @@ TclpObjCopyFile(srcPathPtr, destPathPtr)
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(src, dst)
+DoCopyFile(src, dst, statBufPtr)
CONST char *src; /* Pathname of file to be copied (native). */
CONST char *dst; /* Pathname of file to copy to (native). */
+ CONST Tcl_StatBuf *statBufPtr;
+ /* Used to determine filetype. */
{
- Tcl_StatBuf srcStatBuf, dstStatBuf;
+ Tcl_StatBuf dstStatBuf;
- /*
- * Have to do a stat() to determine the filetype.
- */
-
- 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;
}
@@ -383,7 +387,7 @@ DoCopyFile(src, dst)
}
}
- switch ((int) (srcStatBuf.st_mode & S_IFMT)) {
+ switch ((int) (statBufPtr->st_mode & S_IFMT)) {
#ifndef DJGPP
case S_IFLNK: {
char link[MAXPATHLEN];
@@ -405,20 +409,20 @@ DoCopyFile(src, dst)
#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 CopyFile(src, dst, &srcStatBuf);
+ return CopyFile(src, dst, statBufPtr);
}
}
return TCL_OK;
@@ -832,9 +836,15 @@ TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr, doRewind)
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;
@@ -853,6 +863,7 @@ TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr, doRewind)
return (*traverseProc)(sourcePtr, targetPtr, &statBuf, DOTREE_F,
errorPtr);
}
+#ifndef HAVE_FTS
dirPtr = opendir(source); /* INTL: Native. */
if (dirPtr == NULL) {
/*
@@ -938,6 +949,74 @@ TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr, doRewind)
result = (*traverseProc)(sourcePtr, targetPtr, &statBuf, DOTREE_POSTD,
errorPtr);
}
+#else /* HAVE_FTS */
+ paths[0] = source;
+ fts = fts_open((char**)paths, FTS_PHYSICAL|FTS_NOCHDIR|
+#ifdef HAVE_STRUCT_STAT64
+ FTS_NOSTAT, /* fts doesn't do stat64 */
+#else
+ (doRewind ? FTS_NOSTAT : 0), /* no need to stat for delete */
+#endif
+ NULL);
+ 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;
+ Tcl_StatBuf *statBufPtr = NULL;
+
+ 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;
+ }
+ if (!doRewind) { /* no need to stat for delete */
+#ifdef HAVE_STRUCT_STAT64
+ statBufPtr = &statBuf;
+ if (TclOSlstat(ent->fts_path, statBufPtr) != 0) {
+ errfile = ent->fts_path;
+ break;
+ }
+#else
+ statBufPtr = ent->fts_statp;
+#endif
+ }
+ result = (*traverseProc)(sourcePtr, targetPtr, statBufPtr, type,
+ errorPtr);
+ if (result != TCL_OK) {
+ break;
+ }
+ Tcl_DStringSetLength(sourcePtr, sourceLen);
+ if (targetPtr != NULL) {
+ Tcl_DStringSetLength(targetPtr, targetLen);
+ }
+ }
+#endif /* HAVE_FTS */
+
end:
if (errfile != NULL) {
if (errorPtr != NULL) {
@@ -945,6 +1024,11 @@ TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr, doRewind)
}
result = TCL_ERROR;
}
+#ifdef HAVE_FTS
+ if (fts != NULL) {
+ fts_close(fts);
+ }
+#endif /* HAVE_FTS */
return result;
}
@@ -980,8 +1064,8 @@ TraversalCopy(srcPtr, dstPtr, statBufPtr, type, errorPtr)
{
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;