Tcl Source Code

Artifact [fc1e2a1ea1]
Login

Artifact fc1e2a1ea1a70c2c242cd631cc2e88089d55e11d:

Attachment "1034337-core-8-4-branch.diff" to ticket [1034337fff] added by das 2004-11-11 08:27:53.
Index: tests/fCmd.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/fCmd.test,v
retrieving revision 1.26.2.4
diff -u -p -r1.26.2.4 fCmd.test
--- tests/fCmd.test	7 Oct 2003 15:57:36 -0000	1.26.2.4
+++ tests/fCmd.test	9 Nov 2004 19:12:16 -0000
@@ -1829,6 +1829,15 @@ test fCmd-20.1 {TraverseUnixTree : failu
     set result
 } {1}
 
+test fCmd-20.2 {TraverseUnixTree : recursive delete of large directory: Bug 1034337} \
+	{unix notRoot} {
+    catch {file delete -force -- tfa}
+    file mkdir tfa
+    for {set i 1} {$i <= 200} {incr i} {createfile tfa/testfile_$i}
+    set result [catch {file delete -force tfa} msg]
+    while {[catch {file delete -force tfa}]} {}
+    list $result $msg
+} {0 {}}
 
 #
 # Feature testing for TclCopyFilesCmd
Index: unix/tclUnixFCmd.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixFCmd.c,v
retrieving revision 1.28.2.2
diff -u -p -r1.28.2.2 tclUnixFCmd.c
--- unix/tclUnixFCmd.c	3 Oct 2003 17:45:37 -0000	1.28.2.2
+++ unix/tclUnixFCmd.c	9 Nov 2004 19:12:16 -0000
@@ -147,7 +147,7 @@ static int		TraversalDelete _ANSI_ARGS_(
 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, destPat
 	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, er
      */
 
     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, er
  */
 
 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
     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
 	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);
     
     /*