diff options
author | das <das> | 2004-11-11 01:15:29 (GMT) |
---|---|---|
committer | das <das> | 2004-11-11 01:15:29 (GMT) |
commit | 70c7763d03734b6a1bca07c431abc928cb7bff8a (patch) | |
tree | cf50bdc7f2686f6ac20a0fc3bf2ff63a3ff825b4 /unix | |
parent | 89675228f03f60dc605bc085eaa2ac337dcfef01 (diff) | |
download | tcl-70c7763d03734b6a1bca07c431abc928cb7bff8a.zip tcl-70c7763d03734b6a1bca07c431abc928cb7bff8a.tar.gz tcl-70c7763d03734b6a1bca07c431abc928cb7bff8a.tar.bz2 |
* tests/fCmd.test:
* unix/tclUnixFCmd.c (TraverseUnixTree): added option to rewind()
the readdir() loop whenever the source hierarchy has been modified
by traverseProc (e.g. by deleting files); this is required to ensure
complete traversal of the source hierarchy on certain filesystems
like HFS+. Added test for failing recursive delete on Mac OS X that
was due to this. [Bug 1034337]
Diffstat (limited to 'unix')
-rw-r--r-- | unix/tclUnixFCmd.c | 82 |
1 files changed, 49 insertions, 33 deletions
diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c index a439511..9d709e6 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.2 2003/10/03 17:45:37 vincentdarley Exp $ + * RCS: @(#) $Id: tclUnixFCmd.c,v 1.28.2.3 2004/11/11 01:15:29 das Exp $ * * Portions of this code were derived from NetBSD source code which has * the following copyright notice: @@ -147,7 +147,7 @@ static int TraversalDelete _ANSI_ARGS_((Tcl_DString *srcPtr, static int TraverseUnixTree _ANSI_ARGS_(( TraversalProc *traversalProc, Tcl_DString *sourcePtr, Tcl_DString *destPtr, - Tcl_DString *errorPtr)); + Tcl_DString *errorPtr, int doRewind)); #ifdef PURIFY /* @@ -641,7 +641,7 @@ TclpObjCopyDirectory(srcPathPtr, destPathPtr, errorPtr) Tcl_DecrRefCount(transPtr); } - ret = TraverseUnixTree(TraversalCopy, &srcString, &dstString, &ds); + ret = TraverseUnixTree(TraversalCopy, &srcString, &dstString, &ds, 0); Tcl_DStringFree(&srcString); Tcl_DStringFree(&dstString); @@ -760,7 +760,7 @@ DoRemoveDirectory(pathPtr, recursive, errorPtr) */ if (result == TCL_OK) { - result = TraverseUnixTree(TraversalDelete, pathPtr, NULL, errorPtr); + result = TraverseUnixTree(TraversalDelete, pathPtr, NULL, errorPtr, 1); } if ((result != TCL_OK) && (recursive != 0)) { @@ -793,7 +793,7 @@ DoRemoveDirectory(pathPtr, recursive, errorPtr) */ static int -TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr) +TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr, doRewind) TraversalProc *traverseProc;/* Function to call for every file and * directory in source hierarchy. */ Tcl_DString *sourcePtr; /* Pathname of source directory to be @@ -803,11 +803,18 @@ TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr) Tcl_DString *errorPtr; /* If non-NULL, uninitialized or free * DString filled with UTF-8 name of file * causing error. */ + int doRewind; /* Flag indicating that to ensure complete + * traversal of source hierarchy, the readdir + * loop should be rewound whenever + * traverseProc has returned TCL_OK; this is + * required when traverseProc modifies the + * source hierarchy, e.g. by deleting files. */ { Tcl_StatBuf statBuf; CONST char *source, *errfile; int result, sourceLen; int targetLen; + int needRewind; Tcl_DirEntry *dirEntPtr; DIR *dirPtr; @@ -852,36 +859,45 @@ TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr) targetLen = Tcl_DStringLength(targetPtr); } - while ((dirEntPtr = TclOSreaddir(dirPtr)) != NULL) { /* INTL: Native. */ - if ((dirEntPtr->d_name[0] == '.') - && ((dirEntPtr->d_name[1] == '\0') - || (strcmp(dirEntPtr->d_name, "..") == 0))) { - continue; - } - - /* - * Append name after slash, and recurse on the file. - */ - - Tcl_DStringAppend(sourcePtr, dirEntPtr->d_name, -1); - if (targetPtr != NULL) { - Tcl_DStringAppend(targetPtr, dirEntPtr->d_name, -1); - } - result = TraverseUnixTree(traverseProc, sourcePtr, targetPtr, - errorPtr); - if (result != TCL_OK) { - break; + do { + needRewind = 0; + while ((dirEntPtr = TclOSreaddir(dirPtr)) != NULL) { /* INTL: Native. */ + if ((dirEntPtr->d_name[0] == '.') + && ((dirEntPtr->d_name[1] == '\0') + || (strcmp(dirEntPtr->d_name, "..") == 0))) { + continue; + } + + /* + * Append name after slash, and recurse on the file. + */ + + Tcl_DStringAppend(sourcePtr, dirEntPtr->d_name, -1); + if (targetPtr != NULL) { + Tcl_DStringAppend(targetPtr, dirEntPtr->d_name, -1); + } + result = TraverseUnixTree(traverseProc, sourcePtr, targetPtr, + errorPtr, doRewind); + if (result != TCL_OK) { + needRewind = 0; + break; + } else { + needRewind = doRewind; + } + + /* + * Remove name after slash. + */ + + Tcl_DStringSetLength(sourcePtr, sourceLen); + if (targetPtr != NULL) { + Tcl_DStringSetLength(targetPtr, targetLen); + } } - - /* - * Remove name after slash. - */ - - Tcl_DStringSetLength(sourcePtr, sourceLen); - if (targetPtr != NULL) { - Tcl_DStringSetLength(targetPtr, targetLen); + if (needRewind) { + rewinddir(dirPtr); } - } + } while (needRewind); closedir(dirPtr); /* |