summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhobbs <hobbs>2005-10-07 22:35:02 (GMT)
committerhobbs <hobbs>2005-10-07 22:35:02 (GMT)
commitdae8beb32c6c48c608924febeac3c27ca52e9d67 (patch)
tree1f197d874c54a6b76fec21c3673615ff3afce740
parentc7476f19d45e568e5d766eda62807a5017b18687 (diff)
downloadtcl-dae8beb32c6c48c608924febeac3c27ca52e9d67.zip
tcl-dae8beb32c6c48c608924febeac3c27ca52e9d67.tar.gz
tcl-dae8beb32c6c48c608924febeac3c27ca52e9d67.tar.bz2
* 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]
-rw-r--r--ChangeLog6
-rw-r--r--tests/fCmd.test4
-rw-r--r--unix/tclUnixFCmd.c105
3 files changed, 69 insertions, 46 deletions
diff --git a/ChangeLog b/ChangeLog
index aaaa289..47f87eb 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 bb94d42..cb6d200 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.26.2.6 2004/11/25 11:31:31 rmax Exp $
+# RCS: @(#) $Id: fCmd.test,v 1.26.2.7 2005/10/07 22:35:03 hobbs Exp $
#
if {[lsearch [namespace children] ::tcltest] == -1} {
@@ -1833,7 +1833,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 a96291f..c600ff3 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.4 2005/01/10 11:21:51 dkf Exp $
+ * RCS: @(#) $Id: tclUnixFCmd.c,v 1.28.2.5 2005/10/07 22:35:03 hobbs Exp $
*
* Portions of this code were derived from NetBSD source code which has
* the following copyright notice:
@@ -124,6 +124,21 @@ CONST TclFileAttrProcs tclpFileAttrProcs[] = {
};
/*
+ * 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:
*/
@@ -476,7 +491,7 @@ CopyFile(src, dst, statBufPtr)
break;
}
}
-
+
ckfree(buffer);
close(srcFd);
if ((close(dstFd) != 0) || (nread == -1)) {
@@ -769,7 +784,7 @@ DoRemoveDirectory(pathPtr, recursive, errorPtr)
}
return result;
}
-
+
/*
*---------------------------------------------------------------------------
*
@@ -808,13 +823,13 @@ TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr, doRewind)
* loop should be rewound whenever
* traverseProc has returned TCL_OK; this is
* required when traverseProc modifies the
- * source hierarchy, e.g. by deleting files. */
+ * source hierarchy, e.g. by deleting files. */
{
Tcl_StatBuf statBuf;
CONST char *source, *errfile;
int result, sourceLen;
int targetLen;
- int needRewind;
+ int numProcessed = 0;
Tcl_DirEntry *dirEntPtr;
DIR *dirPtr;
@@ -850,56 +865,58 @@ TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr, doRewind)
closedir(dirPtr);
return result;
}
-
+
Tcl_DStringAppend(sourcePtr, "/", 1);
- sourceLen = Tcl_DStringLength(sourcePtr);
+ sourceLen = Tcl_DStringLength(sourcePtr);
if (targetPtr != NULL) {
Tcl_DStringAppend(targetPtr, "/", 1);
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;
- }
-
- /*
- * 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;
- }
-
+ 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) {
+ break;
+ } else {
+ numProcessed++;
+ }
+
+ /*
+ * Remove name after slash.
+ */
+
+ Tcl_DStringSetLength(sourcePtr, sourceLen);
+ if (targetPtr != NULL) {
+ Tcl_DStringSetLength(targetPtr, targetLen);
+ }
+ if (doRewind && (numProcessed > MAX_READDIR_UNLINK_THRESHOLD)) {
/*
- * Remove name after slash.
+ * 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.
*/
-
- Tcl_DStringSetLength(sourcePtr, sourceLen);
- if (targetPtr != NULL) {
- Tcl_DStringSetLength(targetPtr, targetLen);
- }
- }
- if (needRewind) {
rewinddir(dirPtr);
+ numProcessed = 0;
}
- } while (needRewind);
+ }
closedir(dirPtr);
-
+
/*
* Strip off the trailing slash we added
*/
@@ -925,7 +942,7 @@ TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr, doRewind)
}
result = TCL_ERROR;
}
-
+
return result;
}