summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--tests/fCmd.test4
-rw-r--r--unix/tclUnixFCmd.c86
3 files changed, 60 insertions, 36 deletions
diff --git a/ChangeLog b/ChangeLog
index b9b6e91..659563e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2005-10-07 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * unix/tclUnixFCmd.c (TraverseUnixTree): Adjust 2004-11-11 change to
+ * tests/fCmd.test (fCmd-20.2): account for NFS special
+ files with a readdir rewind threshold. [Bug 1034337]
+
2005-10-05 Andreas Kupries <andreask@activestate.com>
* generic/tclPipe.c (TclCreatePipeline): Fixed [SF Tcl Bug
diff --git a/tests/fCmd.test b/tests/fCmd.test
index 4ba7034..bc7b550 100644
--- a/tests/fCmd.test
+++ b/tests/fCmd.test
@@ -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: fCmd.test,v 1.46 2005/05/10 18:35:19 kennykb Exp $
+# RCS: @(#) $Id: fCmd.test,v 1.47 2005/10/07 22:35:33 hobbs Exp $
#
if {[lsearch [namespace children] ::tcltest] == -1} {
@@ -1766,7 +1766,7 @@ test fCmd-20.2 {TraverseUnixTree : recursive delete of large directory: Bug 1034
{unix notRoot} {
catch {file delete -force -- tfa}
file mkdir tfa
- for {set i 1} {$i <= 200} {incr i} {createfile tfa/testfile_$i}
+ for {set i 1} {$i <= 300} {incr i} {createfile tfa/testfile_$i}
set result [catch {file delete -force tfa} msg]
while {[catch {file delete -force tfa}]} {}
list $result $msg
diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c
index 4105544..a80df2c 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.45 2005/09/15 16:40:03 dgp Exp $
+ * RCS: @(#) $Id: tclUnixFCmd.c,v 1.46 2005/10/07 22:35:33 hobbs Exp $
*
* Portions of this code were derived from NetBSD source code which has the
* following copyright notice:
@@ -162,6 +162,22 @@ CONST TclFileAttrProcs tclpFileAttrProcs[] = {
#endif
};
#endif
+
+/*
+ * This is the maximum number of consecutive readdir/unlink calls that can be
+ * made (with no intervening rewinddir or closedir/opendir) before triggering
+ * a bug that makes readdir return NULL even though some directory entries
+ * have not been processed. The bug afflicts SunOS's readdir when applied to
+ * ufs file systems and Darwin 6.5's (and OSX v.10.3.8's) HFS+. JH found the
+ * Darwin readdir to reset at 172, so 150 is chosen to be conservative. We
+ * can't do a general rewind on failure as NFS can create special files that
+ * recreate themselves when you try and delete them. 8.4.8 added a solution
+ * that was affected by a single such NFS file, this solution should not be
+ * affected by less than THRESHOLD such files. [Bug 1034337]
+ */
+
+#define MAX_READDIR_UNLINK_THRESHOLD 150
+
/*
* Declarations for local procedures defined in this file:
*/
@@ -864,7 +880,7 @@ TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr, doRewind)
CONST char *source, *errfile;
int result, sourceLen;
int targetLen;
- int needRewind;
+ int numProcessed = 0;
Tcl_DirEntry *dirEntPtr;
DIR *dirPtr;
@@ -909,45 +925,47 @@ TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr, doRewind)
targetLen = Tcl_DStringLength(targetPtr);
}
- 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;
- }
+ 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.
- */
+ /*
+ * 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;
- }
+ 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) {
+ break;
+ } else {
+ numProcessed++;
+ }
- /*
- * Remove name after slash.
- */
+ /*
+ * Remove name after slash.
+ */
- Tcl_DStringSetLength(sourcePtr, sourceLen);
- if (targetPtr != NULL) {
- Tcl_DStringSetLength(targetPtr, targetLen);
- }
+ Tcl_DStringSetLength(sourcePtr, sourceLen);
+ if (targetPtr != NULL) {
+ Tcl_DStringSetLength(targetPtr, targetLen);
}
- if (needRewind) {
+ if (doRewind && (numProcessed > MAX_READDIR_UNLINK_THRESHOLD)) {
+ /*
+ * Call rewinddir if we've called unlink or rmdir so many times
+ * (since the opendir or the previous rewinddir), to avoid
+ * a NULL-return that may a symptom of a buggy readdir.
+ */
rewinddir(dirPtr);
+ numProcessed = 0;
}
- } while (needRewind);
+ }
closedir(dirPtr);
/*