summaryrefslogtreecommitdiff
path: root/Src/Modules
diff options
context:
space:
mode:
authorRoman Perepelitsa <roman.perepelitsa@gmail.com>2020-10-23 11:42:30 +0200
committerRoman Perepelitsa <roman.perepelitsa@gmail.com>2020-10-23 11:42:30 +0200
commitead29c2a366eb2c5006d7da64963ce5f60deb684 (patch)
tree56aa0a70daa5384b386f00e937e7b42ee4c6f929 /Src/Modules
parentda534770fd5c8022e90eff5cf4c993d60e3c56f7 (diff)
downloadzsh-ead29c2a366eb2c5006d7da64963ce5f60deb684.tar.gz
zsh-ead29c2a366eb2c5006d7da64963ce5f60deb684.zip
Fix a race condition in zf_mkdir -p
If ~/foo does not exist and `zf_mkdir -p zf_mkdir -p` is executed concurrently in multiple shells, it was possible prior to this patch for the command to fail with EEXIST.
Diffstat (limited to 'Src/Modules')
-rw-r--r--Src/Modules/files.c28
1 files changed, 19 insertions, 9 deletions
diff --git a/Src/Modules/files.c b/Src/Modules/files.c
index 6d20e38a8..7ebacba6c 100644
--- a/Src/Modules/files.c
+++ b/Src/Modules/files.c
@@ -122,19 +122,29 @@ domkdir(char *nam, char *path, mode_t mode, int p)
{
int err;
mode_t oumask;
+ struct stat st;
+ int n = 8;
char const *rpath = unmeta(path);
- if(p) {
- struct stat st;
-
- if(!stat(rpath, &st) && S_ISDIR(st.st_mode))
+ while(n-- > 0) {
+ oumask = umask(0);
+ err = mkdir(rpath, mode) ? errno : 0;
+ umask(oumask);
+ if (!err)
+ return 0;
+ if(!p || err != EEXIST)
+ break;
+ if(stat(rpath, &st)) {
+ if(errno == ENOENT)
+ continue;
+ err = errno;
+ break;
+ }
+ if(S_ISDIR(st.st_mode))
return 0;
+ break;
}
- oumask = umask(0);
- err = mkdir(rpath, mode) ? errno : 0;
- umask(oumask);
- if(!err)
- return 0;
+
zwarnnam(nam, "cannot make directory `%s': %e", path, err);
return 1;
}