diff options
| author | hobbs <hobbs> | 2005-10-07 22:35:02 (GMT) | 
|---|---|---|
| committer | hobbs <hobbs> | 2005-10-07 22:35:02 (GMT) | 
| commit | dae8beb32c6c48c608924febeac3c27ca52e9d67 (patch) | |
| tree | 1f197d874c54a6b76fec21c3673615ff3afce740 /unix/tclUnixFCmd.c | |
| parent | c7476f19d45e568e5d766eda62807a5017b18687 (diff) | |
| download | tcl-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]
Diffstat (limited to 'unix/tclUnixFCmd.c')
| -rw-r--r-- | unix/tclUnixFCmd.c | 105 | 
1 files changed, 61 insertions, 44 deletions
| 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;  } | 
