summaryrefslogtreecommitdiffstats
path: root/unix
diff options
context:
space:
mode:
authorhobbs <hobbs>2005-10-07 22:35:33 (GMT)
committerhobbs <hobbs>2005-10-07 22:35:33 (GMT)
commit98a6fcad96289a40b501fbd2095387a245fd804d (patch)
tree2c3ff8d55bb409730bc8811c577358f3ba743fb7 /unix
parent2a5ae89c4e4c6574518b806cb6e6586823450c5d (diff)
downloadtcl-98a6fcad96289a40b501fbd2095387a245fd804d.zip
tcl-98a6fcad96289a40b501fbd2095387a245fd804d.tar.gz
tcl-98a6fcad96289a40b501fbd2095387a245fd804d.tar.bz2
* unix/tclUnixFCmd.c (TraverseUnixTree): Adjust 2004-11-11 change tomsofer_wcodes_branch_20051007kennykb_numerics_branch_20051008
* tests/fCmd.test (fCmd-20.2): account for NFS special files with a readdir rewind threshold. [Bug 1034337]
Diffstat (limited to 'unix')
-rw-r--r--unix/tclUnixFCmd.c86
1 files changed, 52 insertions, 34 deletions
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);
/*