summaryrefslogtreecommitdiffstats
path: root/generic/tclFCmd.c
diff options
context:
space:
mode:
authorkjnash <k.j.nash@usa.net>2018-09-15 18:41:23 (GMT)
committerkjnash <k.j.nash@usa.net>2018-09-15 18:41:23 (GMT)
commitd24a3eb2babc2868c7935f0815288c9ab02c3880 (patch)
tree2ee6809fdc6448db53cbd12bb6e35df4fe077503 /generic/tclFCmd.c
parent754bb107b4100f394d445d589dddc94e59dd2d04 (diff)
parent9a15a1b58648809ffb208eaa00cd20af4784050d (diff)
downloadtcl-d24a3eb2babc2868c7935f0815288c9ab02c3880.zip
tcl-d24a3eb2babc2868c7935f0815288c9ab02c3880.tar.gz
tcl-d24a3eb2babc2868c7935f0815288c9ab02c3880.tar.bz2
merge 8.6
Diffstat (limited to 'generic/tclFCmd.c')
-rw-r--r--generic/tclFCmd.c54
1 files changed, 30 insertions, 24 deletions
diff --git a/generic/tclFCmd.c b/generic/tclFCmd.c
index bb814ea..fda2940 100644
--- a/generic/tclFCmd.c
+++ b/generic/tclFCmd.c
@@ -240,9 +240,13 @@ TclFileMakeDirsCmd(
break;
}
for (j = 0; j < pobjc; j++) {
+ int errCount = 2;
+
target = Tcl_FSJoinPath(split, j + 1);
Tcl_IncrRefCount(target);
+ createDir:
+
/*
* Call Tcl_FSStat() so that if target is a symlink that points to
* a directory we will create subdirectories in that directory.
@@ -269,23 +273,25 @@ TclFileMakeDirsCmd(
* subdirectory.
*/
- if (errno != EEXIST) {
- errfile = target;
- goto done;
- } else if ((Tcl_FSStat(target, &statBuf) == 0)
- && S_ISDIR(statBuf.st_mode)) {
- /*
- * It is a directory that wasn't there before, so keep
- * going without error.
- */
-
- Tcl_ResetResult(interp);
- } else {
- errfile = target;
- goto done;
+ if (errno == EEXIST) {
+ /* Be aware other workers could delete it immediately after
+ * creation, so give this worker still one chance (repeat once),
+ * see [270f78ca95] for description of the race-condition.
+ * Don't repeat the create always (to avoid endless loop). */
+ if (--errCount > 0) {
+ goto createDir;
+ }
+ /* Already tried, with delete in-between directly after
+ * creation, so just continue (assume created successful). */
+ goto nextPart;
}
+
+ /* return with error */
+ errfile = target;
+ goto done;
}
+ nextPart:
/*
* Forget about this sub-path.
*/
@@ -363,14 +369,7 @@ TclFileDeleteCmd(
*/
if (Tcl_FSLstat(objv[i], &statBuf) != 0) {
- /*
- * Trying to delete a file that does not exist is not considered
- * an error, just a no-op
- */
-
- if (errno != ENOENT) {
- result = TCL_ERROR;
- }
+ result = TCL_ERROR;
} else if (S_ISDIR(statBuf.st_mode)) {
/*
* We own a reference count on errorBuffer, if it was set as a
@@ -406,13 +405,20 @@ TclFileDeleteCmd(
}
if (result != TCL_OK) {
- result = TCL_ERROR;
/*
+ * Avoid possible race condition (file/directory deleted after call
+ * of lstat), so bypass ENOENT because not an error, just a no-op
+ */
+ if (errno == ENOENT) {
+ result = TCL_OK;
+ continue;
+ }
+ /*
* It is important that we break on error, otherwise we might end
* up owning reference counts on numerous errorBuffers.
*/
-
+ result = TCL_ERROR;
break;
}
}