summaryrefslogtreecommitdiffstats
path: root/generic/tclFCmd.c
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2018-07-09 17:18:07 (GMT)
committersebres <sebres@users.sourceforge.net>2018-07-09 17:18:07 (GMT)
commit41357f3f164a23a88a3eaa823988f9b199c34f99 (patch)
tree83f70d64c740daedd9b6be4ed149ee601336e37a /generic/tclFCmd.c
parent09684119211aab8e5202b680549e6e1608254587 (diff)
downloadtcl-41357f3f164a23a88a3eaa823988f9b199c34f99.zip
tcl-41357f3f164a23a88a3eaa823988f9b199c34f99.tar.gz
tcl-41357f3f164a23a88a3eaa823988f9b199c34f99.tar.bz2
closes [270f78ca95b642fb]: fix the race condition for `file mkdir` if some worker deletes directory immediately after the succeded create inside 3rd worker.
Diffstat (limited to 'generic/tclFCmd.c')
-rw-r--r--generic/tclFCmd.c32
1 files changed, 18 insertions, 14 deletions
diff --git a/generic/tclFCmd.c b/generic/tclFCmd.c
index 1363829..da15262 100644
--- a/generic/tclFCmd.c
+++ b/generic/tclFCmd.c
@@ -243,9 +243,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.
@@ -273,24 +277,24 @@ TclFileMakeDirsCmd(
*/
if (errno == EEXIST) {
- 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;
+ /* 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;
}
- } else {
- errfile = target;
- goto done;
+ /* 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.
*/